/* * Copyright (c) 2021-2024 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 "ETSCompiler.h" #include "compiler/base/catchTable.h" #include "checker/ets/dynamic/dynamicCall.h" #include "compiler/base/condition.h" #include "compiler/base/lreference.h" #include "compiler/core/switchBuilder.h" #include "compiler/function/functionBuilder.h" #include "checker/ETSchecker.h" #include "checker/types/ets/etsDynamicFunctionType.h" #include "parser/ETSparser.h" namespace ark::es2panda::compiler { ETSGen *ETSCompiler::GetETSGen() const { return static_cast(GetCodeGen()); } void ETSCompiler::Compile(const ir::CatchClause *st) const { ETSGen *etsg = GetETSGen(); compiler::LocalRegScope lrs(etsg, st->Scope()->ParamScope()); etsg->SetAccumulatorType(st->TsType()); auto lref = compiler::ETSLReference::Create(etsg, st->Param(), true); lref.SetValue(); st->Body()->Compile(etsg); } void ETSCompiler::Compile(const ir::ClassProperty *st) const { ETSGen *etsg = GetETSGen(); if (st->Value() == nullptr && st->TsType()->IsETSPrimitiveType()) { return; } auto ttctx = compiler::TargetTypeContext(etsg, st->TsType()); compiler::RegScope rs(etsg); if (st->Value() == nullptr) { etsg->LoadDefaultValue(st, st->TsType()); } else if (!etsg->TryLoadConstantExpression(st->Value())) { st->Value()->Compile(etsg); etsg->ApplyConversion(st->Value(), st->TsType()); } if (st->IsStatic()) { etsg->StoreStaticOwnProperty(st, st->TsType(), st->Key()->AsIdentifier()->Name()); } else { etsg->StoreProperty(st, st->TsType(), etsg->GetThisReg(), st->Key()->AsIdentifier()->Name()); } } void ETSCompiler::Compile(const ir::TemplateElement *expr) const { ETSGen *etsg = GetETSGen(); etsg->LoadAccumulatorString(expr, expr->Cooked()); etsg->SetAccumulatorType(expr->TsType()); ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType())); } void ETSCompiler::Compile(const ir::ETSClassLiteral *expr) const { ETSGen *etsg = GetETSGen(); auto *literal = expr->Expr(); auto *literalType = literal->TsType(); bool const isPrimitive = !literalType->IsETSReferenceType(); if (!isPrimitive) { literal->Compile(etsg); } else { ASSERT(literalType->IsETSPrimitiveType()); etsg->SetAccumulatorType(literalType); } etsg->GetType(expr, isPrimitive); ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType())); } void ETSCompiler::Compile(const ir::ETSFunctionType *node) const { ETSGen *etsg = GetETSGen(); etsg->LoadAccumulatorNull(node, node->TsType()); ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), node->TsType())); } void ETSCompiler::Compile([[maybe_unused]] const ir::ETSLaunchExpression *expr) const { #ifdef PANDA_WITH_ETS ETSGen *etsg = GetETSGen(); compiler::RegScope rs(etsg); compiler::VReg calleeReg = etsg->AllocReg(); checker::Signature *signature = expr->expr_->Signature(); bool isStatic = signature->HasSignatureFlag(checker::SignatureFlags::STATIC); if (expr->expr_->Callee()->IsIdentifier()) { if (!isStatic) { etsg->LoadThis(expr->expr_); etsg->StoreAccumulator(expr, calleeReg); } } else if (expr->expr_->Callee()->IsMemberExpression()) { if (!isStatic) { expr->expr_->Callee()->AsMemberExpression()->Object()->Compile(etsg); etsg->StoreAccumulator(expr, calleeReg); } } else { expr->expr_->Callee()->Compile(etsg); etsg->StoreAccumulator(expr, calleeReg); } if (isStatic) { etsg->LaunchExact(expr, signature, expr->expr_->Arguments()); } else { etsg->LaunchVirtual(expr, signature, calleeReg, expr->expr_->Arguments()); } etsg->SetAccumulatorType(expr->TsType()); #endif // PANDA_WITH_ETS } void ETSCompiler::Compile(const ir::ETSNewArrayInstanceExpression *expr) const { ETSGen *etsg = GetETSGen(); compiler::RegScope rs(etsg); compiler::TargetTypeContext ttctx(etsg, etsg->Checker()->GlobalIntType()); expr->Dimension()->Compile(etsg); compiler::VReg arr = etsg->AllocReg(); compiler::VReg dim = etsg->AllocReg(); etsg->ApplyConversionAndStoreAccumulator(expr, dim, expr->Dimension()->TsType()); etsg->NewArray(expr, arr, dim, expr->TsType()); const auto *exprType = expr->TypeReference()->TsType(); const bool isUnionTypeContainsUndefined = expr->TypeReference()->IsETSTypeReference() && exprType->IsETSUnionType() && exprType->AsETSUnionType()->HasType(etsg->Checker()->GlobalETSUndefinedType()); if (expr->Signature() != nullptr || isUnionTypeContainsUndefined) { compiler::VReg countReg = etsg->AllocReg(); auto *startLabel = etsg->AllocLabel(); auto *endLabel = etsg->AllocLabel(); etsg->MoveImmediateToRegister(expr, countReg, checker::TypeFlag::INT, static_cast(0)); const auto indexReg = etsg->AllocReg(); etsg->SetLabel(expr, startLabel); etsg->LoadAccumulator(expr, dim); etsg->JumpCompareRegister(expr, countReg, endLabel); etsg->LoadAccumulator(expr, countReg); etsg->StoreAccumulator(expr, indexReg); const compiler::TargetTypeContext ttctx2(etsg, exprType); ArenaVector arguments(GetCodeGen()->Allocator()->Adapter()); if (isUnionTypeContainsUndefined) { exprType = etsg->LoadDefaultValue(expr, exprType); } else { etsg->InitObject(expr, expr->Signature(), arguments); } etsg->StoreArrayElement(expr, arr, indexReg, exprType); etsg->IncrementImmediateRegister(expr, countReg, checker::TypeFlag::INT, static_cast(1)); etsg->JumpTo(expr, startLabel); etsg->SetLabel(expr, endLabel); } etsg->SetVRegType(arr, expr->TsType()); etsg->LoadAccumulator(expr, arr); ASSERT(etsg->Checker()->Relation()->IsIdenticalTo(etsg->GetAccumulatorType(), expr->TsType())); } static std::pair LoadDynamicName(compiler::ETSGen *etsg, const ir::AstNode *node, const ArenaVector &dynName, bool isConstructor) { auto *checker = const_cast(etsg->Checker()->AsETSChecker()); auto *callNames = checker->DynamicCallNames(isConstructor); auto qnameStart = etsg->AllocReg(); auto qnameLen = etsg->AllocReg(); TargetTypeContext ttctx(etsg, nullptr); // without this ints will be cast to JSValue etsg->LoadAccumulatorInt(node, callNames->at(dynName)); etsg->StoreAccumulator(node, qnameStart); etsg->LoadAccumulatorInt(node, dynName.size()); etsg->StoreAccumulator(node, qnameLen); return {qnameStart, qnameLen}; } static void CreateDynamicObject(const ir::AstNode *node, compiler::ETSGen *etsg, const ir::Expression *typeRef, checker::Signature *signature, const ArenaVector &arguments) { auto objReg = etsg->AllocReg(); auto callInfo = checker::DynamicCall::ResolveCall(etsg->VarBinder(), typeRef); if (callInfo.obj->IsETSImportDeclaration()) { etsg->LoadAccumulatorDynamicModule(node, callInfo.obj->AsETSImportDeclaration()); } else { callInfo.obj->Compile(etsg); } etsg->StoreAccumulator(node, objReg); auto [qnameStart, qnameLen] = LoadDynamicName(etsg, node, callInfo.name, true); etsg->CallDynamic(ETSGen::CallDynamicData {node, objReg, qnameStart}, qnameLen, signature, arguments); } static void ConvertRestArguments(checker::ETSChecker *const checker, const ir::ETSNewClassInstanceExpression *expr) { if (expr->GetSignature()->RestVar() != nullptr) { std::size_t const argumentCount = expr->GetArguments().size(); std::size_t const parameterCount = expr->GetSignature()->MinArgCount(); ASSERT(argumentCount >= parameterCount); auto &arguments = const_cast &>(expr->GetArguments()); std::size_t i = parameterCount; if (i < argumentCount && expr->GetArguments()[i]->IsSpreadElement()) { arguments[i] = expr->GetArguments()[i]->AsSpreadElement()->Argument(); } else { ArenaVector elements(checker->Allocator()->Adapter()); for (; i < argumentCount; ++i) { elements.emplace_back(expr->GetArguments()[i]); } auto *arrayExpression = checker->AllocNode(std::move(elements), checker->Allocator()); arrayExpression->SetParent(const_cast(expr)); auto restType = expr->GetSignature()->RestVar()->TsType()->AsETSArrayType(); arrayExpression->SetTsType(restType); arrayExpression->SetPreferredType(restType->ElementType()); arguments.erase(expr->GetArguments().begin() + parameterCount, expr->GetArguments().end()); arguments.emplace_back(arrayExpression); } } } static void HandleUnionTypeInForOf(compiler::ETSGen *etsg, checker::Type const *const exprType, const ir::ForOfStatement *st, VReg objReg, VReg *countReg) { ArenaVector