diff --git a/binder/ETSBinder.cpp b/binder/ETSBinder.cpp index 7f1159975a5b75b3ed578a4b1fc4b9e9a0b12d13..0221d388ca54335120883366e0626b8c2852c031 100644 --- a/binder/ETSBinder.cpp +++ b/binder/ETSBinder.cpp @@ -549,7 +549,7 @@ void ETSBinder::BuildFunctionName(const ir::ScriptFunction *func) const } } - signature->ToAssemblerType(ss); + signature->ToAssemblerType(GetCompilerContext(), ss); util::UString internal_name(ss.str(), Allocator()); func_scope->BindInternalName(internal_name.View()); @@ -619,7 +619,7 @@ void ETSBinder::BuildFunctionalInterfaceName(ir::ETSFunctionType *func_type) auto *invoke_func = functional_interface->Body()->Body()[0]->AsMethodDefinition()->Function(); util::UString functional_interface_name(functional_interface->Id()->Name(), Allocator()); std::stringstream ss; - invoke_func->Signature()->ToAssemblerType(ss); + invoke_func->Signature()->ToAssemblerType(GetCompilerContext(), ss); std::string signature_string = ss.str(); util::StringView signature_name(signature_string); FormFunctionalInterfaceName(functional_interface_name, signature_name); @@ -642,7 +642,7 @@ void ETSBinder::BuildFunctionalInterfaceName(ir::ETSFunctionType *func_type) invoke_internal_name.Append(compiler::Signatures::METHOD_SEPARATOR); invoke_internal_name.Append(invoke_func->Id()->Name()); std::stringstream invoke_signature_ss; - invoke_func->Signature()->ToAssemblerType(invoke_signature_ss); + invoke_func->Signature()->ToAssemblerType(GetCompilerContext(), invoke_signature_ss); invoke_internal_name.Append(invoke_signature_ss.str()); invoke_func_scope->BindInternalName(invoke_internal_name.View()); } diff --git a/binder/variableFlags.h b/binder/variableFlags.h index 0825f2cdf8fa28d17817a7b4970cbbe667ff6519..e195e7feb9d36e757e2e279672ef1f29defe165e 100644 --- a/binder/variableFlags.h +++ b/binder/variableFlags.h @@ -150,6 +150,8 @@ enum class VariableFlags : uint64_t { BUILTIN_TYPE = 1ULL << 32ULL, + BOXED = 1ULL << 33ULL, + HOIST_VAR = HOIST | VAR, CLASS_OR_INTERFACE = CLASS | INTERFACE, CLASS_OR_INTERFACE_OR_ENUM = CLASS_OR_INTERFACE | ENUM_LITERAL, diff --git a/checker/ETSchecker.cpp b/checker/ETSchecker.cpp index 9eb1699989bfed56f9214e818bcb9297ba1b1201..0f32629642649aa76a4f9f8be749b4e4722fb8d2 100644 --- a/checker/ETSchecker.cpp +++ b/checker/ETSchecker.cpp @@ -236,6 +236,32 @@ ETSObjectType *ETSChecker::GlobalBuiltinJSValueType() const return AsETSObjectType(&GlobalTypesHolder::GlobalJSValueBuiltinType); } +ETSObjectType *ETSChecker::GlobalBuiltinBoxType(Type const *contents) const +{ + if (contents == GlobalByteType()) { + return AsETSObjectType(&GlobalTypesHolder::GlobalByteBoxBuiltinType); + } + if (contents == GlobalShortType()) { + return AsETSObjectType(&GlobalTypesHolder::GlobalShortBoxBuiltinType); + } + if (contents == GlobalIntType()) { + return AsETSObjectType(&GlobalTypesHolder::GlobalIntBoxBuiltinType); + } + if (contents == GlobalLongType()) { + return AsETSObjectType(&GlobalTypesHolder::GlobalLongBoxBuiltinType); + } + if (contents == GlobalFloatType()) { + return AsETSObjectType(&GlobalTypesHolder::GlobalFloatBoxBuiltinType); + } + if (contents == GlobalDoubleType()) { + return AsETSObjectType(&GlobalTypesHolder::GlobalDoubleBoxBuiltinType); + } + if (contents == GlobalCharType()) { + return AsETSObjectType(&GlobalTypesHolder::GlobalCharBoxBuiltinType); + } + return AsETSObjectType(&GlobalTypesHolder::GlobalBoxBuiltinType); +} + const checker::WrapperDesc &ETSChecker::PrimitiveWrapper() const { return primitive_wrappers_.Wrappers(); @@ -250,4 +276,12 @@ const GlobalArraySignatureMap &ETSChecker::GlobalArrayTypes() const { return global_array_signatures_; } + +// For use from Signature::ToAssemblerType +// For use in Signature::ToAssemblerType +Type const *GetBoxedType(Checker const *checker, Type const *type) +{ + return checker->AsETSChecker()->GlobalBuiltinBoxType(type); +} + } // namespace panda::es2panda::checker diff --git a/checker/ETSchecker.h b/checker/ETSchecker.h index bcf5b377613b5c18cf5894dab1088bc14d90b3ec..0f5908b63b67c19628766416844cacf9a7dd13f1 100644 --- a/checker/ETSchecker.h +++ b/checker/ETSchecker.h @@ -125,6 +125,7 @@ public: ETSObjectType *GlobalBuiltinPromiseType() const; ETSObjectType *GlobalBuiltinJSRuntimeType() const; ETSObjectType *GlobalBuiltinJSValueType() const; + ETSObjectType *GlobalBuiltinBoxType(Type const *contents) const; const checker::WrapperDesc &PrimitiveWrapper() const; @@ -296,8 +297,8 @@ public: void CreateFunctionalInterfaceForFunctionType(ir::ETSFunctionType *func_type); ir::MethodDefinition *CreateInvokeFunction(ir::ETSFunctionType *func_type); void CheckCapturedVariables(); - void CheckCapturedVariables(ir::AstNode *node, const binder::Variable *var, const lexer::SourcePosition &pos); - void CheckCapturedVariable(ir::AstNode *node, const binder::Variable *var, const lexer::SourcePosition &pos); + void CheckCapturedVariableInSubnodes(ir::AstNode *node, binder::Variable *var); + void CheckCapturedVariable(ir::AstNode *node, binder::Variable *var); void BuildFunctionalInterfaceName(ir::ETSFunctionType *func_type); void CreateAsyncProxyMethods(ir::ClassDefinition *class_def); ir::MethodDefinition *CreateAsyncProxy(ir::MethodDefinition *async_method, ir::ClassDefinition *class_def, @@ -358,6 +359,7 @@ public: void AddBoxingUnboxingFlagToNode(ir::AstNode *node, Type *boxing_unboxing_type); ir::BoxingUnboxingFlags GetBoxingFlag(Type *boxing_type); ir::BoxingUnboxingFlags GetUnboxingFlag(Type *unboxing_type); + Type *BoxedTypeIfNeeded(binder::Variable const *var); void CheckForSameSwitchCases(ArenaVector *cases); std::string GetStringFromIdentifierValue(ir::Expression *identifier) const; bool CompareIdentifiersValuesAreDifferent(ir::Expression *identifier, ir::Expression *compare_value); diff --git a/checker/checker.h b/checker/checker.h index 7c8ceaea7cee3aac82b20e8228a6e867dc4a18c6..8fff88619b7e6782ebf8e83cdc3c65f311d1ce27 100644 --- a/checker/checker.h +++ b/checker/checker.h @@ -141,6 +141,11 @@ public: return reinterpret_cast(this); } + ETSChecker const *AsETSChecker() const + { + return reinterpret_cast(this); + } + virtual bool StartChecker([[maybe_unused]] binder::Binder *binder, const CompilerOptions &options) = 0; virtual Type *CheckTypeCached(ir::Expression *expr) = 0; virtual Type *GetTypeOfVariable(binder::Variable *var) = 0; @@ -279,6 +284,7 @@ private: Checker *checker_; CheckerContext prev_; }; + } // namespace panda::es2panda::checker #endif /* CHECKER_H */ diff --git a/checker/ets/function.cpp b/checker/ets/function.cpp index ebf89ec2a6216238051ed6ad062abf773fe1da54..1360093da5048fe2f49cabfbd38635ef3f6d2976 100644 --- a/checker/ets/function.cpp +++ b/checker/ets/function.cpp @@ -13,6 +13,8 @@ * limitations under the License. */ +#include "binder/variableFlags.h" +#include "checker/types/type.h" #include "plugins/ecmascript/es2panda/ir/astNode.h" #include "plugins/ecmascript/es2panda/ir/typeNode.h" #include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" @@ -41,6 +43,7 @@ #include "plugins/ecmascript/es2panda/checker/ETSchecker.h" #include "plugins/ecmascript/es2panda/checker/ets/typeRelationContext.h" #include "plugins/ecmascript/es2panda/util/helpers.h" +#include "plugins/ecmascript/runtime/napi/include/jsnapi.h" namespace panda::es2panda::checker { @@ -771,7 +774,7 @@ void ETSChecker::ValidateSignatureAccessibility(ETSObjectType *callee, Signature } } -void ETSChecker::CheckCapturedVariable(ir::AstNode *node, const binder::Variable *var, const lexer::SourcePosition &pos) +void ETSChecker::CheckCapturedVariable(ir::AstNode *node, binder::Variable *var) { if (node->IsIdentifier()) { auto *parent = node->Parent(); @@ -781,26 +784,24 @@ void ETSChecker::CheckCapturedVariable(ir::AstNode *node, const binder::Variable ResolveIdentifier(ident_node); if (ident_node->Variable() == var) { - ThrowTypeError({"Local variable ", var->Name(), - " referenced from a lambda expression must be constant or effectively constant"}, - pos); + var->AddFlag(binder::VariableFlags::BOXED); } } } - CheckCapturedVariables(node, var, pos); + CheckCapturedVariableInSubnodes(node, var); } -void ETSChecker::CheckCapturedVariables(ir::AstNode *node, const binder::Variable *var, - const lexer::SourcePosition &pos) +void ETSChecker::CheckCapturedVariableInSubnodes(ir::AstNode *node, binder::Variable *var) { - node->Iterate([this, var, &pos](ir::AstNode *child_node) { CheckCapturedVariable(child_node, var, pos); }); + node->Iterate([this, var](ir::AstNode *child_node) { CheckCapturedVariable(child_node, var); }); } void ETSChecker::CheckCapturedVariables() { // If we want to capture non constant local variables, we should wrap them in a generic reference class - for (auto [var, pos] : Context().CapturedVars()) { + for (auto [var, _] : Context().CapturedVars()) { + (void)_; if ((var->Declaration() == nullptr) || var->Declaration()->IsConstDecl() || !var->HasFlag(binder::VariableFlags::LOCAL) || var->GetScope()->Node()->IsArrowFunctionExpression()) { continue; @@ -812,7 +813,7 @@ void ETSChecker::CheckCapturedVariables() search_node = search_node->Parent()->Parent(); } - CheckCapturedVariables(search_node, var, pos); + CheckCapturedVariableInSubnodes(search_node, var); } } @@ -1111,7 +1112,8 @@ ir::Statement *ETSChecker::ResolveLambdaObjectInvokeFuncBody(ir::ClassDefinition auto *class_prop = lambda_body[i]->AsClassProperty(); auto *param = Allocator()->New(class_prop->Key()->AsIdentifier()->Name(), Allocator()); param->SetVariable(class_prop->Key()->AsIdentifier()->Variable()); - param->SetTsType(class_prop->TsType()); + param->SetIgnoreBox(); + param->SetTsType(BoxedTypeIfNeeded(param->Variable())); call_params.push_back(param); } @@ -1173,6 +1175,7 @@ void ETSChecker::ResolveLambdaObjectCtor(ir::ClassDefinition *lambda_object) auto *left_hand_side = fieldinit->Left(); left_hand_side->AsMemberExpression()->SetObjectType(lambda_object_type); left_hand_side->AsMemberExpression()->SetPropVar(field_var->AsLocalVariable()); + left_hand_side->AsMemberExpression()->SetIgnoreBox(); left_hand_side->AsMemberExpression()->SetTsType(field_var->TsType()); left_hand_side->AsMemberExpression()->Object()->SetTsType(lambda_object_type); fieldinit->Right()->AsIdentifier()->SetVariable(ctor_param_var); @@ -1406,6 +1409,9 @@ binder::FunctionParamScope *ETSChecker::CreateProxyMethodParams(ArenaVectorAddParamDecl(param); (void)_; var->SetTsType(captured_var->TsType()); + if (captured_var->HasFlag(binder::VariableFlags::BOXED)) { + var->AddFlag(binder::VariableFlags::BOXED); + } param->SetTsType(captured_var->TsType()); param->SetVariable(var); proxy_params.push_back(param); @@ -1473,8 +1479,11 @@ ir::ClassProperty *ETSChecker::CreateLambdaCapturedField(const binder::Variable auto [decl, var] = Binder()->NewVarDecl(pos, field_ident->Name()); var->AddFlag(binder::VariableFlags::PROPERTY); var->SetTsType(captured_var->TsType()); + if (captured_var->HasFlag(binder::VariableFlags::BOXED)) { + var->AddFlag(binder::VariableFlags::BOXED); + } field_ident->SetVariable(var); - field->SetTsType(captured_var->TsType()); + field->SetTsType(BoxedTypeIfNeeded(captured_var)); decl->BindNode(field); return field; } @@ -1535,8 +1544,9 @@ binder::FunctionParamScope *ETSChecker::CreateLambdaCtorImplicitParams(ArenaVect auto *param = Allocator()->New(field->Name(), Allocator()); auto [_, var] = Binder()->AddParamDecl(param); (void)_; - var->SetTsType(field->Variable()->TsType()); - param->SetTsType(field->Variable()->TsType()); + auto *type = BoxedTypeIfNeeded(field->Variable()); + var->SetTsType(type); + param->SetTsType(type); param->SetVariable(var); params.push_back(param); } diff --git a/checker/ets/helpers.cpp b/checker/ets/helpers.cpp index 306a1f70a70a4f418176b304619c1b0dbb02b628..5d69c5722740529696eb80035268528bb7c20d6a 100644 --- a/checker/ets/helpers.cpp +++ b/checker/ets/helpers.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "checker/types/globalTypesHolder.h" #include "plugins/ecmascript/es2panda/binder/variableFlags.h" #include "plugins/ecmascript/es2panda/checker/checker.h" #include "plugins/ecmascript/es2panda/checker/checkerContext.h" @@ -1366,6 +1367,40 @@ ir::BoxingUnboxingFlags ETSChecker::GetUnboxingFlag(Type *unboxing_type) } } +Type *ETSChecker::BoxedTypeIfNeeded(binder::Variable const *var) +{ + auto *var_type = var->TsType(); + if (var->HasFlag(binder::VariableFlags::BOXED)) { + if (var_type == GlobalByteType()) { + return GetGlobalTypesHolder()->GlobalByteBoxBuiltinType(); + } + if (var_type == GlobalShortType()) { + return GetGlobalTypesHolder()->GlobalShortBoxBuiltinType(); + } + if (var_type == GlobalIntType()) { + return GetGlobalTypesHolder()->GlobalIntBoxBuiltinType(); + } + if (var_type == GlobalLongType()) { + return GetGlobalTypesHolder()->GlobalLongBoxBuiltinType(); + } + if (var_type == GlobalFloatType()) { + return GetGlobalTypesHolder()->GlobalFloatBoxBuiltinType(); + } + if (var_type == GlobalDoubleType()) { + return GetGlobalTypesHolder()->GlobalDoubleBoxBuiltinType(); + } + if (var_type == GlobalCharType()) { + return GetGlobalTypesHolder()->GlobalCharBoxBuiltinType(); + } + + Type *box = GetGlobalTypesHolder()->GlobalBoxBuiltinType()->Instantiate(Allocator(), Relation(), + GetGlobalTypesHolder()); + box->AsETSObjectType()->TypeArguments().emplace_back(var_type); + return box; + } + return var_type; +} + void ETSChecker::CheckForSameSwitchCases(ArenaVector *cases) { for (size_t case_num = 0; case_num < cases->size(); case_num++) { diff --git a/checker/ets/typeCreation.cpp b/checker/ets/typeCreation.cpp index dfd28c9fefbb3b0532cee1ddd2521a72c236c3cb..b7e7c13c7343476506d9b08731e1388da1d536d1 100644 --- a/checker/ets/typeCreation.cpp +++ b/checker/ets/typeCreation.cpp @@ -205,6 +205,51 @@ ETSObjectType *ETSChecker::CreateETSObjectTypeCheckBuiltins(util::StringView nam return GlobalBuiltinPromiseType(); } GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_PROMISE_BUILTIN)] = obj_type; + } else if (name == compiler::Signatures::BUILTIN_BOX_CLASS) { + if (GlobalBuiltinBoxType(GlobalETSObjectType()) != nullptr) { + return GlobalBuiltinBoxType(GlobalETSObjectType()); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_BOX_BUILTIN)] = obj_type; + } else if (name == compiler::Signatures::BUILTIN_BYTE_BOX_CLASS) { + if (GlobalBuiltinBoxType(GlobalByteType()) != nullptr) { + return GlobalBuiltinBoxType(GlobalByteType()); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_BYTE_BOX_BUILTIN)] = obj_type; + } else if (name == compiler::Signatures::BUILTIN_SHORT_BOX_CLASS) { + if (GlobalBuiltinBoxType(GlobalShortType()) != nullptr) { + return GlobalBuiltinBoxType(GlobalShortType()); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_SHORT_BOX_BUILTIN)] = obj_type; + } else if (name == compiler::Signatures::BUILTIN_INT_BOX_CLASS) { + if (GlobalBuiltinBoxType(GlobalIntType()) != nullptr) { + return GlobalBuiltinBoxType(GlobalIntType()); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_INT_BOX_BUILTIN)] = obj_type; + } else if (name == compiler::Signatures::BUILTIN_LONG_BOX_CLASS) { + if (GlobalBuiltinBoxType(GlobalLongType()) != nullptr) { + return GlobalBuiltinBoxType(GlobalLongType()); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_LONG_BOX_BUILTIN)] = obj_type; + } else if (name == compiler::Signatures::BUILTIN_FLOAT_BOX_CLASS) { + if (GlobalBuiltinBoxType(GlobalFloatType()) != nullptr) { + return GlobalBuiltinBoxType(GlobalFloatType()); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_FLOAT_BOX_BUILTIN)] = obj_type; + } else if (name == compiler::Signatures::BUILTIN_FLOAT_BOX_CLASS) { + if (GlobalBuiltinBoxType(GlobalFloatType()) != nullptr) { + return GlobalBuiltinBoxType(GlobalFloatType()); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_FLOAT_BOX_BUILTIN)] = obj_type; + } else if (name == compiler::Signatures::BUILTIN_DOUBLE_BOX_CLASS) { + if (GlobalBuiltinBoxType(GlobalDoubleType()) != nullptr) { + return GlobalBuiltinBoxType(GlobalDoubleType()); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_DOUBLE_BOX_BUILTIN)] = obj_type; + } else if (name == compiler::Signatures::BUILTIN_CHAR_BOX_CLASS) { + if (GlobalBuiltinBoxType(GlobalCharType()) != nullptr) { + return GlobalBuiltinBoxType(GlobalCharType()); + } + GetGlobalTypesHolder()->GlobalTypes()[static_cast(GlobalTypeId::ETS_CHAR_BOX_BUILTIN)] = obj_type; } return obj_type; diff --git a/checker/types/globalTypesHolder.cpp b/checker/types/globalTypesHolder.cpp index 67623be13b021f64d89b96b4e42f18756a6480cf..1e0e52704b06c1a8d3a0d7422a4eb306ec3490bf 100644 --- a/checker/types/globalTypesHolder.cpp +++ b/checker/types/globalTypesHolder.cpp @@ -134,6 +134,14 @@ GlobalTypesHolder::GlobalTypesHolder(ArenaAllocator *allocator) : builtin_name_m builtin_name_mappings_.emplace("Type", GlobalTypeId::ETS_TYPE_BUILTIN); builtin_name_mappings_.emplace("Types", GlobalTypeId::ETS_TYPES_BUILTIN); builtin_name_mappings_.emplace("Promise", GlobalTypeId::ETS_PROMISE_BUILTIN); + builtin_name_mappings_.emplace("Box", GlobalTypeId::ETS_BOX_BUILTIN); + builtin_name_mappings_.emplace("ByteBox", GlobalTypeId::ETS_BYTE_BOX_BUILTIN); + builtin_name_mappings_.emplace("ShortBox", GlobalTypeId::ETS_SHORT_BOX_BUILTIN); + builtin_name_mappings_.emplace("IntBox", GlobalTypeId::ETS_INT_BOX_BUILTIN); + builtin_name_mappings_.emplace("LongBox", GlobalTypeId::ETS_LONG_BOX_BUILTIN); + builtin_name_mappings_.emplace("FloatBox", GlobalTypeId::ETS_FLOAT_BOX_BUILTIN); + builtin_name_mappings_.emplace("DoubleBox", GlobalTypeId::ETS_DOUBLE_BOX_BUILTIN); + builtin_name_mappings_.emplace("CharBox", GlobalTypeId::ETS_CHAR_BOX_BUILTIN); // ETS interop js specific types builtin_name_mappings_.emplace("JSRuntime", GlobalTypeId::ETS_INTEROP_JSRUNTIME_BUILTIN); @@ -495,6 +503,11 @@ Type *GlobalTypesHolder::GlobalPromiseBuiltinType() return global_types_.at(static_cast(GlobalTypeId::ETS_PROMISE_BUILTIN)); } +Type *GlobalTypesHolder::GlobalBoxBuiltinType() +{ + return global_types_.at(static_cast(GlobalTypeId::ETS_BOX_BUILTIN)); +} + Type *GlobalTypesHolder::GlobalJSRuntimeBuiltinType() { return global_types_.at(static_cast(GlobalTypeId::ETS_INTEROP_JSRUNTIME_BUILTIN)); @@ -505,6 +518,41 @@ Type *GlobalTypesHolder::GlobalJSValueBuiltinType() return global_types_.at(static_cast(GlobalTypeId::ETS_INTEROP_JSVALUE_BUILTIN)); } +Type *GlobalTypesHolder::GlobalByteBoxBuiltinType() +{ + return global_types_.at(static_cast(GlobalTypeId::ETS_BYTE_BOX_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalShortBoxBuiltinType() +{ + return global_types_.at(static_cast(GlobalTypeId::ETS_SHORT_BOX_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalIntBoxBuiltinType() +{ + return global_types_.at(static_cast(GlobalTypeId::ETS_INT_BOX_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalLongBoxBuiltinType() +{ + return global_types_.at(static_cast(GlobalTypeId::ETS_LONG_BOX_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalFloatBoxBuiltinType() +{ + return global_types_.at(static_cast(GlobalTypeId::ETS_FLOAT_BOX_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalDoubleBoxBuiltinType() +{ + return global_types_.at(static_cast(GlobalTypeId::ETS_DOUBLE_BOX_BUILTIN)); +} + +Type *GlobalTypesHolder::GlobalCharBoxBuiltinType() +{ + return global_types_.at(static_cast(GlobalTypeId::ETS_CHAR_BOX_BUILTIN)); +} + void GlobalTypesHolder::InitializeBuiltin(const util::StringView name, Type *type) { const auto type_id = builtin_name_mappings_.find(name); diff --git a/checker/types/globalTypesHolder.h b/checker/types/globalTypesHolder.h index 7fa4f8834d8257abefe8e364f42f0e37fbb32ad4..51eac1478b69a713315e1e143fc2a15698da9400 100644 --- a/checker/types/globalTypesHolder.h +++ b/checker/types/globalTypesHolder.h @@ -94,6 +94,14 @@ enum class GlobalTypeId { ETS_PROMISE_BUILTIN, ETS_INTEROP_JSRUNTIME_BUILTIN, ETS_INTEROP_JSVALUE_BUILTIN, + ETS_BOX_BUILTIN, + ETS_BYTE_BOX_BUILTIN, + ETS_SHORT_BOX_BUILTIN, + ETS_INT_BOX_BUILTIN, + ETS_LONG_BOX_BUILTIN, + ETS_FLOAT_BOX_BUILTIN, + ETS_DOUBLE_BOX_BUILTIN, + ETS_CHAR_BOX_BUILTIN, COUNT, }; @@ -179,6 +187,14 @@ public: Type *GlobalTypeBuiltinType(); Type *GlobalTypesBuiltinType(); Type *GlobalPromiseBuiltinType(); + Type *GlobalBoxBuiltinType(); + Type *GlobalByteBoxBuiltinType(); + Type *GlobalShortBoxBuiltinType(); + Type *GlobalIntBoxBuiltinType(); + Type *GlobalLongBoxBuiltinType(); + Type *GlobalFloatBoxBuiltinType(); + Type *GlobalDoubleBoxBuiltinType(); + Type *GlobalCharBoxBuiltinType(); // JS specific types Type *GlobalJSRuntimeBuiltinType(); diff --git a/checker/types/signature.h b/checker/types/signature.h index c8fe53b793d69cce862afe615594e01aa2725818..85c78e781e227cec969d7f4fbceaa95ce436723c 100644 --- a/checker/types/signature.h +++ b/checker/types/signature.h @@ -19,8 +19,12 @@ #include "type.h" #include "plugins/ecmascript/es2panda/binder/variable.h" +#include "plugins/ecmascript/es2panda/compiler/core/compilerContext.h" namespace panda::es2panda::checker { +// For use in Signature::ToAssemblerType +Type const *GetBoxedType(Checker const *checker, Type const *type); + class SignatureInfo { public: explicit SignatureInfo(ArenaAllocator *allocator) : params(allocator->Adapter()) {} @@ -205,12 +209,16 @@ public: return (flags_ & flag) != 0; } - void ToAssemblerType(std::stringstream &ss) const + void ToAssemblerType(compiler::CompilerContext const *context, std::stringstream &ss) const { ss << compiler::Signatures::MANGLE_BEGIN; for (const auto *param : signature_info_->params) { - param->TsType()->ToAssemblerTypeWithRank(ss); + if (param->HasFlag(binder::VariableFlags::BOXED)) { + GetBoxedType(context->Checker(), param->TsType())->ToAssemblerTypeWithRank(ss); + } else { + param->TsType()->ToAssemblerTypeWithRank(ss); + } ss << compiler::Signatures::MANGLE_SEPARATOR; } diff --git a/compiler/base/lreference.cpp b/compiler/base/lreference.cpp index 92ae312ef4216bdb8d408daf8d77f826063ead3f..3789aa8f958be5b5ebf9b0ae0764971562e81874 100644 --- a/compiler/base/lreference.cpp +++ b/compiler/base/lreference.cpp @@ -266,7 +266,9 @@ void ETSLReference::SetValue() const switch (Kind()) { case ReferenceKind::MEMBER: { auto *member_expr = Node()->AsMemberExpression(); - etsg_->ApplyConversion(Node(), member_expr->TsType()); + if (!member_expr->IsIgnoreBox()) { + etsg_->ApplyConversion(Node(), member_expr->TsType()); + } if (member_expr->IsComputed()) { etsg_->StoreArrayElement(Node(), base_reg_, prop_reg_, @@ -285,9 +287,15 @@ void ETSLReference::SetValue() const if (static_obj_ref_->IsETSDynamicType()) { etsg_->StorePropertyDynamic(Node(), member_expr->TsType(), base_reg_, prop_name); } else { - etsg_->StoreProperty(Node(), member_expr->TsType(), base_reg_, prop_name); + auto type = member_expr->PropVar()->TsType(); + if (member_expr->PropVar()->HasFlag(binder::VariableFlags::BOXED)) { + type = etsg_->Checker()->GlobalBuiltinBoxType(type); + } + + etsg_->StoreProperty(Node(), type, base_reg_, prop_name); } - break; + + break; } default: { etsg_->StoreVar(Node()->AsIdentifier(), Result()); diff --git a/compiler/core/ETSGen.cpp b/compiler/core/ETSGen.cpp index 7017ff273f9bf51452caf009c1bc1a2974e8ab3b..8ae0eed1e33a50bc352531609b5a5afd22b433b2 100644 --- a/compiler/core/ETSGen.cpp +++ b/compiler/core/ETSGen.cpp @@ -15,6 +15,7 @@ #include "ETSGen.h" +#include "binder/variableFlags.h" #include "plugins/ecmascript/es2panda/ir/base/scriptFunction.h" #include "plugins/ecmascript/es2panda/ir/base/classDefinition.h" #include "plugins/ecmascript/es2panda/ir/statement.h" @@ -122,7 +123,9 @@ void ETSGen::LoadAccumulator(const ir::AstNode *node, VReg vreg) { const auto *const vreg_type = GetVRegTypeExpandTypeRef(vreg); - if (vreg_type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { + if (node->IsIdentifier() && node->AsIdentifier()->Variable()->HasFlag(binder::VariableFlags::BOXED)) { + Ra().Emit(node, vreg); + } else if (vreg_type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { Ra().Emit(node, vreg); } else if (vreg_type->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { Ra().Emit(node, vreg); @@ -177,8 +180,7 @@ void ETSGen::LoadVar(const ir::AstNode *node, binder::Variable *var) break; } case ReferenceKind::FIELD: { - const auto full_name = FormClassPropReference(GetVRegType(GetThisReg())->AsETSObjectType(), var->Name()); - LoadProperty(node, var->TsType(), GetThisReg(), full_name); + LoadProperty(node, var->TsType(), GetThisReg(), var->Name()); break; } case ReferenceKind::METHOD: @@ -197,6 +199,10 @@ void ETSGen::LoadVar(const ir::AstNode *node, binder::Variable *var) } } + if (var->HasFlag(binder::VariableFlags::BOXED) && !node->AsIdentifier()->IsIgnoreBox()) { + EmitLocalBoxGet(node, var->TsType()); + } + if (target_type_ != nullptr) { ApplyConversion(node, target_type_); } @@ -218,7 +224,11 @@ void ETSGen::StoreVar(const ir::AstNode *node, const binder::ConstScopeFindResul break; } case ReferenceKind::LOCAL: { - StoreAccumulator(node, local->Vreg()); + if (local->HasFlag(binder::VariableFlags::BOXED)) { + EmitLocalBoxSet(node, local); + } else { + StoreAccumulator(node, local->Vreg()); + } break; } default: { @@ -297,6 +307,9 @@ void ETSGen::StoreProperty(const ir::AstNode *const node, const checker::Type *p const auto full_name = FormClassPropReference(GetVRegType(obj_reg)->AsETSObjectType(), name); prop_type = util::Helpers::GetTypeFromTypeRef(prop_type); + if (node->IsIdentifier() && node->AsIdentifier()->Variable()->HasFlag(binder::VariableFlags::BOXED)) { + prop_type = Checker()->GlobalBuiltinBoxType(prop_type); + } if (prop_type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { Ra().Emit(node, obj_reg, full_name); @@ -308,10 +321,14 @@ void ETSGen::StoreProperty(const ir::AstNode *const node, const checker::Type *p } void ETSGen::LoadProperty(const ir::AstNode *const node, const checker::Type *prop_type, const VReg obj_reg, - const util::StringView &full_name) + const util::StringView &name) { - prop_type = util::Helpers::GetTypeFromTypeRef(prop_type); + util::StringView full_name = FormClassPropReference(GetVRegType(obj_reg)->AsETSObjectType(), name); + prop_type = util::Helpers::GetTypeFromTypeRef(prop_type); + if (node->IsIdentifier() && node->AsIdentifier()->Variable()->HasFlag(binder::VariableFlags::BOXED)) { + prop_type = Checker()->GlobalBuiltinBoxType(prop_type); + } if (prop_type->HasTypeFlag(checker::TypeFlag::ETS_ARRAY_OR_OBJECT)) { Ra().Emit(node, obj_reg, full_name); } else if (prop_type->HasTypeFlag(checker::TypeFlag::ETS_WIDE_NUMERIC)) { @@ -494,7 +511,7 @@ void ETSGen::InitLambdaObject(const ir::AstNode *node, checker::Signature *signa } } -#undef COMPILE_ARG +#undef CONV_LAMBDA_CTOR_ARG // NOLINTEND(cppcoreguidelines-macro-usage, readability-container-size-empty) VReg ETSGen::GetThisReg() const @@ -767,6 +784,76 @@ void ETSGen::SwapBinaryOpArgs(const ir::AstNode *const node, const VReg lhs) MoveVreg(node, lhs, tmp); } +void ETSGen::EmitLocalBoxCtor(ir::AstNode const *node) +{ + auto *content_type = node->AsIdentifier()->Variable()->TsType(); + if (content_type == Checker()->GlobalByteType()) { + Ra().Emit(node, Signatures::BUILTIN_BYTE_BOX_CTOR, dummy_reg_, dummy_reg_); + } else if (content_type == Checker()->GlobalShortType()) { + Ra().Emit(node, Signatures::BUILTIN_SHORT_BOX_CTOR, dummy_reg_, dummy_reg_); + } else if (content_type == Checker()->GlobalIntType()) { + Ra().Emit(node, Signatures::BUILTIN_INT_BOX_CTOR, dummy_reg_, dummy_reg_); + } else if (content_type == Checker()->GlobalLongType()) { + Ra().Emit(node, Signatures::BUILTIN_LONG_BOX_CTOR, dummy_reg_, dummy_reg_); + } else if (content_type == Checker()->GlobalFloatType()) { + Ra().Emit(node, Signatures::BUILTIN_FLOAT_BOX_CTOR, dummy_reg_, dummy_reg_); + } else if (content_type == Checker()->GlobalDoubleType()) { + Ra().Emit(node, Signatures::BUILTIN_DOUBLE_BOX_CTOR, dummy_reg_, dummy_reg_); + } else if (content_type == Checker()->GlobalCharType()) { + Ra().Emit(node, Signatures::BUILTIN_CHAR_BOX_CTOR, dummy_reg_, dummy_reg_); + } else { + Ra().Emit(node, Signatures::BUILTIN_BOX_CTOR, dummy_reg_, dummy_reg_); + } + SetAccumulatorType(Checker()->GlobalBuiltinBoxType(content_type)); +} + +void ETSGen::EmitLocalBoxGet(ir::AstNode const *node, checker::Type const *content_type) +{ + if (content_type == Checker()->GlobalByteType()) { + Ra().Emit(node, Signatures::BUILTIN_BYTE_BOX_GET, dummy_reg_, 0); + } else if (content_type == Checker()->GlobalShortType()) { + Ra().Emit(node, Signatures::BUILTIN_SHORT_BOX_GET, dummy_reg_, 0); + } else if (content_type == Checker()->GlobalIntType()) { + Ra().Emit(node, Signatures::BUILTIN_INT_BOX_GET, dummy_reg_, 0); + } else if (content_type == Checker()->GlobalLongType()) { + Ra().Emit(node, Signatures::BUILTIN_LONG_BOX_GET, dummy_reg_, 0); + } else if (content_type == Checker()->GlobalFloatType()) { + Ra().Emit(node, Signatures::BUILTIN_FLOAT_BOX_GET, dummy_reg_, 0); + } else if (content_type == Checker()->GlobalDoubleType()) { + Ra().Emit(node, Signatures::BUILTIN_DOUBLE_BOX_GET, dummy_reg_, 0); + } else if (content_type == Checker()->GlobalCharType()) { + Ra().Emit(node, Signatures::BUILTIN_CHAR_BOX_GET, dummy_reg_, 0); + } else { + Ra().Emit(node, Signatures::BUILTIN_BOX_GET, dummy_reg_, 0); + Ra().Emit(node, content_type->AsETSObjectType()->AssemblerName()); + } + SetAccumulatorType(content_type); +} + +void ETSGen::EmitLocalBoxSet(ir::AstNode const *node, binder::LocalVariable *lhs_var) +{ + auto *content_type = lhs_var->TsType(); + auto vreg = lhs_var->Vreg(); + if (content_type == Checker()->GlobalByteType()) { + Ra().Emit(node, Signatures::BUILTIN_BYTE_BOX_SET, vreg, 1); + } else if (content_type == Checker()->GlobalShortType()) { + Ra().Emit(node, Signatures::BUILTIN_SHORT_BOX_SET, vreg, 1); + } else if (content_type == Checker()->GlobalIntType()) { + Ra().Emit(node, Signatures::BUILTIN_INT_BOX_SET, vreg, 1); + } else if (content_type == Checker()->GlobalLongType()) { + Ra().Emit(node, Signatures::BUILTIN_LONG_BOX_SET, vreg, 1); + } else if (content_type == Checker()->GlobalFloatType()) { + Ra().Emit(node, Signatures::BUILTIN_FLOAT_BOX_SET, vreg, 1); + } else if (content_type == Checker()->GlobalDoubleType()) { + Ra().Emit(node, Signatures::BUILTIN_DOUBLE_BOX_SET, vreg, 1); + } else if (content_type == Checker()->GlobalCharType()) { + Ra().Emit(node, Signatures::BUILTIN_CHAR_BOX_SET, vreg, 1); + } else { + Ra().Emit(node, Signatures::BUILTIN_BOX_SET, vreg, 1); + } + SetAccumulatorType(Checker()->GetGlobalTypesHolder()->GlobalVoidType()); +} + void ETSGen::CastToBoolean([[maybe_unused]] const ir::AstNode *node) { auto type_kind = checker::ETSChecker::TypeKind(GetAccumulatorType()); diff --git a/compiler/core/ETSGen.h b/compiler/core/ETSGen.h index 7c4feb705472c541d1764110217d3fb3ed35f496..4d8c245886c9f2df53fb3b3ec1c9a0c29c03f0ab 100644 --- a/compiler/core/ETSGen.h +++ b/compiler/core/ETSGen.h @@ -191,6 +191,10 @@ public: void EmitBoxingConversion(const ir::AstNode *node); void SwapBinaryOpArgs(const ir::AstNode *node, VReg lhs); + void EmitLocalBoxCtor(ir::AstNode const *node); + void EmitLocalBoxGet(ir::AstNode const *node, checker::Type const *content_type); + void EmitLocalBoxSet(ir::AstNode const *node, binder::LocalVariable *lhs); + void LoadArrayLength(const ir::AstNode *node, VReg array_reg); void LoadArrayElement(const ir::AstNode *node, VReg object_reg); void StoreArrayElement(const ir::AstNode *node, VReg object_reg, VReg index, const checker::Type *element_type); @@ -566,13 +570,16 @@ private: } } // NOLINTBEGIN(cppcoreguidelines-macro-usage, readability-container-size-empty) -#define COMPILE_ARG(idx) \ - ASSERT(idx < arguments.size()); \ - auto *paramType##idx = signature->Params()[idx]->TsType(); \ - auto ttctx##idx = TargetTypeContext(this, paramType##idx); \ - arguments[idx]->Compile(this); \ - VReg arg##idx = AllocReg(); \ - ApplyConversion(arguments[idx], nullptr); \ +#define COMPILE_ARG(idx) \ + ASSERT(idx < arguments.size()); \ + auto *paramType##idx = signature->Params()[idx]->TsType(); \ + if (signature->Params()[idx]->HasFlag(binder::VariableFlags::BOXED)) { \ + paramType##idx = Checker()->GlobalBuiltinBoxType(paramType##idx); \ + } \ + auto ttctx##idx = TargetTypeContext(this, paramType##idx); \ + arguments[idx]->Compile(this); \ + VReg arg##idx = AllocReg(); \ + ApplyConversion(arguments[idx], nullptr); \ ApplyConversionAndStoreAccumulator(arguments[idx], arg##idx, paramType##idx); template diff --git a/compiler/core/ETSemitter.cpp b/compiler/core/ETSemitter.cpp index c9bc784410dc00d7b450b17674c1c791179dc89b..50701b79477c5db928d1e68cb3e5c62e76a7bcc4 100644 --- a/compiler/core/ETSemitter.cpp +++ b/compiler/core/ETSemitter.cpp @@ -15,6 +15,8 @@ #include "ETSemitter.h" +#include "binder/variableFlags.h" +#include "ir/astNode.h" #include "plugins/ecmascript/es2panda/compiler/core/ETSGen.h" #include "plugins/ecmascript/es2panda/binder/binder.h" #include "plugins/ecmascript/es2panda/binder/ETSBinder.h" @@ -87,7 +89,7 @@ static uint32_t TranslateModifierFlags(ir::ModifierFlags modifier_flags) return access_flags; } -static pandasm::Function GenScriptFunction(const ir::ScriptFunction *script_func) +static pandasm::Function GenScriptFunction(CompilerContext const *context, const ir::ScriptFunction *script_func) { auto *func_scope = script_func->Scope(); auto *param_scope = func_scope->ParamScope(); @@ -98,7 +100,7 @@ static pandasm::Function GenScriptFunction(const ir::ScriptFunction *script_func for (const auto *var : param_scope->Params()) { std::stringstream ss; - var->TsType()->ToAssemblerType(ss); + context->Checker()->AsETSChecker()->BoxedTypeIfNeeded(var)->ToAssemblerType(ss); func.params.emplace_back(pandasm::Type(ss.str(), var->TsType()->Rank()), EXTENSION); } @@ -129,7 +131,7 @@ static pandasm::Function GenScriptFunction(const ir::ScriptFunction *script_func pandasm::Function *ETSFunctionEmitter::GenFunctionSignature() { - auto func = GenScriptFunction(Cg()->RootNode()->AsScriptFunction()); + auto func = GenScriptFunction(Cg()->Context(), Cg()->RootNode()->AsScriptFunction()); auto *func_element = new pandasm::Function(func.name, func.language); *func_element = std::move(func); GetProgramElement()->SetFunction(func_element); @@ -210,7 +212,7 @@ void ETSEmitter::GenAnnotation() for (auto *signature : global_record_table->Signatures()) { auto *script_func = signature->Node()->AsScriptFunction(); - auto func = GenScriptFunction(script_func); + auto func = GenScriptFunction(Context(), script_func); if (script_func->IsAsyncFunc()) { std::vector annotations; annotations.push_back(GenAnnotationAsync(script_func)); @@ -243,7 +245,7 @@ void ETSEmitter::GenExternalRecord(binder::RecordTable *record_table) } for (auto *signature : record_table->Signatures()) { - auto func = GenScriptFunction(signature->Node()->AsScriptFunction()); + auto func = GenScriptFunction(Context(), signature->Node()->AsScriptFunction()); if (!is_gen_std_lib) { func.metadata->SetAttribute(Signatures::EXTERNAL); @@ -323,7 +325,7 @@ void ETSEmitter::EmitDefaultFieldValue(pandasm::Field &class_field, const ir::Ex void ETSEmitter::GenInterfaceMethodDefinition(const ir::MethodDefinition *method_def, bool external) { auto *script_func = method_def->Function(); - auto func = GenScriptFunction(script_func); + auto func = GenScriptFunction(Context(), script_func); if (external) { func.metadata->SetAttribute(Signatures::EXTERNAL); diff --git a/compiler/core/codeGen.h b/compiler/core/codeGen.h index 69c20cae145b09e6adc394d7347b5b221ead16bf..20563a0a67c2ab01bb767fdd03f5dcbc1aa9c7e9 100644 --- a/compiler/core/codeGen.h +++ b/compiler/core/codeGen.h @@ -173,6 +173,7 @@ public: [[noreturn]] static void Unimplemented(); void SetVRegType(VReg vreg, const checker::Type *type); + [[nodiscard]] CompilerContext *Context() const noexcept; [[nodiscard]] const checker::Type *GetVRegType(VReg vreg) const; [[nodiscard]] const checker::Type *GetVRegFutureType(VReg vreg) const; @@ -185,7 +186,6 @@ protected: [[nodiscard]] const RegAllocator &Ra() const noexcept; [[nodiscard]] RangeRegAllocator &Rra() noexcept; [[nodiscard]] const RangeRegAllocator &Rra() const noexcept; - [[nodiscard]] CompilerContext *Context() const noexcept; [[nodiscard]] ProgramElement *ProgElement() const noexcept; [[nodiscard]] TypeMap &GetTypeMap() noexcept; [[nodiscard]] const TypeMap &GetTypeMap() const noexcept; diff --git a/compiler/scripts/signatures.yaml b/compiler/scripts/signatures.yaml index 5bd4a6f33a38aa33a642483fc273b1643386622f..879bba9bfc4fb540e4f651845a33949e206dfa38 100644 --- a/compiler/scripts/signatures.yaml +++ b/compiler/scripts/signatures.yaml @@ -229,6 +229,30 @@ builtins: - name: JSValue package: PKG_STD_INTEROP_JS ref: BUILTIN_JSVALUE + - name: Box + package: PKG_STD_CORE + ref: BUILTIN_BOX + - name: ByteBox + package: PKG_STD_CORE + ref: BUILTIN_BYTE_BOX + - name: ShortBox + package: PKG_STD_CORE + ref: BUILTIN_SHORT_BOX + - name: IntBox + package: PKG_STD_CORE + ref: BUILTIN_INT_BOX + - name: LongBox + package: PKG_STD_CORE + ref: BUILTIN_LONG_BOX + - name: FloatBox + package: PKG_STD_CORE + ref: BUILTIN_FLOAT_BOX + - name: DoubleBox + package: PKG_STD_CORE + ref: BUILTIN_DOUBLE_BOX + - name: CharBox + package: PKG_STD_CORE + ref: BUILTIN_CHAR_BOX signatures: - callee: BUILTIN_OBJECT @@ -636,3 +660,147 @@ signatures: params: [BUILTIN_JSVALUE, BUILTIN_STRING, BUILTIN_JSVALUE] return_type: PRIMITIVE_VOID ref: BUILTIN_JSRUNTIME_SET_PROPERTY_JSVALUE + + - callee: BUILTIN_BOX + method_name: $CTOR + params: [] + return_type: PRIMITIVE_VOID + ref: BUILTIN_BOX_CTOR + + - callee: BUILTIN_BOX + method_name: get + params: [] + return_type: BUILTIN_OBJECT + ref: BUILTIN_BOX_GET + + - callee: BUILTIN_BOX + method_name: set + params: [BUILTIN_OBJECT] + return_type: PRIMITIVE_VOID + ref: BUILTIN_BOX_SET + + - callee: BUILTIN_BYTE_BOX + method_name: $CTOR + params: [] + return_type: PRIMITIVE_VOID + ref: BUILTIN_BYTE_BOX_CTOR + + - callee: BUILTIN_BYTE_BOX + method_name: get + params: [] + return_type: PRIMITIVE_BYTE + ref: BUILTIN_BYTE_BOX_GET + + - callee: BUILTIN_BYTE_BOX + method_name: set + params: [PRIMITIVE_BYTE] + return_type: PRIMITIVE_VOID + ref: BUILTIN_BYTE_BOX_SET + + - callee: BUILTIN_SHORT_BOX + method_name: $CTOR + params: [] + return_type: PRIMITIVE_VOID + ref: BUILTIN_SHORT_BOX_CTOR + + - callee: BUILTIN_SHORT_BOX + method_name: get + params: [] + return_type: PRIMITIVE_SHORT + ref: BUILTIN_SHORT_BOX_GET + + - callee: BUILTIN_SHORT_BOX + method_name: set + params: [PRIMITIVE_SHORT] + return_type: PRIMITIVE_VOID + ref: BUILTIN_SHORT_BOX_SET + + - callee: BUILTIN_INT_BOX + method_name: $CTOR + params: [] + return_type: PRIMITIVE_VOID + ref: BUILTIN_INT_BOX_CTOR + + - callee: BUILTIN_INT_BOX + method_name: get + params: [] + return_type: PRIMITIVE_INT + ref: BUILTIN_INT_BOX_GET + + - callee: BUILTIN_INT_BOX + method_name: set + params: [PRIMITIVE_INT] + return_type: PRIMITIVE_VOID + ref: BUILTIN_INT_BOX_SET + + - callee: BUILTIN_LONG_BOX + method_name: $CTOR + params: [] + return_type: PRIMITIVE_VOID + ref: BUILTIN_LONG_BOX_CTOR + + - callee: BUILTIN_LONG_BOX + method_name: get + params: [] + return_type: PRIMITIVE_LONG + ref: BUILTIN_LONG_BOX_GET + + - callee: BUILTIN_LONG_BOX + method_name: set + params: [PRIMITIVE_LONG] + return_type: PRIMITIVE_VOID + ref: BUILTIN_LONG_BOX_SET + + - callee: BUILTIN_FLOAT_BOX + method_name: $CTOR + params: [] + return_type: PRIMITIVE_VOID + ref: BUILTIN_FLOAT_BOX_CTOR + + - callee: BUILTIN_FLOAT_BOX + method_name: get + params: [] + return_type: PRIMITIVE_FLOAT + ref: BUILTIN_FLOAT_BOX_GET + + - callee: BUILTIN_FLOAT_BOX + method_name: set + params: [PRIMITIVE_FLOAT] + return_type: PRIMITIVE_VOID + ref: BUILTIN_FLOAT_BOX_SET + + - callee: BUILTIN_DOUBLE_BOX + method_name: $CTOR + params: [] + return_type: PRIMITIVE_VOID + ref: BUILTIN_DOUBLE_BOX_CTOR + + - callee: BUILTIN_DOUBLE_BOX + method_name: get + params: [] + return_type: PRIMITIVE_DOUBLE + ref: BUILTIN_DOUBLE_BOX_GET + + - callee: BUILTIN_DOUBLE_BOX + method_name: set + params: [PRIMITIVE_DOUBLE] + return_type: PRIMITIVE_VOID + ref: BUILTIN_DOUBLE_BOX_SET + + - callee: BUILTIN_CHAR_BOX + method_name: $CTOR + params: [] + return_type: PRIMITIVE_VOID + ref: BUILTIN_CHAR_BOX_CTOR + + - callee: BUILTIN_CHAR_BOX + method_name: get + params: [] + return_type: PRIMITIVE_CHAR + ref: BUILTIN_CHAR_BOX_GET + + - callee: BUILTIN_CHAR_BOX + method_name: set + params: [PRIMITIVE_CHAR] + return_type: PRIMITIVE_VOID + ref: BUILTIN_CHAR_BOX_SET diff --git a/ir/expressions/identifier.h b/ir/expressions/identifier.h index aa98213bb89e12dac9ae2371747e34ff2954ac7e..a2d601db3230032a4048619be12d161226623a34 100644 --- a/ir/expressions/identifier.h +++ b/ir/expressions/identifier.h @@ -31,6 +31,7 @@ enum class IdentifierFlags : uint32_t { REFERENCE = 1U << 1U, TDZ = 1U << 2U, PRIVATE = 1U << 3U, + IGNORE_BOX = 1U << 4U, }; DEFINE_BITOPS(IdentifierFlags) @@ -120,6 +121,16 @@ public: } } + bool IsIgnoreBox() const + { + return flags_ & IdentifierFlags::IGNORE_BOX; + } + + void SetIgnoreBox() + { + flags_ |= IdentifierFlags::IGNORE_BOX; + } + binder::Variable *Variable() const { return variable_; diff --git a/ir/expressions/memberExpression.h b/ir/expressions/memberExpression.h index 65a369b339853533adc89aa42874010e6f0864fa..8687f305a21f659525a3d26c296be8bff9137f7f 100644 --- a/ir/expressions/memberExpression.h +++ b/ir/expressions/memberExpression.h @@ -100,6 +100,16 @@ public: obj_type_ = obj_type; } + bool IsIgnoreBox() const + { + return ignore_box_; + } + + void SetIgnoreBox() + { + ignore_box_ = true; + } + bool IsPrivateReference() const; void Iterate(const NodeTraverser &cb) const override; @@ -118,6 +128,7 @@ private: MemberExpressionKind kind_; bool computed_; bool optional_; + bool ignore_box_ {false}; binder::LocalVariable *prop_var_ {}; checker::ETSObjectType *obj_type_ {}; }; diff --git a/ir/statements/variableDeclarator.cpp b/ir/statements/variableDeclarator.cpp index 1c9b7e8828bb1b8e1664b25b113a703b895124e9..65fe98fa19d67d0f283c7fbd55eb108a726ec485 100644 --- a/ir/statements/variableDeclarator.cpp +++ b/ir/statements/variableDeclarator.cpp @@ -15,6 +15,8 @@ #include "variableDeclarator.h" +#include "binder/variableFlags.h" +#include "ir/astNode.h" #include "plugins/ecmascript/es2panda/compiler/base/lreference.h" #include "plugins/ecmascript/es2panda/compiler/core/pandagen.h" #include "plugins/ecmascript/es2panda/compiler/core/ETSGen.h" @@ -64,11 +66,16 @@ void VariableDeclarator::Compile([[maybe_unused]] compiler::PandaGen *pg) const lref.SetValue(); } -void VariableDeclarator::Compile([[maybe_unused]] compiler::ETSGen *etsg) const +void VariableDeclarator::Compile(compiler::ETSGen *etsg) const { auto lref = compiler::ETSLReference::Create(etsg, id_, true); auto ttctx = compiler::TargetTypeContext(etsg, TsType()); + if (id_->AsIdentifier()->Variable()->HasFlag(binder::VariableFlags::BOXED)) { + etsg->EmitLocalBoxCtor(id_); + etsg->StoreAccumulator(this, lref.Variable()->AsLocalVariable()->Vreg()); + } + if (init_ != nullptr) { if (!etsg->TryLoadConstantExpression(init_)) { init_->Compile(etsg); diff --git a/test/compiler/ets/lambdaFunction2-expected.txt b/test/compiler/ets/lambdaFunction2-expected.txt deleted file mode 100644 index 9fd0ff65f9fc208fc66219f442120ebdb86c99bd..0000000000000000000000000000000000000000 --- a/test/compiler/ets/lambdaFunction2-expected.txt +++ /dev/null @@ -1,500 +0,0 @@ -{ - "type": "Program", - "statements": [ - { - "type": "ClassDeclaration", - "definition": { - "id": { - "type": "Identifier", - "name": "ETSGLOBAL", - "decorators": [], - "loc": { - "start": { - "line": 1, - "column": 1 - }, - "end": { - "line": 1, - "column": 1 - } - } - }, - "superClass": null, - "implements": [], - "body": [ - { - "type": "MethodDefinition", - "key": { - "type": "Identifier", - "name": "foo", - "decorators": [], - "loc": { - "start": { - "line": 1, - "column": 10 - }, - "end": { - "line": 1, - "column": 13 - } - } - }, - "kind": "method", - "accessibility": "public", - "static": true, - "optional": false, - "computed": false, - "value": { - "type": "FunctionExpression", - "function": { - "type": "ScriptFunction", - "id": { - "type": "Identifier", - "name": "foo", - "decorators": [], - "loc": { - "start": { - "line": 1, - "column": 10 - }, - "end": { - "line": 1, - "column": 13 - } - } - }, - "generator": false, - "async": false, - "expression": false, - "params": [], - "returnType": { - "type": "ETSPrimitiveType", - "loc": { - "start": { - "line": 1, - "column": 17 - }, - "end": { - "line": 1, - "column": 21 - } - } - }, - "body": { - "type": "BlockStatement", - "statements": [ - { - "type": "VariableDeclaration", - "declarations": [ - { - "type": "VariableDeclarator", - "id": { - "type": "Identifier", - "name": "a", - "decorators": [], - "loc": { - "start": { - "line": 2, - "column": 9 - }, - "end": { - "line": 2, - "column": 10 - } - } - }, - "init": { - "type": "NumberLiteral", - "value": 1, - "loc": { - "start": { - "line": 2, - "column": 13 - }, - "end": { - "line": 2, - "column": 14 - } - } - }, - "loc": { - "start": { - "line": 2, - "column": 9 - }, - "end": { - "line": 2, - "column": 14 - } - } - } - ], - "kind": "let", - "loc": { - "start": { - "line": 2, - "column": 5 - }, - "end": { - "line": 2, - "column": 15 - } - } - }, - { - "type": "VariableDeclaration", - "declarations": [ - { - "type": "VariableDeclarator", - "id": { - "type": "Identifier", - "name": "lambda", - "typeAnnotation": { - "type": "ETSFunctionType", - "params": [ - { - "type": "Identifier", - "name": "b", - "typeAnnotation": { - "type": "ETSPrimitiveType", - "loc": { - "start": { - "line": 3, - "column": 21 - }, - "end": { - "line": 3, - "column": 24 - } - } - }, - "decorators": [], - "loc": { - "start": { - "line": 3, - "column": 18 - }, - "end": { - "line": 3, - "column": 24 - } - } - } - ], - "returnType": { - "type": "ETSPrimitiveType", - "loc": { - "start": { - "line": 3, - "column": 29 - }, - "end": { - "line": 3, - "column": 33 - } - } - }, - "loc": { - "start": { - "line": 3, - "column": 17 - }, - "end": { - "line": 3, - "column": 33 - } - } - }, - "decorators": [], - "loc": { - "start": { - "line": 3, - "column": 9 - }, - "end": { - "line": 3, - "column": 15 - } - } - }, - "init": { - "type": "ArrowFunctionExpression", - "function": { - "type": "ScriptFunction", - "id": null, - "generator": false, - "async": false, - "expression": false, - "params": [ - { - "type": "Identifier", - "name": "b", - "typeAnnotation": { - "type": "ETSPrimitiveType", - "loc": { - "start": { - "line": 3, - "column": 40 - }, - "end": { - "line": 3, - "column": 43 - } - } - }, - "decorators": [], - "loc": { - "start": { - "line": 3, - "column": 37 - }, - "end": { - "line": 3, - "column": 43 - } - } - } - ], - "returnType": { - "type": "ETSPrimitiveType", - "loc": { - "start": { - "line": 3, - "column": 46 - }, - "end": { - "line": 3, - "column": 50 - } - } - }, - "body": { - "type": "BlockStatement", - "statements": [ - { - "type": "ExpressionStatement", - "expression": { - "type": "UpdateExpression", - "operator": "++", - "prefix": false, - "argument": { - "type": "Identifier", - "name": "b", - "decorators": [], - "loc": { - "start": { - "line": 4, - "column": 9 - }, - "end": { - "line": 4, - "column": 10 - } - } - }, - "loc": { - "start": { - "line": 4, - "column": 9 - }, - "end": { - "line": 4, - "column": 12 - } - } - }, - "loc": { - "start": { - "line": 4, - "column": 9 - }, - "end": { - "line": 4, - "column": 13 - } - } - }, - { - "type": "ExpressionStatement", - "expression": { - "type": "UpdateExpression", - "operator": "++", - "prefix": false, - "argument": { - "type": "Identifier", - "name": "a", - "decorators": [], - "loc": { - "start": { - "line": 5, - "column": 9 - }, - "end": { - "line": 5, - "column": 10 - } - } - }, - "loc": { - "start": { - "line": 5, - "column": 9 - }, - "end": { - "line": 5, - "column": 12 - } - } - }, - "loc": { - "start": { - "line": 5, - "column": 9 - }, - "end": { - "line": 5, - "column": 13 - } - } - } - ], - "loc": { - "start": { - "line": 3, - "column": 54 - }, - "end": { - "line": 6, - "column": 6 - } - } - }, - "loc": { - "start": { - "line": 3, - "column": 36 - }, - "end": { - "line": 6, - "column": 6 - } - } - }, - "loc": { - "start": { - "line": 3, - "column": 36 - }, - "end": { - "line": 6, - "column": 6 - } - } - }, - "loc": { - "start": { - "line": 3, - "column": 9 - }, - "end": { - "line": 6, - "column": 6 - } - } - } - ], - "kind": "let", - "loc": { - "start": { - "line": 3, - "column": 5 - }, - "end": { - "line": 6, - "column": 6 - } - } - } - ], - "loc": { - "start": { - "line": 1, - "column": 22 - }, - "end": { - "line": 7, - "column": 2 - } - } - }, - "loc": { - "start": { - "line": 1, - "column": 13 - }, - "end": { - "line": 7, - "column": 2 - } - } - }, - "loc": { - "start": { - "line": 1, - "column": 13 - }, - "end": { - "line": 7, - "column": 2 - } - } - }, - "overloads": [], - "decorators": [], - "loc": { - "start": { - "line": 1, - "column": 1 - }, - "end": { - "line": 7, - "column": 2 - } - } - } - ], - "loc": { - "start": { - "line": 1, - "column": 1 - }, - "end": { - "line": 1, - "column": 1 - } - } - }, - "loc": { - "start": { - "line": 1, - "column": 1 - }, - "end": { - "line": 1, - "column": 1 - } - } - } - ], - "loc": { - "start": { - "line": 1, - "column": 1 - }, - "end": { - "line": 8, - "column": 1 - } - } -} -TypeError: Local variable a referenced from a lambda expression must be constant or effectively constant [lambdaFunction2.ets:5:9] diff --git a/test/compiler/ets/lambdaFunction2.ets b/test/compiler/ets/lambdaFunction2.ets deleted file mode 100644 index b8bf623b6fcf667b9e238d17db3e74ca7610a6ed..0000000000000000000000000000000000000000 --- a/test/compiler/ets/lambdaFunction2.ets +++ /dev/null @@ -1,7 +0,0 @@ -function foo(): void { - let a = 1; - let lambda: (b: int) => void = (b: int): void => { - b++; - a++; - } -} diff --git a/test/runtime/ets/non-const-capture.ets b/test/runtime/ets/non-const-capture.ets new file mode 100644 index 0000000000000000000000000000000000000000..1e618dbcaf208c8a94b53302b9f4b7bfcedde0d5 --- /dev/null +++ b/test/runtime/ets/non-const-capture.ets @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023 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. + */ + +class C { + v: int = 0; + constructor (v: int) { + this.v = v; + } +} + +function part1(): void { + let b: byte = 0; + let s: short = 0; + let i: int = 0; + let c: char = 0; + let lam: () => void = () => { + assert b == 1; + assert s == 2; + assert i == 3; + assert c == 4; + b = 5; + s = 6; + i = 7; + c = 8; + }; + b = 1; + s = 2; + i = 3; + c = 4; + lam(); + assert b == 5; + assert s == 6; + assert i == 7; + assert c == 8; +} + +function part2(): void { + let l: long = 0; + let f: float = 0.0; + let d: double = 0.0; + let o = new C(0); + let lam: () => void = () => { + assert l == 9; + assert f == 10.0; + assert d == 11.0; + assert o.v == 12; + l = 13; + f = 14.0; + d = 15.0; + o = new C(16); + } + l = 9; + f = 10.0; + d = 11.0; + o = new C(12); + lam(); + assert l == 13; + assert f == 14.0; + assert d == 15.0; + assert o.v == 16; +} + +function main(): void { + part1(); + part2(); +}