diff --git a/ets2panda/checker/ets/helpers.cpp b/ets2panda/checker/ets/helpers.cpp index 73311393661a09964e961fe4673159a8a0ac6b8a..d1f449fc428b16c523bb626854147b28b07f9f47 100644 --- a/ets2panda/checker/ets/helpers.cpp +++ b/ets2panda/checker/ets/helpers.cpp @@ -439,7 +439,7 @@ void ETSChecker::ValidateResolvedIdentifier(ir::Identifier *const ident, varbind if (!resolved_type->IsETSObjectType() && !resolved_type->IsETSArrayType() && !resolved_type->IsETSEnumType() && !resolved_type->IsETSStringEnumType() && - !resolved_type->IsETSUnionType()) { + !resolved_type->IsETSUnionType() && !resolved_type->HasTypeFlag(TypeFlag::ETS_PRIMITIVE)) { throw_error(); } diff --git a/ets2panda/compiler/core/ETSCompiler.cpp b/ets2panda/compiler/core/ETSCompiler.cpp index 6ee70ad191040eb3ba06d358f357beeb3794599e..7df01ed60391a0e8423b411c7f5c2d957ac34699 100644 --- a/ets2panda/compiler/core/ETSCompiler.cpp +++ b/ets2panda/compiler/core/ETSCompiler.cpp @@ -524,7 +524,9 @@ void ETSCompiler::CompileDynamic(const ir::CallExpression *expr, compiler::VReg void ETSCompiler::EmitCall(const ir::CallExpression *expr, compiler::VReg &callee_reg, bool is_static) const { ETSGen *etsg = GetETSGen(); - + if (expr->Callee()->GetBoxingUnboxingFlags() != ir::BoxingUnboxingFlags::NONE) { + etsg->ApplyConversionAndStoreAccumulator(expr->Callee(), callee_reg, nullptr); + } if (is_static) { etsg->CallStatic(expr, expr->Signature(), expr->Arguments()); } else if (expr->Signature()->HasSignatureFlag(checker::SignatureFlags::PRIVATE) || expr->IsETSConstructorCall() || diff --git a/ets2panda/ir/expressions/memberExpression.cpp b/ets2panda/ir/expressions/memberExpression.cpp index eda32a4f54bc8b03bc90d84116794cfc99a46cad..a308acfd149eb268b9632c096a418cefc442f114 100644 --- a/ets2panda/ir/expressions/memberExpression.cpp +++ b/ets2panda/ir/expressions/memberExpression.cpp @@ -451,6 +451,15 @@ checker::Type *MemberExpression::Check(checker::ETSChecker *checker) return AdjustOptional(checker, CheckUnionMember(checker, base_type)); } + if (base_type->HasTypeFlag(checker::TypeFlag::ETS_PRIMITIVE)) { + checker->Relation()->SetNode(this); + SetObjectType(checker->PrimitiveTypeAsETSBuiltinType(base_type)->AsETSObjectType()); + checker->AddBoxingUnboxingFlagToNode(this, obj_type_); + auto [res_type, res_var] = ResolveObjectMember(checker); + SetPropVar(res_var); + return AdjustOptional(checker, res_type); + } + checker->ThrowTypeError({"Cannot access property of non-object or non-enum type"}, object_->Start()); } diff --git a/ets2panda/test/CMakeLists.txt b/ets2panda/test/CMakeLists.txt index a602e480e52b0af635d8bcf31cb82414f9adcf08..ba88fb843fdd08bd7be30b2cd223938012cc7ab1 100644 --- a/ets2panda/test/CMakeLists.txt +++ b/ets2panda/test/CMakeLists.txt @@ -118,3 +118,5 @@ if(PANDA_WITH_ETS) add_subdirectory(tsconfig) endif() + +add_subdirectory(options) diff --git a/ets2panda/test/options/CMakeLists.txt b/ets2panda/test/options/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..dd46aabd24b3a973ddc8c820bc2c5ce49e6e2a7f --- /dev/null +++ b/ets2panda/test/options/CMakeLists.txt @@ -0,0 +1,36 @@ +# Copyright (c) 2021-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. + +if(CMAKE_CROSSCOMPILING) + return() +endif() + +add_custom_target(es2panda_tests_options) +add_dependencies(es2panda_tests es2panda_tests_options) + +function(check_option_help_otput target_name INPUT_ARGS OUTPUT_HELP_LINE) + separate_arguments(INPUT_ARGS) + add_custom_target(es2panda_check_opts_${target_name} + COMMENT "es2panda: checking option ${INPUT_ARGS}" + COMMAND es2panda ${INPUT_ARGS} 2> ${CMAKE_BINARY_DIR}/es2panda_check_opts_${target_name}.out || true + COMMAND grep -q ${OUTPUT_HELP_LINE} ${CMAKE_BINARY_DIR}/es2panda_check_opts_${target_name}.out + DEPENDS es2panda + ) + + add_dependencies(es2panda_tests_options es2panda_check_opts_${target_name}) +endfunction() + +check_option_help_otput(bco_opt "--help" "bco-optimizer:") +check_option_help_otput(bco_opt_help "--bco-optimizer --help" "bytecode-opt-peepholes:") +check_option_help_otput(comp_opt "--help" "bco-compiler:") +check_option_help_otput(comp_opt_help "--bco-compiler --help" "compiler-disasm-dump:") diff --git a/ets2panda/test/runtime/ets/autoboxing.ets b/ets2panda/test/runtime/ets/autoboxing.ets new file mode 100644 index 0000000000000000000000000000000000000000..f66dbbb41beb1e59fbe8b454950c4bdca77c0a9d --- /dev/null +++ b/ets2panda/test/runtime/ets/autoboxing.ets @@ -0,0 +1,35 @@ +/* + * 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. + */ + +function foo_i(value: int): string { + return value.toString(); +} + +function foo_d(value: double): string { + return value.toString(); +} + +function foo_n(value: number): string { + return value.toString(); +} + +function main(): void { + let str_i: string = foo_i(4); + assert str_i == "4"; + let str_d: string = foo_d(3.14); + assert str_d == "3.14"; + let str_n: string = foo_n(5); + assert str_n == "5"; +} \ No newline at end of file diff --git a/ets2panda/util/options.cpp b/ets2panda/util/options.cpp index c7f2350ca873daa63d904e6b08960356591d56f9..60e35b3075d7159197182ee00774dec4786a07f9 100644 --- a/ets2panda/util/options.cpp +++ b/ets2panda/util/options.cpp @@ -19,6 +19,11 @@ #include +#ifdef PANDA_WITH_BYTECODE_OPTIMIZER +#include "bytecode_optimizer/bytecodeopt_options.h" +#include "compiler/compiler_options.h" +#endif + namespace panda::es2panda::util { template T RemoveExtension(T const &filename) @@ -55,9 +60,84 @@ static std::unordered_set StringToStringSet(const std::string &str) return res; } +// NOLINTNEXTLINE(modernize-avoid-c-arrays, hicpp-avoid-c-arrays) +static void SplitArgs(int argc, const char *argv[], std::vector &es2panda_args, + std::vector &bco_compiler_args, std::vector &bytecodeopt_args) +{ + constexpr std::string_view COMPILER_PREFIX = "--bco-compiler"; + constexpr std::string_view OPTIMIZER_PREFIX = "--bco-optimizer"; + + enum class OptState { ES2PANDA, JIT_COMPILER, OPTIMIZER }; + OptState opt_state = OptState::ES2PANDA; + + std::unordered_map *> args_map = {{OptState::ES2PANDA, &es2panda_args}, + {OptState::JIT_COMPILER, &bco_compiler_args}, + {OptState::OPTIMIZER, &bytecodeopt_args}}; + + for (int i = 1; i < argc; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + const char *arg_i = argv[i]; + if (COMPILER_PREFIX == arg_i) { + opt_state = OptState::JIT_COMPILER; + continue; + } + + if (OPTIMIZER_PREFIX == arg_i) { + opt_state = OptState::OPTIMIZER; + continue; + } + + args_map[opt_state]->emplace_back(arg_i); + opt_state = OptState::ES2PANDA; + } +} + +template +static bool ParseComponentArgs(const std::vector &args, T &options) +{ + panda::PandArgParser parser; + options.AddOptions(&parser); + if (!parser.Parse(args)) { + std::cerr << parser.GetErrorString(); + std::cerr << parser.GetHelpString(); + return false; + } + + if (auto options_err = options.Validate(); options_err) { + std::cerr << "Error: " << options_err.value().GetMessage() << std::endl; + return false; + } + + return true; +} + +static bool ParseBCOCompilerOptions([[maybe_unused]] const std::vector &compiler_args, + [[maybe_unused]] const std::vector &bytecodeopt_args) +{ +#ifdef PANDA_WITH_BYTECODE_OPTIMIZER + if (!ParseComponentArgs(compiler_args, panda::compiler::OPTIONS)) { + return false; + } + if (!ParseComponentArgs(bytecodeopt_args, panda::bytecodeopt::OPTIONS)) { + return false; + } +#endif + + return true; +} + // NOLINTNEXTLINE(readability-function-size) bool Options::Parse(int argc, const char **argv) { + std::vector es2panda_args; + std::vector bco_compiler_args; + std::vector bytecodeopt_args; + + SplitArgs(argc, argv, es2panda_args, bco_compiler_args, bytecodeopt_args); + if (!ParseBCOCompilerOptions(bco_compiler_args, bytecodeopt_args)) { + return false; + } + panda::PandArg op_help("help", false, "Print this message and exit"); // parser @@ -128,7 +208,7 @@ bool Options::Parse(int argc, const char **argv) argparser_->EnableTail(); argparser_->EnableRemainder(); - if (!argparser_->Parse(argc, argv) || op_help.GetValue()) { + if (!argparser_->Parse(es2panda_args) || op_help.GetValue()) { std::stringstream ss; ss << argparser_->GetErrorString() << std::endl; @@ -139,6 +219,12 @@ bool Options::Parse(int argc, const char **argv) ss << "optional arguments:" << std::endl; ss << argparser_->GetHelpString() << std::endl; + ss << std::endl; + ss << "--bco-optimizer: Argument directly to bytecode optimizer can be passed after this prefix" << std::endl; + ss << "--bco-compiler: Argument directly to jit-compiler inside bytecode optimizer can be passed after this " + "prefix" + << std::endl; + error_msg_ = ss.str(); return false; }