• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2022 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 "plugins/ets/runtime/ets_entrypoints.h"
17 
18 #include "libpandafile/shorty_iterator.h"
19 #include "plugins/ets/runtime/ets_coroutine.h"
20 #include "plugins/ets/runtime/ets_runtime_interface.h"
21 #include "plugins/ets/runtime/ets_vm.h"
22 #include "plugins/ets/runtime/ets_handle_scope.h"
23 #include "plugins/ets/runtime/ets_handle.h"
24 #include "plugins/ets/runtime/types/ets_promise.h"
25 #include "runtime/arch/helpers.h"
26 #include "runtime/interpreter/vregister_iterator.h"
27 
28 namespace panda::ets {
29 
30 using TypeId = panda_file::Type::TypeId;
31 
32 #if defined(__clang__)
33 #pragma clang diagnostic push
34 #pragma clang diagnostic ignored "-Wgnu-label-as-value"
35 #elif defined(__GNUC__)
36 #pragma GCC diagnostic push
37 #pragma GCC diagnostic ignored "-Wpedantic"
38 #endif
39 
Launch(EtsCoroutine * currentCoro,Method * method,const EtsHandle<EtsPromise> & promiseHandle,PandaVector<Value> && args)40 static inline bool Launch(EtsCoroutine *currentCoro, Method *method, const EtsHandle<EtsPromise> &promiseHandle,
41                           PandaVector<Value> &&args)
42 {
43     ASSERT(currentCoro != nullptr);
44     PandaEtsVM *etsVm = currentCoro->GetPandaVM();
45     auto promiseRef = etsVm->GetGlobalObjectStorage()->Add(promiseHandle.GetPtr(), mem::Reference::ObjectType::WEAK);
46     auto evt = Runtime::GetCurrent()->GetInternalAllocator()->New<CompletionEvent>(promiseRef);
47     promiseHandle.GetPtr()->SetEventPtr(evt);
48     // create the coro and put it to the ready queue
49     auto *coro = currentCoro->GetCoroutineManager()->Launch(evt, method, std::move(args), CoroutineAffinity::NONE);
50     if (UNLIKELY(coro == nullptr)) {
51         // OOM
52         promiseHandle.GetPtr()->SetEventPtr(nullptr);
53         Runtime::GetCurrent()->GetInternalAllocator()->Delete(evt);
54         return false;
55     }
56     return true;
57 }
58 
LaunchCoroutine(Method * method,ObjectHeader * obj,uint64_t * args,ObjectHeader * thisObj)59 void LaunchCoroutine(Method *method, ObjectHeader *obj, uint64_t *args, ObjectHeader *thisObj)
60 {
61     auto *promise = reinterpret_cast<EtsPromise *>(obj);
62     ASSERT(promise != nullptr);
63 
64     PandaVector<Value> values;
65     if (thisObj != nullptr) {
66         ASSERT(!method->IsStatic());
67         // Add this for virtual call
68         values.push_back(Value(thisObj));
69     } else {
70         ASSERT(method->IsStatic());
71     }
72     arch::ArgReaderStack<RUNTIME_ARCH> argReader(reinterpret_cast<uint8_t *>(args));
73     arch::ValueWriter writer(&values);
74     ARCH_COPY_METHOD_ARGS(method, argReader, writer);
75 
76     auto *currentCoro = EtsCoroutine::GetCurrent();
77     [[maybe_unused]] EtsHandleScope scope(currentCoro);
78     EtsHandle<EtsPromise> promiseHandle(currentCoro, promise);
79     bool successfulLaunch = Launch(currentCoro, method, promiseHandle, std::move(values));
80     if (UNLIKELY(!successfulLaunch)) {
81         HandlePendingException();
82         UNREACHABLE();
83     }
84 }
85 
CreateLaunchStaticCoroutineEntrypoint(Method * method,ObjectHeader * obj,uint64_t * args)86 extern "C" void CreateLaunchStaticCoroutineEntrypoint(Method *method, ObjectHeader *obj, uint64_t *args)
87 {
88     LaunchCoroutine(method, obj, args, nullptr);
89 }
90 
CreateLaunchVirtualCoroutineEntrypoint(Method * method,ObjectHeader * obj,uint64_t * args,ObjectHeader * thisObj)91 extern "C" void CreateLaunchVirtualCoroutineEntrypoint(Method *method, ObjectHeader *obj, uint64_t *args,
92                                                        ObjectHeader *thisObj)
93 {
94     LaunchCoroutine(method, obj, args, thisObj);
95 }
96 
97 template <BytecodeInstruction::Format FORMAT>
LaunchFromInterpreterImpl(Method * method,Frame * frame,const uint8_t * pc)98 ObjectHeader *LaunchFromInterpreterImpl(Method *method, Frame *frame, const uint8_t *pc)
99 {
100     EtsPromise *promise = EtsPromise::Create();
101     if (UNLIKELY(promise == nullptr)) {
102         return nullptr;
103     }
104 
105     auto numArgs = method->GetNumArgs();
106     auto args = PandaVector<Value> {numArgs};
107     auto frameHandler = StaticFrameHandler(frame);
108     auto vregIter = interpreter::VRegisterIterator<FORMAT> {BytecodeInstruction(pc), frame};
109     for (decltype(numArgs) i = 0; i < numArgs; ++i) {
110         args[i] = Value::FromVReg(frameHandler.GetVReg(vregIter.GetVRegIdx(i)));
111     }
112 
113     auto *currentCoro = EtsCoroutine::GetCurrent();
114     [[maybe_unused]] EtsHandleScope scope(currentCoro);
115     EtsHandle<EtsPromise> promiseHandle(currentCoro, promise);
116     bool successfulLaunch = Launch(currentCoro, method, promiseHandle, std::move(args));
117     if (UNLIKELY(!successfulLaunch)) {
118         return nullptr;
119     }
120     frame->GetAccAsVReg().SetReference(promiseHandle.GetPtr());
121     return promiseHandle.GetPtr();
122 }
123 
LaunchFromInterpreterShort(Method * method,Frame * frame,const uint8_t * pc)124 extern "C" ObjectHeader *LaunchFromInterpreterShort(Method *method, Frame *frame, const uint8_t *pc)
125 {
126     return LaunchFromInterpreterImpl<BytecodeInstruction::Format::PREF_V4_V4_ID16>(method, frame, pc);
127 }
128 
LaunchFromInterpreterLong(Method * method,Frame * frame,const uint8_t * pc)129 extern "C" ObjectHeader *LaunchFromInterpreterLong(Method *method, Frame *frame, const uint8_t *pc)
130 {
131     return LaunchFromInterpreterImpl<BytecodeInstruction::Format::PREF_V4_V4_V4_V4_ID16>(method, frame, pc);
132 }
133 
LaunchFromInterpreterRange(Method * method,Frame * frame,const uint8_t * pc)134 extern "C" ObjectHeader *LaunchFromInterpreterRange(Method *method, Frame *frame, const uint8_t *pc)
135 {
136     return LaunchFromInterpreterImpl<BytecodeInstruction::Format::PREF_V8_ID16>(method, frame, pc);
137 }
138 
139 }  // namespace panda::ets
140