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 info->SetCallArg(iterResult.GetTaggedValue());
94 return pcap->GetPromise();
95 }
96 JSTaggedValue ret;
97 // 8.If value is present, then
98 if (value->IsNull()) {
99 EcmaRuntimeCallInfo *callInfo =
100 EcmaInterpreter::NewRuntimeCallInfo(thread, throwResult, syncIterator, undefinedValue, 0);
101 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, throwResult, pcap);
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 info->SetCallArg(resolutionError.GetTaggedValue());
123 JSFunction::Call(info);
124 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
125
126 // b.Return promiseCapability.[[Promise]].
127 JSHandle<JSObject> promise(thread, pcap->GetPromise());
128 return promise.GetTaggedValue();
129 }
130 // 12.Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability).
131 return JSAsyncFromSyncIterator::AsyncFromSyncIteratorContinuation(thread, result, pcap);
132 }
133
Return(EcmaRuntimeCallInfo *argv)134 JSTaggedValue BuiltinsAsyncFromSyncIterator::Return(EcmaRuntimeCallInfo *argv)
135 {
136 JSThread *thread = argv->GetThread();
137 BUILTINS_API_TRACE(thread, AsyncFromSyncIterator, Return);
138 [[maybe_unused]] EcmaHandleScope scope(thread);
139 auto vm = thread->GetEcmaVM();
140 const GlobalEnvConstants *globalConstant = thread->GlobalConstants();
141 ObjectFactory *factory = vm->GetFactory();
142 // 1.Let O be the this value.
143 JSHandle<JSTaggedValue> thisValue = GetThis(argv);
144 if (!thisValue->IsAsyncFromSyncIterator()) {
145 THROW_TYPE_ERROR_AND_RETURN(thread, "is not AsyncFromSyncIterator", JSTaggedValue::Exception());
146 }
147
148 // 3.Let promiseCapability be ! NewPromiseCapability(%Promise%).
149 JSHandle<GlobalEnv> env = vm->GetGlobalEnv();
150 JSHandle<PromiseCapability> pcap =
151 JSPromise::NewPromiseCapability(thread, JSHandle<JSTaggedValue>::Cast(env->GetPromiseFunction()));
152 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
153 // 4.Let syncIterator be O.[[SyncIteratorRecord]].[[Iterator]].
154 JSHandle<JSAsyncFromSyncIterator> asyncIterator(thisValue);
155 JSHandle<AsyncIteratorRecord> syncIteratorRecord(thread, asyncIterator->GetSyncIteratorRecord());
156 JSHandle<JSTaggedValue> syncIterator(thread, syncIteratorRecord->GetIterator());
157 // 5.Let return be GetMethod(syncIterator, "return").
158 JSHandle<JSTaggedValue> returnString = globalConstant->GetHandledReturnString();
159 JSHandle<JSTaggedValue> returnResult = JSObject::GetMethod(thread, syncIterator, returnString);
160 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, returnResult, pcap);
161 JSHandle<JSTaggedValue> value = base::BuiltinsBase::GetCallArg(argv, 0);
162 JSHandle<JSTaggedValue> undefinedValue = globalConstant->GetHandledUndefined();
163 // 7.If return is undefined, then
164 if (returnResult->IsUndefined()) {
165 JSHandle<JSObject> iterResult = JSIterator::CreateIterResultObject(thread, value, true);
166 JSHandle<JSTaggedValue> its = JSHandle<JSTaggedValue>::Cast(iterResult);
167 JSHandle<JSTaggedValue> resolve(thread, pcap->GetResolve());
168 EcmaRuntimeCallInfo *info =
169 EcmaInterpreter::NewRuntimeCallInfo(thread, resolve, undefinedValue, undefinedValue, 1);
170 info->SetCallArg(its.GetTaggedValue());
171 JSHandle<JSObject> promise(thread, pcap->GetPromise());
172 return promise.GetTaggedValue();
173 }
174 JSTaggedValue ret;
175 // 8.If value is present, then
176 if (value->IsNull()) {
177 EcmaRuntimeCallInfo *callInfo =
178 EcmaInterpreter::NewRuntimeCallInfo(thread, returnResult, syncIterator, undefinedValue, 0);
179 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, returnResult, pcap);
180 ret = JSFunction::Call(callInfo);
181 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
182 } else {
183 EcmaRuntimeCallInfo *callInfo =
184 EcmaInterpreter::NewRuntimeCallInfo(thread, returnResult, syncIterator, undefinedValue, 1);
185 RETURN_REJECT_PROMISE_IF_ABRUPT(thread, returnResult, pcap);
186 callInfo->SetCallArg(value.GetTaggedValue());
187 ret = JSFunction::Call(callInfo);
188 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
189 }
190 JSHandle<JSTaggedValue> result(thread, ret);
191 // 11.If Type(result) is not Object, then
192 if (!result->IsECMAObject()) {
193 // a.Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).
194 JSHandle<JSObject> resolutionError = factory->GetJSError(ErrorType::TYPE_ERROR,
195 "AsyncFromSyncIteratorPrototype.return: is not Object.", StackCheck::NO);
196 JSHandle<JSTaggedValue> rstErr = JSHandle<JSTaggedValue>::Cast(resolutionError);
197 JSHandle<JSTaggedValue> reject(thread, pcap->GetReject());
198 EcmaRuntimeCallInfo *info =
199 EcmaInterpreter::NewRuntimeCallInfo(thread, reject, undefinedValue, undefinedValue, 1);
200 info->SetCallArg(rstErr.GetTaggedValue());
201 JSFunction::Call(info);
202 RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread);
203
204 // b.Return promiseCapability.[[Promise]].
205 JSHandle<JSObject> promise(thread, pcap->GetPromise());
206 return promise.GetTaggedValue();
207 }
208 // 12.Return ! AsyncFromSyncIteratorContinuation(result, promiseCapability).
209 return JSAsyncFromSyncIterator::AsyncFromSyncIteratorContinuation(thread, result, pcap);
210 }
211 } // namespace panda::ecmascript::builtins
212