1/* 2 * Copyright (c) 2021-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/js_generator_object.h" 17 18#include "ecmascript/generator_helper.h" 19#include "ecmascript/js_iterator.h" 20#include "ecmascript/js_object-inl.h" 21#include "ecmascript/js_tagged_value-inl.h" 22 23namespace panda::ecmascript { 24JSGeneratorState JSGeneratorObject::GeneratorValidate(JSThread *thread, const JSHandle<JSTaggedValue> &obj) 25{ 26 // 1.Perform ? RequireInternalSlot(generator, [[GeneratorState]]). 27 // 2.Assert: generator also has a [[GeneratorContext]] internal slot. 28 if (!obj->IsECMAObject()) { 29 THROW_TYPE_ERROR_AND_RETURN(thread, "Is not object", 30 JSGeneratorState::UNDEFINED); 31 } 32 JSHandle<JSObject> toObj = JSTaggedValue::ToObject(thread, obj); 33 if (!toObj->IsGeneratorObject()) { 34 THROW_TYPE_ERROR_AND_RETURN(thread, "Is not generator object", JSGeneratorState::UNDEFINED); 35 } 36 37 // 3.Let state be generator.[[GeneratorState]]. 38 JSHandle<JSGeneratorObject> generator(thread, JSGeneratorObject::Cast(*(toObj))); 39 JSGeneratorState state = generator->GetGeneratorState(); 40 // 4.If state is executing, throw a TypeError exception. 41 if (state == JSGeneratorState::EXECUTING) { 42 THROW_TYPE_ERROR_AND_RETURN(thread, "State is executing", JSGeneratorState::UNDEFINED); 43 } 44 // 5.Return state. 45 return state; 46} 47 48JSHandle<JSObject> JSGeneratorObject::GeneratorResume(JSThread *thread, const JSHandle<JSGeneratorObject> &generator, 49 JSTaggedValue value) 50{ 51 // 1.Let state be ? GeneratorValidate(generator). 52 JSHandle<JSTaggedValue> gen(thread, generator.GetTaggedValue()); 53 JSGeneratorState state = GeneratorValidate(thread, gen); 54 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread); 55 56 // 2.If state is completed, return CreateIterResultObject(undefined, true). 57 if (state == JSGeneratorState::COMPLETED) { 58 JSHandle<JSTaggedValue> valueHandle(thread, JSTaggedValue::Undefined()); 59 return JSIterator::CreateIterResultObject(thread, valueHandle, true); 60 } 61 62 // 3.Assert: state is either suspendedStart or suspendedYield. 63 ASSERT_PRINT(state == JSGeneratorState::SUSPENDED_START || 64 state == JSGeneratorState::SUSPENDED_YIELD, 65 "state is neither suspendedStart nor suspendedYield"); 66 67 // 4.Let genContext be generator.[[GeneratorContext]]. 68 JSHandle<GeneratorContext> genContext(thread, generator->GetGeneratorContext()); 69 70 // 5.Let methodContext be the running execution context. 71 // 6.Suspend methodContext. 72 73 // 7.Set generator.[[GeneratorState]] to executing. 74 generator->SetGeneratorState(JSGeneratorState::EXECUTING); 75 76 // 8.Push genContext onto the execution context stack; genContext is now the running execution context. 77 // 9.Resume the suspended evaluation of genContext using NormalCompletion(value) as the result of the operation 78 // that suspended it. Let result be the value returned by the resumed computation. 79 // 10.Assert: When we return here, genContext has already been removed from the execution context stack and 80 // methodContext is the currently running execution context. 81 // 11.Return Completion(result). 82 JSHandle<JSObject> result = GeneratorHelper::Next(thread, genContext, value); 83 return result; 84} 85 86JSHandle<JSObject> JSGeneratorObject::GeneratorResumeAbrupt(JSThread *thread, 87 const JSHandle<JSGeneratorObject> &generator, 88 const JSHandle<CompletionRecord> &abruptCompletion) 89{ 90 // 1.Let state be ? GeneratorValidate(generator). 91 JSHandle<JSTaggedValue> gen(thread, generator.GetTaggedValue()); 92 JSGeneratorState state = GeneratorValidate(thread, gen); 93 RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSObject, thread); 94 95 // 2.If state is suspendedStart, then 96 // a.Set generator.[[GeneratorState]] to completed. 97 // b.Once a generator enters the completed state it never leaves it and its associated execution context is 98 // never resumed. Any execution state associated with generator can be discarded at this point. 99 // c.Set state to completed. 100 if (state == JSGeneratorState::SUSPENDED_START) { 101 state = JSGeneratorState::COMPLETED; 102 generator->SetGeneratorState(state); 103 } 104 105 // 3.If state is completed, then 106 // a.If abruptCompletion.[[Type]] is return, then 107 // i.Return CreateIterResultObject(abruptCompletion.[[Value]], true). 108 // b.Return Completion(abruptCompletion). 109 if (state == JSGeneratorState::COMPLETED) { 110 JSHandle<JSTaggedValue> valueHandle(thread, abruptCompletion->GetValue()); 111 JSHandle<JSObject> result = JSIterator::CreateIterResultObject(thread, valueHandle, true); 112 if (abruptCompletion->GetType() == CompletionRecordType::RETURN) { 113 return result; 114 } 115 THROW_NEW_ERROR_AND_RETURN_VALUE(thread, valueHandle.GetTaggedValue(), result); 116 } 117 118 // 4.Assert: state is suspendedYield. 119 ASSERT_PRINT(state == JSGeneratorState::SUSPENDED_YIELD, "state is not suspendedYield"); 120 121 // 5.Let genContext be generator.[[GeneratorContext]]. 122 JSHandle<GeneratorContext> genContext(thread, generator->GetGeneratorContext()); 123 124 // 6.Let methodContext be the running execution context. 125 // 7.Suspend methodContext. 126 127 // 8.Set generator.[[GeneratorState]] to executing. 128 generator->SetGeneratorState(JSGeneratorState::EXECUTING); 129 130 // 9.Push genContext onto the execution context stack; genContext is now the running execution context. 131 // 10.Resume the suspended evaluation of genContext using abruptCompletion as the result of the operation that 132 // suspended it. Let result be the completion record returned by the resumed computation. 133 // 11.Assert: When we return here, genContext has already been removed from the execution context stack and 134 // methodContext is the currently running execution context. 135 // 12.Return Completion(result). 136 JSHandle<JSObject> result; 137 if (abruptCompletion->GetType() == CompletionRecordType::RETURN) { 138 result = GeneratorHelper::Return(thread, genContext, abruptCompletion->GetValue()); 139 } else { 140 result = GeneratorHelper::Throw(thread, genContext, abruptCompletion->GetValue()); 141 } 142 return result; 143} 144} // namespace panda::ecmascript 145