14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/js_generator_object.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include "ecmascript/generator_helper.h" 194514f5e3Sopenharmony_ci#include "ecmascript/js_iterator.h" 204514f5e3Sopenharmony_ci#include "ecmascript/js_object-inl.h" 214514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value-inl.h" 224514f5e3Sopenharmony_ci 234514f5e3Sopenharmony_cinamespace panda::ecmascript { 244514f5e3Sopenharmony_ciJSGeneratorState JSGeneratorObject::GeneratorValidate(JSThread *thread, const JSHandle<JSTaggedValue> &obj) 254514f5e3Sopenharmony_ci{ 264514f5e3Sopenharmony_ci // 1.Perform ? RequireInternalSlot(generator, [[GeneratorState]]). 274514f5e3Sopenharmony_ci // 2.Assert: generator also has a [[GeneratorContext]] internal slot. 284514f5e3Sopenharmony_ci if (!obj->IsECMAObject()) { 294514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "Is not object", 304514f5e3Sopenharmony_ci JSGeneratorState::UNDEFINED); 314514f5e3Sopenharmony_ci } 324514f5e3Sopenharmony_ci JSHandle<JSObject> toObj = JSTaggedValue::ToObject(thread, obj); 334514f5e3Sopenharmony_ci if (!toObj->IsGeneratorObject()) { 344514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "Is not generator object", JSGeneratorState::UNDEFINED); 354514f5e3Sopenharmony_ci } 364514f5e3Sopenharmony_ci 374514f5e3Sopenharmony_ci // 3.Let state be generator.[[GeneratorState]]. 384514f5e3Sopenharmony_ci JSHandle<JSGeneratorObject> generator(thread, JSGeneratorObject::Cast(*(toObj))); 394514f5e3Sopenharmony_ci JSGeneratorState state = generator->GetGeneratorState(); 404514f5e3Sopenharmony_ci // 4.If state is executing, throw a TypeError exception. 414514f5e3Sopenharmony_ci if (state == JSGeneratorState::EXECUTING) { 424514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "State is executing", JSGeneratorState::UNDEFINED); 434514f5e3Sopenharmony_ci } 444514f5e3Sopenharmony_ci // 5.Return state. 454514f5e3Sopenharmony_ci return state; 464514f5e3Sopenharmony_ci} 474514f5e3Sopenharmony_ci 484514f5e3Sopenharmony_ciJSHandle<JSObject> JSGeneratorObject::GeneratorResume(JSThread *thread, const JSHandle<JSGeneratorObject> &generator, 494514f5e3Sopenharmony_ci JSTaggedValue value) 504514f5e3Sopenharmony_ci{ 514514f5e3Sopenharmony_ci // 1.Let state be ? GeneratorValidate(generator). 524514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> gen(thread, generator.GetTaggedValue()); 534514f5e3Sopenharmony_ci JSGeneratorState state = GeneratorValidate(thread, gen); 544514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread); 554514f5e3Sopenharmony_ci 564514f5e3Sopenharmony_ci // 2.If state is completed, return CreateIterResultObject(undefined, true). 574514f5e3Sopenharmony_ci if (state == JSGeneratorState::COMPLETED) { 584514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined()); 594514f5e3Sopenharmony_ci return JSIterator::CreateIterResultObject(thread, valueHandle, true); 604514f5e3Sopenharmony_ci } 614514f5e3Sopenharmony_ci 624514f5e3Sopenharmony_ci // 3.Assert: state is either suspendedStart or suspendedYield. 634514f5e3Sopenharmony_ci ASSERT_PRINT(state == JSGeneratorState::SUSPENDED_START || 644514f5e3Sopenharmony_ci state == JSGeneratorState::SUSPENDED_YIELD, 654514f5e3Sopenharmony_ci "state is neither suspendedStart nor suspendedYield"); 664514f5e3Sopenharmony_ci 674514f5e3Sopenharmony_ci // 4.Let genContext be generator.[[GeneratorContext]]. 684514f5e3Sopenharmony_ci JSHandle<GeneratorContext> genContext(thread, generator->GetGeneratorContext()); 694514f5e3Sopenharmony_ci 704514f5e3Sopenharmony_ci // 5.Let methodContext be the running execution context. 714514f5e3Sopenharmony_ci // 6.Suspend methodContext. 724514f5e3Sopenharmony_ci 734514f5e3Sopenharmony_ci // 7.Set generator.[[GeneratorState]] to executing. 744514f5e3Sopenharmony_ci generator->SetGeneratorState(JSGeneratorState::EXECUTING); 754514f5e3Sopenharmony_ci 764514f5e3Sopenharmony_ci // 8.Push genContext onto the execution context stack; genContext is now the running execution context. 774514f5e3Sopenharmony_ci // 9.Resume the suspended evaluation of genContext using NormalCompletion(value) as the result of the operation 784514f5e3Sopenharmony_ci // that suspended it. Let result be the value returned by the resumed computation. 794514f5e3Sopenharmony_ci // 10.Assert: When we return here, genContext has already been removed from the execution context stack and 804514f5e3Sopenharmony_ci // methodContext is the currently running execution context. 814514f5e3Sopenharmony_ci // 11.Return Completion(result). 824514f5e3Sopenharmony_ci JSHandle<JSObject> result = GeneratorHelper::Next(thread, genContext, value); 834514f5e3Sopenharmony_ci return result; 844514f5e3Sopenharmony_ci} 854514f5e3Sopenharmony_ci 864514f5e3Sopenharmony_ciJSHandle<JSObject> JSGeneratorObject::GeneratorResumeAbrupt(JSThread *thread, 874514f5e3Sopenharmony_ci const JSHandle<JSGeneratorObject> &generator, 884514f5e3Sopenharmony_ci const JSHandle<CompletionRecord> &abruptCompletion) 894514f5e3Sopenharmony_ci{ 904514f5e3Sopenharmony_ci // 1.Let state be ? GeneratorValidate(generator). 914514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> gen(thread, generator.GetTaggedValue()); 924514f5e3Sopenharmony_ci JSGeneratorState state = GeneratorValidate(thread, gen); 934514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread); 944514f5e3Sopenharmony_ci 954514f5e3Sopenharmony_ci // 2.If state is suspendedStart, then 964514f5e3Sopenharmony_ci // a.Set generator.[[GeneratorState]] to completed. 974514f5e3Sopenharmony_ci // b.Once a generator enters the completed state it never leaves it and its associated execution context is 984514f5e3Sopenharmony_ci // never resumed. Any execution state associated with generator can be discarded at this point. 994514f5e3Sopenharmony_ci // c.Set state to completed. 1004514f5e3Sopenharmony_ci if (state == JSGeneratorState::SUSPENDED_START) { 1014514f5e3Sopenharmony_ci state = JSGeneratorState::COMPLETED; 1024514f5e3Sopenharmony_ci generator->SetGeneratorState(state); 1034514f5e3Sopenharmony_ci } 1044514f5e3Sopenharmony_ci 1054514f5e3Sopenharmony_ci // 3.If state is completed, then 1064514f5e3Sopenharmony_ci // a.If abruptCompletion.[[Type]] is return, then 1074514f5e3Sopenharmony_ci // i.Return CreateIterResultObject(abruptCompletion.[[Value]], true). 1084514f5e3Sopenharmony_ci // b.Return Completion(abruptCompletion). 1094514f5e3Sopenharmony_ci if (state == JSGeneratorState::COMPLETED) { 1104514f5e3Sopenharmony_ci JSHandle<JSTaggedValue> valueHandle(thread, abruptCompletion->GetValue()); 1114514f5e3Sopenharmony_ci JSHandle<JSObject> result = JSIterator::CreateIterResultObject(thread, valueHandle, true); 1124514f5e3Sopenharmony_ci if (abruptCompletion->GetType() == CompletionRecordType::RETURN) { 1134514f5e3Sopenharmony_ci return result; 1144514f5e3Sopenharmony_ci } 1154514f5e3Sopenharmony_ci THROW_NEW_ERROR_AND_RETURN_VALUE(thread, valueHandle.GetTaggedValue(), result); 1164514f5e3Sopenharmony_ci } 1174514f5e3Sopenharmony_ci 1184514f5e3Sopenharmony_ci // 4.Assert: state is suspendedYield. 1194514f5e3Sopenharmony_ci ASSERT_PRINT(state == JSGeneratorState::SUSPENDED_YIELD, "state is not suspendedYield"); 1204514f5e3Sopenharmony_ci 1214514f5e3Sopenharmony_ci // 5.Let genContext be generator.[[GeneratorContext]]. 1224514f5e3Sopenharmony_ci JSHandle<GeneratorContext> genContext(thread, generator->GetGeneratorContext()); 1234514f5e3Sopenharmony_ci 1244514f5e3Sopenharmony_ci // 6.Let methodContext be the running execution context. 1254514f5e3Sopenharmony_ci // 7.Suspend methodContext. 1264514f5e3Sopenharmony_ci 1274514f5e3Sopenharmony_ci // 8.Set generator.[[GeneratorState]] to executing. 1284514f5e3Sopenharmony_ci generator->SetGeneratorState(JSGeneratorState::EXECUTING); 1294514f5e3Sopenharmony_ci 1304514f5e3Sopenharmony_ci // 9.Push genContext onto the execution context stack; genContext is now the running execution context. 1314514f5e3Sopenharmony_ci // 10.Resume the suspended evaluation of genContext using abruptCompletion as the result of the operation that 1324514f5e3Sopenharmony_ci // suspended it. Let result be the completion record returned by the resumed computation. 1334514f5e3Sopenharmony_ci // 11.Assert: When we return here, genContext has already been removed from the execution context stack and 1344514f5e3Sopenharmony_ci // methodContext is the currently running execution context. 1354514f5e3Sopenharmony_ci // 12.Return Completion(result). 1364514f5e3Sopenharmony_ci JSHandle<JSObject> result; 1374514f5e3Sopenharmony_ci if (abruptCompletion->GetType() == CompletionRecordType::RETURN) { 1384514f5e3Sopenharmony_ci result = GeneratorHelper::Return(thread, genContext, abruptCompletion->GetValue()); 1394514f5e3Sopenharmony_ci } else { 1404514f5e3Sopenharmony_ci result = GeneratorHelper::Throw(thread, genContext, abruptCompletion->GetValue()); 1414514f5e3Sopenharmony_ci } 1424514f5e3Sopenharmony_ci return result; 1434514f5e3Sopenharmony_ci} 1444514f5e3Sopenharmony_ci} // namespace panda::ecmascript 145