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 FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_API_INTERNAL_H
17#define FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_API_INTERNAL_H
18
19#include "napi/native_api.h"
20#include "native_engine.h"
21#include "utils/log.h"
22
23static inline napi_status napi_clear_last_error(napi_env env)
24{
25    ((NativeEngine*)env)->ClearLastError();
26    return napi_ok;
27}
28
29static inline napi_status napi_set_last_error(napi_env env,
30                                              napi_status error_code,
31                                              uint32_t engine_error_code = 0,
32                                              void* engine_reserved = nullptr)
33{
34    ((NativeEngine*)env)->SetLastError(error_code, engine_error_code, engine_reserved);
35    return error_code;
36}
37
38#define RETURN_STATUS_IF_FALSE(env, condition, status) \
39    if (!(condition)) {                                \
40        return napi_set_last_error((env), (status));   \
41    }
42
43#define CHECK_ENV(env)           \
44    if ((env) == nullptr) {      \
45        return napi_invalid_arg; \
46    }
47
48#define CHECK_ARG(env, arg) RETURN_STATUS_IF_FALSE((env), ((arg) != nullptr), napi_invalid_arg)
49
50#define NAPI_PREAMBLE(env)                                                     \
51    CHECK_ENV((env));                                                          \
52    RETURN_STATUS_IF_FALSE(                                                    \
53        (env),                                                                 \
54        (reinterpret_cast<NativeEngine*>(env))->lastException_.IsEmpty(),      \
55        napi_pending_exception);                                               \
56        napi_clear_last_error((env));                                          \
57    TryCatch tryCatch(env)
58
59#define GET_RETURN_STATUS(env)                                                 \
60    (!tryCatch.HasCaught()                                                     \
61        ? napi_ok                                                              \
62        : napi_set_last_error((env), napi_pending_exception))
63
64#define CHECK_WITH_RETURN(condition, status)   \
65    if (!(condition)) {                        \
66        return status;                         \
67    }
68
69#define CHECK_AND_CONVERT_TO_OBJECT(env, vm, nativeValue, obj)                 \
70    bool isObj = (nativeValue)->IsObject((vm));                                \
71    bool isFunc = (nativeValue)->IsFunction((vm));                             \
72    RETURN_STATUS_IF_FALSE((env), isObj || isFunc, napi_object_expected);      \
73    Local<ObjectRef> (obj);                                                    \
74    if (LIKELY(isObj)) {                                                       \
75        (obj) = Local<ObjectRef>((nativeValue));                               \
76    } else {                                                                   \
77        (obj) = (nativeValue)->ToObject((vm));                                 \
78    }
79
80#define CROSS_THREAD_CHECK(env)                                                     \
81    do {                                                                            \
82        NativeEngine* engine = reinterpret_cast<NativeEngine*>((env));              \
83        if (UNLIKELY(engine->IsCrossThreadCheckEnabled())) {                        \
84            ThreadId tid = NativeEngine::GetCurSysTid();                            \
85            if (tid != engine->GetSysTid()) {                                       \
86                HILOG_FATAL("current napi interface cannot run in multi-thread, "   \
87                            "thread id: %{public}d, current thread id: %{public}d", \
88                            engine->GetSysTid(), tid);                              \
89            };                                                                      \
90        };                                                                          \
91    } while (0)
92
93#define WEAK_CROSS_THREAD_CHECK(env)                                                \
94    do {                                                                            \
95        NativeEngine* engine = reinterpret_cast<NativeEngine*>((env));              \
96        if (UNLIKELY(engine->IsCrossThreadCheckEnabled())) {                        \
97            ThreadId tid = NativeEngine::GetCurSysTid();                            \
98            if (tid != engine->GetSysTid()) {                                       \
99                HILOG_ERROR("current napi interface cannot run in multi-thread, "   \
100                            "thread id: %{public}d, current thread id: %{public}d", \
101                            engine->GetSysTid(), tid);                              \
102            };                                                                      \
103        };                                                                          \
104    } while (0)
105
106#ifndef LIKELY
107#define LIKELY(exp) (__builtin_expect((exp) != 0, true))  // NOLINT(cppcoreguidelines-macro-usage)
108#endif
109
110#ifndef UNLIKELY
111#define UNLIKELY(exp) (__builtin_expect((exp) != 0, false))  // NOLINT(cppcoreguidelines-macro-usage)
112#endif
113
114#endif /* FOUNDATION_ACE_NAPI_NATIVE_ENGINE_NATIVE_API_INTERNAL_H */
115