!1454 Support transfer custom native object

Merge pull request !1454 from wangzhaoyong/master
This commit is contained in:
openharmony_ci 2022-06-07 11:51:17 +00:00 committed by Gitee
commit 267f0a20ac
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
8 changed files with 162 additions and 6 deletions

View File

@ -589,6 +589,10 @@ void Builtins::InitializeSymbol(const JSHandle<GlobalEnv> &env, const JSHandle<J
SetNoneAttributeProperty(symbolFunction, "toPrimitive", toPrimitiveSymbol);
JSHandle<JSTaggedValue> unscopablesSymbol(factory_->NewPublicSymbolWithChar("Symbol.unscopables"));
SetNoneAttributeProperty(symbolFunction, "unscopables", unscopablesSymbol);
JSHandle<JSTaggedValue> attachSymbol(factory_->NewPublicSymbolWithChar("Symbol.attach"));
SetNoneAttributeProperty(symbolFunction, "attach", attachSymbol);
JSHandle<JSTaggedValue> detachSymbol(factory_->NewPublicSymbolWithChar("Symbol.detach"));
SetNoneAttributeProperty(symbolFunction, "detach", detachSymbol);
// symbol.prototype.description
PropertyDescriptor descriptionDesc(thread_);
@ -618,6 +622,8 @@ void Builtins::InitializeSymbol(const JSHandle<GlobalEnv> &env, const JSHandle<J
env->SetSplitSymbol(thread_, splitSymbol);
env->SetToPrimitiveSymbol(thread_, toPrimitiveSymbol);
env->SetUnscopablesSymbol(thread_, unscopablesSymbol);
env->SetAttachSymbol(thread_, attachSymbol);
env->SetDetachSymbol(thread_, detachSymbol);
// Setup %SymbolPrototype%
SetStringTagSymbol(env, symbolFuncPrototype, "Symbol");
@ -673,6 +679,8 @@ void Builtins::InitializeSymbolWithRealm(const JSHandle<GlobalEnv> &realm,
SetNoneAttributeProperty(symbolFunction, "split", env->GetSplitSymbol());
SetNoneAttributeProperty(symbolFunction, "toPrimitive", env->GetToPrimitiveSymbol());
SetNoneAttributeProperty(symbolFunction, "unscopables", env->GetUnscopablesSymbol());
SetNoneAttributeProperty(symbolFunction, "attach", env->GetAttachSymbol());
SetNoneAttributeProperty(symbolFunction, "detach", env->GetDetachSymbol());
// symbol.prototype.description
PropertyDescriptor descriptionDesc(thread_);
@ -703,6 +711,8 @@ void Builtins::InitializeSymbolWithRealm(const JSHandle<GlobalEnv> &realm,
realm->SetSplitSymbol(thread_, env->GetSplitSymbol());
realm->SetToPrimitiveSymbol(thread_, env->GetToPrimitiveSymbol());
realm->SetUnscopablesSymbol(thread_, env->GetUnscopablesSymbol());
realm->SetAttachSymbol(thread_, env->GetAttachSymbol());
realm->SetDetachSymbol(thread_, env->GetDetachSymbol());
// Setup %SymbolPrototype%
SetStringTagSymbol(realm, symbolFuncPrototype, "Symbol");

View File

@ -1967,6 +1967,10 @@ void GlobalEnv::Dump(std::ostream &os) const
GetUnscopablesSymbol().GetTaggedValue().Dump(os);
os << " - HoleySymbol: ";
GetHoleySymbol().GetTaggedValue().Dump(os);
os << " - AttachSymbol: ";
GetAttachSymbol().GetTaggedValue().Dump(os);
os << " - DetachSymbol: ";
GetDetachSymbol().GetTaggedValue().Dump(os);
os << " - ConstructorString: ";
globalConst->GetConstructorString().Dump(os);
os << " - IteratorPrototype: ";
@ -3892,6 +3896,8 @@ void GlobalEnv::DumpForSnapshot(std::vector<std::pair<CString, JSTaggedValue>> &
vec.push_back(std::make_pair(CString("ToPrimitiveSymbol"), GetToPrimitiveSymbol().GetTaggedValue()));
vec.push_back(std::make_pair(CString("UnscopablesSymbol"), GetUnscopablesSymbol().GetTaggedValue()));
vec.push_back(std::make_pair(CString("HoleySymbol"), GetHoleySymbol().GetTaggedValue()));
vec.push_back(std::make_pair(CString("AttachSymbol"), GetAttachSymbol().GetTaggedValue()));
vec.push_back(std::make_pair(CString("DetachSymbol"), GetDetachSymbol().GetTaggedValue()));
vec.push_back(std::make_pair(CString("ConstructorString"), globalConst->GetConstructorString()));
vec.push_back(std::make_pair(CString("IteratorPrototype"), GetIteratorPrototype().GetTaggedValue()));
vec.push_back(std::make_pair(CString("ForinIteratorPrototype"), GetForinIteratorPrototype().GetTaggedValue()));

View File

@ -150,7 +150,9 @@ class JSThread;
V(JSTaggedValue, ModuleNamespaceClass, MODULENAMESPACE_CLASS) \
V(JSTaggedValue, ObjectLiteralHClassCache, OBJECT_LITERAL_HCLASS_CACHE) \
V(JSTaggedValue, WeakRefKeepObjects, WEAK_REF_KEEP_OBJECTS) \
V(JSTaggedValue, FinRegLists, FIN_REG_LISTS)
V(JSTaggedValue, FinRegLists, FIN_REG_LISTS) \
V(JSTaggedValue, AttachSymbol, ATTACH_SYMBOL_INDEX) \
V(JSTaggedValue, DetachSymbol, DETACH_SYMBOL_INDEX)
class GlobalEnv : public TaggedObject {
public:

View File

@ -664,6 +664,16 @@ bool JSSerializer::WritePlainObject(const JSHandle<JSTaggedValue> &objValue)
{
JSHandle<JSObject> obj = JSHandle<JSObject>::Cast(objValue);
size_t oldSize = bufferSize_;
std::vector<JSTaggedValue> keyVector;
uint32_t propertiesLength = obj->GetNumberOfKeys();
JSObject::GetAllKeys(thread_, obj, keyVector);
if (keyVector.size() != propertiesLength) {
return false;
}
if (keyVector.size() >= 2 && (keyVector[0].IsSymbol() && keyVector[1].IsSymbol())) { // 2:attachSymbol, detachSymbol
return WriteNativeObject(objValue, keyVector);
}
if (!WriteType(SerializationUID::JS_PLAIN_OBJECT)) {
return false;
}
@ -673,7 +683,7 @@ bool JSSerializer::WritePlainObject(const JSHandle<JSTaggedValue> &objValue)
bufferSize_ = oldSize;
return false;
}
std::vector<JSTaggedValue> keyVector;
keyVector.clear();
JSObject::GetALLElementKeysIntoVector(thread_, obj, keyVector);
// Write elements' description attributes and value
if (keyVector.size() != elementsLength) {
@ -700,7 +710,6 @@ bool JSSerializer::WritePlainObject(const JSHandle<JSTaggedValue> &objValue)
}
// Get the number of k-v form properties stored in obj
keyVector.clear();
uint32_t propertiesLength = obj->GetNumberOfKeys();
if (!WriteInt(static_cast<int32_t>(propertiesLength))) {
bufferSize_ = oldSize;
return false;
@ -736,6 +745,65 @@ bool JSSerializer::WritePlainObject(const JSHandle<JSTaggedValue> &objValue)
return true;
}
bool JSSerializer::WriteNativeObject(const JSHandle<JSTaggedValue> &objValue, std::vector<JSTaggedValue> keyVector)
{
JSHandle<JSObject> obj = JSHandle<JSObject>::Cast(objValue);
size_t oldSize = bufferSize_;
JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> detach = env->GetDetachSymbol();
JSHandle<JSTaggedValue> attach = env->GetAttachSymbol();
if (!(JSTaggedValue::Equal(thread_, detach, JSHandle<JSTaggedValue>(thread_, keyVector[0]))) ||
!(JSTaggedValue::Equal(thread_, attach, JSHandle<JSTaggedValue>(thread_, keyVector[1])))) {
return false;
}
if (!WriteType(SerializationUID::JS_NATIVE_OBJECT)) {
return false;
}
// Write custom object's values: AttachFunc*, buffer*
JSHandle<JSTaggedValue> detachVal = JSObject::GetProperty(thread_, obj, detach).GetRawValue();
JSHandle<JSTaggedValue> attackVal = JSObject::GetProperty(thread_, obj, attach).GetRawValue();
DetachFunc detachNative = reinterpret_cast<DetachFunc>(JSNativePointer::Cast(
detachVal.GetTaggedValue().GetTaggedObject())->GetExternalPointer());
void *buffer = detachNative();
AttachFunc attachNative = reinterpret_cast<AttachFunc>(JSNativePointer::Cast(
attackVal.GetTaggedValue().GetTaggedObject())->GetExternalPointer());
if (!WriteRawData(&attachNative, sizeof(uintptr_t))) {
bufferSize_ = oldSize;
return false;
}
if (!WriteRawData(&buffer, sizeof(uintptr_t))) {
bufferSize_ = oldSize;
return false;
}
if (keyVector.size() > 2) { // 2:attachSymbol, detachSymbol
uint32_t propertiesLength = keyVector.size() - 2;
if (!WriteInt(static_cast<int32_t>(propertiesLength))) {
bufferSize_ = oldSize;
return false;
}
// Write keys' description attributes and related values
for (uint32_t i = 0; i < propertiesLength; i++) {
JSMutableHandle<JSTaggedValue> key(thread_, keyVector[i + 2]); // 2:attachSymbol, detachSymbol
if (!SerializeJSTaggedValue(key)) {
bufferSize_ = oldSize;
return false;
}
PropertyDescriptor desc(thread_);
JSObject::OrdinaryGetOwnProperty(thread_, obj, key, desc);
if (!WriteDesc(desc)) {
bufferSize_ = oldSize;
return false;
}
JSHandle<JSTaggedValue> value = desc.GetValue();
if (!SerializeJSTaggedValue(value)) {
bufferSize_ = oldSize;
return false;
}
}
}
return true;
}
bool JSSerializer::WriteDesc(const PropertyDescriptor &desc)
{
size_t oldSize = bufferSize_;
@ -874,6 +942,8 @@ JSHandle<JSTaggedValue> JSDeserializer::DeserializeJSTaggedValue()
return ReadJSDate();
case SerializationUID::JS_PLAIN_OBJECT:
return ReadPlainObject();
case SerializationUID::JS_NATIVE_OBJECT:
return ReadNativeObject();
case SerializationUID::JS_ARRAY:
return ReadJSArray();
case SerializationUID::ECMASTRING:
@ -1045,6 +1115,52 @@ JSHandle<JSTaggedValue> JSDeserializer::ReadPlainObject()
return objTag;
}
JSHandle<JSTaggedValue> JSDeserializer::ReadNativeObject()
{
JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();
JSHandle<JSTaggedValue> objFunc = env->GetObjectFunction();
JSHandle<JSObject> jsObject =
thread_->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle<JSFunction>(objFunc), objFunc);
JSHandle<JSTaggedValue> objTag(jsObject);
referenceMap_.insert(std::pair(objectId_++, objTag));
JSTaggedValue pointer;
if (!ReadJSTaggedValue(&pointer)) {
return JSHandle<JSTaggedValue>();
}
AttachFunc attachFunc = reinterpret_cast<AttachFunc>(JSNativePointer::Cast(pointer.GetTaggedObject()));
JSTaggedValue bufferPointer;
if (!ReadJSTaggedValue(&bufferPointer)) {
return JSHandle<JSTaggedValue>();
}
void *buffer = reinterpret_cast<void *>(JSNativePointer::Cast(bufferPointer.GetTaggedObject()));
attachFunc(buffer);
int32_t propertyLength;
if (!JudgeType(SerializationUID::INT32) || !ReadInt(&propertyLength)) {
return objTag;
}
for (int32_t i = 0; i < propertyLength; i++) {
JSHandle<JSTaggedValue> key = DeserializeJSTaggedValue();
if (key.IsEmpty()) {
return JSHandle<JSTaggedValue>();
}
PropertyDescriptor desc(thread_);
if (!ReadDesc(&desc)) {
return JSHandle<JSTaggedValue>();
}
JSHandle<JSTaggedValue> value = DeserializeJSTaggedValue();
if (value.IsEmpty()) {
return JSHandle<JSTaggedValue>();
}
desc.SetValue(value);
if (!JSTaggedValue::DefineOwnProperty(thread_, objTag, key, desc)) {
return JSHandle<JSTaggedValue>();
}
}
return objTag;
}
JSHandle<JSTaggedValue> JSDeserializer::ReadJSMap()
{
JSHandle<GlobalEnv> env = thread_->GetEcmaVM()->GetGlobalEnv();

View File

@ -28,6 +28,9 @@
#include "ecmascript/mem/dyn_chunk.h"
namespace panda::ecmascript {
typedef void* (*DetachFunc)(void);
typedef void (*AttachFunc)(void* buffer);
enum class SerializationUID : uint8_t {
// JS special values
JS_NULL = 0x01,
@ -50,6 +53,7 @@ enum class SerializationUID : uint8_t {
JS_DATE,
JS_REG_EXP,
JS_PLAIN_OBJECT,
JS_NATIVE_OBJECT,
JS_SET,
JS_MAP,
JS_ARRAY,
@ -113,6 +117,7 @@ private:
bool WriteEcmaString(const JSHandle<JSTaggedValue> &value);
bool WriteJSTypedArray(const JSHandle<JSTaggedValue> &value, SerializationUID uId);
bool WritePlainObject(const JSHandle<JSTaggedValue> &value);
bool WriteNativeObject(const JSHandle<JSTaggedValue> &value, std::vector<JSTaggedValue> keyVector);
bool WriteNativeFunctionPointer(const JSHandle<JSTaggedValue> &value);
bool WriteJSArrayBuffer(const JSHandle<JSTaggedValue> &value);
bool WriteDesc(const PropertyDescriptor &desc);
@ -160,6 +165,7 @@ private:
JSHandle<JSTaggedValue> ReadNativeFunctionPointer();
JSHandle<JSTaggedValue> ReadJSArrayBuffer();
JSHandle<JSTaggedValue> ReadReference();
JSHandle<JSTaggedValue> ReadNativeObject();
bool JudgeType(SerializationUID targetUid);
void *GetBuffer(uint32_t bufferSize);
bool ReadJSTaggedValue(JSTaggedValue *originalFlags);

View File

@ -72,12 +72,10 @@ void LayoutInfo::GetAllKeys(const JSThread *thread, int end, int offset, TaggedA
void LayoutInfo::GetAllKeys([[maybe_unused]] const JSThread *thread, int end, std::vector<JSTaggedValue> &keyVector)
{
ASSERT(end <= NumberOfElements());
int enumKeys = 0;
for (int i = 0; i < end; i++) {
JSTaggedValue key = GetKey(i);
if (key.IsString()) {
if (key.IsString() || key.IsSymbol()) {
keyVector.emplace_back(key);
enumKeys++;
}
}
}

View File

@ -669,6 +669,7 @@ public:
return static_cast<ObjectRef *>(value);
}
static Local<ObjectRef> New(const EcmaVM *vm);
static Local<ObjectRef> New(const EcmaVM *vm, void *attach, void *detach);
bool Set(const EcmaVM *vm, Local<JSValueRef> key, Local<JSValueRef> value);
bool Set(const EcmaVM *vm, uint32_t key, Local<JSValueRef> value);
bool SetAccessorProperty(const EcmaVM *vm, Local<JSValueRef> key, Local<FunctionRef> getter,

View File

@ -741,6 +741,23 @@ Local<ObjectRef> ObjectRef::New(const EcmaVM *vm)
return JSNApiHelper::ToLocal<ObjectRef>(object);
}
Local<ObjectRef> ObjectRef::New(const EcmaVM *vm, void *detach, void *attach)
{
ObjectFactory *factory = vm->GetFactory();
JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
JSHandle<JSTaggedValue> constructor = env->GetObjectFunction();
JSHandle<JSTaggedValue> object(factory->NewJSObjectByConstructor(JSHandle<JSFunction>(constructor), constructor));
JSHandle<JSTaggedValue> detachKey = env->GetDetachSymbol();
JSHandle<JSTaggedValue> attachKey = env->GetAttachSymbol();
JSHandle<JSTaggedValue> detachValue = JSNApiHelper::ToJSHandle(NativePointerRef::New(vm, detach));
JSHandle<JSTaggedValue> attachValue = JSNApiHelper::ToJSHandle(NativePointerRef::New(vm, attach));
JSTaggedValue::SetProperty(vm->GetJSThread(), object, detachKey, detachValue);
RETURN_VALUE_IF_ABRUPT(vm->GetJSThread(), JSValueRef::Exception(vm));
JSTaggedValue::SetProperty(vm->GetJSThread(), object, attachKey, attachValue);
RETURN_VALUE_IF_ABRUPT(vm->GetJSThread(), JSValueRef::Exception(vm));
return JSNApiHelper::ToLocal<ObjectRef>(object);
}
bool ObjectRef::Set(const EcmaVM *vm, Local<JSValueRef> key, Local<JSValueRef> value)
{
[[maybe_unused]] LocalScope scope(vm);