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#include "native_callback_scope_manager.h"
17#include "native_engine/native_engine.h"
18
19NativeCallbackScope::NativeCallbackScope(NativeEngine* env,
20                                         panda::Local<panda::ObjectRef> object,
21                                         const AsyncIdInfo& asyncIdInfo,
22                                         int flags) : env_(env), asyncIdInfo_(asyncIdInfo),
23    object_(object), skipHooks_(flags & SKIP_ASYNC_HOOKS), skipTaskQueues_(flags & SKIP_TASK_QUEUES)
24{
25    [[maybe_unused]] panda::LocalScope scope(env_->GetEcmaVm());
26
27    // not support async_hook yet, and push_async_context actions need to be improved in the future
28
29    pushedIds_ = true;
30
31    if (asyncIdInfo.asyncId != 0 && !skipHooks_) {
32        NativeAsyncWrap::EmitBefore(env, asyncIdInfo.asyncId);
33    }
34}
35
36NativeCallbackScope::~NativeCallbackScope()
37{
38    Close();
39}
40
41void NativeCallbackScope::Close()
42{
43    if (closed_) {
44        return;
45    }
46    closed_ = true;
47
48    auto performStoppingCheck = [this]() {
49        if (env_->IsStopping()) {
50            MarkAsFailed();
51            // not support async_hook yet, and clear_async_id_stack actions need to be improved in the future
52        }
53    };
54    performStoppingCheck();
55
56    if (env_->IsStopping()) {
57        return;
58    }
59
60    if (!failed_ && asyncIdInfo_.asyncId != 0 && !skipHooks_) {
61        NativeAsyncWrap::EmitAfter(env_, asyncIdInfo_.asyncId);
62    }
63
64    if (pushedIds_) {
65        pushedIds_ = false;
66        // not support async_hook yet, and pop_async_context actions need to be improved in the future
67    }
68
69    if (failed_) {
70        return;
71    }
72
73    if (env_->GetCallbackScopeManager()->GetOpenCallbackScopes() > 1 || skipTaskQueues_) {
74        return;
75    }
76}
77
78NativeCallbackScopeManager::NativeCallbackScopeManager() {}
79
80NativeCallbackScopeManager::~NativeCallbackScopeManager() {}
81
82NativeCallbackScope* NativeCallbackScopeManager::Open(NativeEngine* env,
83                                                      panda::Local<panda::ObjectRef> object,
84                                                      AsyncIdInfo asyncIdInfo)
85{
86    NativeCallbackScope* scope = new (std::nothrow)NativeCallbackScope(env, object, asyncIdInfo);
87
88    if (scope) {
89        asyncCallbackScopeDepth_++;
90        return scope;
91    } else {
92        return nullptr;
93    }
94}
95
96void NativeCallbackScopeManager::Close(NativeCallbackScope* scope)
97{
98    if (scope != nullptr) {
99        delete scope;
100    }
101    asyncCallbackScopeDepth_--;
102}
103
104size_t NativeCallbackScopeManager::IncrementOpenCallbackScopes()
105{
106    openCallbackScopes_++;
107    return openCallbackScopes_;
108}
109
110size_t NativeCallbackScopeManager::DecrementOpenCallbackScopes()
111{
112    openCallbackScopes_--;
113    return openCallbackScopes_;
114}
115