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