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