133eb0b6dSopenharmony_ci/*
233eb0b6dSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
333eb0b6dSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
433eb0b6dSopenharmony_ci * you may not use this file except in compliance with the License.
533eb0b6dSopenharmony_ci * You may obtain a copy of the License at
633eb0b6dSopenharmony_ci *
733eb0b6dSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
833eb0b6dSopenharmony_ci *
933eb0b6dSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
1033eb0b6dSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
1133eb0b6dSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1233eb0b6dSopenharmony_ci * See the License for the specific language governing permissions and
1333eb0b6dSopenharmony_ci * limitations under the License.
1433eb0b6dSopenharmony_ci */
1533eb0b6dSopenharmony_ci
1633eb0b6dSopenharmony_ci#include "native_sendable.h"
1733eb0b6dSopenharmony_ci
1833eb0b6dSopenharmony_ci#include "ark_native_engine.h"
1933eb0b6dSopenharmony_ci#include "native_engine/native_utils.h"
2033eb0b6dSopenharmony_ci
2133eb0b6dSopenharmony_ciusing panda::ObjectRef;
2233eb0b6dSopenharmony_ciusing panda::StringRef;
2333eb0b6dSopenharmony_ciusing panda::SymbolRef;
2433eb0b6dSopenharmony_ci
2533eb0b6dSopenharmony_ciFunctionRef::SendablePropertiesInfos NativeSendable::CreateSendablePropertiesInfos(
2633eb0b6dSopenharmony_ci    napi_env env,
2733eb0b6dSopenharmony_ci    const NapiPropertyDescriptor* properties,
2833eb0b6dSopenharmony_ci    size_t propertiesLength)
2933eb0b6dSopenharmony_ci{
3033eb0b6dSopenharmony_ci    FunctionRef::SendablePropertiesInfos infos;
3133eb0b6dSopenharmony_ci
3233eb0b6dSopenharmony_ci    for (size_t i = 0; i < propertiesLength; ++i) {
3333eb0b6dSopenharmony_ci        if (properties[i].attributes & NATIVE_STATIC) {
3433eb0b6dSopenharmony_ci            InitSendablePropertiesInfo(env, infos.staticPropertiesInfo, properties[i]);
3533eb0b6dSopenharmony_ci        } else if (properties[i].attributes & NATIVE_INSTANCE) {
3633eb0b6dSopenharmony_ci            InitSendablePropertiesInfo(env, infos.instancePropertiesInfo, properties[i]);
3733eb0b6dSopenharmony_ci        } else if (properties[i].attributes & NATIVE_INSTANCE_OBJECT) {
3833eb0b6dSopenharmony_ci            InitSendablePropertiesInfo(env, infos.instancePropertiesInfo, properties[i],
3933eb0b6dSopenharmony_ci                                       FunctionRef::SendableType::OBJECT);
4033eb0b6dSopenharmony_ci        } else if (properties[i].attributes & NATIVE_INSTANCE_GENERIC) {
4133eb0b6dSopenharmony_ci            InitSendablePropertiesInfo(env, infos.instancePropertiesInfo, properties[i],
4233eb0b6dSopenharmony_ci                                       FunctionRef::SendableType::GENERIC);
4333eb0b6dSopenharmony_ci        } else {
4433eb0b6dSopenharmony_ci            InitSendablePropertiesInfo(env, infos.nonStaticPropertiesInfo, properties[i]);
4533eb0b6dSopenharmony_ci        }
4633eb0b6dSopenharmony_ci    }
4733eb0b6dSopenharmony_ci
4833eb0b6dSopenharmony_ci    return infos;
4933eb0b6dSopenharmony_ci}
5033eb0b6dSopenharmony_ci
5133eb0b6dSopenharmony_civoid NativeSendable::InitSendablePropertiesInfo(napi_env env,
5233eb0b6dSopenharmony_ci                                                FunctionRef::SendablePropertiesInfo& info,
5333eb0b6dSopenharmony_ci                                                NapiPropertyDescriptor propertyDescriptor,
5433eb0b6dSopenharmony_ci                                                FunctionRef::SendableType type)
5533eb0b6dSopenharmony_ci{
5633eb0b6dSopenharmony_ci    auto engine = reinterpret_cast<NativeEngine*>(env);
5733eb0b6dSopenharmony_ci    auto vm = engine->GetEcmaVm();
5833eb0b6dSopenharmony_ci
5933eb0b6dSopenharmony_ci    bool writable = (propertyDescriptor.attributes & NATIVE_WRITABLE) != 0;
6033eb0b6dSopenharmony_ci    bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0;
6133eb0b6dSopenharmony_ci    bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0;
6233eb0b6dSopenharmony_ci
6333eb0b6dSopenharmony_ci    Local<StringRef> key;
6433eb0b6dSopenharmony_ci    if (propertyDescriptor.utf8name == nullptr) {
6533eb0b6dSopenharmony_ci        key = LocalValueFromJsValue(propertyDescriptor.name);
6633eb0b6dSopenharmony_ci    } else {
6733eb0b6dSopenharmony_ci        key = StringRef::NewFromUtf8(vm, propertyDescriptor.utf8name);
6833eb0b6dSopenharmony_ci    }
6933eb0b6dSopenharmony_ci    info.keys.push_back(key);
7033eb0b6dSopenharmony_ci
7133eb0b6dSopenharmony_ci    if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) {
7233eb0b6dSopenharmony_ci        Local<JSValueRef> localGetter = JSValueRef::Undefined(vm);
7333eb0b6dSopenharmony_ci        Local<JSValueRef> localSetter = JSValueRef::Undefined(vm);
7433eb0b6dSopenharmony_ci
7533eb0b6dSopenharmony_ci        if (propertyDescriptor.getter != nullptr) {
7633eb0b6dSopenharmony_ci            localGetter =
7733eb0b6dSopenharmony_ci                NapiNativeCreateSendableFunction(env, "getter", propertyDescriptor.getter, propertyDescriptor.data);
7833eb0b6dSopenharmony_ci        }
7933eb0b6dSopenharmony_ci        if (propertyDescriptor.setter != nullptr) {
8033eb0b6dSopenharmony_ci            localSetter =
8133eb0b6dSopenharmony_ci                NapiNativeCreateSendableFunction(env, "setter", propertyDescriptor.setter, propertyDescriptor.data);
8233eb0b6dSopenharmony_ci        }
8333eb0b6dSopenharmony_ci
8433eb0b6dSopenharmony_ci        Local<JSValueRef> val = ObjectRef::CreateSendableAccessorData(vm, localGetter, localSetter);
8533eb0b6dSopenharmony_ci        info.types.push_back(FunctionRef::SendableType::OBJECT);
8633eb0b6dSopenharmony_ci        info.attributes.push_back(PropertyAttribute(val, false, enumable, configable));
8733eb0b6dSopenharmony_ci    } else if (propertyDescriptor.method != nullptr) {
8833eb0b6dSopenharmony_ci        std::string fullName;
8933eb0b6dSopenharmony_ci        if (propertyDescriptor.utf8name != nullptr) {
9033eb0b6dSopenharmony_ci            fullName += propertyDescriptor.utf8name;
9133eb0b6dSopenharmony_ci        } else {
9233eb0b6dSopenharmony_ci            fullName += key->IsString(vm) ? Local<StringRef>(key)->ToString(vm)
9333eb0b6dSopenharmony_ci                                          : Local<SymbolRef>(key)->GetDescription(vm)->ToString(vm);
9433eb0b6dSopenharmony_ci        }
9533eb0b6dSopenharmony_ci
9633eb0b6dSopenharmony_ci        Local<JSValueRef> func =
9733eb0b6dSopenharmony_ci            NapiNativeCreateSendableFunction(env, fullName.c_str(), propertyDescriptor.method, propertyDescriptor.data);
9833eb0b6dSopenharmony_ci        info.types.push_back(FunctionRef::SendableType::OBJECT);
9933eb0b6dSopenharmony_ci        info.attributes.push_back(PropertyAttribute(func, writable, enumable, configable));
10033eb0b6dSopenharmony_ci    } else {
10133eb0b6dSopenharmony_ci        Local<JSValueRef> val = LocalValueFromJsValue(propertyDescriptor.value);
10233eb0b6dSopenharmony_ci        info.types.push_back(type);
10333eb0b6dSopenharmony_ci        info.attributes.push_back(PropertyAttribute(val, writable, enumable, configable));
10433eb0b6dSopenharmony_ci    }
10533eb0b6dSopenharmony_ci}
10633eb0b6dSopenharmony_ci
10733eb0b6dSopenharmony_ciLocal<JSValueRef> NativeSendable::NapiNativeCreateSendableFunction(napi_env env,
10833eb0b6dSopenharmony_ci                                                                   const char* name,
10933eb0b6dSopenharmony_ci                                                                   NapiNativeCallback cb,
11033eb0b6dSopenharmony_ci                                                                   void* value)
11133eb0b6dSopenharmony_ci{
11233eb0b6dSopenharmony_ci    auto engine = reinterpret_cast<NativeEngine*>(env);
11333eb0b6dSopenharmony_ci    auto vm = const_cast<EcmaVM*>(engine->GetEcmaVm());
11433eb0b6dSopenharmony_ci    NapiFunctionInfo* funcInfo = NapiFunctionInfo::CreateNewInstance();
11533eb0b6dSopenharmony_ci    if (funcInfo == nullptr) {
11633eb0b6dSopenharmony_ci        HILOG_ERROR("funcInfo is nullptr");
11733eb0b6dSopenharmony_ci        return JSValueRef::Undefined(vm);
11833eb0b6dSopenharmony_ci    }
11933eb0b6dSopenharmony_ci    funcInfo->callback = cb;
12033eb0b6dSopenharmony_ci    funcInfo->data = value;
12133eb0b6dSopenharmony_ci
12233eb0b6dSopenharmony_ci    Local<FunctionRef> fn = FunctionRef::NewSendable(
12333eb0b6dSopenharmony_ci        vm, ArkNativeFunctionCallBack,
12433eb0b6dSopenharmony_ci        [](void* env, void* externalPointer, void* data) {
12533eb0b6dSopenharmony_ci            auto info = reinterpret_cast<NapiFunctionInfo*>(data);
12633eb0b6dSopenharmony_ci            if (info != nullptr) {
12733eb0b6dSopenharmony_ci                delete info;
12833eb0b6dSopenharmony_ci            }
12933eb0b6dSopenharmony_ci        },
13033eb0b6dSopenharmony_ci        reinterpret_cast<void*>(funcInfo), true);
13133eb0b6dSopenharmony_ci    return fn;
13233eb0b6dSopenharmony_ci}
13333eb0b6dSopenharmony_ci
13433eb0b6dSopenharmony_civoid NativeSendable::NapiDefineSendabledProperty(napi_env env,
13533eb0b6dSopenharmony_ci                                                 Local<ObjectRef>& obj,
13633eb0b6dSopenharmony_ci                                                 NapiPropertyDescriptor& propertyDescriptor,
13733eb0b6dSopenharmony_ci                                                 Local<JSValueRef>& propertyName,
13833eb0b6dSopenharmony_ci                                                 bool& result)
13933eb0b6dSopenharmony_ci{
14033eb0b6dSopenharmony_ci    auto engine = reinterpret_cast<NativeEngine*>(env);
14133eb0b6dSopenharmony_ci    auto vm = engine->GetEcmaVm();
14233eb0b6dSopenharmony_ci
14333eb0b6dSopenharmony_ci    bool enumable = (propertyDescriptor.attributes & NATIVE_ENUMERABLE) != 0;
14433eb0b6dSopenharmony_ci    bool configable = (propertyDescriptor.attributes & NATIVE_CONFIGURABLE) != 0;
14533eb0b6dSopenharmony_ci
14633eb0b6dSopenharmony_ci    if (propertyDescriptor.getter != nullptr || propertyDescriptor.setter != nullptr) {
14733eb0b6dSopenharmony_ci        Local<JSValueRef> localGetter = JSValueRef::Undefined(vm);
14833eb0b6dSopenharmony_ci        Local<JSValueRef> localSetter = JSValueRef::Undefined(vm);
14933eb0b6dSopenharmony_ci
15033eb0b6dSopenharmony_ci        if (propertyDescriptor.getter != nullptr) {
15133eb0b6dSopenharmony_ci            localGetter =
15233eb0b6dSopenharmony_ci                NapiNativeCreateSendableFunction(env, "getter", propertyDescriptor.getter, propertyDescriptor.data);
15333eb0b6dSopenharmony_ci        }
15433eb0b6dSopenharmony_ci        if (propertyDescriptor.setter != nullptr) {
15533eb0b6dSopenharmony_ci            localSetter =
15633eb0b6dSopenharmony_ci                NapiNativeCreateSendableFunction(env, "setter", propertyDescriptor.setter, propertyDescriptor.data);
15733eb0b6dSopenharmony_ci        }
15833eb0b6dSopenharmony_ci
15933eb0b6dSopenharmony_ci        PropertyAttribute attr(JSValueRef::Undefined(vm), false, enumable, configable);
16033eb0b6dSopenharmony_ci        // note(lzl): SetSendableAccessorProperty?
16133eb0b6dSopenharmony_ci        result = obj->SetAccessorProperty(vm, propertyName, localGetter, localSetter, attr);
16233eb0b6dSopenharmony_ci    } else if (propertyDescriptor.method != nullptr) {
16333eb0b6dSopenharmony_ci        std::string fullName;
16433eb0b6dSopenharmony_ci        if (propertyDescriptor.utf8name != nullptr) {
16533eb0b6dSopenharmony_ci            fullName += propertyDescriptor.utf8name;
16633eb0b6dSopenharmony_ci        } else {
16733eb0b6dSopenharmony_ci            fullName += propertyName->IsString(vm) ? Local<StringRef>(propertyName)->ToString(vm)
16833eb0b6dSopenharmony_ci                                                   : Local<SymbolRef>(propertyName)->GetDescription(vm)->ToString(vm);
16933eb0b6dSopenharmony_ci        }
17033eb0b6dSopenharmony_ci
17133eb0b6dSopenharmony_ci        Local<JSValueRef> func =
17233eb0b6dSopenharmony_ci            NapiNativeCreateSendableFunction(env, fullName.c_str(), propertyDescriptor.method, propertyDescriptor.data);
17333eb0b6dSopenharmony_ci        result = obj->Set(vm, propertyName, func);
17433eb0b6dSopenharmony_ci    } else {
17533eb0b6dSopenharmony_ci        Local<JSValueRef> val = LocalValueFromJsValue(propertyDescriptor.value);
17633eb0b6dSopenharmony_ci        result = obj->Set(vm, propertyName, val);
17733eb0b6dSopenharmony_ci    }
17833eb0b6dSopenharmony_ci}
179