/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/interpreter/slow_runtime_stub.h" #include "ecmascript/base/number_helper.h" #include "ecmascript/builtins/builtins_regexp.h" #include "ecmascript/global_dictionary-inl.h" #include "ecmascript/ic/profile_type_info.h" #include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/interpreter/interpreter-inl.h" #include "ecmascript/interpreter/slow_runtime_helper.h" #include "ecmascript/jspandafile/program_object.h" #include "ecmascript/jspandafile/scope_info_extractor.h" #include "ecmascript/js_arguments.h" #include "ecmascript/js_array.h" #include "ecmascript/js_array_iterator.h" #include "ecmascript/js_async_function.h" #include "ecmascript/js_for_in_iterator.h" #include "ecmascript/js_function.h" #include "ecmascript/js_generator_object.h" #include "ecmascript/js_hclass-inl.h" #include "ecmascript/js_iterator.h" #include "ecmascript/js_promise.h" #include "ecmascript/js_proxy.h" #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/js_thread.h" #include "ecmascript/module/js_module_manager.h" #include "ecmascript/tagged_dictionary.h" #include "ecmascript/runtime_call_id.h" #include "ecmascript/template_string.h" namespace panda::ecmascript { JSTaggedValue SlowRuntimeStub::CallSpreadDyn(JSThread *thread, JSTaggedValue func, JSTaggedValue obj, JSTaggedValue array) { INTERPRETER_TRACE(thread, CallSpreadDyn); if ((!obj.IsUndefined() && !obj.IsECMAObject()) || !func.IsJSFunction() || !array.IsJSArray()) { THROW_TYPE_ERROR_AND_RETURN(thread, "cannot Callspread", JSTaggedValue::Exception()); } [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle jsFunc(thread, func); JSHandle jsArray(thread, array); JSHandle taggedObj(thread, obj); JSHandle coretypesArray(thread, GetCallSpreadArgs(thread, jsArray.GetTaggedValue())); const size_t argsLength = coretypesArray->GetLength(); JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo info = EcmaInterpreter::NewRuntimeCallInfo(thread, JSHandle(jsFunc), taggedObj, undefined, argsLength); info.SetCallArg(argsLength, coretypesArray); return EcmaInterpreter::Execute(&info); } JSTaggedValue SlowRuntimeStub::NegDyn(JSThread *thread, JSTaggedValue value) { INTERPRETER_TRACE(thread, NegDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle inputTag(thread, value); JSHandle inputVal = JSTaggedValue::ToNumeric(thread, inputTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (inputVal->IsBigInt()) { JSHandle bigValue(inputVal); return BigInt::UnaryMinus(thread, bigValue).GetTaggedValue(); } JSTaggedNumber number(inputVal.GetTaggedValue()); if (number.IsInt()) { int32_t intValue = number.GetInt(); if (intValue == 0) { return JSTaggedValue(-0.0); } return JSTaggedValue(-intValue); } if (number.IsDouble()) { return JSTaggedValue(-number.GetDouble()); } UNREACHABLE(); } JSTaggedValue SlowRuntimeStub::AsyncFunctionEnter(JSThread *thread) { INTERPRETER_TRACE(thread, AsyncFunctionEnter); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); [[maybe_unused]] EcmaHandleScope handleScope(thread); // 1. create promise JSHandle globalEnv = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle promiseFunc = globalEnv->GetPromiseFunction(); JSHandle promiseObject = JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(promiseFunc), promiseFunc)); promiseObject->SetPromiseState(PromiseState::PENDING); // 2. create asyncfuncobj JSHandle asyncFuncObj = factory->NewJSAsyncFuncObject(); asyncFuncObj->SetPromise(thread, promiseObject); JSHandle context = factory->NewGeneratorContext(); context->SetGeneratorObject(thread, asyncFuncObj); // change state to EXECUTING asyncFuncObj->SetGeneratorState(JSGeneratorState::EXECUTING); asyncFuncObj->SetGeneratorContext(thread, context); // 3. return asyncfuncobj RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return asyncFuncObj.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::ToNumber(JSThread *thread, JSTaggedValue value) { INTERPRETER_TRACE(thread, Tonumber); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle number(thread, value); // may return exception return JSTaggedValue::ToNumeric(thread, number).GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::NotDyn(JSThread *thread, JSTaggedValue value) { INTERPRETER_TRACE(thread, NotDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle inputTag(thread, value); JSHandle inputVal = JSTaggedValue::ToNumeric(thread, inputTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (inputVal->IsBigInt()) { JSHandle bigValue(inputVal); return BigInt::BitwiseNOT(thread, bigValue).GetTaggedValue(); } int32_t number = JSTaggedValue::ToInt32(thread, inputVal); return JSTaggedValue(~number); // NOLINT(hicpp-signed-bitwise) } JSTaggedValue SlowRuntimeStub::IncDyn(JSThread *thread, JSTaggedValue value) { INTERPRETER_TRACE(thread, IncDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle inputTag(thread, value); JSHandle inputVal = JSTaggedValue::ToNumeric(thread, inputTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (inputVal->IsBigInt()) { JSHandle bigValue(inputVal); return BigInt::BigintAddOne(thread, bigValue).GetTaggedValue(); } JSTaggedNumber number(inputVal.GetTaggedValue()); return JSTaggedValue(++number); } JSTaggedValue SlowRuntimeStub::DecDyn(JSThread *thread, JSTaggedValue value) { INTERPRETER_TRACE(thread, DecDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle inputTag(thread, value); JSHandle inputVal = JSTaggedValue::ToNumeric(thread, inputTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (inputVal->IsBigInt()) { JSHandle bigValue(inputVal); return BigInt::BigintSubOne(thread, bigValue).GetTaggedValue(); } JSTaggedNumber number(inputVal.GetTaggedValue()); return JSTaggedValue(--number); } void SlowRuntimeStub::ThrowDyn(JSThread *thread, JSTaggedValue value) { INTERPRETER_TRACE(thread, ThrowDyn); thread->SetException(value); } JSTaggedValue SlowRuntimeStub::GetPropIterator(JSThread *thread, JSTaggedValue value) { INTERPRETER_TRACE(thread, GetPropIterator); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle objHandle(thread, value); JSHandle iteratorHandle = JSObject::EnumerateObjectProperties(thread, objHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return iteratorHandle.GetTaggedValue(); } void SlowRuntimeStub::ThrowConstAssignment(JSThread *thread, JSTaggedValue value) { INTERPRETER_TRACE(thread, ThrowConstAssignment); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle name(thread, value.GetTaggedObject()); JSHandle info = factory->NewFromASCII("Assignment to const variable "); JSHandle msg = factory->ConcatFromString(info, name); THROW_NEW_ERROR_AND_RETURN(thread, factory->NewJSError(base::ErrorType::TYPE_ERROR, msg).GetTaggedValue()); } JSTaggedValue SlowRuntimeStub::Add2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, Add2Dyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftValue(thread, left); JSHandle rightValue(thread, right); if (leftValue->IsString() && rightValue->IsString()) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle newString = factory->ConcatFromString(JSHandle(leftValue), JSHandle(rightValue)); return newString.GetTaggedValue(); } JSHandle primitiveA0(thread, JSTaggedValue::ToPrimitive(thread, leftValue)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle primitiveA1(thread, JSTaggedValue::ToPrimitive(thread, rightValue)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // contain string if (primitiveA0->IsString() || primitiveA1->IsString()) { JSHandle stringA0 = JSTaggedValue::ToString(thread, primitiveA0); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle stringA1 = JSTaggedValue::ToString(thread, primitiveA1); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle newString = factory->ConcatFromString(stringA0, stringA1); return newString.GetTaggedValue(); } JSHandle valLeft = JSTaggedValue::ToNumeric(thread, primitiveA0); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle valRight = JSTaggedValue::ToNumeric(thread, primitiveA1); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (valLeft->IsBigInt() || valRight->IsBigInt()) { if (valLeft->IsBigInt() && valRight->IsBigInt()) { JSHandle bigLeft(valLeft); JSHandle bigRight(valRight); return BigInt::Add(thread, bigLeft, bigRight).GetTaggedValue(); } return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); } double doubleA0 = valLeft->GetNumber(); double doubleA1 = valRight->GetNumber(); return JSTaggedValue(doubleA0 + doubleA1); } JSTaggedValue SlowRuntimeStub::Sub2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, Sub2Dyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftTag(thread, left); JSHandle rightTag(thread, right); JSHandle valLeft = JSTaggedValue::ToNumeric(thread, leftTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle valRight = JSTaggedValue::ToNumeric(thread, rightTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (valLeft->IsBigInt() || valRight->IsBigInt()) { if (valLeft->IsBigInt() && valRight->IsBigInt()) { JSHandle bigLeft(valLeft); JSHandle bigRight(valRight); return BigInt::Subtract(thread, bigLeft, bigRight).GetTaggedValue(); } return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); } JSTaggedNumber number0(valLeft.GetTaggedValue()); JSTaggedNumber number1(valRight.GetTaggedValue()); return number0 - number1; } JSTaggedValue SlowRuntimeStub::Mul2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, Mul2Dyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftTag(thread, left); JSHandle rightTag(thread, right); JSHandle valLeft = JSTaggedValue::ToNumeric(thread, leftTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle valRight = JSTaggedValue::ToNumeric(thread, rightTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 9. ReturnIfAbrupt(rnum). if (valLeft->IsBigInt() || valRight->IsBigInt()) { if (valLeft->IsBigInt() && valRight->IsBigInt()) { JSHandle bigLeft(valLeft); JSHandle bigRight(valRight); return BigInt::Multiply(thread, bigLeft, bigRight).GetTaggedValue(); } return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); } // 12.6.3.1 Applying the * Operator JSTaggedNumber number0(valLeft.GetTaggedValue()); JSTaggedNumber number1(valRight.GetTaggedValue()); return number0 * number1; } JSTaggedValue SlowRuntimeStub::Div2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, Div2Dyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftTag(thread, left); JSHandle rightTag(thread, right); JSHandle valLeft = JSTaggedValue::ToNumeric(thread, leftTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle valRight = JSTaggedValue::ToNumeric(thread, rightTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (valLeft->IsBigInt() || valRight->IsBigInt()) { if (valLeft->IsBigInt() && valRight->IsBigInt()) { JSHandle bigLeft(valLeft); JSHandle bigRight(valRight); return BigInt::Divide(thread, bigLeft, bigRight).GetTaggedValue(); } return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); } double dLeft = valLeft->GetNumber(); double dRight = valRight->GetNumber(); if (dRight == 0) { if (dLeft == 0 || std::isnan(dLeft)) { return JSTaggedValue(base::NAN_VALUE); } bool positive = (((bit_cast(dRight)) & base::DOUBLE_SIGN_MASK) == ((bit_cast(dLeft)) & base::DOUBLE_SIGN_MASK)); return JSTaggedValue(positive ? base::POSITIVE_INFINITY : -base::POSITIVE_INFINITY); } return JSTaggedValue(dLeft / dRight); } JSTaggedValue SlowRuntimeStub::Mod2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, Mod2Dyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftTag(thread, left); JSHandle rightTag(thread, right); JSHandle valLeft = JSTaggedValue::ToNumeric(thread, leftTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle valRight = JSTaggedValue::ToNumeric(thread, rightTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 12.6.3.3 Applying the % Operator if (valLeft->IsBigInt() || valRight->IsBigInt()) { if (valLeft->IsBigInt() && valRight->IsBigInt()) { JSHandle leftBigint(valLeft); JSHandle rightBigint(valRight); return BigInt::Remainder(thread, leftBigint, rightBigint).GetTaggedValue(); } return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); } double dLeft = valLeft->GetNumber(); double dRight = valRight->GetNumber(); // 12.6.3.3 Applying the % Operator if ((dRight == 0.0) || std::isnan(dRight) || std::isnan(dLeft) || std::isinf(dLeft)) { return JSTaggedValue(base::NAN_VALUE); } if ((dLeft == 0.0) || std::isinf(dRight)) { return JSTaggedValue(dLeft); } return JSTaggedValue(std::fmod(dLeft, dRight)); } JSTaggedValue SlowRuntimeStub::EqDyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, EqDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftValue(thread, left); JSHandle rightValue(thread, right); bool ret = JSTaggedValue::Equal(thread, leftValue, rightValue); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return (ret ? JSTaggedValue::True() : JSTaggedValue::False()); } JSTaggedValue SlowRuntimeStub::NotEqDyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, NotEqDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftValue(thread, left); JSHandle rightValue(thread, right); bool ret = JSTaggedValue::Equal(thread, leftValue, rightValue); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return (ret ? JSTaggedValue::False() : JSTaggedValue::True()); } JSTaggedValue SlowRuntimeStub::LessDyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, LessDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftValue(thread, left); JSHandle rightValue(thread, right); bool ret = JSTaggedValue::Compare(thread, leftValue, rightValue) == ComparisonResult::LESS; RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return (ret ? JSTaggedValue::True() : JSTaggedValue::False()); } JSTaggedValue SlowRuntimeStub::LessEqDyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, LessEqDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftValue(thread, left); JSHandle rightValue(thread, right); bool ret = JSTaggedValue::Compare(thread, leftValue, rightValue) <= ComparisonResult::EQUAL; RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return (ret ? JSTaggedValue::True() : JSTaggedValue::False()); } JSTaggedValue SlowRuntimeStub::GreaterDyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, GreaterDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftValue(thread, left); JSHandle rightValue(thread, right); bool ret = JSTaggedValue::Compare(thread, leftValue, rightValue) == ComparisonResult::GREAT; RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return (ret ? JSTaggedValue::True() : JSTaggedValue::False()); } JSTaggedValue SlowRuntimeStub::GreaterEqDyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, GreaterEqDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftValue(thread, left); JSHandle rightValue(thread, right); ComparisonResult comparison = JSTaggedValue::Compare(thread, leftValue, rightValue); bool ret = (comparison == ComparisonResult::GREAT) || (comparison == ComparisonResult::EQUAL); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return (ret ? JSTaggedValue::True() : JSTaggedValue::False()); } JSTaggedValue SlowRuntimeStub::Shl2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, Shl2Dyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftTag(thread, left); JSHandle rightTag(thread, right); JSHandle leftValue = JSTaggedValue::ToNumeric(thread, leftTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle rightValue = JSTaggedValue::ToNumeric(thread, rightTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (leftValue->IsBigInt() || rightValue->IsBigInt()) { if (leftValue->IsBigInt() && rightValue->IsBigInt()) { JSHandle leftBigint(leftValue); JSHandle rightBigint(rightValue); return BigInt::LeftShift(thread, leftBigint, rightBigint).GetTaggedValue(); } return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); } JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, leftValue.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, rightValue.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); int32_t opNumber0 = taggedNumber0.GetInt(); int32_t opNumber1 = taggedNumber1.GetInt(); uint32_t shift = static_cast(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers) using unsigned_type = std::make_unsigned_t; auto ret = static_cast(static_cast(opNumber0) << shift); // NOLINT(hicpp-signed-bitwise) return JSTaggedValue(ret); } JSTaggedValue SlowRuntimeStub::Shr2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, Shr2Dyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftTag(thread, left); JSHandle rightTag(thread, right); JSHandle valLeft = JSTaggedValue::ToNumeric(thread, leftTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle valRight = JSTaggedValue::ToNumeric(thread, rightTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (valLeft->IsBigInt() || valRight->IsBigInt()) { if (valLeft->IsBigInt() && valRight->IsBigInt()) { return BigInt::UnsignedRightShift(thread); } return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); } JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, valLeft.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, valRight.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); int32_t opNumber0 = taggedNumber0.GetInt(); int32_t opNumber1 = taggedNumber1.GetInt(); uint32_t shift = static_cast(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers) using unsigned_type = std::make_unsigned_t; auto ret = static_cast(static_cast(opNumber0) >> shift); // NOLINT(hicpp-signed-bitwise) return JSTaggedValue(ret); } JSTaggedValue SlowRuntimeStub::Ashr2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, Ashr2Dyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftTag(thread, left); JSHandle rightTag(thread, right); JSHandle valLeft = JSTaggedValue::ToNumeric(thread, leftTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle valRight = JSTaggedValue::ToNumeric(thread, rightTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (valLeft->IsBigInt() || valRight->IsBigInt()) { if (valLeft->IsBigInt() && valRight->IsBigInt()) { JSHandle bigLeft(valLeft); JSHandle bigRight(valRight); return BigInt::SignedRightShift(thread, bigLeft, bigRight).GetTaggedValue(); } return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); } JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, valLeft.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, valRight.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); int32_t opNumber0 = taggedNumber0.GetInt(); int32_t opNumber1 = taggedNumber1.GetInt(); uint32_t shift = static_cast(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers) auto ret = static_cast(opNumber0 >> shift); // NOLINT(hicpp-signed-bitwise) return JSTaggedValue(ret); } JSTaggedValue SlowRuntimeStub::And2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, And2Dyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftTag(thread, left); JSHandle rightTag(thread, right); JSHandle valLeft = JSTaggedValue::ToNumeric(thread, leftTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle valRight = JSTaggedValue::ToNumeric(thread, rightTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (valLeft->IsBigInt() || valRight->IsBigInt()) { if (valLeft->IsBigInt() && valRight->IsBigInt()) { JSHandle leftBigint(valLeft); JSHandle rightBigint(valRight); return BigInt::BitwiseAND(thread, leftBigint, rightBigint).GetTaggedValue(); } return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); } JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, valLeft.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, valRight.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); int32_t opNumber0 = taggedNumber0.GetInt(); int32_t opNumber1 = taggedNumber1.GetInt(); // NOLINT(hicpp-signed-bitwise) auto ret = static_cast(opNumber0) & static_cast(opNumber1); return JSTaggedValue(static_cast(ret)); } JSTaggedValue SlowRuntimeStub::Or2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, Or2Dyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftTag(thread, left); JSHandle rightTag(thread, right); JSHandle valLeft = JSTaggedValue::ToNumeric(thread, leftTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle valRight = JSTaggedValue::ToNumeric(thread, rightTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (valLeft->IsBigInt() || valRight->IsBigInt()) { if (valLeft->IsBigInt() && valRight->IsBigInt()) { JSHandle leftBigint(valLeft); JSHandle rightBigint(valRight); return BigInt::BitwiseOR(thread, leftBigint, rightBigint).GetTaggedValue(); } return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); } JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, valLeft.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, valRight.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); int32_t opNumber0 = taggedNumber0.GetInt(); int32_t opNumber1 = taggedNumber1.GetInt(); // NOLINT(hicpp-signed-bitwise) auto ret = static_cast(opNumber0) | static_cast(opNumber1); return JSTaggedValue(static_cast(ret)); } JSTaggedValue SlowRuntimeStub::Xor2Dyn(JSThread *thread, JSTaggedValue left, JSTaggedValue right) { INTERPRETER_TRACE(thread, Xor2Dyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle leftTag(thread, left); JSHandle rightTag(thread, right); JSHandle valLeft = JSTaggedValue::ToNumeric(thread, leftTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle valRight = JSTaggedValue::ToNumeric(thread, rightTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (valLeft->IsBigInt() || valRight->IsBigInt()) { if (valLeft->IsBigInt() && valRight->IsBigInt()) { JSHandle leftBigint(valLeft); JSHandle rightBigint(valRight); return BigInt::BitwiseXOR(thread, leftBigint, rightBigint).GetTaggedValue(); } return ThrowTypeError(thread, "Cannot mix BigInt and other types, use explicit conversions"); } JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, valLeft.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, valRight.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); int32_t opNumber0 = taggedNumber0.GetInt(); int32_t opNumber1 = taggedNumber1.GetInt(); // NOLINT(hicpp-signed-bitwise) auto ret = static_cast(opNumber0) ^ static_cast(opNumber1); return JSTaggedValue(static_cast(ret)); } JSTaggedValue SlowRuntimeStub::ToJSTaggedValueWithInt32(JSThread *thread, JSTaggedValue value) { INTERPRETER_TRACE(thread, ToJSTaggedValueWithInt32); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle valueHandle(thread, value); int32_t res = JSTaggedValue::ToInt32(thread, valueHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue(res); } JSTaggedValue SlowRuntimeStub::ToJSTaggedValueWithUint32(JSThread *thread, JSTaggedValue value) { INTERPRETER_TRACE(thread, ToJSTaggedValueWithUint32); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle valueHandle(thread, value); int32_t res = JSTaggedValue::ToUint32(thread, valueHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue(res); } JSTaggedValue SlowRuntimeStub::DelObjProp(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop) { INTERPRETER_TRACE(thread, Delobjprop); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle objHandle(thread, obj); JSHandle propHandle(thread, prop); JSHandle jsObj(JSTaggedValue::ToObject(thread, objHandle)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle propKey = JSTaggedValue::ToPropertyKey(thread, propHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); bool ret = JSTaggedValue::DeletePropertyOrThrow(thread, jsObj, propKey); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue(ret); } JSTaggedValue SlowRuntimeStub::NewObjDynRange(JSThread *thread, JSTaggedValue func, JSTaggedValue newTarget, uint16_t firstArgIdx, uint16_t length) { INTERPRETER_TRACE(thread, NewobjDynrange); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle funcHandle(thread, func); JSHandle newTargetHandle(thread, newTarget); JSHandle preArgs(thread, JSTaggedValue::Undefined()); auto tagged = SlowRuntimeHelper::Construct(thread, funcHandle, newTargetHandle, preArgs, length, firstArgIdx); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return tagged; } JSTaggedValue SlowRuntimeStub::CreateObjectWithExcludedKeys(JSThread *thread, uint16_t numKeys, JSTaggedValue objVal, uint16_t firstArgRegIdx) { INTERPRETER_TRACE(thread, CreateObjectWithExcludedKeys); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); ASSERT(objVal.IsJSObject()); JSHandle obj(thread, objVal); uint32_t numExcludedKeys = 0; JSHandle excludedKeys = factory->NewTaggedArray(numKeys + 1); FrameHandler frameHandler(thread); JSTaggedValue excludedKey = frameHandler.GetVRegValue(firstArgRegIdx); if (!excludedKey.IsUndefined()) { numExcludedKeys = numKeys + 1; excludedKeys->Set(thread, 0, excludedKey); for (uint32_t i = 1; i < numExcludedKeys; i++) { excludedKey = frameHandler.GetVRegValue(firstArgRegIdx + i); excludedKeys->Set(thread, i, excludedKey); } } uint32_t numAllKeys = obj->GetNumberOfKeys(); JSHandle allKeys = factory->NewTaggedArray(numAllKeys); JSObject::GetAllKeys(thread, obj, 0, allKeys); JSHandle restObj = factory->NewEmptyJSObject(); JSMutableHandle key(thread, JSTaggedValue::Undefined()); for (uint32_t i = 0; i < numAllKeys; i++) { key.Update(allKeys->Get(i)); bool isExcludedKey = false; for (uint32_t j = 0; j < numExcludedKeys; j++) { if (JSTaggedValue::Equal(thread, key, JSHandle(thread, excludedKeys->Get(j)))) { isExcludedKey = true; break; } } if (!isExcludedKey) { PropertyDescriptor desc(thread); bool success = JSObject::GetOwnProperty(thread, obj, key, desc); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (success && desc.IsEnumerable()) { JSHandle value = JSObject::GetProperty(thread, obj, key).GetValue(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSObject::SetProperty(thread, restObj, key, value, true); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } } } return restObj.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::ExpDyn(JSThread *thread, JSTaggedValue base, JSTaggedValue exponent) { INTERPRETER_TRACE(thread, ExpDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle baseTag(thread, base); JSHandle exponentTag(thread, exponent); JSHandle valBase = JSTaggedValue::ToNumeric(thread, baseTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle valExponent = JSTaggedValue::ToNumeric(thread, exponentTag); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (valBase->IsBigInt() || valExponent->IsBigInt()) { if (valBase->IsBigInt() && valExponent->IsBigInt()) { JSHandle bigBaseVale(valBase); JSHandle bigExponentValue(valExponent); return BigInt::Exponentiate(thread, bigBaseVale, bigExponentValue).GetTaggedValue(); } THROW_TYPE_ERROR_AND_RETURN(thread, "Cannot mix BigInt and other types, use explicit conversions", JSTaggedValue::Exception()); } double doubleBase = valBase->GetNumber(); double doubleExponent = valExponent->GetNumber(); if (std::abs(doubleBase) == 1 && std::isinf(doubleExponent)) { return JSTaggedValue(base::NAN_VALUE); } if (((doubleBase == 0) && ((bit_cast(doubleBase)) & base::DOUBLE_SIGN_MASK) == base::DOUBLE_SIGN_MASK) && std::isfinite(doubleExponent) && base::NumberHelper::TruncateDouble(doubleExponent) == doubleExponent && base::NumberHelper::TruncateDouble(doubleExponent / 2) + base::HALF == (doubleExponent / 2)) { // 2: half if (doubleExponent > 0) { return JSTaggedValue(-0.0); } if (doubleExponent < 0) { return JSTaggedValue(-base::POSITIVE_INFINITY); } } return JSTaggedValue(std::pow(doubleBase, doubleExponent)); } JSTaggedValue SlowRuntimeStub::IsInDyn(JSThread *thread, JSTaggedValue prop, JSTaggedValue obj) { INTERPRETER_TRACE(thread, IsInDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle propHandle(thread, prop); JSHandle objHandle(thread, obj); if (!objHandle->IsECMAObject()) { return ThrowTypeError(thread, "Cannot use 'in' operator in Non-Object"); } JSHandle propKey = JSTaggedValue::ToPropertyKey(thread, propHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); bool ret = JSTaggedValue::HasProperty(thread, objHandle, propKey); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue(ret); } JSTaggedValue SlowRuntimeStub::InstanceofDyn(JSThread *thread, JSTaggedValue obj, JSTaggedValue target) { INTERPRETER_TRACE(thread, InstanceofDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle objHandle(thread, obj); JSHandle targetHandle(thread, target); bool ret = JSObject::InstanceOf(thread, objHandle, targetHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue(ret); } JSTaggedValue SlowRuntimeStub::NewLexicalEnvDyn(JSThread *thread, uint16_t numVars) { INTERPRETER_TRACE(thread, NewlexenvDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle newEnv = factory->NewLexicalEnv(numVars); JSTaggedValue currentLexenv = thread->GetCurrentLexenv(); newEnv->SetParentEnv(thread, currentLexenv); newEnv->SetScopeInfo(thread, JSTaggedValue::Hole()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return newEnv.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::NewLexicalEnvWithNameDyn(JSThread *thread, uint16_t numVars, uint16_t scopeId) { INTERPRETER_TRACE(thread, NewlexenvwithNameDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle newEnv = factory->NewLexicalEnv(numVars); JSTaggedValue currentLexenv = thread->GetCurrentLexenv(); newEnv->SetParentEnv(thread, currentLexenv); JSTaggedValue scopeInfo = ScopeInfoExtractor::GenerateScopeInfo(thread, scopeId); newEnv->SetScopeInfo(thread, scopeInfo); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return newEnv.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::CreateIterResultObj(JSThread *thread, JSTaggedValue value, JSTaggedValue flag) { INTERPRETER_TRACE(thread, CreateIterResultObj); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle valueHandle(thread, value); ASSERT(flag.IsBoolean()); bool done = flag.IsTrue(); JSHandle iter = JSIterator::CreateIterResultObject(thread, valueHandle, done); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return iter.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::CreateGeneratorObj(JSThread *thread, JSTaggedValue genFunc) { INTERPRETER_TRACE(thread, CreateGeneratorObj); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle generatorFunction(thread, genFunc); JSHandle obj = factory->NewJSGeneratorObject(generatorFunction); JSHandle context = factory->NewGeneratorContext(); context->SetGeneratorObject(thread, obj.GetTaggedValue()); // change state to SUSPENDED_START obj->SetGeneratorState(JSGeneratorState::SUSPENDED_START); obj->SetGeneratorContext(thread, context); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return obj.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::SuspendGenerator(JSThread *thread, JSTaggedValue genObj, JSTaggedValue value) { INTERPRETER_TRACE(thread, SuspendGenerator); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle generatorObjectHandle(thread, genObj); JSHandle genContextHandle(thread, generatorObjectHandle->GetGeneratorContext()); JSHandle valueHandle(thread, value); // save stack, should copy cur_frame, function execute over will free cur_frame SlowRuntimeHelper::SaveFrameToContext(thread, genContextHandle); // change state to SuspendedYield if (generatorObjectHandle->IsExecuting()) { generatorObjectHandle->SetGeneratorState(JSGeneratorState::SUSPENDED_YIELD); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return valueHandle.GetTaggedValue(); } RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return generatorObjectHandle.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::AsyncFunctionAwaitUncaught(JSThread *thread, JSTaggedValue asyncFuncObj, JSTaggedValue value) { INTERPRETER_TRACE(thread, AsyncFunctionAwaitUncaught); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle asyncFuncObjHandle(thread, asyncFuncObj); JSHandle valueHandle(thread, value); JSAsyncFunction::AsyncFunctionAwait(thread, asyncFuncObjHandle, valueHandle); JSHandle promise(thread, asyncFuncObjHandle->GetPromise()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return promise.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::AsyncFunctionResolveOrReject(JSThread *thread, JSTaggedValue asyncFuncObj, JSTaggedValue value, bool is_resolve) { INTERPRETER_TRACE(thread, AsyncFunctionResolveOrReject); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle asyncFuncObjHandle(thread, asyncFuncObj); JSHandle promise(thread, asyncFuncObjHandle->GetPromise()); JSHandle valueHandle(thread, value); // ActivePromise JSHandle reactions = JSPromise::CreateResolvingFunctions(thread, promise); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle thisArg = globalConst->GetHandledUndefined(); JSHandle activeFunc; if (is_resolve) { activeFunc = JSHandle(thread, reactions->GetResolveFunction()); } else { activeFunc = JSHandle(thread, reactions->GetRejectFunction()); } JSHandle undefined = globalConst->GetHandledUndefined(); EcmaRuntimeCallInfo info = EcmaInterpreter::NewRuntimeCallInfo(thread, activeFunc, thisArg, undefined, 1); info.SetCallArg(valueHandle.GetTaggedValue()); [[maybe_unused]] JSTaggedValue res = JSFunction::Call(&info); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return promise.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::NewObjSpreadDyn(JSThread *thread, JSTaggedValue func, JSTaggedValue newTarget, JSTaggedValue array) { INTERPRETER_TRACE(thread, NewobjspreadDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle funcHandle(thread, func); JSHandle newTargetHandle(thread, newTarget); JSHandle jsArray(thread, array); if (!jsArray->IsJSArray()) { return ThrowTypeError(thread, "Cannot Newobjspread"); } uint32_t length = JSHandle::Cast(jsArray)->GetArrayLength(); JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo info = EcmaInterpreter::NewRuntimeCallInfo(thread, funcHandle, undefined, newTargetHandle, length); for (size_t i = 0; i < length; i++) { auto prop = JSTaggedValue::GetProperty(thread, jsArray, i).GetValue(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); info.SetCallArg(i, prop.GetTaggedValue()); } return SlowRuntimeHelper::NewObject(&info); } void SlowRuntimeStub::ThrowUndefinedIfHole(JSThread *thread, JSTaggedValue obj) { INTERPRETER_TRACE(thread, ThrowUndefinedIfHole); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle name(thread, obj); JSHandle info = factory->NewFromASCII(" is not initialized"); JSHandle msg = factory->ConcatFromString(info, name); THROW_NEW_ERROR_AND_RETURN(thread, factory->NewJSError(base::ErrorType::REFERENCE_ERROR, msg).GetTaggedValue()); } JSTaggedValue SlowRuntimeStub::ThrowIfSuperNotCorrectCall(JSThread *thread, uint16_t index, JSTaggedValue thisValue) { INTERPRETER_TRACE(thread, ThrowIfSuperNotCorrectCall); [[maybe_unused]] EcmaHandleScope handleScope(thread); if (index == 0 && (thisValue.IsUndefined() || thisValue.IsHole())) { return ThrowReferenceError(thread, JSTaggedValue::Undefined(), "sub-class must call super before use 'this'"); } if (index == 1 && !thisValue.IsUndefined() && !thisValue.IsHole()) { return ThrowReferenceError(thread, JSTaggedValue::Undefined(), "super() forbidden re-bind 'this'"); } return JSTaggedValue::True(); } void SlowRuntimeStub::ThrowIfNotObject(JSThread *thread) { INTERPRETER_TRACE(thread, ThrowIfNotObject); [[maybe_unused]] EcmaHandleScope handleScope(thread); THROW_TYPE_ERROR(thread, "Inner return result is not object"); } void SlowRuntimeStub::ThrowThrowNotExists(JSThread *thread) { INTERPRETER_TRACE(thread, ThrowThrowNotExists); [[maybe_unused]] EcmaHandleScope handleScope(thread); THROW_TYPE_ERROR(thread, "Throw method is not defined"); } void SlowRuntimeStub::ThrowPatternNonCoercible(JSThread *thread) { INTERPRETER_TRACE(thread, ThrowPatternNonCoercible); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle msg(thread->GlobalConstants()->GetHandledObjNotCoercibleString()); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); THROW_NEW_ERROR_AND_RETURN(thread, factory->NewJSError(base::ErrorType::TYPE_ERROR, msg).GetTaggedValue()); } JSTaggedValue SlowRuntimeStub::StOwnByName(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, JSTaggedValue value) { INTERPRETER_TRACE(thread, StOwnByNameDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle objHandle(thread, obj); JSHandle propHandle(thread, prop); JSHandle valueHandle(thread, value); ASSERT(propHandle->IsStringOrSymbol()); // property in class is non-enumerable bool enumerable = !(objHandle->IsClassPrototype() || objHandle->IsClassConstructor()); PropertyDescriptor desc(thread, valueHandle, true, enumerable, true); bool ret = JSTaggedValue::DefineOwnProperty(thread, objHandle, propHandle, desc); if (!ret) { return ThrowTypeError(thread, "SetOwnByName failed"); } return JSTaggedValue::True(); } JSTaggedValue SlowRuntimeStub::StOwnByNameWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, JSTaggedValue value) { INTERPRETER_TRACE(thread, StOwnByNameDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle objHandle(thread, obj); JSHandle propHandle(thread, prop); JSHandle valueHandle(thread, value); ASSERT(propHandle->IsStringOrSymbol()); JSHandle propKey = JSTaggedValue::ToPropertyKey(thread, propHandle); // property in class is non-enumerable bool enumerable = !(objHandle->IsClassPrototype() || objHandle->IsClassConstructor()); PropertyDescriptor desc(thread, valueHandle, true, enumerable, true); bool ret = JSTaggedValue::DefineOwnProperty(thread, objHandle, propHandle, desc); if (!ret) { return ThrowTypeError(thread, "SetOwnByNameWithNameSet failed"); } JSFunctionBase::SetFunctionName(thread, JSHandle::Cast(valueHandle), propKey, JSHandle(thread, JSTaggedValue::Undefined())); return JSTaggedValue::True(); } JSTaggedValue SlowRuntimeStub::StOwnByIndex(JSThread *thread, JSTaggedValue obj, uint32_t idx, JSTaggedValue value) { INTERPRETER_TRACE(thread, StOwnByIdDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle objHandle(thread, obj); JSHandle idxHandle(thread, JSTaggedValue(idx)); JSHandle valueHandle(thread, value); // property in class is non-enumerable bool enumerable = !(objHandle->IsClassPrototype() || objHandle->IsClassConstructor()); PropertyDescriptor desc(thread, valueHandle, true, enumerable, true); bool ret = JSTaggedValue::DefineOwnProperty(thread, objHandle, idxHandle, desc); if (!ret) { return ThrowTypeError(thread, "SetOwnByIndex failed"); } return JSTaggedValue::True(); } JSTaggedValue SlowRuntimeStub::StOwnByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue value) { [[maybe_unused]] EcmaHandleScope handleScope(thread); INTERPRETER_TRACE(thread, StOwnByValueDyn); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle objHandle(thread, obj); JSHandle keyHandle(thread, key); JSHandle valueHandle(thread, value); if (objHandle->IsClassConstructor() && JSTaggedValue::SameValue(keyHandle, globalConst->GetHandledPrototypeString())) { return ThrowTypeError(thread, "In a class, static property named 'prototype' throw a TypeError"); } // property in class is non-enumerable bool enumerable = !(objHandle->IsClassPrototype() || objHandle->IsClassConstructor()); PropertyDescriptor desc(thread, valueHandle, true, enumerable, true); JSMutableHandle propKey(JSTaggedValue::ToPropertyKey(thread, keyHandle)); bool ret = JSTaggedValue::DefineOwnProperty(thread, objHandle, propKey, desc); if (!ret) { return ThrowTypeError(thread, "StOwnByValue failed"); } return JSTaggedValue::True(); } JSTaggedValue SlowRuntimeStub::StOwnByValueWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue value) { [[maybe_unused]] EcmaHandleScope handleScope(thread); INTERPRETER_TRACE(thread, StOwnByValueDyn); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle objHandle(thread, obj); JSHandle keyHandle(thread, key); JSHandle valueHandle(thread, value); if (objHandle->IsClassConstructor() && JSTaggedValue::SameValue(keyHandle, globalConst->GetHandledPrototypeString())) { return ThrowTypeError(thread, "In a class, static property named 'prototype' throw a TypeError"); } // property in class is non-enumerable bool enumerable = !(objHandle->IsClassPrototype() || objHandle->IsClassConstructor()); PropertyDescriptor desc(thread, valueHandle, true, enumerable, true); JSMutableHandle propKey(JSTaggedValue::ToPropertyKey(thread, keyHandle)); bool ret = JSTaggedValue::DefineOwnProperty(thread, objHandle, propKey, desc); if (!ret) { return ThrowTypeError(thread, "StOwnByValueWithNameSet failed"); } if (valueHandle->IsJSFunction()) { if (propKey->IsNumber()) { propKey.Update(base::NumberHelper::NumberToString(thread, propKey.GetTaggedValue()).GetTaggedValue()); } JSFunctionBase::SetFunctionName(thread, JSHandle::Cast(valueHandle), propKey, JSHandle(thread, JSTaggedValue::Undefined())); } return JSTaggedValue::True(); } JSTaggedValue SlowRuntimeStub::CreateEmptyArray(JSThread *thread, ObjectFactory *factory, JSHandle globalEnv) { INTERPRETER_TRACE(thread, CreateEmptyArray); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle builtinObj(globalEnv->GetArrayFunction()); JSHandle arr = factory->NewJSObjectByConstructor(builtinObj, JSHandle(builtinObj)); return arr.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::CreateEmptyObject(JSThread *thread, ObjectFactory *factory, JSHandle globalEnv) { INTERPRETER_TRACE(thread, CreateEmptyObject); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle builtinObj(globalEnv->GetObjectFunction()); JSHandle obj = factory->NewJSObjectByConstructor(builtinObj, JSHandle(builtinObj)); return obj.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::CreateObjectWithBuffer(JSThread *thread, ObjectFactory *factory, JSObject *literal) { INTERPRETER_TRACE(thread, CreateObjectWithBuffer); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle obj(thread, literal); JSHandle objLiteral = factory->CloneObjectLiteral(obj); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return objLiteral.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::CreateObjectHavingMethod(JSThread *thread, ObjectFactory *factory, JSObject *literal, JSTaggedValue env, ConstantPool *constpool) { INTERPRETER_TRACE(thread, CreateObjectHavingMethod); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle obj(thread, literal); JSHandle objLiteral = factory->CloneObjectLiteral( obj, JSHandle(thread, env), JSHandle(thread, JSTaggedValue(constpool))); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return objLiteral.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::SetObjectWithProto(JSThread *thread, JSTaggedValue proto, JSTaggedValue obj) { INTERPRETER_TRACE(thread, SetObjectWithProto); [[maybe_unused]] EcmaHandleScope handleScope(thread); if (!proto.IsECMAObject() && !proto.IsNull()) { return JSTaggedValue::False(); } JSHandle protoHandle(thread, proto); JSHandle objHandle(thread, obj); JSObject::SetPrototype(thread, objHandle, protoHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::True(); } JSTaggedValue SlowRuntimeStub::IterNext(JSThread *thread, JSTaggedValue iter) { INTERPRETER_TRACE(thread, IterNext); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle iterHandle(thread, iter); JSHandle resultObj = JSIterator::IteratorNext(thread, iterHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return resultObj.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::CloseIterator(JSThread *thread, JSTaggedValue iter) { INTERPRETER_TRACE(thread, CloseIterator); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle iterHandle(thread, iter); JSHandle record; if (thread->HasPendingException()) { record = JSHandle(factory->NewCompletionRecord( CompletionRecordType::THROW, JSHandle(thread, thread->GetException()))); } else { JSHandle undefinedVal = globalConst->GetHandledUndefined(); record = JSHandle(factory->NewCompletionRecord(CompletionRecordType::NORMAL, undefinedVal)); } JSHandle result = JSIterator::IteratorClose(thread, iterHandle, record); if (result->IsCompletionRecord()) { return CompletionRecord::Cast(result->GetTaggedObject())->GetValue(); } return result.GetTaggedValue(); } void SlowRuntimeStub::StModuleVar([[maybe_unused]] JSThread *thread, [[maybe_unused]] JSTaggedValue key, [[maybe_unused]] JSTaggedValue value) { INTERPRETER_TRACE(thread, StModuleVar); [[maybe_unused]] EcmaHandleScope scope(thread); thread->GetEcmaVM()->GetModuleManager()->StoreModuleValue(key, value); } JSTaggedValue SlowRuntimeStub::LdModuleVar([[maybe_unused]] JSThread *thread, [[maybe_unused]] JSTaggedValue key, [[maybe_unused]] bool inner) { INTERPRETER_TRACE(thread, LdModuleVar); [[maybe_unused]] EcmaHandleScope scope(thread); if (inner) { JSTaggedValue moduleValue = thread->GetEcmaVM()->GetModuleManager()->GetModuleValueInner(key); return moduleValue; } return thread->GetEcmaVM()->GetModuleManager()->GetModuleValueOutter(key); } JSTaggedValue SlowRuntimeStub::CreateRegExpWithLiteral(JSThread *thread, JSTaggedValue pattern, uint8_t flags) { INTERPRETER_TRACE(thread, CreateRegExpWithLiteral); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle patternHandle(thread, pattern); JSHandle flagsHandle(thread, JSTaggedValue(flags)); return builtins::BuiltinsRegExp::RegExpCreate(thread, patternHandle, flagsHandle); } JSTaggedValue SlowRuntimeStub::CreateArrayWithBuffer(JSThread *thread, ObjectFactory *factory, JSArray *literal) { INTERPRETER_TRACE(thread, CreateArrayWithBuffer); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle array(thread, literal); JSHandle arrLiteral = factory->CloneArrayLiteral(array); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return arrLiteral.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::GetTemplateObject(JSThread *thread, JSTaggedValue literal) { INTERPRETER_TRACE(thread, GetTemplateObject); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle templateLiteral(thread, literal); JSHandle templateObj = TemplateString::GetTemplateObject(thread, templateLiteral); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return templateObj.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::GetNextPropName(JSThread *thread, JSTaggedValue iter) { INTERPRETER_TRACE(thread, GetNextPropName); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle iterator(thread, iter); ASSERT(iterator->IsForinIterator()); std::pair res = JSForInIterator::NextInternal(thread, JSHandle::Cast(iterator)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return res.first; } JSTaggedValue SlowRuntimeStub::CopyDataProperties(JSThread *thread, JSTaggedValue dst, JSTaggedValue src) { INTERPRETER_TRACE(thread, CopyDataProperties); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle dstHandle(thread, dst); JSHandle srcHandle(thread, src); if (!srcHandle->IsNull() && !srcHandle->IsUndefined()) { JSHandle keys = JSTaggedValue::GetOwnPropertyKeys(thread, srcHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSMutableHandle key(thread, JSTaggedValue::Undefined()); uint32_t keysLen = keys->GetLength(); for (uint32_t i = 0; i < keysLen; i++) { PropertyDescriptor desc(thread); key.Update(keys->Get(i)); bool success = JSTaggedValue::GetOwnProperty(thread, srcHandle, key, desc); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (success && desc.IsEnumerable()) { JSTaggedValue::DefineOwnProperty(thread, dstHandle, key, desc); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } } } return dstHandle.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::GetIteratorNext(JSThread *thread, JSTaggedValue obj, JSTaggedValue method) { INTERPRETER_TRACE(thread, GetIteratorNext); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle iter(thread, obj); JSHandle next(thread, method); ASSERT(next->IsCallable()); JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo info = EcmaInterpreter::NewRuntimeCallInfo(thread, next, iter, undefined, 0); JSTaggedValue ret = JSFunction::Call(&info); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (!ret.IsECMAObject()) { return ThrowTypeError(thread, "the Iterator is not an ecmaobject."); } return ret; } JSTaggedValue SlowRuntimeStub::GetUnmapedArgs(JSThread *thread, JSTaggedType *sp, uint32_t actualNumArgs, uint32_t startIdx) { INTERPRETER_TRACE(thread, GetUnmapedArgs); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle globalEnv = thread->GetEcmaVM()->GetGlobalEnv(); JSHandle argumentsList = factory->NewTaggedArray(actualNumArgs); for (uint32_t i = 0; i < actualNumArgs; ++i) { argumentsList->Set(thread, i, JSTaggedValue(sp[startIdx + i])); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } // 1. Let len be the number of elements in argumentsList uint32_t len = argumentsList->GetLength(); // 2. Let obj be ObjectCreate(%ObjectPrototype%, «[[ParameterMap]]»). // 3. Set obj’s [[ParameterMap]] internal slot to undefined. JSHandle obj = factory->NewJSArguments(); // 4. Perform DefinePropertyOrThrow(obj, "length", PropertyDescriptor{[[Value]]: len, [[Writable]]: true, // [[Enumerable]]: false, [[Configurable]]: true}). obj->SetPropertyInlinedProps(thread, JSArguments::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(len)); // 5. Let index be 0. // 6. Repeat while index < len, // a. Let val be argumentsList[index]. // b. Perform CreateDataProperty(obj, ToString(index), val). // c. Let index be index + 1 obj->SetElements(thread, argumentsList.GetTaggedValue()); // 7. Perform DefinePropertyOrThrow(obj, @@iterator, PropertyDescriptor // {[[Value]]:%ArrayProto_values%, // [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true}). obj->SetPropertyInlinedProps(thread, JSArguments::ITERATOR_INLINE_PROPERTY_INDEX, globalEnv->GetArrayProtoValuesFunction().GetTaggedValue()); // 8. Perform DefinePropertyOrThrow(obj, "caller", PropertyDescriptor {[[Get]]: %ThrowTypeError%, // [[Set]]: %ThrowTypeError%, [[Enumerable]]: false, [[Configurable]]: false}). JSHandle throwFunction = globalEnv->GetThrowTypeError(); JSHandle accessor = factory->NewAccessorData(); accessor->SetGetter(thread, throwFunction); accessor->SetSetter(thread, throwFunction); obj->SetPropertyInlinedProps(thread, JSArguments::CALLER_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue()); // 9. Perform DefinePropertyOrThrow(obj, "callee", PropertyDescriptor {[[Get]]: %ThrowTypeError%, // [[Set]]: %ThrowTypeError%, [[Enumerable]]: false, [[Configurable]]: false}). accessor = factory->NewAccessorData(); accessor->SetGetter(thread, throwFunction); accessor->SetSetter(thread, throwFunction); obj->SetPropertyInlinedProps(thread, JSArguments::CALLEE_INLINE_PROPERTY_INDEX, accessor.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 11. Return obj return obj.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::CopyRestArgs(JSThread *thread, JSTaggedType *sp, uint32_t restNumArgs, uint32_t startIdx) { INTERPRETER_TRACE(thread, Copyrestargs); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle restArray = JSArray::ArrayCreate(thread, JSTaggedNumber(restNumArgs)); JSMutableHandle element(thread, JSTaggedValue::Undefined()); for (uint32_t i = 0; i < restNumArgs; ++i) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) element.Update(JSTaggedValue(sp[startIdx + i])); JSObject::SetProperty(thread, restArray, i, element, true); } RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return restArray.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::GetIterator(JSThread *thread, JSTaggedValue obj) { INTERPRETER_TRACE(thread, GetIterator); [[maybe_unused]] EcmaHandleScope handleScope(thread); EcmaVM *vm = thread->GetEcmaVM(); JSHandle env = vm->GetGlobalEnv(); JSHandle objHandle(thread, obj); JSHandle valuesFunc = JSTaggedValue::GetProperty(thread, objHandle, env->GetIteratorSymbol()).GetValue(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (!valuesFunc->IsCallable()) { return valuesFunc.GetTaggedValue(); } JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo info = EcmaInterpreter::NewRuntimeCallInfo(thread, valuesFunc, objHandle, undefined, 0); return EcmaInterpreter::Execute(&info); } JSTaggedValue SlowRuntimeStub::DefineGetterSetterByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, JSTaggedValue getter, JSTaggedValue setter, bool flag) { INTERPRETER_TRACE(thread, DefineGetterSetterByValue); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle objHandle(thread, obj); JSHandle propHandle(thread, prop); JSHandle getterHandle(thread, getter); JSHandle setterHandle(thread, setter); JSHandle propKey = JSTaggedValue::ToPropertyKey(thread, propHandle); auto globalConst = thread->GlobalConstants(); if (objHandle.GetTaggedValue().IsClassConstructor() && JSTaggedValue::SameValue(propKey, globalConst->GetHandledPrototypeString())) { return ThrowTypeError( thread, "In a class, computed property names for static getter that are named 'prototype' throw a TypeError"); } if (flag) { if (!getterHandle->IsUndefined()) { if (propKey->IsNumber()) { propKey = JSHandle::Cast(base::NumberHelper::NumberToString(thread, propKey.GetTaggedValue())); } JSFunctionBase::SetFunctionName(thread, JSHandle::Cast(getterHandle), propKey, JSHandle(thread, globalConst->GetGetString())); } if (!setterHandle->IsUndefined()) { if (propKey->IsNumber()) { propKey = JSHandle::Cast(base::NumberHelper::NumberToString(thread, propKey.GetTaggedValue())); } JSFunctionBase::SetFunctionName(thread, JSHandle::Cast(setterHandle), propKey, JSHandle(thread, globalConst->GetSetString())); } } // set accessor bool enumerable = !(objHandle.GetTaggedValue().IsClassPrototype() || objHandle.GetTaggedValue().IsClassConstructor()); PropertyDescriptor desc(thread, true, enumerable, true); if (!getterHandle->IsUndefined()) { JSHandle::Cast(getterHandle)->SetFunctionKind(FunctionKind::GETTER_FUNCTION); desc.SetGetter(getterHandle); } if (!setterHandle->IsUndefined()) { JSHandle::Cast(setterHandle)->SetFunctionKind(FunctionKind::SETTER_FUNCTION); desc.SetSetter(setterHandle); } JSObject::DefineOwnProperty(thread, objHandle, propKey, desc); return objHandle.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::LdObjByIndex(JSThread *thread, JSTaggedValue obj, uint32_t idx, bool callGetter, JSTaggedValue receiver) { INTERPRETER_TRACE(thread, LdObjByIndexDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSTaggedValue res; JSHandle objHandle(thread, obj); if (callGetter) { res = JSObject::CallGetter(thread, AccessorData::Cast(receiver.GetTaggedObject()), objHandle); } else { res = JSTaggedValue::GetProperty(thread, objHandle, idx).GetValue().GetTaggedValue(); } RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return res; } JSTaggedValue SlowRuntimeStub::StObjByIndex(JSThread *thread, JSTaggedValue obj, uint32_t idx, JSTaggedValue value) { INTERPRETER_TRACE(thread, StObjByIndexDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSTaggedValue::SetProperty(thread, JSHandle(thread, obj), idx, JSHandle(thread, value), true); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::True(); } JSTaggedValue SlowRuntimeStub::LdObjByName(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, bool callGetter, JSTaggedValue receiver) { INTERPRETER_TRACE(thread, LdObjByNameDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle objHandle(thread, obj); JSTaggedValue res; if (callGetter) { res = JSObject::CallGetter(thread, AccessorData::Cast(receiver.GetTaggedObject()), objHandle); } else { JSHandle propHandle(thread, prop); res = JSTaggedValue::GetProperty(thread, objHandle, propHandle).GetValue().GetTaggedValue(); } RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return res; } JSTaggedValue SlowRuntimeStub::StObjByName(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, JSTaggedValue value) { INTERPRETER_TRACE(thread, StObjByNameDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle objHandle(thread, obj); JSHandle propHandle(thread, prop); JSHandle valueHandle(thread, value); JSTaggedValue::SetProperty(thread, objHandle, propHandle, valueHandle, true); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::True(); } JSTaggedValue SlowRuntimeStub::LdObjByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, bool callGetter, JSTaggedValue receiver) { INTERPRETER_TRACE(thread, LdObjByValueDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle objHandle(thread, obj); JSTaggedValue res; if (callGetter) { res = JSObject::CallGetter(thread, AccessorData::Cast(receiver.GetTaggedObject()), objHandle); } else { JSHandle propKey = JSTaggedValue::ToPropertyKey(thread, JSHandle(thread, prop)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); res = JSTaggedValue::GetProperty(thread, objHandle, propKey).GetValue().GetTaggedValue(); } RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return res; } JSTaggedValue SlowRuntimeStub::StObjByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, JSTaggedValue value) { INTERPRETER_TRACE(thread, StObjByValueDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle objHandle(thread, obj); JSHandle propHandle(thread, prop); JSHandle valueHandle(thread, value); JSHandle propKey(JSTaggedValue::ToPropertyKey(thread, propHandle)); // strict mode is true JSTaggedValue::SetProperty(thread, objHandle, propKey, valueHandle, true); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::True(); } JSTaggedValue SlowRuntimeStub::TryLdGlobalByName(JSThread *thread, JSTaggedValue global, JSTaggedValue prop) { INTERPRETER_TRACE(thread, Trygetobjprop); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle obj(thread, global.GetTaggedObject()->GetClass()->GetPrototype()); JSHandle propHandle(thread, prop); OperationResult res = JSTaggedValue::GetProperty(thread, obj, propHandle); if (!res.GetPropertyMetaData().IsFound()) { return ThrowReferenceError(thread, prop, " is not defined"); } return res.GetValue().GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::TryStGlobalByName(JSThread *thread, JSTaggedValue prop) { INTERPRETER_TRACE(thread, TryStGlobalByName); // If fast path is fail, not need slow path, just throw error. return ThrowReferenceError(thread, prop, " is not defined"); } JSTaggedValue SlowRuntimeStub::LdGlobalVar(JSThread *thread, JSTaggedValue global, JSTaggedValue prop) { INTERPRETER_TRACE(thread, LdGlobalVar); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle objHandle(thread, global.GetTaggedObject()->GetClass()->GetPrototype()); JSHandle propHandle(thread, prop); OperationResult res = JSTaggedValue::GetProperty(thread, objHandle, propHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return res.GetValue().GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::StGlobalVar(JSThread *thread, JSTaggedValue prop, JSTaggedValue value) { INTERPRETER_TRACE(thread, StGlobalVar); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle global(thread, thread->GetEcmaVM()->GetGlobalEnv()->GetGlobalObject()); JSHandle propHandle(thread, prop); JSHandle valueHandle(thread, value); JSObject::GlobalSetProperty(thread, propHandle, valueHandle, true); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::True(); } JSTaggedValue SlowRuntimeStub::TryUpdateGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value) { INTERPRETER_TRACE(thread, TryUpdateGlobalRecord); [[maybe_unused]] EcmaHandleScope handleScope(thread); EcmaVM *vm = thread->GetEcmaVM(); JSHandle env = vm->GetGlobalEnv(); GlobalDictionary *dict = GlobalDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); int entry = dict->FindEntry(prop); ASSERT(entry != -1); if (dict->GetAttributes(entry).IsConstProps()) { return ThrowSyntaxError(thread, "const variable can not be modified"); } PropertyBox *box = dict->GetBox(entry); box->SetValue(thread, value); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::True(); } // return box JSTaggedValue SlowRuntimeStub::LdGlobalRecord(JSThread *thread, JSTaggedValue key) { INTERPRETER_TRACE(thread, LdGlobalRecord); [[maybe_unused]] EcmaHandleScope handleScope(thread); EcmaVM *vm = thread->GetEcmaVM(); JSHandle env = vm->GetGlobalEnv(); GlobalDictionary *dict = GlobalDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); int entry = dict->FindEntry(key); if (entry != -1) { return JSTaggedValue(dict->GetBox(entry)); } return JSTaggedValue::Undefined(); } JSTaggedValue SlowRuntimeStub::StGlobalRecord(JSThread *thread, JSTaggedValue prop, JSTaggedValue value, bool isConst) { INTERPRETER_TRACE(thread, StGlobalRecord); [[maybe_unused]] EcmaHandleScope handleScope(thread); EcmaVM *vm = thread->GetEcmaVM(); JSHandle env = vm->GetGlobalEnv(); GlobalDictionary *dict = GlobalDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); // cross files global record name binding judgment int entry = dict->FindEntry(prop); if (entry != -1) { return ThrowSyntaxError(thread, "Duplicate identifier"); } PropertyAttributes attributes; if (isConst) { attributes.SetIsConstProps(true); } JSHandle propHandle(thread, prop); JSHandle valueHandle(thread, value); JSHandle dictHandle(thread, dict); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle box = factory->NewPropertyBox(valueHandle); PropertyBoxType boxType = valueHandle->IsUndefined() ? PropertyBoxType::UNDEFINED : PropertyBoxType::CONSTANT; attributes.SetBoxType(boxType); dict = *GlobalDictionary::PutIfAbsent(thread, dictHandle, propHandle, JSHandle(box), attributes); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); env->SetGlobalRecord(thread, JSTaggedValue(dict)); return JSTaggedValue::True(); } JSTaggedValue SlowRuntimeStub::ThrowReferenceError(JSThread *thread, JSTaggedValue prop, const char *desc) { INTERPRETER_TRACE(thread, ThrowReferenceError); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle propName = JSTaggedValue::ToString(thread, JSHandle(thread, prop)); ASSERT_NO_ABRUPT_COMPLETION(thread); JSHandle info = factory->NewFromUtf8(desc); JSHandle msg = factory->ConcatFromString(propName, info); THROW_NEW_ERROR_AND_RETURN_VALUE(thread, factory->NewJSError(base::ErrorType::REFERENCE_ERROR, msg).GetTaggedValue(), JSTaggedValue::Exception()); } JSTaggedValue SlowRuntimeStub::ThrowTypeError(JSThread *thread, const char *message) { INTERPRETER_TRACE(thread, ThrowTypeError); [[maybe_unused]] EcmaHandleScope handleScope(thread); ASSERT_NO_ABRUPT_COMPLETION(thread); THROW_TYPE_ERROR_AND_RETURN(thread, message, JSTaggedValue::Exception()); } JSTaggedValue SlowRuntimeStub::ThrowSyntaxError(JSThread *thread, const char *message) { INTERPRETER_TRACE(thread, ThrowSyntaxError); [[maybe_unused]] EcmaHandleScope handleScope(thread); ASSERT_NO_ABRUPT_COMPLETION(thread); THROW_SYNTAX_ERROR_AND_RETURN(thread, message, JSTaggedValue::Exception()); } JSTaggedValue SlowRuntimeStub::StArraySpread(JSThread *thread, JSTaggedValue dst, JSTaggedValue index, JSTaggedValue src) { INTERPRETER_TRACE(thread, StArraySpread); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle dstHandle(thread, dst); JSHandle srcHandle(thread, src); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); ASSERT(dstHandle->IsJSArray() && !srcHandle->IsNull() && !srcHandle->IsUndefined()); if (srcHandle->IsString()) { JSHandle srcString = JSTaggedValue::ToString(thread, srcHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); uint32_t dstLen = static_cast(index.GetInt()); uint32_t strLen = srcString->GetLength(); for (uint32_t i = 0; i < strLen; i++) { uint16_t res = srcString->At(i); JSHandle strValue(factory->NewFromUtf16Literal(&res, 1)); JSTaggedValue::SetProperty(thread, dstHandle, dstLen + i, strValue, true); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } return JSTaggedValue(dstLen + strLen); } JSHandle iter; auto globalConst = thread->GlobalConstants(); if (srcHandle->IsJSArrayIterator() || srcHandle->IsJSMapIterator() || srcHandle->IsJSSetIterator() || srcHandle->IsIterator()) { iter = srcHandle; } else if (srcHandle->IsJSArray() || srcHandle->IsJSMap() || srcHandle->IsTypedArray() || srcHandle->IsJSSet()) { JSHandle valuesStr = globalConst->GetHandledValuesString(); JSHandle valuesMethod = JSObject::GetMethod(thread, srcHandle, valuesStr); iter = JSIterator::GetIterator(thread, srcHandle, valuesMethod); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } else { iter = JSIterator::GetIterator(thread, srcHandle); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } JSMutableHandle indexHandle(thread, index); JSHandle valueStr = globalConst->GetHandledValueString(); PropertyDescriptor desc(thread); JSHandle iterResult; do { iterResult = JSIterator::IteratorStep(thread, iter); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (iterResult->IsFalse()) { break; } bool success = JSTaggedValue::GetOwnProperty(thread, iterResult, valueStr, desc); if (success && desc.IsEnumerable()) { JSTaggedValue::DefineOwnProperty(thread, dstHandle, indexHandle, desc); int tmp = indexHandle->GetInt(); indexHandle.Update(JSTaggedValue(tmp + 1)); } } while (true); return indexHandle.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::DefineGeneratorFunc(JSThread *thread, JSFunction *func) { INTERPRETER_TRACE(thread, DefineGeneratorFunc); [[maybe_unused]] EcmaHandleScope handleScope(thread); auto method = func->GetCallTarget(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle jsFunc = factory->NewJSGeneratorFunction(method); ASSERT_NO_ABRUPT_COMPLETION(thread); // 26.3.4.3 prototype // Whenever a GeneratorFunction instance is created another ordinary object is also created and // is the initial value of the generator function's "prototype" property. JSHandle objFun = env->GetObjectFunction(); JSHandle initialGeneratorFuncPrototype = factory->NewJSObjectByConstructor(JSHandle(objFun), objFun); JSObject::SetPrototype(thread, initialGeneratorFuncPrototype, env->GetGeneratorPrototype()); ASSERT_NO_ABRUPT_COMPLETION(thread); jsFunc->SetProtoOrDynClass(thread, initialGeneratorFuncPrototype); return jsFunc.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::DefineAsyncFunc(JSThread *thread, JSFunction *func) { INTERPRETER_TRACE(thread, DefineAsyncFunc); [[maybe_unused]] EcmaHandleScope handleScope(thread); auto method = func->GetCallTarget(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle dynclass = JSHandle::Cast(env->GetAsyncFunctionClass()); JSHandle jsFunc = factory->NewJSFunctionByDynClass(method, dynclass, FunctionKind::ASYNC_FUNCTION); ASSERT_NO_ABRUPT_COMPLETION(thread); return jsFunc.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::DefineNCFuncDyn(JSThread *thread, JSFunction *func) { INTERPRETER_TRACE(thread, DefineNCFuncDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); auto method = func->GetCallTarget(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle dynclass = JSHandle::Cast(env->GetFunctionClassWithoutProto()); JSHandle jsFunc = factory->NewJSFunctionByDynClass(method, dynclass, FunctionKind::ARROW_FUNCTION); ASSERT_NO_ABRUPT_COMPLETION(thread); return jsFunc.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::DefinefuncDyn(JSThread *thread, JSFunction *func) { INTERPRETER_TRACE(thread, DefinefuncDyn); [[maybe_unused]] EcmaHandleScope handleScope(thread); auto method = func->GetCallTarget(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle dynclass = JSHandle::Cast(env->GetFunctionClassWithProto()); JSHandle jsFunc = factory->NewJSFunctionByDynClass(method, dynclass, FunctionKind::BASE_CONSTRUCTOR); ASSERT_NO_ABRUPT_COMPLETION(thread); return jsFunc.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::GetSuperConstructor(JSThread *thread, JSTaggedValue ctor) { INTERPRETER_TRACE(thread, GetSuperConstructor); JSHandle ctorHandle(thread, ctor); JSHandle superConstructor(thread, JSTaggedValue::GetPrototype(thread, ctorHandle)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return superConstructor.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::SuperCall(JSThread *thread, JSTaggedValue func, JSTaggedValue newTarget, uint16_t firstVRegIdx, uint16_t length) { INTERPRETER_TRACE(thread, SuperCall); [[maybe_unused]] EcmaHandleScope handleScope(thread); FrameHandler frameHandler(thread); JSHandle funcHandle(thread, func); JSHandle newTargetHandle(thread, newTarget); JSHandle superFunc(thread, JSTaggedValue::GetPrototype(thread, funcHandle)); ASSERT(superFunc->IsJSFunction()); JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo info = EcmaInterpreter::NewRuntimeCallInfo(thread, superFunc, undefined, newTargetHandle, length); for (size_t i = 0; i < length; i++) { info.SetCallArg(i, frameHandler.GetVRegValue(firstVRegIdx + i)); } JSTaggedValue result = JSFunction::Construct(&info); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return result; } JSTaggedValue SlowRuntimeStub::SuperCallSpread(JSThread *thread, JSTaggedValue func, JSTaggedValue newTarget, JSTaggedValue array) { INTERPRETER_TRACE(thread, SuperCallSpread); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle funcHandle(thread, func); JSHandle newTargetHandle(thread, newTarget); JSHandle jsArray(thread, array); JSHandle superFunc(thread, JSTaggedValue::GetPrototype(thread, funcHandle)); ASSERT(superFunc->IsJSFunction()); JSHandle argv(thread, GetCallSpreadArgs(thread, jsArray.GetTaggedValue())); const size_t argsLength = argv->GetLength(); JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); EcmaRuntimeCallInfo info = EcmaInterpreter::NewRuntimeCallInfo(thread, superFunc, undefined, newTargetHandle, argsLength); info.SetCallArg(argsLength, argv); JSTaggedValue result = JSFunction::Construct(&info); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return result; } JSTaggedValue SlowRuntimeStub::DefineMethod(JSThread *thread, JSFunction *func, JSTaggedValue homeObject) { INTERPRETER_TRACE(thread, DefineMethod); [[maybe_unused]] EcmaHandleScope handleScope(thread); ASSERT(homeObject.IsECMAObject()); JSHandle homeObjectHandle(thread, homeObject); auto method = func->GetCallTarget(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle dynclass = JSHandle::Cast(env->GetFunctionClassWithoutProto()); JSHandle jsFunc = factory->NewJSFunctionByDynClass(method, dynclass, FunctionKind::NORMAL_FUNCTION); jsFunc->SetHomeObject(thread, homeObjectHandle); ASSERT_NO_ABRUPT_COMPLETION(thread); return jsFunc.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::LdSuperByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue thisFunc) { INTERPRETER_TRACE(thread, LdSuperByValue); [[maybe_unused]] EcmaHandleScope handleScope(thread); ASSERT(thisFunc.IsJSFunction()); // get Homeobject form function JSHandle homeObject(thread, JSFunction::Cast(thisFunc.GetTaggedObject())->GetHomeObject()); if (obj.IsUndefined()) { return ThrowReferenceError(thread, obj, "this is uninitialized."); } JSHandle objHandle(thread, obj); JSHandle propHandle(thread, key); JSHandle propKey(JSTaggedValue::ToPropertyKey(thread, propHandle)); JSHandle superBase(thread, JSTaggedValue::GetSuperBase(thread, homeObject)); JSTaggedValue::RequireObjectCoercible(thread, superBase); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSTaggedValue res = JSTaggedValue::GetProperty(thread, superBase, propKey, objHandle).GetValue().GetTaggedValue(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return res; } JSTaggedValue SlowRuntimeStub::StSuperByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue value, JSTaggedValue thisFunc) { INTERPRETER_TRACE(thread, StSuperByValue); [[maybe_unused]] EcmaHandleScope handleScope(thread); ASSERT(thisFunc.IsJSFunction()); // get Homeobject form function JSHandle homeObject(thread, JSFunction::Cast(thisFunc.GetTaggedObject())->GetHomeObject()); if (obj.IsUndefined()) { return ThrowReferenceError(thread, obj, "this is uninitialized."); } JSHandle objHandle(thread, obj); JSHandle propHandle(thread, key); JSHandle valueHandle(thread, value); JSHandle propKey(JSTaggedValue::ToPropertyKey(thread, propHandle)); JSHandle superBase(thread, JSTaggedValue::GetSuperBase(thread, homeObject)); JSTaggedValue::RequireObjectCoercible(thread, superBase); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // check may_throw is false? JSTaggedValue::SetProperty(thread, superBase, propKey, valueHandle, objHandle, true); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::True(); } JSTaggedValue SlowRuntimeStub::GetCallSpreadArgs(JSThread *thread, JSTaggedValue array) { INTERPRETER_TRACE(thread, GetCallSpreadArgs); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle jsArray(thread, array); uint32_t argvMayMaxLength = JSHandle::Cast(jsArray)->GetArrayLength(); JSHandle argv = factory->NewTaggedArray(argvMayMaxLength); JSHandle itor = JSIterator::GetIterator(thread, jsArray); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSMutableHandle next(thread, JSTaggedValue::Undefined()); JSMutableHandle nextArg(thread, JSTaggedValue::Undefined()); size_t argvIndex = 0; while (true) { next.Update(JSIterator::IteratorStep(thread, itor).GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (JSTaggedValue::SameValue(next.GetTaggedValue(), JSTaggedValue::False())) { break; } nextArg.Update(JSIterator::IteratorValue(thread, next).GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); argv->Set(thread, argvIndex++, nextArg); } argv = factory->CopyArray(argv, argvMayMaxLength, argvIndex); return argv.GetTaggedValue(); } void SlowRuntimeStub::ThrowDeleteSuperProperty(JSThread *thread) { INTERPRETER_TRACE(thread, ThrowDeleteSuperProperty); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle info = factory->NewFromASCII("Can not delete super property"); JSHandle errorObj = factory->NewJSError(base::ErrorType::REFERENCE_ERROR, info); THROW_NEW_ERROR_AND_RETURN(thread, errorObj.GetTaggedValue()); } JSTaggedValue SlowRuntimeStub::NotifyInlineCache(JSThread *thread, JSFunction *func, JSMethod *method) { INTERPRETER_TRACE(thread, NotifyInlineCache); uint32_t icSlotSize = method->GetSlotSize(); if (icSlotSize > 0 && icSlotSize < ProfileTypeInfo::INVALID_SLOT_INDEX) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle funcHandle(thread, func); JSHandle profileTypeInfo = factory->NewProfileTypeInfo(icSlotSize); funcHandle->SetProfileTypeInfo(thread, profileTypeInfo.GetTaggedValue()); return profileTypeInfo.GetTaggedValue(); } return JSTaggedValue::Undefined(); } JSTaggedValue SlowRuntimeStub::ResolveClass(JSThread *thread, JSTaggedValue ctor, TaggedArray *literal, JSTaggedValue base, JSTaggedValue lexenv, ConstantPool *constpool) { ASSERT(ctor.IsClassConstructor()); JSHandle cls(thread, ctor); JSHandle literalBuffer(thread, literal); JSHandle lexicalEnv(thread, lexenv); JSHandle constpoolHandle(thread, constpool); FrameHandler frameHandler(thread); JSTaggedValue currentFunc = frameHandler.GetFunction(); JSHandle ecmaModule(thread, JSFunction::Cast(currentFunc.GetTaggedObject())->GetModule()); SetClassInheritanceRelationship(thread, ctor, base); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); uint32_t literalBufferLength = literalBuffer->GetLength(); // only traverse the value of key-value pair for (uint32_t index = 1; index < literalBufferLength - 1; index += 2) { // 2: key-value pair JSTaggedValue value = literalBuffer->Get(index); if (LIKELY(value.IsJSFunction())) { JSFunction::Cast(value.GetTaggedObject())->SetLexicalEnv(thread, lexicalEnv.GetTaggedValue()); JSFunction::Cast(value.GetTaggedObject())->SetConstantPool(thread, constpoolHandle.GetTaggedValue()); JSFunction::Cast(value.GetTaggedObject())->SetModule(thread, ecmaModule); } } cls->SetResolved(true); return cls.GetTaggedValue(); } // clone class may need re-set inheritance relationship due to extends may be a variable. JSTaggedValue SlowRuntimeStub::CloneClassFromTemplate(JSThread *thread, JSTaggedValue ctor, JSTaggedValue base, JSTaggedValue lexenv, ConstantPool *constpool) { [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); ASSERT(ctor.IsClassConstructor()); JSHandle lexenvHandle(thread, lexenv); JSHandle constpoolHandle(thread, JSTaggedValue(constpool)); JSHandle baseHandle(thread, base); JSHandle cls(thread, ctor); JSHandle clsPrototype(thread, cls->GetFunctionPrototype()); bool canShareHClass = false; JSHandle cloneClass = factory->CloneClassCtor(cls, lexenvHandle, canShareHClass); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle cloneClassPrototype = factory->CloneObjectLiteral(JSHandle(clsPrototype), lexenvHandle, constpoolHandle, canShareHClass); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // After clone both, reset "constructor" and "prototype" properties. cloneClass->SetFunctionPrototype(thread, cloneClassPrototype.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); PropertyDescriptor ctorDesc(thread, JSHandle(cloneClass), true, false, true); JSTaggedValue::DefinePropertyOrThrow(thread, JSHandle(cloneClassPrototype), globalConst->GetHandledConstructorString(), ctorDesc); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); cloneClass->SetHomeObject(thread, cloneClassPrototype); if (!canShareHClass) { SetClassInheritanceRelationship(thread, cloneClass.GetTaggedValue(), baseHandle.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } return cloneClass.GetTaggedValue(); } JSTaggedValue SlowRuntimeStub::SetClassInheritanceRelationship(JSThread *thread, JSTaggedValue ctor, JSTaggedValue base) { [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle cls(thread, ctor); ASSERT(cls->IsJSFunction()); JSMutableHandle parent(thread, base); /* * class A / class A extends null class A extends B * a a * | | * | __proto__ | __proto__ * | | * A ----> A.prototype A ----> A.prototype * | | | | * | __proto__ | __proto__ | __proto__ | __proto__ * | | | | * Function.prototype Object.prototype / null B ----> B.prototype */ JSHandle parentPrototype; // hole means parent is not present if (parent->IsHole()) { JSHandle::Cast(cls)->SetFunctionKind(FunctionKind::CLASS_CONSTRUCTOR); parentPrototype = env->GetObjectFunctionPrototype(); parent.Update(env->GetFunctionPrototype().GetTaggedValue()); } else if (parent->IsNull()) { JSHandle::Cast(cls)->SetFunctionKind(FunctionKind::DERIVED_CONSTRUCTOR); parentPrototype = JSHandle(thread, JSTaggedValue::Null()); parent.Update(env->GetFunctionPrototype().GetTaggedValue()); } else if (!parent->IsConstructor()) { return ThrowTypeError(thread, "parent class is not constructor"); } else { JSHandle::Cast(cls)->SetFunctionKind(FunctionKind::DERIVED_CONSTRUCTOR); parentPrototype = JSTaggedValue::GetProperty(thread, parent, globalConst->GetHandledPrototypeString()).GetValue(); if (!parentPrototype->IsECMAObject() && !parentPrototype->IsNull()) { return ThrowTypeError(thread, "parent class have no valid prototype"); } } cls->GetTaggedObject()->GetClass()->SetPrototype(thread, parent); JSHandle clsPrototype(thread, JSHandle(cls)->GetFunctionPrototype()); clsPrototype->GetClass()->SetPrototype(thread, parentPrototype); return JSTaggedValue::Undefined(); } JSTaggedValue SlowRuntimeStub::SetClassConstructorLength(JSThread *thread, JSTaggedValue ctor, JSTaggedValue length) { ASSERT(ctor.IsClassConstructor()); JSFunction* cls = JSFunction::Cast(ctor.GetTaggedObject()); if (LIKELY(!cls->GetClass()->IsDictionaryMode())) { cls->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, length); } else { const GlobalEnvConstants *globalConst = thread->GlobalConstants(); cls->UpdatePropertyInDictionary(thread, globalConst->GetLengthString(), length); } return JSTaggedValue::Undefined(); } JSTaggedValue SlowRuntimeStub::GetModuleNamespace(JSThread *thread, JSTaggedValue localName) { return thread->GetEcmaVM()->GetModuleManager()->GetModuleNamespace(localName); } JSTaggedValue SlowRuntimeStub::LdBigInt(JSThread *thread, JSTaggedValue numberBigInt) { INTERPRETER_TRACE(thread, LdBigInt); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle bigint(thread, numberBigInt); return JSTaggedValue::ToBigInt(thread, bigint); } } // namespace panda::ecmascript