• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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_async_from_sync_iterator.h"
17 #include "ecmascript/builtins/builtins_promise.h"
18 #include "ecmascript/builtins/builtins_promise_handler.h"
19 #include "ecmascript/base/builtins_base.h"
20 #include "ecmascript/ecma_vm.h"
21 #include "ecmascript/global_env.h"
22 #include "ecmascript/js_tagged_value.h"
23 #include "ecmascript/js_async_from_sync_iterator.h"
24 #include "ecmascript/object_factory.h"
25 #include "ecmascript/js_iterator.h"
26 #include "ecmascript/js_promise.h"
27 #include "ecmascript/js_function.h"
28 
29 namespace panda::ecmascript::builtins {
30 
Next(EcmaRuntimeCallInfo * argv)31 JSTaggedValue BuiltinsAsyncFromSyncIterator::Next(EcmaRuntimeCallInfo *argv)
32 {
33     JSThread *thread = argv->GetThread();
34     BUILTINS_API_TRACE(thread, AsyncFromSyncIterator, Next);
35     [[maybe_unused]] EcmaHandleScope scope(thread);
36     auto vm = thread->GetEcmaVM();
37     JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
38     // 1.Let O be the this value.
39     JSHandle<JSTaggedValue> thisValue = GetThis(argv);
40     // 2.Assert: Type(O) is Object and O has a [[SyncIteratorRecord]] internal slot.
41     if (!thisValue->IsAsyncFromSyncIterator()) {
42         THROW_TYPE_ERROR_AND_RETURN(thread, "is not AsyncFromSyncIterator", JSTaggedValue::Exception());
43     }
44     // 3.Let promiseCapability be ! NewPromiseCapability(%Promise%).
45     JSHandle<PromiseCapability> pcap =
46         JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()));
47     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
48     // 4.Let syncIteratorRecord be O.[[SyncIteratorRecord]].
49     JSHandle<JSAsyncFromSyncIterator> asyncIterator(thisValue);
50     JSHandle<AsyncIteratorRecord> syncIteratorRecord(thread, asyncIterator->GetSyncIteratorRecord());
51     // 5.If value is present, then
52     // a.Let result be IteratorNext(syncIteratorRecord, value).
53     // 6.Else,
54     // a.Let result be IteratorNext(syncIteratorRecord).
55     JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
56     JSHandle<JSTaggedValue> result;
57     if (value->IsNull()) {
58         result = JSIterator::IteratorNext(thread, syncIteratorRecord);
59     } else {
60         result = JSIterator::IteratorNext(thread, syncIteratorRecord, value);
61     }
62     // 7.IfAbruptRejectPromise(result, promiseCapability).
63     RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, pcap);
64     // 8.Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability).
65     return JSAsyncFromSyncIterator::AsyncFromSyncIteratorContinuation(thread, result, pcap);
66 }
67 
Throw(EcmaRuntimeCallInfo * argv)68 JSTaggedValue BuiltinsAsyncFromSyncIterator::Throw(EcmaRuntimeCallInfo *argv)
69 {
70     JSThread *thread = argv->GetThread();
71     BUILTINS_API_TRACE(thread, AsyncFromSyncIterator, Throw);
72     [[maybe_unused]] EcmaHandleScope scope(thread);
73     auto vm = thread->GetEcmaVM();
74     const GlobalEnvConstants *globalConstant = thread->GlobalConstants();
75     ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
76     // 1.Let O be the this value.
77     JSHandle<JSTaggedValue> input(BuiltinsBase::GetThis(argv));
78     JSHandle<JSAsyncFromSyncIterator> asyncIterator(input);
79     // 3.Let promiseCapability be ! NewPromiseCapability(%Promise%).
80     JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
81     JSHandle<PromiseCapability> pcap =
82         JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()));
83     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
84     // 4.Let syncIterator be O.[[SyncIteratorRecord]].[[Iterator]].
85     JSHandle<AsyncIteratorRecord> syncIteratorRecord(thread, asyncIterator->GetSyncIteratorRecord());
86     JSHandle<JSTaggedValue> syncIterator(thread, syncIteratorRecord->GetIterator());
87     // 5.Let return be GetMethod(syncIterator, "throw").
88     JSHandle<JSTaggedValue> throwString = globalConstant->GetHandledThrowString();
89     JSHandle<JSTaggedValue> throwResult = JSObject::GetMethod(thread, syncIterator, throwString);
90     RETURN_REJECT_PROMISE_IF_ABRUPT(thread, throwString, pcap);
91     JSHandle<JSTaggedValue> value = base::BuiltinsBase::GetCallArg(argv, 0);
92     JSHandle<JSTaggedValue> undefinedValue = globalConstant->GetHandledUndefined();
93     // 7.If throw is undefined, then
94     if (throwResult->IsUndefined()) {
95         JSHandle<JSObject> iterResult = JSIterator::CreateIterResultObject(thread, value, true);
96         JSHandle<JSTaggedValue> reject(thread, pcap->GetReject());
97         EcmaRuntimeCallInfo *info =
98             EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefinedValue, undefinedValue, 1);
99         info->SetCallArg(iterResult.GetTaggedValue());
100         return pcap->GetPromise();
101     }
102     JSTaggedValue ret;
103     // 8.If value is present, then
104     if (value->IsNull()) {
105         EcmaRuntimeCallInfo *callInfo =
106             EcmaInterpreter::NewRuntimeCallInfo(thread, throwResult, syncIterator, undefinedValue, 0);
107         RETURN_REJECT_PROMISE_IF_ABRUPT(thread, throwResult, pcap);
108         ret = JSFunction::Call(callInfo);
109     } else {
110         EcmaRuntimeCallInfo *callInfo =
111             EcmaInterpreter::NewRuntimeCallInfo(thread, throwResult, syncIterator, undefinedValue, 1);
112         RETURN_REJECT_PROMISE_IF_ABRUPT(thread, throwResult, pcap);
113         callInfo->SetCallArg(value.GetTaggedValue());
114         ret = JSFunction::Call(callInfo);
115     }
116     JSHandle<JSTaggedValue> result(thread, ret);
117     RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, pcap);
118     // 11.If Type(result) is not Object, then
119     if (!result->IsECMAObject()) {
120         // a.Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
121         JSHandle<JSObject> resolutionError =
122             factory->GetJSError(ErrorType::TYPE_ERROR, "AsyncFromSyncIteratorPrototype.throw: is not Object.");
123         JSHandle<JSTaggedValue> reject(thread, pcap->GetReject());
124         EcmaRuntimeCallInfo *info =
125             EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefinedValue, undefinedValue, 1);
126         info->SetCallArg(resolutionError.GetTaggedValue());
127         JSFunction::Call(info);
128 
129         // b.Return promiseCapability.[[Promise]].
130         JSHandle<JSObject> promise(thread, pcap->GetPromise());
131         return promise.GetTaggedValue();
132     }
133     // 12.Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability).
134     return JSAsyncFromSyncIterator::AsyncFromSyncIteratorContinuation(thread, result, pcap);
135 }
136 
Return(EcmaRuntimeCallInfo * argv)137 JSTaggedValue BuiltinsAsyncFromSyncIterator::Return(EcmaRuntimeCallInfo *argv)
138 {
139     JSThread *thread = argv->GetThread();
140     BUILTINS_API_TRACE(thread, AsyncFromSyncIterator, Return);
141     [[maybe_unused]] EcmaHandleScope scope(thread);
142     auto vm = thread->GetEcmaVM();
143     const GlobalEnvConstants *globalConstant = thread->GlobalConstants();
144     ObjectFactory *factory = vm->GetFactory();
145     // 1.Let O be the this value.
146     JSHandle<JSTaggedValue> thisValue = GetThis(argv);
147     if (!thisValue->IsAsyncFromSyncIterator()) {
148         THROW_TYPE_ERROR_AND_RETURN(thread, "is not AsyncFromSyncIterator", JSTaggedValue::Exception());
149     }
150 
151     // 3.Let promiseCapability be ! NewPromiseCapability(%Promise%).
152     JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
153     JSHandle<PromiseCapability> pcap =
154         JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()));
155     RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
156     // 4.Let syncIterator be O.[[SyncIteratorRecord]].[[Iterator]].
157     JSHandle<JSAsyncFromSyncIterator> asyncIterator(thisValue);
158     JSHandle<AsyncIteratorRecord> syncIteratorRecord(thread, asyncIterator->GetSyncIteratorRecord());
159     JSHandle<JSTaggedValue> syncIterator(thread, syncIteratorRecord->GetIterator());
160     // 5.Let return be GetMethod(syncIterator, "return").
161     JSHandle<JSTaggedValue> returnString = globalConstant->GetHandledReturnString();
162     JSHandle<JSTaggedValue> returnResult = JSObject::GetMethod(thread, syncIterator, returnString);
163     RETURN_REJECT_PROMISE_IF_ABRUPT(thread, returnResult, pcap);
164     JSHandle<JSTaggedValue> value = base::BuiltinsBase::GetCallArg(argv, 0);
165     JSHandle<JSTaggedValue> undefinedValue = globalConstant->GetHandledUndefined();
166     // 7.If return is undefined, then
167     if (returnResult->IsUndefined()) {
168         JSHandle<JSObject> iterResult = JSIterator::CreateIterResultObject(thread, value, true);
169         JSHandle<JSTaggedValue> its = JSHandle<JSTaggedValue>::Cast(iterResult);
170         JSHandle<JSTaggedValue> resolve(thread, pcap->GetResolve());
171         EcmaRuntimeCallInfo *info =
172             EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefinedValue, undefinedValue, 1);
173         info->SetCallArg(its.GetTaggedValue());
174         JSHandle<JSObject> promise(thread, pcap->GetPromise());
175         return promise.GetTaggedValue();
176     }
177     JSTaggedValue ret;
178     // 8.If value is present, then
179     if (value->IsNull()) {
180         EcmaRuntimeCallInfo *callInfo =
181             EcmaInterpreter::NewRuntimeCallInfo(thread, returnResult, syncIterator, undefinedValue, 0);
182         RETURN_REJECT_PROMISE_IF_ABRUPT(thread, returnResult, pcap);
183         ret = JSFunction::Call(callInfo);
184     } else {
185         EcmaRuntimeCallInfo *callInfo =
186             EcmaInterpreter::NewRuntimeCallInfo(thread, returnResult, syncIterator, undefinedValue, 1);
187         RETURN_REJECT_PROMISE_IF_ABRUPT(thread, returnResult, pcap);
188         callInfo->SetCallArg(value.GetTaggedValue());
189         ret = JSFunction::Call(callInfo);
190     }
191     JSHandle<JSTaggedValue> result(thread, ret);
192     RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, pcap);
193     // 11.If Type(result) is not Object, then
194     if (!result->IsECMAObject()) {
195         // a.Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
196         JSHandle<JSObject> resolutionError =
197             factory->GetJSError(ErrorType::TYPE_ERROR, "AsyncFromSyncIteratorPrototype.return: is not Object.");
198         JSHandle<JSTaggedValue> rstErr = JSHandle<JSTaggedValue>::Cast(resolutionError);
199         JSHandle<JSTaggedValue> reject(thread, pcap->GetReject());
200         EcmaRuntimeCallInfo *info =
201             EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefinedValue, undefinedValue, 1);
202         info->SetCallArg(rstErr.GetTaggedValue());
203         JSFunction::Call(info);
204 
205         // b.Return promiseCapability.[[Promise]].
206         JSHandle<JSObject> promise(thread, pcap->GetPromise());
207         return promise.GetTaggedValue();
208     }
209     // 12.Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability).
210     return JSAsyncFromSyncIterator::AsyncFromSyncIteratorContinuation(thread, result, pcap);
211 }
212 }  // namespace panda::ecmascript::builtins
213