• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ecmascript/builtins/builtins_promise_job.h"
17 #include "ecmascript/ecma_macros.h"
18 #include "ecmascript/global_env.h"
19 #include "ecmascript/internal_call_params.h"
20 #include "ecmascript/js_function.h"
21 #include "ecmascript/js_handle.h"
22 #include "ecmascript/js_promise.h"
23 #include "ecmascript/js_tagged_value.h"
24 #include "libpandabase/macros.h"
25 
26 namespace panda::ecmascript::builtins {
PromiseReactionJob(EcmaRuntimeCallInfo * argv)27 JSTaggedValue BuiltinsPromiseJob::PromiseReactionJob(EcmaRuntimeCallInfo *argv)
28 {
29     ASSERT(argv);
30     BUILTINS_API_TRACE(argv->GetThread(), PromiseJob, Reaction);
31     JSThread *thread = argv->GetThread();
32     [[maybe_unused]] EcmaHandleScope handleScope(thread);
33     // 1. Assert: reaction is a PromiseReaction Record.
34     JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
35     ASSERT(value->IsPromiseReaction());
36     JSHandle<PromiseReaction> reaction = JSHandle<PromiseReaction>::Cast(value);
37     JSHandle<JSTaggedValue> argument = GetCallArg(argv, 1);
38 
39     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
40     // 2. Let promiseCapability be reaction.[[Capabilities]].
41     JSHandle<PromiseCapability> capability(thread, reaction->GetPromiseCapability());
42     // 3. Let handler be reaction.[[Handler]].
43     JSHandle<JSTaggedValue> handler(thread, reaction->GetHandler());
44     JSHandle<JSTaggedValue> thisValue = globalConst->GetHandledUndefined();
45     JSMutableHandle<JSTaggedValue> call(thread, capability->GetResolve());
46     InternalCallParams *result = thread->GetInternalCallParams();
47     result->MakeArgv(argument);
48     if (handler->IsString()) {
49         // 4. If handler is "Identity", let handlerResult be NormalCompletion(argument).
50         // 5. Else if handler is "Thrower", let handlerResult be Completion{[[type]]: throw, [[value]]: argument,
51         // [[target]]: empty}.
52 
53         if (EcmaString::StringsAreEqual(handler.GetObject<EcmaString>(),
54                                         globalConst->GetHandledThrowerString().GetObject<EcmaString>())) {
55             call.Update(capability->GetReject());
56         }
57     } else {
58         // 6. Else, let handlerResult be Call(handler, undefined, «argument»).
59         JSTaggedValue taggedValue = JSFunction::Call(thread, handler, thisValue, 1, result->GetArgv());
60         result->MakeArgv(taggedValue);
61         // 7. If handlerResult is an abrupt completion, then
62         // a. Let status be Call(promiseCapability.[[Reject]], undefined, «handlerResult.[[value]]»).
63         // b. NextJob Completion(status).
64         if (thread->HasPendingException()) {
65             JSHandle<JSTaggedValue> throwValue = JSPromise::IfThrowGetThrowValue(thread);
66             thread->ClearException();
67             result->MakeArgv(throwValue);
68             call.Update(capability->GetReject());
69         }
70     }
71     // 8. Let status be Call(promiseCapability.[[Resolve]], undefined, «handlerResult.[[value]]»).
72     return JSFunction::Call(thread, call, thisValue, 1, result->GetArgv());
73 }
74 
PromiseResolveThenableJob(EcmaRuntimeCallInfo * argv)75 JSTaggedValue BuiltinsPromiseJob::PromiseResolveThenableJob(EcmaRuntimeCallInfo *argv)
76 {
77     ASSERT(argv);
78     BUILTINS_API_TRACE(argv->GetThread(), PromiseJob, ResolveThenableJob);
79     JSThread *thread = argv->GetThread();
80     [[maybe_unused]] EcmaHandleScope handleScope(thread);
81     const GlobalEnvConstants *globalConst = thread->GlobalConstants();
82     JSHandle<JSTaggedValue> promise = GetCallArg(argv, 0);
83     ASSERT(promise->IsJSPromise());
84     // 1. Let resolvingFunctions be CreateResolvingFunctions(promiseToResolve).
85     JSHandle<ResolvingFunctionsRecord> resolvingFunctions =
86         JSPromise::CreateResolvingFunctions(thread, JSHandle<JSPromise>::Cast(promise));
87     JSHandle<JSTaggedValue> thenable = GetCallArg(argv, 1);
88     JSHandle<JSTaggedValue> then = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD);
89 
90     // 2. Let thenCallResult be Call(then, thenable, «resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]»).
91     InternalCallParams *arguments = thread->GetInternalCallParams();
92     arguments->MakeArgv(resolvingFunctions->GetResolveFunction(), resolvingFunctions->GetRejectFunction());
93     JSTaggedValue result = JSFunction::Call(thread, then, thenable, 2, arguments->GetArgv());  // 2: two args
94     JSHandle<JSTaggedValue> thenResult(thread, result);
95     // 3. If thenCallResult is an abrupt completion,
96     // a. Let status be Call(resolvingFunctions.[[Reject]], undefined, «thenCallResult.[[value]]»).
97     // b. NextJob Completion(status).
98     if (thread->HasPendingException()) {
99         thenResult = JSPromise::IfThrowGetThrowValue(thread);
100         thread->ClearException();
101         JSHandle<JSTaggedValue> reject(thread, resolvingFunctions->GetRejectFunction());
102         JSHandle<JSTaggedValue> undefined = globalConst->GetHandledUndefined();
103         arguments->MakeArgv(thenResult);
104         return JSFunction::Call(thread, reject, undefined, 1, arguments->GetArgv());
105     }
106     // 4. NextJob Completion(thenCallResult).
107     return result;
108 }
109 }  // namespace panda::ecmascript::builtins
110