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