From a4599e5405246dd756f10bb5c19aa6ae882b43d1 Mon Sep 17 00:00:00 2001 From: y00576111 Date: Tue, 7 Sep 2021 21:51:18 +0800 Subject: [PATCH 1/6] upload runtime_core Signed-off-by: y00576111 Change-Id: I2509006818624fd3960ef645165fdb1f317d3d5e --- ark_config.gni | 4 +- assembler/BUILD.gn | 12 +- assembler/asm_isapi.rb | 28 +- assembler/assembly-emitter.cpp | 15 +- assembler/assembly-ins.h | 5 - assembler/assembly-label.h | 1 - assembler/assembly-parser.cpp | 8 +- assembler/assembly-parser.h | 2 +- assembler/templates/builtin_parsing.cpp.erb | 6 +- assembler/templates/ins_emit.h.erb | 7 +- assembler/templates/ins_to_string.cpp.erb | 4 +- assembler/templates/opcode_parsing.h.erb | 6 +- assembler/utils/number-utils.h | 7 +- cmake/README.md | 6 +- cmake/TemplateBasedGen.cmake | 5 +- disassembler/BUILD.gn | 10 +- disassembler/CMakeLists.txt | 11 - .../templates/get_instructions.cpp.erb | 8 +- disassembler/tests/instructions_test.cpp | 29 - isa/BUILD.gn | 31 + isa/CMakeLists.txt | 28 +- isa/ChangeLog.md | 6 + isa/asserts.rb | 44 +- isa/builtins.yaml | 139 +- isa/builtinsapi.rb | 4 +- isa/combine.rb | 65 + isa/isa.yaml | 1083 ++++--- isa/isapi.rb | 194 +- ldscripts/panda.ld | 2 +- ldscripts/panda_test_asan.ld | 1 - libpandabase/os/filesystem.cpp | 2 +- libpandafile/BUILD.gn | 8 +- libpandafile/CMakeLists.txt | 6 +- libpandafile/bytecode_instruction.h | 18 +- libpandafile/file.cpp | 63 +- libpandafile/file.h | 6 +- libpandafile/file_format_version.cpp | 37 + libpandafile/file_item_container.cpp | 8 +- libpandafile/file_items.h | 2 +- libpandafile/literal_data_accessor-inl.h | 3 + libpandafile/literal_data_accessor.h | 5 +- .../bytecode_instruction-inl_gen.h.erb | 18 + .../templates/file_format_version.h.erb | 43 + libpandafile/tests/bytecode_emitter_tests.cpp | 2 +- .../tests/file_format_version_test.cpp | 47 + .../tests/file_item_container_test.cpp | 147 +- libpandafile/type_helper.h | 7 +- libziparchive/tests/libziparchive_tests.cpp | 3 - runtime/BUILD.gn | 5 +- runtime/CMakeLists.txt | 9 +- runtime/arch/helpers.h | 25 +- ...eter_to_compiled_code_bridge_dyn_aarch64.S | 2 +- ...nterpreter_to_compiled_code_bridge_armhf.S | 57 +- .../interpreter_to_compiled_code_bridge_x86.S | 12 +- runtime/coretypes/array.cpp | 1 - runtime/coretypes/string.cpp | 4 +- runtime/include/cframe_iterators.h | 55 +- runtime/include/coretypes/tagged_value.h | 1 - runtime/include/language_context.h | 1 - runtime/include/method-inl.h | 5 + runtime/include/object_header.h | 1 - .../interpreter/instruction_handler_base.h | 7 +- .../interpreter/instruction_handler_state.h | 5 + runtime/interpreter/interpreter-inl.h | 243 +- .../templates/builtin_insn_handlers.h.erb | 5 +- .../templates/interpreter-inl_gen.h.erb | 37 +- .../templates/isa_constants_gen.h.erb | 10 +- runtime/interpreter/vregister.h | 17 +- runtime/mark_word.h | 2 - runtime/mem/allocator.cpp | 1 - runtime/mem/frame_allocator-inl.h | 1 - runtime/mem/gc/gc.cpp | 2 +- runtime/mem/gc/gc.h | 1 - runtime/mem/gc/gc_stats.h | 2 +- runtime/mem/mem_stats.h | 1 - runtime/mem/mem_stats_additional_info.h | 1 - runtime/mem/mem_stats_default.cpp | 1 - runtime/mem/mem_stats_default.h | 1 - runtime/mem/object_helpers.cpp | 1 - runtime/mem/panda_string.cpp | 11 +- runtime/mem/pygote_space_allocator.h | 1 - .../mem/refstorage/global_object_storage.cpp | 1 - runtime/mem/refstorage/ref_block.cpp | 1 - runtime/mem/region_allocator.h | 1 - runtime/mem/region_space.cpp | 1 - runtime/mem/runslots_allocator-inl.h | 1 - runtime/object_accessor-impl.cpp | 1 + runtime/options.yaml | 25 +- runtime/runtime.cpp | 4 +- runtime/templates/bridge_helpers_static.rb | 4 +- runtime/templates/runtime.rb | 43 +- runtime/templates/shorty_values.h.erb | 10 +- .../unimplemented_intrinsics-inl.cpp.erb | 5 + runtime/tests/arch/arm/invokation_helper_hf.S | 50 + runtime/tests/card_table_test.cpp | 2 +- runtime/tests/class_linker_test.cpp | 2 +- runtime/tests/interpreter_test.cpp | 2 +- runtime/tests/invokation_helper.h | 44 +- runtime/tests/method_test.cpp | 2 +- runtime/tests/region_allocator_test.cpp | 2 +- scripts/install-third-party | 2 +- tests/CMakeLists.txt | 2 - tests/cts-assembly/arrays-04.pa | 44 +- tests/cts-assembly/big_ark_option_value.pa | 20 +- tests/cts-assembly/intrinsics-03.pa | 30 +- tests/cts-assembly/intrinsics-05.pa | 16 +- tests/cts-assembly/intrinsics-07.pa | 16 +- tests/cts-assembly/intrinsics-09.pa | 18 +- tests/cts-assembly/intrinsics-11.pa | 16 +- tests/cts-assembly/intrinsics-15.pa | 2 +- tests/cts-assembly/intrinsics-f32-01.pa | 6 +- tests/cts-coverage-tool/CMakeLists.txt | 2 +- .../cts-template/call.acc.short.yaml | 2296 ++++++++++++++ .../cts-generator/cts-template/call.acc.yaml | 2272 ++++++++++++++ .../cts-template/call.virt.acc.short.yaml | 2638 +++++++++++++++++ .../cts-template/call.virt.acc.yaml | 2387 +++++++++++++++ .../cts-generator/cts-template/fldarr.32.yaml | 38 +- .../cts-generator/cts-template/fstarr.32.yaml | 32 +- .../cts-template/initobj.range.yaml | 88 +- .../cts-template/initobj.short.yaml | 83 +- tests/cts-generator/cts-template/initobj.yaml | 84 +- .../cts-generator/cts-template/ldobj.64.yaml | 32 +- .../cts-template/ldobj.v.64.yaml | 539 ++++ tests/cts-generator/cts-template/ldobj.v.yaml | 451 +++ tests/cts-generator/cts-template/ldobj.yaml | 39 +- .../cts-template/ldstatic.64.yaml | 26 +- .../cts-generator/cts-template/ldstatic.yaml | 2 - tests/cts-generator/cts-template/newarr.yaml | 4 +- tests/cts-generator/cts-template/newobj.yaml | 8 +- .../cts-generator/cts-template/stobj.64.yaml | 46 - .../cts-template/stobj.v.64.yaml | 848 ++++++ tests/cts-generator/cts-template/stobj.v.yaml | 897 ++++++ tests/cts-generator/cts-template/stobj.yaml | 71 +- .../cts-template/ststatic.64.yaml | 66 +- .../cts-generator/cts-template/ststatic.yaml | 77 +- tests/cts-generator/test-runner.rb | 1 - tests/verifier-tests/bug_3060.pa | 2 +- verification/absint/abs_int_inl.h | 375 +-- verification/absint/exec_context.h | 1 - verification/cflow/instructions_map.h | 8 - verification/cflow/jumps_map.h | 6 - verification/debug/README.md | 2 +- verification/debug/config_load.cpp | 1 - .../templates/abs_int_builtin_handlers.h.erb | 13 + .../templates/abs_int_inl_compat_checks.h.erb | 3 +- .../gen/templates/abs_int_inl_gen.h.erb | 19 +- .../gen/templates/cflow_iterate_inl_gen.h.erb | 25 +- verification/gen/templates/job_fill_gen.h.erb | 16 +- verification/util/tests/verifier_test.h | 2 +- verification/verification.yaml | 8 + 150 files changed, 14660 insertions(+), 1945 deletions(-) create mode 100644 isa/BUILD.gn create mode 100644 isa/ChangeLog.md create mode 100755 isa/combine.rb create mode 100644 libpandafile/file_format_version.cpp create mode 100644 libpandafile/templates/file_format_version.h.erb create mode 100644 libpandafile/tests/file_format_version_test.cpp create mode 100644 tests/cts-generator/cts-template/call.acc.short.yaml create mode 100644 tests/cts-generator/cts-template/call.acc.yaml create mode 100644 tests/cts-generator/cts-template/call.virt.acc.short.yaml create mode 100644 tests/cts-generator/cts-template/call.virt.acc.yaml create mode 100644 tests/cts-generator/cts-template/ldobj.v.64.yaml create mode 100644 tests/cts-generator/cts-template/ldobj.v.yaml create mode 100644 tests/cts-generator/cts-template/stobj.v.64.yaml create mode 100644 tests/cts-generator/cts-template/stobj.v.yaml diff --git a/ark_config.gni b/ark_config.gni index ac59f56275..10ddc2c113 100644 --- a/ark_config.gni +++ b/ark_config.gni @@ -164,13 +164,13 @@ template("ark_gen") { # * requires -- if defined, will require additional Ruby files for template generation, must be list # * extra_dependencies -- a list of files that should be considered as dependencies lable, must be list, not used template("ark_isa_gen") { - isa_data = "$ark_root/isa/isa.yaml" + isa_data = "$root_gen_dir/isa/isa.yaml" isa_requires = [ "$ark_root/isa/isapi.rb" ] if (defined(invoker.requires)) { isa_requires += invoker.requires } - dependencies = [] + dependencies = ["$ark_root/isa:isa_combine"] if (defined(invoker.extra_dependencies)) { dependencies += invoker.extra_dependencies } diff --git a/assembler/BUILD.gn b/assembler/BUILD.gn index 92f155ebbf..0c0297880b 100644 --- a/assembler/BUILD.gn +++ b/assembler/BUILD.gn @@ -20,6 +20,8 @@ config("arkassembler_public_config") { "$target_gen_dir", "$target_gen_dir/include", ] + + defines = [ "PANDA_WITH_ECMASCRIPT" ] } libarkassembler_sources = [ @@ -162,20 +164,14 @@ ark_gen_file("ark_asm_ins_create_builtins_api_h") { ark_gen_file("builtin_parsing_cpp") { template_file = "templates/builtin_parsing.cpp.erb" data_file = "../isa/builtins.yaml" - requires = [ - "../isa/builtinsapi.rb", - "//ark/js_runtime/ecmascript/ecma_builtins.rb", - ] + requires = [ "../isa/builtinsapi.rb" ] output_file = "$target_gen_dir/builtin_parsing.cpp" } ark_gen_file("builtin_parsing_tests_cpp") { template_file = "templates/builtin_parsing_tests.cpp.erb" data_file = "../isa/builtins.yaml" - requires = [ - "../isa/builtinsapi.rb", - "//ark/js_runtime/ecmascript/ecma_builtins.rb", - ] + requires = [ "../isa/builtinsapi.rb" ] output_file = "$target_gen_dir/builtin_parsing_tests.cpp" } diff --git a/assembler/asm_isapi.rb b/assembler/asm_isapi.rb index afd0087319..7481a51ba5 100755 --- a/assembler/asm_isapi.rb +++ b/assembler/asm_isapi.rb @@ -18,35 +18,19 @@ Instruction.class_eval do end def builtin? - %w[builtin].include?(stripped_mnemonic) - end - - def builtin_idr4? - builtin? && mnemonic.split('.')[-1] == 'idr4' - end - - def builtin_idr6? - builtin? && mnemonic.split('.')[-1] == 'idr6' + stripped_mnemonic == 'builtin' end def call? - %w[call initobj].include?(stripped_mnemonic) - end - - def calli? - %w[calli].include?(stripped_mnemonic) - end - - def call_range? - call? && mnemonic.split('.')[-1] == 'range' + properties.include?('call') || stripped_mnemonic == 'initobj' end - def calli_range? - calli? && mnemonic.split('.')[-1] == 'range' + def range? + mnemonic.split('.')[-1] == 'range' end def simple_call? - (call? || calli?) && !call_range? + call? && !range? end def return? @@ -108,7 +92,7 @@ end def assembler_signature(group, is_jump) insn = group.first sig = format_ops(insn.format) - sig.each_with_index do |o, i| + sig.each do |o| if o.name.start_with?('imm') if insn.asm_token.start_with?('F') o.type, o.name = is_jump ? ['const std::string &', 'label'] : ["double", o.name] diff --git a/assembler/assembly-emitter.cpp b/assembler/assembly-emitter.cpp index 561b606e50..2e300c4fe5 100644 --- a/assembler/assembly-emitter.cpp +++ b/assembler/assembly-emitter.cpp @@ -772,6 +772,10 @@ static std::unique_ptr CreateValue(const panda::pandasm::LiteralArr { switch (literal.tag_) { case panda_file::LiteralTag::TAGVALUE: + [[fallthrough]]; + case panda_file::LiteralTag::ACCESSOR: + [[fallthrough]]; + case panda_file::LiteralTag::NULLVALUE: return std::make_unique( ScalarValue::Create(std::get(literal.value_))); case panda_file::LiteralTag::BOOL: @@ -780,6 +784,9 @@ static std::unique_ptr CreateValue(const panda::pandasm::LiteralArr case panda_file::LiteralTag::ARRAY_I8: return std::make_unique( ScalarValue::Create(std::get(literal.value_))); + case panda_file::LiteralTag::METHODAFFILIATE: + return std::make_unique( + ScalarValue::Create(std::get(literal.value_))); case panda_file::LiteralTag::ARRAY_I16: return std::make_unique( ScalarValue::Create(std::get(literal.value_))); @@ -807,16 +814,10 @@ static std::unique_ptr CreateValue(const panda::pandasm::LiteralArr return std::make_unique( ScalarValue::Create(std::string_view(std::get(literal.value_)))); case panda_file::LiteralTag::METHOD: - return std::make_unique( - ScalarValue::Create(std::string_view(std::get(literal.value_)))); + [[fallthrough]]; case panda_file::LiteralTag::GENERATORMETHOD: return std::make_unique( ScalarValue::Create(std::string_view(std::get(literal.value_)))); - case panda_file::LiteralTag::ACCESSOR: - [[fallthrough]]; - case panda_file::LiteralTag::NULLVALUE: - return std::make_unique( - ScalarValue::Create(std::get(literal.value_))); default: UNREACHABLE(); break; diff --git a/assembler/assembly-ins.h b/assembler/assembly-ins.h index 0aa6dec28d..49bf071001 100644 --- a/assembler/assembly-ins.h +++ b/assembler/assembly-ins.h @@ -146,11 +146,6 @@ struct Ins { return HasFlag(InstFlags::CALL); } - bool IsBuiltinIdr6() const - { - return opcode == Opcode::BUILTIN_IDR6; - } - bool IsPseudoCall() const { return HasFlag(InstFlags::PSEUDO) && HasFlag(InstFlags::CALL); diff --git a/assembler/assembly-label.h b/assembler/assembly-label.h index 5ea36dac52..ea3e3ed127 100644 --- a/assembler/assembly-label.h +++ b/assembler/assembly-label.h @@ -18,7 +18,6 @@ #include #include - #include "assembly-file-location.h" namespace panda::pandasm { diff --git a/assembler/assembly-parser.cpp b/assembler/assembly-parser.cpp index 1c9f8ea7ef..bd1af98bfe 100644 --- a/assembler/assembly-parser.cpp +++ b/assembler/assembly-parser.cpp @@ -59,7 +59,6 @@ bool Parser::ParseRecordFields() context_.ins_number = curr_record_->field_list.size(); LOG(DEBUG, ASSEMBLER) << "parse line " << line_stric_ << " as field (.field name)"; - if (!ParseRecordField()) { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; @@ -228,7 +227,6 @@ bool Parser::ParseFunctionCode() void Parser::ParseAsRecord(const std::vector &tokens) { LOG(DEBUG, ASSEMBLER) << "started parsing of record (line " << line_stric_ << "): " << tokens[0].whole_line; - func_def_ = false; record_def_ = true; @@ -271,7 +269,6 @@ void Parser::ParseAsRecord(const std::vector &tokens) void Parser::ParseAsFunction(const std::vector &tokens) { LOG(DEBUG, ASSEMBLER) << "started parsing of function (line " << line_stric_ << "): " << tokens[0].whole_line; - record_def_ = false; func_def_ = true; @@ -708,7 +705,6 @@ Expected Parser::Parse(TokenSet &vectors_tokens, const std::stri } } } - if (!ParseAfterLine(is_first_statement)) { break; } @@ -1182,7 +1178,7 @@ bool Parser::ParseOperandInteger() return true; } -bool Parser::ParseOperandFloat() +bool Parser::ParseOperandFloat(bool is_64bit) { if (context_.err.err != Error::ErrorType::ERR_NONE) { return false; @@ -1202,7 +1198,7 @@ bool Parser::ParseOperandFloat() return false; } - double n = FloatNumber(p); + double n = FloatNumber(p, is_64bit); if (errno == ERANGE) { context_.err = GetError("Too large immediate (length is more than 64 bit).", Error::ErrorType::ERR_BAD_FLOAT_WIDTH); diff --git a/assembler/assembly-parser.h b/assembler/assembly-parser.h index 1cfc5ceb11..b3179bde36 100644 --- a/assembler/assembly-parser.h +++ b/assembler/assembly-parser.h @@ -161,7 +161,7 @@ private: bool ParseOperandVreg(); bool ParseOperandComma(); bool ParseOperandInteger(); - bool ParseOperandFloat(); + bool ParseOperandFloat(bool is_64bit); bool ParseOperandId(); bool ParseOperandLabel(); bool ParseOperandField(); diff --git a/assembler/templates/builtin_parsing.cpp.erb b/assembler/templates/builtin_parsing.cpp.erb index 00af94da88..2bc8fbd9d5 100644 --- a/assembler/templates/builtin_parsing.cpp.erb +++ b/assembler/templates/builtin_parsing.cpp.erb @@ -20,10 +20,10 @@ namespace panda::pandasm { int64_t Parser::MnemonicToBuiltinId() { - const auto token = context_.GiveToken(); + [[maybe_unused]] const auto token = context_.GiveToken(); --context_; - const auto ins = context_.GiveToken(); + [[maybe_unused]] const auto ins = context_.GiveToken(); ++context_; % PandaBuiltins::builtins.each_with_index do |builtin, i| @@ -60,4 +60,4 @@ bool Parser::ParseOperandBuiltinMnemonic() { return true; } -} // namespace panda::pandasm \ No newline at end of file +} // namespace panda::pandasm diff --git a/assembler/templates/ins_emit.h.erb b/assembler/templates/ins_emit.h.erb index 53ef78957e..c5867c86d7 100644 --- a/assembler/templates/ins_emit.h.erb +++ b/assembler/templates/ins_emit.h.erb @@ -17,7 +17,6 @@ #include "mangling.h" namespace panda::pandasm { - bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method, const std::unordered_map &methods, const std::unordered_map &fields, @@ -101,7 +100,7 @@ bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method, % raise "Unexpected operand type" % end % end -% if insn.call? +% if insn.call? && insn.properties.include?('method_id') % ops << ops.shift % end % ops @@ -137,7 +136,7 @@ bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method, % imms_num += 1 % end % end -% if (insn.call? && !insn.call_range?) || (insn.calli? && !insn.calli_range?) || insn.builtin_idr4? || insn.builtin_idr6? +% if insn.simple_call? % if imms_num > 0 if (imms.size() < <%= imms_num %>) { return false; @@ -164,7 +163,7 @@ bool Ins::Emit(BytecodeEmitter& emitter, panda_file::MethodItem *method, } % end % end -% if (insn.call? && !insn.call_range?) || (insn.calli? && !insn.calli_range?) || insn.builtin_idr4? || insn.builtin_idr6? +% if insn.simple_call? auto registers = regs; % call_map[insn.mnemonic].map { |m| inst_map[m] }.each do |i| % registers = i.operands.select(&:reg?) diff --git a/assembler/templates/ins_to_string.cpp.erb b/assembler/templates/ins_to_string.cpp.erb index d6cd1f9691..9f8ab7f92b 100644 --- a/assembler/templates/ins_to_string.cpp.erb +++ b/assembler/templates/ins_to_string.cpp.erb @@ -34,10 +34,10 @@ std::string panda::pandasm::Ins::ToString(std::string endline, bool print_args / case panda::pandasm::Opcode::<%= insn.asm_token%>: { full_operation += "<%= insn.mnemonic%>"; % print_kind = case +% when insn.call? && !insn.properties.include?('method_id') +% 'PrintKind::CALLI' % when insn.call? || !insn.public? % 'PrintKind::CALL' -% when insn.calli? -% 'PrintKind::CALLI' % else % 'PrintKind::DEFAULT' % end diff --git a/assembler/templates/opcode_parsing.h.erb b/assembler/templates/opcode_parsing.h.erb index 3b69c5867e..c2c173aec5 100644 --- a/assembler/templates/opcode_parsing.h.erb +++ b/assembler/templates/opcode_parsing.h.erb @@ -49,7 +49,7 @@ bool Parser::ParseOperands() % end % required_args = operands.size % required_args = 1 if insn.call? -% required_args = 2 if insn.calli? +% required_args = 2 if insn.stripped_mnemonic == 'calli' % operands.each_with_index do |op, j| % % if (j != 0) @@ -83,13 +83,13 @@ bool Parser::ParseOperands() ParseOperandVreg(); % elsif op.imm? -% if (!insn.public? && j == 0) +% if (insn.builtin? && j == 0) ParseOperandBuiltinMnemonic(); % elsif properties.include?("jump") ParseOperandLabel(); % else % if properties.include?("float") - ParseOperandFloat(); + ParseOperandFloat(<%= op.size == 64 ? "true" : "false" %>); % else ParseOperandInteger(); % end diff --git a/assembler/utils/number-utils.h b/assembler/utils/number-utils.h index 75aeb1462c..f2d1e3a3eb 100644 --- a/assembler/utils/number-utils.h +++ b/assembler/utils/number-utils.h @@ -176,13 +176,16 @@ inline bool ValidateFloat(std::string_view p) return !nowexp; } -inline double FloatNumber(std::string_view p) +inline double FloatNumber(std::string_view p, bool is_64bit) { constexpr size_t GENERAL_SHIFT = 2; // expects a valid number if (p.size() > GENERAL_SHIFT && p.substr(0, GENERAL_SHIFT) == "0x") { // hex literal char *end = nullptr; - return bit_cast(strtoull(p.data(), &end, 0)); + if (is_64bit) { + return bit_cast(strtoull(p.data(), &end, 0)); + } + return bit_cast(static_cast(strtoull(p.data(), &end, 0))); } return std::strtold(std::string(p.data(), p.length()).c_str(), nullptr); } diff --git a/cmake/README.md b/cmake/README.md index 5f3fcdc07d..0b6cc5fd70 100644 --- a/cmake/README.md +++ b/cmake/README.md @@ -39,7 +39,7 @@ $ make coverage ``` Location of the code coverage report: BUILD_DIR/compiler/coverage_report -## Check style +## Check style To check the style, perform the previous steps and build style-checker targets. Note that you must install clang-format and clang-tidy with libraries. For details, see scripts/bootstrap*.sh. ``` @@ -62,12 +62,12 @@ Run `make help | grep clang` to see all possible clang-[format|style] targets. For issues in opt.cpp, you may check the style through clang-format `make clang_format_opt_opt.cpp`, or through clang-tidy `make clang_tidy_opt_opt.cpp`. For the force clang-format code style, use `make clang_force_format_opt_opt.cpp`. For code-style check through one check system, use `make clang_tidy` or `make clang_format`. -Generated files: +Generated files: * `compile_commands.json` - json nija-commands file to correct execution clang-tidy. * Standard cmake-files: `CMakeCache.txt`, `Makefile`, `cmake_install.cmake` and folder `CMakeFiles`. -Discussion about format : rus-os-team/virtual-machines-and-tools/vm-investigation-and-design#24 +Discussion about format : rus-os-team/virtual-machines-and-tools/vm-investigation-and-design#24 * Clang-tidy style file - `.clang-tidy` * Clang-format style file - `.clang-format` * Script to show diff through clang-format execution - `build/run-clang-format.py` diff --git a/cmake/TemplateBasedGen.cmake b/cmake/TemplateBasedGen.cmake index 50cfbe05de..6cb62b52fc 100644 --- a/cmake/TemplateBasedGen.cmake +++ b/cmake/TemplateBasedGen.cmake @@ -75,7 +75,7 @@ function(panda_gen) REQUIRES ${GEN_ARG_REQUIRES} EXTRA_DEPENDENCIES ${GEN_ARG_EXTRA_DEPENDENCIES} ) - add_custom_target(${TARGET} ALL DEPENDS ${OUTPUT_FILE}) + add_custom_target(${TARGET} DEPENDS ${OUTPUT_FILE}) add_dependencies(${GEN_ARG_TARGET_NAME} ${TARGET}) endforeach() endfunction() @@ -103,9 +103,10 @@ function(panda_isa_gen) "${multivalues}" ${ARGN} ) - set(ISA_DATA "${PANDA_ROOT}/isa/isa.yaml") + set(ISA_DATA "${CMAKE_BINARY_DIR}/isa/isa.yaml") set(ISAPI "${PANDA_ROOT}/isa/isapi.rb") list(INSERT ISA_GEN_ARG_REQUIRES 0 ${ISAPI}) + list(APPEND ISA_GEN_ARG_EXTRA_DEPENDENCIES isa_assert) panda_gen(DATA ${ISA_DATA} TEMPLATES ${ISA_GEN_ARG_TEMPLATES} SOURCE ${ISA_GEN_ARG_SOURCE} diff --git a/disassembler/BUILD.gn b/disassembler/BUILD.gn index e064d34066..5ce73714ec 100644 --- a/disassembler/BUILD.gn +++ b/disassembler/BUILD.gn @@ -14,6 +14,10 @@ import("//ark/runtime_core/ark_config.gni") import("//build/ohos.gni") +config("arkdisassembler_public_config") { + defines = [ "PANDA_WITH_ECMASCRIPT" ] +} + arkdisassembler_sources = [ "$target_gen_dir/bc_ins_to_pandasm_ins.cpp", "$target_gen_dir/get_ins_info.cpp", @@ -25,6 +29,7 @@ arkdisassembler_sources = [ arkdisassembler_configs = [ sdk_libc_secshared_config, + ":arkdisassembler_public_config", "$ark_root:ark_config", "$ark_root/libpandabase:arkbase_public_config", "$ark_root/assembler:arkassembler_public_config", @@ -121,10 +126,7 @@ ark_isa_gen("isa_gen_ark_disam") { ark_gen_file("get_instructions_cpp") { template_file = "$ark_root/disassembler/templates/get_instructions.cpp.erb" data_file = "$ark_root/isa/builtins.yaml" - requires = [ - "$ark_root/isa/builtinsapi.rb", - "//ark/js_runtime/ecmascript/ecma_builtins.rb", - ] + requires = [ "$ark_root/isa/builtinsapi.rb" ] output_file = "$target_gen_dir/get_instructions.cpp" } diff --git a/disassembler/CMakeLists.txt b/disassembler/CMakeLists.txt index 910814c9f9..abb1a28b5e 100644 --- a/disassembler/CMakeLists.txt +++ b/disassembler/CMakeLists.txt @@ -230,17 +230,6 @@ add_custom_target(disasm_binaries_test_metadata) add_dependencies(disasm_binaries_test_metadata disasm_binaries-meta) -# builtin_tests files -compile_pre_build(TARGET disasm_binaries-builtins - FILE_SRC ${DISASM_TESTS_DIR}/builtins.pa - FILE_DST ${DISASM_BIN_DIR}/builtins.bc) - -add_custom_target(disasm_binaries_test_builtins) - -add_dependencies(disasm_binaries_test_builtins disasm_binaries-builtins) - -add_dependencies(disasm_test_instructions disasm_binaries_test_builtins) - add_custom_target(disasm_tests DEPENDS disasm_test_records DEPENDS disasm_test_labels diff --git a/disassembler/templates/get_instructions.cpp.erb b/disassembler/templates/get_instructions.cpp.erb index 084d997007..48befa49b2 100644 --- a/disassembler/templates/get_instructions.cpp.erb +++ b/disassembler/templates/get_instructions.cpp.erb @@ -43,7 +43,7 @@ IdList Disassembler::GetInstructions(pandasm::Function *method, panda_file::File } auto pa_ins = BytecodeInstructionToPandasmInstruction(bc_ins, method_id, method->language); - + // alter instructions operands depending on instruction type if (pa_ins.IsConditionalJump() || pa_ins.IsJump()) { const int32_t jmp_offset = std::get(pa_ins.imms.at(0)); @@ -65,7 +65,7 @@ IdList Disassembler::GetInstructions(pandasm::Function *method, panda_file::File << "0x" << std::hex << code_id.GetOffset() << "). incorrect instruction at offset " << (bc_ins.GetAddress() - ins_arr) << ": invalid jump offset " << jmp_offset << " - jumping in the middle of another instruction!"; - + } } else { LOG(ERROR, DISASSEMBLER) << "> error encountered at " << std::dec << code_id.GetOffset() << " (" @@ -78,7 +78,7 @@ IdList Disassembler::GetInstructions(pandasm::Function *method, panda_file::File // if builtin - change imm to mnemonic switch (pa_ins.opcode) { % PandaBuiltins::instructions.each do |insn| - case pandasm::Opcode::<%=insn.mnemonic.tr('.', '_').upcase%>: + case pandasm::Opcode::<%=insn.mnemonic.tr('.', '_').upcase%>: switch(pa_ins.imms[0].index()) { // contains int64_t case 0: @@ -140,4 +140,4 @@ IdList Disassembler::GetInstructions(pandasm::Function *method, panda_file::File return unknown_external_methods; } -} // namespace panda::disasm \ No newline at end of file +} // namespace panda::disasm diff --git a/disassembler/tests/instructions_test.cpp b/disassembler/tests/instructions_test.cpp index b5b1bd1367..64043c7bac 100644 --- a/disassembler/tests/instructions_test.cpp +++ b/disassembler/tests/instructions_test.cpp @@ -310,35 +310,6 @@ TEST(instructions_test, test_newarr) EXPECT_TRUE(body_g.find("\tnewarr v0, a0, u64[]") != std::string::npos); } -TEST(instructions_test, test_builtins) -{ - Disassembler d {}; - - std::stringstream ss {}; - d.Disassemble(g_bin_path_abs + "builtins.bc"); - d.Serialize(ss); - - size_t beg_g = ss.str().find("g_f32_f32_void_(f32 a0, f32 a1) {"); - size_t end_g = ss.str().find('}', beg_g); - - ASSERT_TRUE(beg_g != std::string::npos && end_g != std::string::npos) << "function g not found"; - - std::string body_g = ss.str().substr(beg_g + strlen("g() {"), end_g - (beg_g + strlen("g() {"))); - - EXPECT_TRUE(body_g.find("\tbuiltin.acc i32tof32") != std::string::npos); - EXPECT_TRUE(body_g.find("\tbuiltin.acc i64tof32") != std::string::npos); - EXPECT_TRUE(body_g.find("\tbuiltin.acc f64tof32") != std::string::npos); - EXPECT_TRUE(body_g.find("\tbuiltin.acc monitorenter") != std::string::npos); - EXPECT_TRUE(body_g.find("\tbuiltin.acc monitorexit") != std::string::npos); - EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fadd2f32, a1") != std::string::npos); - EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fsub2f32, v13") != std::string::npos); - EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fmul2f32, v13") != std::string::npos); - EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fdiv2f32, v13") != std::string::npos); - EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fmod2f32, v13") != std::string::npos); - EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fcmpl2f32, a0") != std::string::npos); - EXPECT_TRUE(body_g.find("\tbuiltin.bin2 fcmpg2f32, v13") != std::string::npos); -} - int main(int argc, char **argv) { std::string dir_basename {}; diff --git a/isa/BUILD.gn b/isa/BUILD.gn new file mode 100644 index 0000000000..64c028b09c --- /dev/null +++ b/isa/BUILD.gn @@ -0,0 +1,31 @@ +# 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. + +import("//ark/runtime_core/ark_config.gni") + +action("isa_combine") { + script = "$ark_root/isa/combine.rb" + inputs = [ + "$ark_root/isa/isa.yaml", + "$ark_root/../js_runtime/ecmascript/ecma_isa.yaml" + ] + input0 = rebase_path(inputs[0], root_build_dir) + input1 = rebase_path(inputs[1], root_build_dir) + outputs = ["$root_gen_dir/isa/isa.yaml"] + args = [ + "-d", + "$input0,$input1", + "-o", + rebase_path(outputs[0], root_build_dir) + ] +} diff --git a/isa/CMakeLists.txt b/isa/CMakeLists.txt index 6f4a9f887b..38b599fa85 100644 --- a/isa/CMakeLists.txt +++ b/isa/CMakeLists.txt @@ -11,25 +11,24 @@ # See the License for the specific language governing permissions and # limitations under the License. -cmake_minimum_required(VERSION 3.5.2 FATAL_ERROR) - project(isa) -set(ISA_FILE "${PROJECT_SOURCE_DIR}/isa.yaml") +set(ISA_FILE "${CMAKE_BINARY_DIR}/isa/isa.yaml") +set(ISA_CORE_FILE "${PROJECT_SOURCE_DIR}/isa.yaml") set(ISA_ASSERTS "${PROJECT_SOURCE_DIR}/asserts.rb") +set(ISA_COMBINE "${PROJECT_SOURCE_DIR}/combine.rb") set(ISAPI "${PROJECT_SOURCE_DIR}/isapi.rb") +set(ISA_PLUGIN_FILES "") -# ISA YAML validation against the schema - -set(ISA_SCHEMA "${PROJECT_SOURCE_DIR}/schema.json") +string(REPLACE ";" "," ISA_PLUGIN_FILES_STR "${ISA_PLUGIN_FILES}") -set(VALIDATE_MARKER "${PROJECT_BINARY_DIR}/validate.ok") -add_custom_command(OUTPUT ${VALIDATE_MARKER} - COMMENT "Validate ISA file" - COMMAND pajv -s ${ISA_SCHEMA} -d ${ISA_FILE} && ${CMAKE_COMMAND} -E touch ${VALIDATE_MARKER} - DEPENDS ${ISA_SCHEMA} ${ISA_FILE} +# ISA combine +add_custom_command(OUTPUT ${ISA_FILE} + COMMENT "Combine ISA files" + COMMAND ${ISA_COMBINE} -d "${ISA_CORE_FILE},${ISA_PLUGIN_FILES_STR}" -o ${ISA_FILE} + DEPENDS ${ISA_COMBINE} ${ISA_CORE_FILE} ${ISA_PLUGIN_FILES} ) -add_custom_target(isa_validate DEPENDS ${VALIDATE_MARKER}) +add_custom_target(isa_combine DEPENDS ${ISA_FILE}) # Check ISA_FILE content @@ -41,13 +40,12 @@ add_custom_command(OUTPUT ${ASSERT_MARKER} COMMAND ${CMAKE_COMMAND} -E touch ${ASSERT_MARKER} DEPENDS ${ISA_FILE} ${ISA_GEN_RB} ${ISA_ASSERTS} ${ISAPI} ) -add_custom_target(isa_assert ALL DEPENDS ${ASSERT_MARKER}) +add_custom_target(isa_assert DEPENDS ${ASSERT_MARKER}) +add_dependencies(isa_assert isa_combine) # Template generation - set(TEMPLATES instructions.txt.erb isa.md.erb ) - panda_isa_gen(TEMPLATES ${TEMPLATES}) diff --git a/isa/ChangeLog.md b/isa/ChangeLog.md new file mode 100644 index 0000000000..dc9ba60fef --- /dev/null +++ b/isa/ChangeLog.md @@ -0,0 +1,6 @@ +File format and ISA ChangeLog +============================= + +* 0.0.0.2 + + Removed compatibility check based on the isa checksum. + + Introduced new backward compatibility policy. diff --git a/isa/asserts.rb b/isa/asserts.rb index 760ed50382..c4aa0a928d 100755 --- a/isa/asserts.rb +++ b/isa/asserts.rb @@ -16,16 +16,34 @@ def assert(name) raise "#{loc.path}:#{loc.lineno}: '#{name}' assertion failed" unless yield end -def uniq?(arr) - arr.uniq.size == arr.size +module Enumerable + def sorted? + each_cons(2).all? { |a, b| (a <=> b) <= 0 } + end + + def sorted_by?(&block) + map(&block).sorted? + end + + def uniq? + uniq.size == size + end end -assert('Unique opcodes') { uniq?(Panda.instructions.map(&:opcode)) } +assert('Unique opcodes') { Panda.instructions.map(&:opcode).uniq? } assert('Non-prefixed instruction opcodes and prefixes should fit one byte') do Panda.instructions.reject(&:prefix).size + Panda.prefixes.size <= 256 end +assert('Non-prefixed instruction opcode indexes are sorted') do + Panda.instructions.reject(&:prefix).sorted_by?(&:opcode_idx) +end + +assert('Prefix opcode indexes are sorted') do + Panda.prefixes.sorted_by?(&:opcode_idx) +end + assert('All instructions for a prefix should fit one byte') do Panda.prefixes.map do |prefix| Panda.instructions.select { |insn| insn.prefix && (insn.prefix.name == prefix.name) }.size <= 256 @@ -47,11 +65,19 @@ assert('Prefix should be defined') do end assert('All prefixes should have unique name') do - uniq?(Panda.prefixes.map(&:name)) + Panda.prefixes.map(&:name).uniq? +end + +assert('There should be non-zero gap between non-prefixed and prefixes') do + !Panda.dispatch_table.invalid_non_prefixed_interval.to_a.empty? +end + +assert('There should be non-zero gap between public and private prefixes') do + !Panda.dispatch_table.invalid_prefixes_interval.to_a.empty? end assert('All tags are unique between categories') do - uniq?(%i[verification exceptions properties].flat_map { |type| Panda.send(type).map(&:tag) }) + %i[verification exceptions properties].flat_map { |type| Panda.send(type).map(&:tag) }.uniq? end assert('All tags are used') do @@ -116,7 +142,9 @@ assert('All calls write into accumulator') do end assert('Calls should be non-prefixed') do # otherwise support in interpreter-to-compiler bridges - Panda.instructions.select { |i| i.properties.include?('call') }.select(&:prefix).empty? + Panda.instructions.select do |i| + i.properties.include?('call') && !i.mnemonic.include?('polymorphic') + end.select(&:prefix).empty? end assert('Jumps differ from other control-flow') do # At least currently @@ -135,8 +163,8 @@ assert('Conversions should correspond to source and destination type') do end.all? end -assert('Operand type should be one of none, ref, u1, u2, i8, u8, i16, u16, i32, u32, i64, u64, b64, f64, top, any') do - types = %w[none ref u1 u2 i8 u8 i16 u16 i32 u32 f32 i64 u64 b64 f64 top any] +assert('Operand type should be one of none, ref, u1, u2, i8, u8, i16, u16, i32, u32, b32, i64, u64, b64, f64, top, any') do + types = %w[none ref u1 u2 i8 u8 i16 u16 i32 u32 b32 f32 i64 u64 b64 f64 top any] Panda.instructions.map do |i| i.acc_and_operands.all? { |op| types.include?(op.type.sub('[]', '')) } end.all? diff --git a/isa/builtins.yaml b/isa/builtins.yaml index f469fcfd7a..d3608b914f 100644 --- a/isa/builtins.yaml +++ b/isa/builtins.yaml @@ -394,142 +394,5 @@ groups: acc: out:top format: [op_imm1_8_id_16_imm2_16_v1_8_v2_8] - - title: Built-in opcode with method id and one regs - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_write - - method_id - pseudo: | - pseudo: | - builtin = resolve_builtin(imm) - acc = builtin(id, v1) - semantics: | - skip - instructions: - - sig: builtin.idr3 imm, v1:in:top, method_id - acc: out:top - format: [op_imm_8_v1_8_id_16] - - - title: Built-in opcode with method id and two regs - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_write - - method_id - pseudo: | - pseudo: | - builtin = resolve_builtin(imm) - acc = builtin(id, v1, v2) - semantics: | - skip - instructions: - - sig: builtin.idr4 imm, v1:in:top, v2:in:top, method_id - acc: out:top - format: [op_imm_8_v1_4_v2_4_id_16] - - - title: Built-in opcode with method id and four regs - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_write - - method_id - pseudo: | - pseudo: | - builtin = resolve_builtin(imm) - acc = builtin(id, v1, v2, v3, v4) - semantics: | - skip - instructions: - - sig: builtin.idr6 imm, v1:in:top, v2:in:top, v3:in:top, v4:in:top, method_id - acc: out:top - format: [op_imm_8_v1_4_v2_4_v3_4_v4_4_id_16] - -builtins: - +builtins: [ ] # -# f64 conversions and binary operations (including comparisons) -# that preserve f32 precision for more accurate emulation of -# Java single-precision floats. f64 is consumed and produced, -# otherwise semantics and output values match corresponding -# f64 instructions from the public part of the ISA. -# - - - sig: i32tof32 - acc: inout:i32->f64 - - - sig: i64tof32 - acc: inout:i64->f64 - - - sig: f64tof32 - acc: inout:f64->f64 - - - sig: fadd2f32 v:in:f64 - acc: inout:f64 - - - sig: fsub2f32 v:in:f64 - acc: inout:f64 - - - sig: fmul2f32 v:in:f64 - acc: inout:f64 - - - sig: fdiv2f32 v:in:f64 - acc: inout:f64 - - - sig: fmod2f32 v:in:f64 - acc: inout:f64 - - - sig: fcmpl2f32 v:in:f64 - acc: inout:f64->i32 - - - sig: fcmpg2f32 v:in:f64 - acc: inout:f64->i32 - -# -# monitorenter and monitorexit are used to synchronize object access between threads. -# Each object is associated with a monitor, and each monitor has a counter that allows one -# to control access to the monitor object. -# -# These two opcodes take acc as input, and acc is assumed to hold the reference to the object. -# -# * monitorenter -# When the thread tries to gain ownership of the monitor it -# executes monitorenter and then one of three things can happen: -# - The monitor entry count is zero. It means the monitor does not -# belong to any thread. Then the thread enters the monitor and sets -# the monitor entry count to one. The thread becomes the monitor owner. -# - The monitor already belongs to the thread. In this case the thread re-enters -# the monitor and increments the monitor entry count. -# - The monitor already belongs to another thread. At this rate the thread blocks. -# When the monitor entry count is zero, the blocked thread may try to enter -# the monitor again. -# -# It is worth noting that as result of this opcode, an exception may be thrown: -# - If acc stores null then NullPointerException is thrown -# -# * monitorexit -# When the owner thread executes monitorexit it decrements the entry monitor count. -# If the one turns to zero, the thread exits the monitor and the monitor -# no longer belongs to it. Then other threads may try to gain ownership -# of the monitor. -# -# It is worth noting that as result of this opcode, an exception may be thrown: -# - If acc stores null then NullPointerException is thrown -# - If the thread that executes monitorexit is not the monitor owner then -# IllegalMonitorStateException is thrown -# - - - sig: monitorenter - acc: in:ref - - - sig: monitorexit - acc: in:ref diff --git a/isa/builtinsapi.rb b/isa/builtinsapi.rb index 4a7b1e2788..cc881f1303 100755 --- a/isa/builtinsapi.rb +++ b/isa/builtinsapi.rb @@ -100,7 +100,7 @@ module PandaBuiltins id = 0 unless all_builtins[i - 1][:insn] == all_builtins[i][:insn] end - all_builtins[all_builtins.length() - 1][:id] = id + all_builtins[all_builtins.length() - 1][:id] = id if all_builtins.any? all_builtins end @@ -214,11 +214,9 @@ end module ExtBuiltins def self.load_ecma_builtins(data); end - def self.load_polymorphic_builtins(data); end end def Gen.on_require(data) - ExtBuiltins.load_polymorphic_builtins(data) ExtBuiltins.load_ecma_builtins(data) prepared_data = prepare_data(data) PandaBuiltins.wrap_data(prepared_data) diff --git a/isa/combine.rb b/isa/combine.rb new file mode 100755 index 0000000000..8cb3ab4378 --- /dev/null +++ b/isa/combine.rb @@ -0,0 +1,65 @@ +#!/usr/bin/env ruby +# 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. + +require 'optparse' +require 'ostruct' +require 'yaml' + +def data_instructions(data) + data['groups'].flat_map { |g| g['instructions'] } +end + +options = OpenStruct.new +optparser = OptionParser.new do |opts| + opts.banner = 'Usage: combine.rb [options]' + + opts.on('-d', '--data FILE1,FILE2,...', Array, 'List of source data files in YAML format') + opts.on('-o', '--output FILE', 'Output file (default is stdout)') + + opts.on('-h', '--help', 'Prints this help') do + puts opts + exit + end +end +optparser.parse!(into: options) + +exit unless options.data +exit if options.data.empty? + +# TODO: Unify check with combining loop when we have assigned opcodes +options.data.drop(1).each do |path| + tmp_data = YAML.load_file(File.expand_path(path)) + # check that all instructions are prefixed: + instructions = data_instructions(tmp_data) + raise 'Plugged in instructions must be prefixed' unless instructions.reject { |i| i['prefix'] }.empty? +end + +# TODO: Remove when we have assigned opcodes: +options.data = options.data.rotate # put plug-in prefixes first + +data = YAML.load_file(File.expand_path(options.data.first)) +options.data.drop(1).each do |path| + tmp_data = YAML.load_file(File.expand_path(path)) + %w[prefixes groups properties exceptions verification version min_version chapters].each do |attr| + if data[attr] + data[attr] += tmp_data[attr] if tmp_data[attr] + else + data[attr] = tmp_data[attr] + end + end +end + +output = options.output ? File.open(File.expand_path(options.output), 'w') : $stdout +output.write(data.to_yaml) +output.close diff --git a/isa/isa.yaml b/isa/isa.yaml index e76a9510ae..0489b8c0c9 100644 --- a/isa/isa.yaml +++ b/isa/isa.yaml @@ -55,13 +55,10 @@ chapters: can be loaded/stored into records and arrays with corresponding bytecodes. In that case, VM will extend/truncate value to match storage size with i32. Similarly, passing an 8-bit or 16-bit value to a function can be emulated by passing a value, which is zero or sign-extended to i32. - VM support operations on registers with f64 values, which corresponds to IEEE-754 double precision - floating-point representation. However, f32 data type (IEEE-754 single precision) can be loaded/stored - into records and arrays with corresponding bytecodes. In that case, VM will convert f64 to f32 on store - and f32 to f64 on load. Similarly, passing f32 value to a function can be emulated by passing a value, which - is converted from f32 to f64. + VM support operations on registers with f32 and f64 values, which corresponds to IEEE-754 single and double precision + floating-point represenation. Primitive data type of a register is not tracked by VM and is interpreted by separate bytecodes. - Integral values are not inherently signed or unsigned, and signedness is interpreted by bytecodes as well. + Integral values are not inherently signed or unsigned, signedness is interpreted by bytecodes as well. If bytecode treats register value as signed integer, it uses two's complement representation. To denote that bytecode treats register values as unsigned integer, u32/u64 notation is used. For moves, loads and stores it is not always possible to denote a type of result, because it depends on type @@ -108,6 +105,10 @@ chapters: to hold 'any' value. When VM executes code inside dynamically-typed language context, regular static instructions also may be used. +# File format and ISA versioning +min_version: 0.0.0.2 +version: 0.0.0.2 + properties: - tag: acc_none description: Doesn't use accumulator register. @@ -183,6 +184,8 @@ verification: description: First operand contains a reference to an object or null. - tag: v2_i32 description: Second operand contains a value of i32 type. + - tag: v2_object + description: Second operand contains a reference to an object (other than array). - tag: v2_type description: Second operand contains a value of type corresponding to bytecode. - tag: acc_i32 @@ -231,12 +234,36 @@ verification: prefixes: - name: bit description: Bit operations. + opcode_idx: 0xef - name: unsigned description: Unsigned operations. + opcode_idx: 0xee - name: cast description: Cast operations. + opcode_idx: 0xed + - name: f32 + description: IEEE-754 single precision floating-point operations. + opcode_idx: 0xec groups: + - title: No operation + description: Perform an operation without behavior. + properties: + - acc_none + exceptions: + - x_none + verification: + - none + pseudo: | + skip + semantics: |- + skip + instructions: + - sig: nop + acc: none + format: [op_none] + opcode_idx: [0x0] + - title: Move register-to-register description: Move values between registers. properties: @@ -254,15 +281,18 @@ groups: raise exception(UndefinedSemantics) if true that Op not in [[ "mov", "mov.64", "mov.obj" ]]; Vd <~ Vs instructions: - - sig: mov v1:out:i32, v2:in:i32 + - sig: mov v1:out:b32, v2:in:b32 acc: none format: [op_v1_4_v2_4, op_v1_8_v2_8, op_v1_16_v2_16] + opcode_idx: [0x1, 0x2, 0x3] - sig: mov.64 v1:out:b64, v2:in:b64 acc: none format: [op_v1_4_v2_4, op_v1_16_v2_16] + opcode_idx: [0x4, 0x5] - sig: mov.obj v1:out:ref, v2:in:ref acc: none format: [op_v1_4_v2_4, op_v1_8_v2_8, op_v1_16_v2_16] + opcode_idx: [0x6, 0x7, 0x8] - title: Move immediate-to-register description: > @@ -285,6 +315,10 @@ groups: raise exception(WrongImmediateValue) if undefined int_of(Imm); Vd <~ value_of(signed(64), int_of(Imm)) end when; + when Op == "fmovi" do + raise exception(WrongImmediateValue) if undefined float_of(Imm); + Vd <~ value_of(float, float_of(Imm)) + end when; when Op == "fmovi.64" do raise exception(WrongImmediateValue) if undefined float_of(Imm); Vd <~ value_of(float, float_of(Imm)) @@ -296,15 +330,25 @@ groups: - sig: movi v:out:i32, imm:i32 acc: none format: [op_v_4_imm_4, op_v_8_imm_8, op_v_8_imm_16] + opcode_idx: [0x9, 0xa, 0xb] - sig: movi v:out:i32, imm:i32 acc: none format: [op_v_8_imm_32] + opcode_idx: [0xc] - sig: movi.64 v:out:i64, imm:i64 acc: none format: [op_v_8_imm_64] + opcode_idx: [0xd] + - sig: fmovi v:out:f32, imm:f32 + acc: none + prefix: f32 + format: [pref_op_v_8_imm_32] + opcode_idx: [0x0] + properties: [acc_none, float] - sig: fmovi.64 v:out:f64, imm:f64 acc: none format: [op_v_8_imm_64] + opcode_idx: [0xe] properties: [acc_none, float] - title: Move null reference into register @@ -323,6 +367,7 @@ groups: - sig: mov.null v:out:ref acc: none format: [op_v_8] + opcode_idx: [0xf] - title: Load accumulator from register description: Moves register content into an accumulator. @@ -355,12 +400,15 @@ groups: - sig: lda v:in:i32 acc: out:i32 format: [op_v_8] + opcode_idx: [0x10] - sig: lda.64 v:in:b64 acc: out:b64 format: [op_v_8] + opcode_idx: [0x11] - sig: lda.obj v:in:ref acc: out:ref format: [op_v_8] + opcode_idx: [0x12] - title: Load accumulator from immediate description: > @@ -383,6 +431,10 @@ groups: raise exception(WrongImmediateValue) if undefined int_of(Imm); acc <~ value_of(i64, int_of(Imm)) end when; + when Op == "fldai" do + raise exception(WrongImmediateValue) if undefined float_of(Imm); + acc <~ value_of(float, float_of(Imm)) + end when when Op == "fldai.64" do raise exception(WrongImmediateValue) if undefined float_of(Imm); acc <~ value_of(float, float_of(Imm)) @@ -394,15 +446,25 @@ groups: - sig: ldai imm:i32 acc: out:i32 format: [op_imm_8, op_imm_16] + opcode_idx: [0x13, 0x14] - sig: ldai imm:i32 acc: out:i32 format: [op_imm_32] + opcode_idx: [0x15] - sig: ldai.64 imm:i64 acc: out:i64 format: [op_imm_64] + opcode_idx: [0x16] + - sig: fldai imm:f32 + acc: out:f32 + prefix: f32 + format: [pref_op_imm_32] + opcode_idx: [0x1] + properties: [acc_write, float] - sig: fldai.64 imm:f64 acc: out:f64 format: [op_imm_64] + opcode_idx: [0x17] properties: [acc_write, float] - title: Load accumulator from string constant pool @@ -426,6 +488,7 @@ groups: - sig: lda.str string_id acc: out:ref format: [op_id_32] + opcode_idx: [0x18] - title: Create and initialize new constant array description: > @@ -445,6 +508,7 @@ groups: - sig: lda.const v:out:ref, literalarray_id acc: none format: [op_v_8_id_32] + opcode_idx: [0x19] - title: Load accumulator from type constant pool description: Load type specified by id into accumulator. @@ -464,6 +528,7 @@ groups: - sig: lda.type type_id acc: out:ref format: [op_id_16] + opcode_idx: [0x1a] - title: Load null reference into accumulator description: Load null reference into accumulator. @@ -481,6 +546,7 @@ groups: - sig: lda.null acc: out:ref format: [op_none] + opcode_idx: [0x1b] - title: Store accumulator description: Moves accumulator content into a register. @@ -503,32 +569,15 @@ groups: - sig: sta v:out:i32 acc: in:i32 format: [op_v_8] + opcode_idx: [0x1c] - sig: sta.64 v:out:b64 acc: in:b64 format: [op_v_8] + opcode_idx: [0x1d] - sig: sta.obj v:out:ref acc: in:ref format: [op_v_8] - - - title: Unconditional jump - description: > - Unconditionally transfer execution to an instruction at offset bytes from the beginning of the current - instruction. Offset is sign extended to the size of instruction address. - properties: - - acc_none - - jump - exceptions: - - x_none - verification: - - branch_target - pseudo: | - pc += imm - semantics: |- - perform_jump(LabelId) - instructions: - - sig: jmp imm:i32 - acc: none - format: [op_imm_8, op_imm_16, op_imm_32] + opcode_idx: [0x1e] - title: Integer comparison description: Perform specified signed or unsigned integer comparison between register and accumulator. @@ -564,14 +613,17 @@ groups: - sig: cmp.64 v:in:i64 acc: inout:i64->i32 format: [op_v_8] + opcode_idx: [0x1f] - sig: ucmp v:in:u32 acc: inout:u32->i32 prefix: unsigned format: [pref_op_v_8] + opcode_idx: [0x0] - sig: ucmp.64 v:in:u64 acc: inout:u64->i32 prefix: unsigned format: [pref_op_v_8] + opcode_idx: [0x1] - title: Floating-point comparison description: Perform specified floating point comparison between register and accumulator. @@ -587,8 +639,10 @@ groups: pseudo: | if isnan(acc) or isnan(vs) then switch (op) + case fcmpg: case fcmpg.64: acc = 1 + case fcmpl: case fcmpl.64: acc = -1 else @@ -619,12 +673,45 @@ groups: undefined raise exception(WrongRegisterValue) end if instructions: + - sig: fcmpl v:in:f32 + acc: inout:f32->i32 + prefix: f32 + format: [pref_op_v_8] + opcode_idx: [0x2] - sig: fcmpl.64 v:in:f64 acc: inout:f64->i32 format: [op_v_8] + opcode_idx: [0x20] + - sig: fcmpg v:in:f32 + acc: inout:f32->i32 + prefix: f32 + format: [pref_op_v_8] + opcode_idx: [0x3] - sig: fcmpg.64 v:in:f64 acc: inout:f64->i32 format: [op_v_8] + opcode_idx: [0x21] + + - title: Unconditional jump + description: > + Unconditionally transfer execution to an instruction at offset bytes from the beginning of the current + instruction. Offset is sign extended to the size of instruction address. + properties: + - acc_none + - jump + exceptions: + - x_none + verification: + - branch_target + pseudo: | + pc += imm + semantics: |- + perform_jump(LabelId) + instructions: + - sig: jmp imm:i32 + acc: none + format: [op_imm_8, op_imm_16, op_imm_32] + opcode_idx: [0x22, 0x23, 0x24] - title: Conditional object comparison jump description: > @@ -657,9 +744,11 @@ groups: - sig: jeq.obj v:in:ref, imm:i32 acc: in:ref format: [op_v_8_imm_8, op_v_8_imm_16] + opcode_idx: [0x25, 0x26] - sig: jne.obj v:in:ref, imm:i32 acc: in:ref format: [op_v_8_imm_8, op_v_8_imm_16] + opcode_idx: [0x27, 0x28] - title: Conditional compared to null jump description: > @@ -691,9 +780,11 @@ groups: - sig: jeqz.obj imm:i32 acc: in:ref format: [op_imm_8, op_imm_16] + opcode_idx: [0x29, 0x2a] - sig: jnez.obj imm:i32 acc: in:ref format: [op_imm_8, op_imm_16] + opcode_idx: [0x2b, 0x2c] - title: Conditional compared to zero jump description: > @@ -752,21 +843,27 @@ groups: - sig: jeqz imm:i32 acc: in:i32 format: [op_imm_8, op_imm_16] + opcode_idx: [0x2d, 0x2e] - sig: jnez imm:i32 acc: in:i32 format: [op_imm_8, op_imm_16] + opcode_idx: [0x2f, 0x30] - sig: jltz imm:i32 acc: in:i32 format: [op_imm_8, op_imm_16] + opcode_idx: [0x31, 0x32] - sig: jgtz imm:i32 acc: in:i32 format: [op_imm_8, op_imm_16] + opcode_idx: [0x33, 0x34] - sig: jlez imm:i32 acc: in:i32 format: [op_imm_8, op_imm_16] + opcode_idx: [0x35, 0x36] - sig: jgez imm:i32 acc: in:i32 format: [op_imm_8, op_imm_16] + opcode_idx: [0x37, 0x38] - title: Conditional compared to register jump description: > @@ -829,39 +926,30 @@ groups: - sig: jeq v:in:i32, imm:i32 acc: in:i32 format: [op_v_8_imm_8, op_v_8_imm_16] + opcode_idx: [0x39, 0x3a] - sig: jne v:in:i32, imm:i32 acc: in:i32 format: [op_v_8_imm_8, op_v_8_imm_16] + opcode_idx: [0x3b, 0x3c] - sig: jlt v:in:i32, imm:i32 acc: in:i32 format: [op_v_8_imm_8, op_v_8_imm_16] + opcode_idx: [0x3d, 0x3e] - sig: jgt v:in:i32, imm:i32 acc: in:i32 format: [op_v_8_imm_8, op_v_8_imm_16] + opcode_idx: [0x3f, 0x40] - sig: jle v:in:i32, imm:i32 acc: in:i32 format: [op_v_8_imm_8, op_v_8_imm_16] + opcode_idx: [0x41, 0x42] - sig: jge v:in:i32, imm:i32 acc: in:i32 format: [op_v_8_imm_8, op_v_8_imm_16] + opcode_idx: [0x43, 0x44] - - title: Two address floating-point binary operation on accumulator - description: | - Perform specified floating-point binary operation on accumulator and register and store result into accumulator. - The results of instructions correspond IEEE-754 arithmetic rules. - - - Any operation with NaN results to NaN value. - - The sum of opposite infinities or the difference of the same sign infinities is NaN. - - Division is NaN if Infinity is divided by Infinity. - - Division is NaN if zero is divided by zero. - - Multiplication is NaN if zero is multiplied by infinity. - - The sign of division or multiplication result is positive if both values have the same sign, negative if the values have different sign. - - Division is infinity if any non zero value is divided by zero. - - Multiplication is infinity if any non zero value is multiplied by infinity. - - The sum of two infinities of the same sign or the difference of two infinities of opposite sign is infinity. The sign of result matches the sign of accumulator value. - - The sum or the difference of infinity and any finite value is infinity. The sign of result matches the sign of infinity. - - The sum or the difference of zeros is zero. Exceptions are the sum of two negative zeros and the difference of negative and positive zero - the result is negative zero. - + - title: Floating-point unary + description: Perform specified floating-point operation on accumulator properties: - acc_read - acc_write @@ -870,49 +958,83 @@ groups: - x_none verification: - acc_type - - v1_type pseudo: | switch (op) - case fadd2.64: - acc = acc + vs - case fsub2.64: - acc = acc - vs - case fmul2.64: - acc = acc * vs - case fdiv2.64: - acc = acc / vs - case fmod2.64: - acc = acc % vs + case fneg: + case fneg.64: + acc = -acc semantics: |- raise exception(WrongRegisterValue) if false that type_of(@acc) is float; - raise exception(WrongRegisterValue) if false that type_of(@Vs) is float; - Acc := float_of(@acc); - Vs := float_of(@Vs); + acc <~ neg(@acc) + instructions: + - sig: fneg + acc: inout:f32 + prefix: f32 + format: [pref_op_none] + opcode_idx: [0x4] + - sig: fneg.64 + acc: inout:f64 + format: [op_none] + opcode_idx: [0x45] + + - title: Unary + description: Perform specified operation on accumulator + properties: + - acc_read + - acc_write + exceptions: + - x_none + verification: + - acc_type + pseudo: | + switch (op) + case neg: + case neg.64: + acc = -acc + case not: + case not.64: + acc = ~acc + semantics: |- + Acc := @acc; cases - when Op == "fadd2.64" do acc <~ Acc + Vs end when; - when Op == "fsub2.64" do acc <~ Acc - Vs end when; - when Op == "fmul2.64" do acc <~ Acc * Vs end when; - when Op == "fdiv2.64" do acc <~ Acc / Vs end when; - when Op == "fmod2.64" do acc <~ Acc % Vs end when - else raise exception(UndefinedSemantics) - undefined raise exception(InternalError) + when Op == "neg" do + raise exception(WrongRegisterValue) if false that type_of(Acc) is i32; + acc <~ neg(Acc) + end when; + when Op == "neg.64" do + raise exception(WrongRegisterValue) if false that type_of(Acc) is i64; + acc <~ neg(Acc) + end when; + when Op == "not" do + raise exception(WrongRegisterValue) if false that type_of(Acc) is i32; + acc <~ neg(Acc) - value(i32, 1) + end when; + when Op == "not.64" do + raise exception(WrongRegisterValue) if false that type_of(Acc) is i64; + acc <~ neg(Acc) - value(i64, 1) + end when; + else raise exception (UndefinedSemantics) + undefined raise exception (InternalError) end cases instructions: - - sig: fadd2.64 v:in:f64 - acc: inout:f64 - format: [op_v_8] - - sig: fsub2.64 v:in:f64 - acc: inout:f64 - format: [op_v_8] - - sig: fmul2.64 v:in:f64 - acc: inout:f64 - format: [op_v_8] - - sig: fdiv2.64 v:in:f64 - acc: inout:f64 - format: [op_v_8] - - sig: fmod2.64 v:in:f64 - acc: inout:f64 - format: [op_v_8] + - sig: neg + acc: inout:i32 + format: [op_none] + opcode_idx: [0x46] + - sig: neg.64 + acc: inout:i64 + format: [op_none] + opcode_idx: [0x47] + - sig: not + acc: inout:i32 + prefix: bit + format: [pref_op_none] + opcode_idx: [0x0] + - sig: not.64 + acc: inout:i64 + prefix: bit + format: [pref_op_none] + opcode_idx: [0x1] - title: Two address binary operation on accumulator description: Perform specified binary operation on accumulator and register and store result into accumulator @@ -1049,69 +1171,191 @@ groups: - sig: add2 v:in:i32 acc: inout:i32 format: [op_v_8] + opcode_idx: [0x48] - sig: add2.64 v:in:i64 acc: inout:i64 format: [op_v_8] + opcode_idx: [0x49] - sig: sub2 v:in:i32 acc: inout:i32 format: [op_v_8] + opcode_idx: [0x4a] - sig: sub2.64 v:in:i64 acc: inout:i64 format: [op_v_8] + opcode_idx: [0x4b] - sig: mul2 v:in:i32 acc: inout:i32 format: [op_v_8] + opcode_idx: [0x4c] - sig: mul2.64 v:in:i64 acc: inout:i64 format: [op_v_8] + opcode_idx: [0x4d] - sig: and2 v:in:i32 acc: inout:i32 prefix: bit format: [pref_op_v_8] + opcode_idx: [0x2] - sig: and2.64 v:in:i64 acc: inout:i64 prefix: bit format: [pref_op_v_8] + opcode_idx: [0x3] - sig: or2 v:in:i32 acc: inout:i32 prefix: bit format: [pref_op_v_8] + opcode_idx: [0x4] - sig: or2.64 v:in:i64 acc: inout:i64 prefix: bit format: [pref_op_v_8] + opcode_idx: [0x5] - sig: xor2 v:in:i32 acc: inout:i32 prefix: bit format: [pref_op_v_8] + opcode_idx: [0x6] - sig: xor2.64 v:in:i64 acc: inout:i64 prefix: bit format: [pref_op_v_8] + opcode_idx: [0x7] - sig: shl2 v:in:i32 acc: inout:i32 prefix: bit format: [pref_op_v_8] + opcode_idx: [0x8] - sig: shl2.64 v:in:i64 acc: inout:i64 prefix: bit format: [pref_op_v_8] + opcode_idx: [0x9] - sig: shr2 v:in:i32 acc: inout:i32 prefix: bit format: [pref_op_v_8] + opcode_idx: [0xa] - sig: shr2.64 v:in:i64 acc: inout:i64 prefix: bit format: [pref_op_v_8] + opcode_idx: [0xb] - sig: ashr2 v:in:i32 acc: inout:i32 prefix: bit format: [pref_op_v_8] + opcode_idx: [0xc] - sig: ashr2.64 v:in:i64 acc: inout:i64 prefix: bit format: [pref_op_v_8] + opcode_idx: [0xd] + + - title: Two address floating-point binary operation on accumulator + description: | + Perform specified floating-point binary operation on accumulator and register and store result into accumulator. + The results of instructions correspond IEEE-754 arithmetic rules. + + - Any operation with NaN results to NaN value. + - The sum of opposite infinities or the difference of the same sign infinities is NaN. + - Division is NaN if Infinity is divided by Infinity. + - Division is NaN if zero is divided by zero. + - Multiplication is NaN if zero is multiplied by infinity. + - The sign of division or multiplication result is positive if both values have the same sign, negative if the values have different sign. + - Division is infinity if any non zero value is divided by zero. + - Multiplication is infinity if any non zero value is multiplied by infinity. + - The sum of two infinities of the same sign or the difference of two infinities of opposite sign is infinity. The sign of result matches the sign of accumulator value. + - The sum or the difference of infinity and any finite value is infinity. The sign of result matches the sign of infinity. + - The sum or the difference of zeros is zero. Exceptions are the sum of two negative zeros and the difference of negative and positive zero - the result is negative zero. + + properties: + - acc_read + - acc_write + - float + exceptions: + - x_none + verification: + - acc_type + - v1_type + pseudo: | + switch (op) + case fadd2: + case fadd2.64: + acc = acc + vs + case fsub2: + case fsub2.64: + acc = acc - vs + case fmul2: + case fmul2.64: + acc = acc * vs + case fdiv2: + case fdiv2.64: + acc = acc / vs + case fmod2: + case fmod2.64: + acc = acc % vs + semantics: |- + raise exception(WrongRegisterValue) if false that type_of(@acc) is float; + raise exception(WrongRegisterValue) if false that type_of(@Vs) is float; + Acc := float_of(@acc); + Vs := float_of(@Vs); + cases + when Op == "fadd2" or Op == "fadd2.64" do acc <~ Acc + Vs end when; + when Op == "fsub2" or Op == "fsub2.64" do acc <~ Acc - Vs end when; + when Op == "fmul2" or Op == "fmul2.64" do acc <~ Acc * Vs end when; + when Op == "fdiv2" or Op == "fdiv2.64" do acc <~ Acc / Vs end when; + when Op == "fmod2" or Op == "fmod2.64" do acc <~ Acc % Vs end when + else raise exception(UndefinedSemantics) + undefined raise exception(InternalError) + end cases + instructions: + - sig: fadd2 v:in:f32 + acc: inout:f32 + prefix: f32 + format: [pref_op_v_8] + opcode_idx: [0x5] + - sig: fadd2.64 v:in:f64 + acc: inout:f64 + format: [op_v_8] + opcode_idx: [0x4e] + - sig: fsub2 v:in:f32 + acc: inout:f32 + prefix: f32 + format: [pref_op_v_8] + opcode_idx: [0x6] + - sig: fsub2.64 v:in:f64 + acc: inout:f64 + format: [op_v_8] + opcode_idx: [0x4f] + - sig: fmul2 v:in:f32 + acc: inout:f32 + prefix: f32 + format: [pref_op_v_8] + opcode_idx: [0x7] + - sig: fmul2.64 v:in:f64 + acc: inout:f64 + format: [op_v_8] + opcode_idx: [0x50] + - sig: fdiv2 v:in:f32 + acc: inout:f32 + prefix: f32 + format: [pref_op_v_8] + opcode_idx: [0x8] + - sig: fdiv2.64 v:in:f64 + acc: inout:f64 + format: [op_v_8] + opcode_idx: [0x51] + - sig: fmod2 v:in:f32 + acc: inout:f32 + prefix: f32 + format: [pref_op_v_8] + opcode_idx: [0x9] + - sig: fmod2.64 v:in:f64 + acc: inout:f64 + format: [op_v_8] + opcode_idx: [0x52] - title: Two address integer division and modulo on accumulator description: Perform integer division or modulo on accumulator and register and store result into accumulator @@ -1201,189 +1445,51 @@ groups: - sig: div2 v:in:i32 acc: inout:i32 format: [op_v_8] + opcode_idx: [0x53] - sig: div2.64 v:in:i64 acc: inout:i64 format: [op_v_8] + opcode_idx: [0x54] - sig: mod2 v:in:i32 acc: inout:i32 format: [op_v_8] + opcode_idx: [0x55] - sig: mod2.64 v:in:i64 acc: inout:i64 format: [op_v_8] + opcode_idx: [0x56] - sig: divu2 v:in:u32 acc: inout:u32 prefix: unsigned format: [pref_op_v_8] + opcode_idx: [0x2] - sig: divu2.64 v:in:u64 acc: inout:u64 prefix: unsigned format: [pref_op_v_8] + opcode_idx: [0x3] - sig: modu2 v:in:u32 acc: inout:u32 prefix: unsigned format: [pref_op_v_8] + opcode_idx: [0x4] - sig: modu2.64 v:in:u64 acc: inout:u64 prefix: unsigned format: [pref_op_v_8] + opcode_idx: [0x5] - - title: Three address binary operation - description: Perform specified binary operation on two registers and store result into accumulator + - title: Two address binary operation with immediate on accumulator + description: > + Perform specified binary operation on accumulator and immediate and store result into accumulator. + Immediate is sign extended to operand size. properties: - acc_write + - acc_read exceptions: - x_none verification: - - v1_type - - v2_type - pseudo: | - switch (op) - case add: - acc = (vs1 + vs2) % 2^32 - case sub: - acc = (vs1 - vs2) % 2^32 - case mul: - acc = (vs1 * vs2) % 2^32 - case and: - acc = vs1 & vs2 - case or: - acc = vs1 | vs2 - case xor: - acc = vs1 ^ vs2 - case shl: - acc = vs1 << (vs2 & 0x1f) - case shr: - acc = vs1 >> (vs2 & 0x1f) - case ashr: - acc = arith_shift_right(vs1, vs2 & 0x1f) - semantics: |- - Vs1 := @Vs1; - Vs2 := @Vs2; - raise exception(WrongRegisterValue) if false that type_of(Vs1) is i32 and type_of(Vs2) is i32; - cases - when Op == "add" do - acc <~ truncate_int(Vs1 + Vs2) - end when; - when Op == "sub" do - acc <~ truncate_int(Vs1 - Vs2) - end when; - when Op == "mul" do - acc <~ truncate_int(Vs1 * Vs2) - end when; - when Op == "and" do - acc <~ truncate_int(Vs1 & Vs2) - end when; - when Op == "or" do - acc <~ truncate_int(Vs1 | Vs2) - end when; - when Op == "xor" do - acc <~ truncate_int(Vs1 ^ Vs2) - end when; - when Op == "shl" do - acc <~ truncate_int(Vs1 << Vs2) - end when; - when Op == "shr" do - acc <~ truncate_int(Vs1 >> Vs2) - end when - // when Op == "ashr" do - // end when - else raise exception(UndefinedSemantics) - undefined raise exception(InternalError) - end cases - instructions: - - sig: add v1:in:i32, v2:in:i32 - acc: out:i32 - format: [op_v1_4_v2_4] - - sig: sub v1:in:i32, v2:in:i32 - acc: out:i32 - format: [op_v1_4_v2_4] - - sig: mul v1:in:i32, v2:in:i32 - acc: out:i32 - format: [op_v1_4_v2_4] - - sig: and v1:in:i32, v2:in:i32 - acc: out:i32 - prefix: bit - format: [pref_op_v1_4_v2_4] - - sig: or v1:in:i32, v2:in:i32 - acc: out:i32 - prefix: bit - format: [pref_op_v1_4_v2_4] - - sig: xor v1:in:i32, v2:in:i32 - acc: out:i32 - prefix: bit - format: [pref_op_v1_4_v2_4] - - sig: shl v1:in:i32, v2:in:i32 - acc: out:i32 - prefix: bit - format: [pref_op_v1_4_v2_4] - - sig: shr v1:in:i32, v2:in:i32 - acc: out:i32 - prefix: bit - format: [pref_op_v1_4_v2_4] - - sig: ashr v1:in:i32, v2:in:i32 - acc: out:i32 - prefix: bit - format: [pref_op_v1_4_v2_4] - - - title: Three address integer division or modulo - description: Perform integer division or modulo on two registers and store result into accumulator - properties: - - acc_write - exceptions: - - x_arith - verification: - - v1_type - - v2_type - pseudo: | - if vs2 == 0 then - throw ArithmeticException - end - switch(op) - case div: - if vs1 == INT32_MIN and vs2 == -1 then - acc = INT32_MIN - else - acc = vs1 / vs2 - end - case mod: - if vs1 == INT32_MIN and vs2 == -1 then - acc = 0 - else - acc = vs1 % vs2 - end - semantics: |- - Vs1 := @Vs1; - Vs2 := @Vs2; - raise exception(WrongRegisterValue) if false that type_of(Vs1) is i32 and type_of(Vs2) is i32; - cases - when Op == "div" do - acc <~ Vs1 / Vs2 - end when; - when Op == "mod" do - acc <~ Vs1 % Vs2 - end when - else raise exception(UndefinedSemantics) - undefined raise exception(InternalError) - end cases - instructions: - - sig: div v1:in:i32, v2:in:i32 - acc: out:i32 - format: [op_v1_4_v2_4] - - sig: mod v1:in:i32, v2:in:i32 - acc: out:i32 - format: [op_v1_4_v2_4] - - - title: Two address binary operation with immediate on accumulator - description: > - Perform specified binary operation on accumulator and immediate and store result into accumulator. - Immediate is sign extended to operand size. - properties: - - acc_write - - acc_read - exceptions: - - x_none - verification: - - acc_type + - acc_type pseudo: | switch (op) case addi: @@ -1444,31 +1550,40 @@ groups: - sig: addi imm:i32 acc: inout:i32 format: [op_imm_8] + opcode_idx: [0x57] - sig: subi imm:i32 acc: inout:i32 format: [op_imm_8] + opcode_idx: [0x58] - sig: muli imm:i32 acc: inout:i32 format: [op_imm_8] + opcode_idx: [0x59] - sig: andi imm:i32 acc: inout:i32 format: [op_imm_32] + opcode_idx: [0x5a] - sig: ori imm:i32 acc: inout:i32 format: [op_imm_32] + opcode_idx: [0x5b] - sig: xori imm:i32 acc: inout:i32 prefix: bit format: [pref_op_imm_32] + opcode_idx: [0xe] - sig: shli imm:i32 acc: inout:i32 format: [op_imm_8] + opcode_idx: [0x5c] - sig: shri imm:i32 acc: inout:i32 format: [op_imm_8] + opcode_idx: [0x5d] - sig: ashri imm:i32 acc: inout:i32 format: [op_imm_8] + opcode_idx: [0x5e] - title: Two address integer division or modulo with immediate on accumulator description: > @@ -1517,86 +1632,168 @@ groups: - sig: divi imm:i32 acc: inout:i32 format: [op_imm_8] + opcode_idx: [0x5f] - sig: modi imm:i32 acc: inout:i32 format: [op_imm_8] + opcode_idx: [0x60] - - title: Floating-point unary - description: Perform specified floating-point operation on accumulator + - title: Three address binary operation + description: Perform specified binary operation on two registers and store result into accumulator properties: - - acc_read - acc_write - - float exceptions: - x_none verification: - - acc_type + - v1_type + - v2_type pseudo: | switch (op) - case fneg.64: - acc = -acc + case add: + acc = (vs1 + vs2) % 2^32 + case sub: + acc = (vs1 - vs2) % 2^32 + case mul: + acc = (vs1 * vs2) % 2^32 + case and: + acc = vs1 & vs2 + case or: + acc = vs1 | vs2 + case xor: + acc = vs1 ^ vs2 + case shl: + acc = vs1 << (vs2 & 0x1f) + case shr: + acc = vs1 >> (vs2 & 0x1f) + case ashr: + acc = arith_shift_right(vs1, vs2 & 0x1f) semantics: |- - raise exception(WrongRegisterValue) if false that type_of(@acc) is float; - acc <~ neg(@acc) + Vs1 := @Vs1; + Vs2 := @Vs2; + raise exception(WrongRegisterValue) if false that type_of(Vs1) is i32 and type_of(Vs2) is i32; + cases + when Op == "add" do + acc <~ truncate_int(Vs1 + Vs2) + end when; + when Op == "sub" do + acc <~ truncate_int(Vs1 - Vs2) + end when; + when Op == "mul" do + acc <~ truncate_int(Vs1 * Vs2) + end when; + when Op == "and" do + acc <~ truncate_int(Vs1 & Vs2) + end when; + when Op == "or" do + acc <~ truncate_int(Vs1 | Vs2) + end when; + when Op == "xor" do + acc <~ truncate_int(Vs1 ^ Vs2) + end when; + when Op == "shl" do + acc <~ truncate_int(Vs1 << Vs2) + end when; + when Op == "shr" do + acc <~ truncate_int(Vs1 >> Vs2) + end when + // when Op == "ashr" do + // end when + else raise exception(UndefinedSemantics) + undefined raise exception(InternalError) + end cases instructions: - - sig: fneg.64 - acc: inout:f64 - format: [op_none] + - sig: add v1:in:i32, v2:in:i32 + acc: out:i32 + format: [op_v1_4_v2_4] + opcode_idx: [0x61] + - sig: sub v1:in:i32, v2:in:i32 + acc: out:i32 + format: [op_v1_4_v2_4] + opcode_idx: [0x62] + - sig: mul v1:in:i32, v2:in:i32 + acc: out:i32 + format: [op_v1_4_v2_4] + opcode_idx: [0x63] + - sig: and v1:in:i32, v2:in:i32 + acc: out:i32 + prefix: bit + format: [pref_op_v1_4_v2_4] + opcode_idx: [0xf] + - sig: or v1:in:i32, v2:in:i32 + acc: out:i32 + prefix: bit + format: [pref_op_v1_4_v2_4] + opcode_idx: [0x10] + - sig: xor v1:in:i32, v2:in:i32 + acc: out:i32 + prefix: bit + format: [pref_op_v1_4_v2_4] + opcode_idx: [0x11] + - sig: shl v1:in:i32, v2:in:i32 + acc: out:i32 + prefix: bit + format: [pref_op_v1_4_v2_4] + opcode_idx: [0x12] + - sig: shr v1:in:i32, v2:in:i32 + acc: out:i32 + prefix: bit + format: [pref_op_v1_4_v2_4] + opcode_idx: [0x13] + - sig: ashr v1:in:i32, v2:in:i32 + acc: out:i32 + prefix: bit + format: [pref_op_v1_4_v2_4] + opcode_idx: [0x14] - - title: Unary - description: Perform specified operation on accumulator + - title: Three address integer division or modulo + description: Perform integer division or modulo on two registers and store result into accumulator properties: - - acc_read - acc_write exceptions: - - x_none + - x_arith verification: - - acc_type + - v1_type + - v2_type pseudo: | - switch (op) - case neg: - case neg.64: - acc = -acc - case not: - case not.64: - acc = ~acc + if vs2 == 0 then + throw ArithmeticException + end + switch(op) + case div: + if vs1 == INT32_MIN and vs2 == -1 then + acc = INT32_MIN + else + acc = vs1 / vs2 + end + case mod: + if vs1 == INT32_MIN and vs2 == -1 then + acc = 0 + else + acc = vs1 % vs2 + end semantics: |- - Acc := @acc; + Vs1 := @Vs1; + Vs2 := @Vs2; + raise exception(WrongRegisterValue) if false that type_of(Vs1) is i32 and type_of(Vs2) is i32; cases - when Op == "neg" do - raise exception(WrongRegisterValue) if false that type_of(Acc) is i32; - acc <~ neg(Acc) - end when; - when Op == "neg.64" do - raise exception(WrongRegisterValue) if false that type_of(Acc) is i64; - acc <~ neg(Acc) - end when; - when Op == "not" do - raise exception(WrongRegisterValue) if false that type_of(Acc) is i32; - acc <~ neg(Acc) - value(i32, 1) - end when; - when Op == "not.64" do - raise exception(WrongRegisterValue) if false that type_of(Acc) is i64; - acc <~ neg(Acc) - value(i64, 1) + when Op == "div" do + acc <~ Vs1 / Vs2 end when; - else raise exception (UndefinedSemantics) - undefined raise exception (InternalError) + when Op == "mod" do + acc <~ Vs1 % Vs2 + end when + else raise exception(UndefinedSemantics) + undefined raise exception(InternalError) end cases instructions: - - sig: neg - acc: inout:i32 - format: [op_none] - - sig: neg.64 - acc: inout:i64 - format: [op_none] - - sig: not - acc: inout:i32 - prefix: bit - format: [pref_op_none] - - sig: not.64 - acc: inout:i64 - prefix: bit - format: [pref_op_none] + - sig: div v1:in:i32, v2:in:i32 + acc: out:i32 + format: [op_v1_4_v2_4] + opcode_idx: [0x64] + - sig: mod v1:in:i32, v2:in:i32 + acc: out:i32 + format: [op_v1_4_v2_4] + opcode_idx: [0x65] - title: Increment register with immediate description: > @@ -1619,6 +1816,7 @@ groups: - sig: inci v:inout:i32, imm:i32 acc: none format: [op_v_4_imm_4] + opcode_idx: [0x66] - title: Conversions between integer and floating point types description: | @@ -1644,74 +1842,168 @@ groups: (dest_type) acc = (src_type) acc semantics: |- cases + when Op == "i32tof32" do + raise exception(WrongRegisterValue) if false that type_of(@acc) is i32; + acc <~ i32tof32(@acc) + end when; when Op == "i32tof64" do raise exception(WrongRegisterValue) if false that type_of(@acc) is i32; acc <~ i32tof64(@acc) end when; + when Op == "u32tof32" do + raise exception(WrongRegisterValue) if false that type_of(@acc) is u32; + acc <~ u32tof32(@acc) + end when; when Op == "u32tof64" do raise exception(WrongRegisterValue) if false that type_of(@acc) is u32; acc <~ u32tof64(@acc) end when; + when Op == "i64tof32" do + raise exception(WrongRegisterValue) if false that type_of(@acc) is i64; + acc <~ i64tof32(@acc) + end when; when Op == "i64tof64" do raise exception(WrongRegisterValue) if false that type_of(@acc) is i64; acc <~ i64tof64(@acc) end when; + when Op == "u64tof32" do + raise exception(WrongRegisterValue) if false that type_of(@acc) is u64; + acc <~ u64tof32(@acc) + end when; when Op == "u64tof64" do raise exception(WrongRegisterValue) if false that type_of(@acc) is u64; acc <~ u64tof64(@acc) end when; + when Op == "f32toi32" do + raise exception(WrongRegisterValue) if false that type_of(@acc) is f32; + acc <~ f32toi32(@acc) + end when; + when Op == "f32tou32" do + raise exception(WrongRegisterValue) if false that type_of(@acc) is f32; + acc <~ f32tou32(@acc) + end when; + when Op == "f32toi64" do + raise exception(WrongRegisterValue) if false that type_of(@acc) is f32; + acc <~ f32toi64(@acc) + end when; + when Op == "f32tou64" do + raise exception(WrongRegisterValue) if false that type_of(@acc) is f32; + acc <~ f32tou64(@acc) + end when when Op == "f64toi32" do - raise exception(WrongRegisterValue) if false that type_of(@acc) is float; + raise exception(WrongRegisterValue) if false that type_of(@acc) is f64; acc <~ f64toi32(@acc) end when; when Op == "f64tou32" do - raise exception(WrongRegisterValue) if false that type_of(@acc) is float; + raise exception(WrongRegisterValue) if false that type_of(@acc) is f64; acc <~ f64tou32(@acc) end when; when Op == "f64toi64" do - raise exception(WrongRegisterValue) if false that type_of(@acc) is float; + raise exception(WrongRegisterValue) if false that type_of(@acc) is f64; acc <~ f64toi64(@acc) end when; when Op == "f64tou64" do - raise exception(WrongRegisterValue) if false that type_of(@acc) is float; + raise exception(WrongRegisterValue) if false that type_of(@acc) is f64; acc <~ f64tou64(@acc) end when + when Op == "f64tof32" do + raise exception(WrongRegisterValue) if false that type_of(@acc) is f64; + acc <~ f64tof32(@acc) + end when else raise exception(UndefinedSemantics) undefined raise exception(InternalError) end cases instructions: + - sig: i32tof32 + acc: inout:i32->f32 + prefix: f32 + format: [pref_op_none] + opcode_idx: [0xa] - sig: i32tof64 acc: inout:i32->f64 prefix: cast format: [pref_op_none] + opcode_idx: [0x0] + - sig: u32tof32 + acc: inout:u32->f32 + prefix: f32 + format: [pref_op_none] + opcode_idx: [0xb] - sig: u32tof64 acc: inout:u32->f64 prefix: cast format: [pref_op_none] + opcode_idx: [0x1] + - sig: i64tof32 + acc: inout:i64->f32 + prefix: f32 + format: [pref_op_none] + opcode_idx: [0xc] - sig: i64tof64 acc: inout:i64->f64 prefix: cast format: [pref_op_none] + opcode_idx: [0x2] + - sig: u64tof32 + acc: inout:u64->f32 + prefix: f32 + format: [pref_op_none] + opcode_idx: [0xd] - sig: u64tof64 acc: inout:u64->f64 prefix: cast format: [pref_op_none] + opcode_idx: [0x3] + - sig: f32tof64 + acc: inout:f32->f64 + prefix: f32 + format: [pref_op_none] + opcode_idx: [0xe] + - sig: f32toi32 + acc: inout:f32->i32 + prefix: f32 + format: [pref_op_none] + opcode_idx: [0xf] + - sig: f32toi64 + acc: inout:f32->i64 + prefix: f32 + format: [pref_op_none] + opcode_idx: [0x10] + - sig: f32tou32 + acc: inout:f32->u32 + prefix: f32 + format: [pref_op_none] + opcode_idx: [0x11] + - sig: f32tou64 + acc: inout:f32->u64 + prefix: f32 + format: [pref_op_none] + opcode_idx: [0x12] - sig: f64toi32 acc: inout:f64->i32 prefix: cast format: [pref_op_none] + opcode_idx: [0x4] - sig: f64toi64 acc: inout:f64->i64 prefix: cast format: [pref_op_none] + opcode_idx: [0x5] - sig: f64tou32 acc: inout:f64->u32 prefix: cast format: [pref_op_none] + opcode_idx: [0x6] - sig: f64tou64 acc: inout:f64->u64 prefix: cast format: [pref_op_none] + opcode_idx: [0x7] + - sig: f64tof32 + acc: inout:f64->f32 + prefix: f32 + format: [pref_op_none] + opcode_idx: [0x13] - title: Conversions from integer types to u1 description: | @@ -1755,18 +2047,22 @@ groups: acc: inout:i32->u1 prefix: cast format: [pref_op_none] + opcode_idx: [0x8] - sig: i64tou1 acc: inout:i64->u1 prefix: cast format: [pref_op_none] + opcode_idx: [0x9] - sig: u32tou1 acc: inout:u32->u1 prefix: cast format: [pref_op_none] + opcode_idx: [0xa] - sig: u64tou1 acc: inout:u64->u1 prefix: cast format: [pref_op_none] + opcode_idx: [0xb] - title: Integer truncations and extensions. description: > @@ -1853,59 +2149,72 @@ groups: acc: inout:i32->i64 prefix: cast format: [pref_op_none] + opcode_idx: [0xc] - sig: i32toi16 acc: inout:i32->i16 prefix: cast format: [pref_op_none] + opcode_idx: [0xd] - sig: i32tou16 acc: inout:i32->u16 prefix: cast format: [pref_op_none] + opcode_idx: [0xe] - sig: i32toi8 acc: inout:i32->i8 prefix: cast format: [pref_op_none] + opcode_idx: [0xf] - sig: i32tou8 acc: inout:i32->u8 prefix: cast format: [pref_op_none] + opcode_idx: [0x10] - sig: i64toi32 acc: inout:i64->i32 prefix: cast format: [pref_op_none] + opcode_idx: [0x11] - sig: u32toi64 acc: inout:u32->i64 prefix: cast format: [pref_op_none] + opcode_idx: [0x12] - sig: u32toi16 acc: inout:u32->i16 prefix: cast format: [pref_op_none] + opcode_idx: [0x13] - sig: u32tou16 acc: inout:u32->u16 prefix: cast format: [pref_op_none] + opcode_idx: [0x14] - sig: u32toi8 acc: inout:u32->i8 prefix: cast format: [pref_op_none] + opcode_idx: [0x15] - sig: u32tou8 acc: inout:u32->u8 prefix: cast format: [pref_op_none] + opcode_idx: [0x16] - sig: u64toi32 acc: inout:u64->i32 prefix: cast format: [pref_op_none] + opcode_idx: [0x17] - sig: u64tou32 acc: inout:u64->u32 prefix: cast format: [pref_op_none] + opcode_idx: [0x18] - title: Load from array description: > - Load an element from array using accumulator as an index and put it into accumulator. - If element size is smaller than 32 bits, it will be zero or sign extended (depending on bytecode) + Load an element from array using accumulator as an index and puts it into accumulator. + If element size is smaller then 32 bits, it will be zero or sign extended (depending on bytecode) to i32. verification: - v1_array_type @@ -1923,9 +2232,7 @@ groups: if acc < 0 || acc >= len(vs) then throw ArrayIndexOutOfBoundsException end - if op == fldarr.32 then - acc = f32tof64(vs[acc]) - else if op == ldarr.8 then + if op == ldarr.8 then acc = i8toi32(vs[acc]) else if op == ldarru.8 then acc = u8toi32(vs[acc]) @@ -1942,32 +2249,41 @@ groups: - sig: ldarr.8 v:in:i8[] acc: inout:i32 format: [op_v_8] + opcode_idx: [0x67] - sig: ldarru.8 v:in:u8[] acc: inout:i32 format: [op_v_8] + opcode_idx: [0x68] - sig: ldarr.16 v:in:i16[] acc: inout:i32 format: [op_v_8] + opcode_idx: [0x69] - sig: ldarru.16 v:in:u16[] acc: inout:i32 format: [op_v_8] + opcode_idx: [0x6a] - sig: ldarr v:in:i32[] acc: inout:i32 format: [op_v_8] + opcode_idx: [0x6b] - sig: ldarr.64 v:in:i64[] acc: inout:i32->i64 format: [op_v_8] + opcode_idx: [0x6c] - sig: fldarr.32 v:in:f32[] - acc: inout:i32->f64 + acc: inout:i32->f32 format: [op_v_8] + opcode_idx: [0x6d] properties: [acc_read, acc_write, float] - sig: fldarr.64 v:in:f64[] acc: inout:i32->f64 format: [op_v_8] + opcode_idx: [0x6e] properties: [acc_read, acc_write, float] - sig: ldarr.obj v:in:ref[] acc: inout:i32->ref format: [op_v_8] + opcode_idx: [0x6f] - title: Store to array description: > @@ -1994,9 +2310,7 @@ groups: if op == starr.obj && !has_type(acc, component_type(vs1)) throw ArrayStoreException end - if op == fstarr.32 then - vs1[vs2] = f64tof32(acc) - else if op == starr.8 then + if op == starr.8 then vs1[vs2] = truncateto8(acc) else if op == starr.16 then vs1[vs2] = truncateto16(acc) @@ -2009,26 +2323,33 @@ groups: - sig: starr.8 v1:in:i8[], v2:in:i32 acc: in:i8 format: [op_v1_4_v2_4] + opcode_idx: [0x70] - sig: starr.16 v1:in:i16[], v2:in:i32 acc: in:i16 format: [op_v1_4_v2_4] + opcode_idx: [0x71] - sig: starr v1:in:i32[], v2:in:i32 acc: in:i32 format: [op_v1_4_v2_4] + opcode_idx: [0x72] - sig: starr.64 v1:in:i64[], v2:in:i32 acc: in:i64 format: [op_v1_4_v2_4] + opcode_idx: [0x73] - sig: fstarr.32 v1:in:f32[], v2:in:i32 - acc: in:f64 + acc: in:f32 format: [op_v1_4_v2_4] + opcode_idx: [0x74] properties: [acc_read, float] - sig: fstarr.64 v1:in:f64[], v2:in:i32 acc: in:f64 format: [op_v1_4_v2_4] + opcode_idx: [0x75] properties: [acc_read, float] - sig: starr.obj v1:in:ref[], v2:in:i32 acc: in:ref format: [op_v1_4_v2_4] + opcode_idx: [0x76] - title: Array length description: Get length of an array and put it into accumulator. @@ -2049,6 +2370,7 @@ groups: - sig: lenarr v:in:top[] acc: out:i32 format: [op_v_8] + opcode_idx: [0x77] - title: Create new array description: > @@ -2079,6 +2401,7 @@ groups: - sig: newarr v1:out:ref, v2:in:i32, type_id acc: none format: [op_v1_4_v2_4_id_16] + opcode_idx: [0x78] - title: Create new object description: | @@ -2105,6 +2428,7 @@ groups: - sig: newobj v:out:ref, type_id acc: none format: [op_v_8_id_16] + opcode_idx: [0x79] - title: Create new object and call initializer description: > @@ -2139,20 +2463,22 @@ groups: - sig: initobj.short method_id, v1:in:none, v2:in:none acc: out:ref format: [op_v1_4_v2_4_id_16] + opcode_idx: [0x7a] - sig: initobj method_id, v1:in:none, v2:in:none, v3:in:none, v4:in:none acc: out:ref format: [op_v1_4_v2_4_v3_4_v4_4_id_16] + opcode_idx: [0x7b] - sig: initobj.range method_id, v:in:none acc: out:ref format: [op_v_8_id_16] + opcode_idx: [0x7c] - title: Get field from object to accumulator description: > Get field value from an object by field id and put it into accumulator. For non-object variant, the size of the field is determined by the field_id, - most significant bits are signed or unsigned extended based on the field type to fit accumulator size. + most significant bits are sign or unsigned extended based on the field type to fit accumulator size. If field type is less than 32, then loaded value is sign or zero extended to i32 depending on field type. - If field type is f32, load will implicitly convert value into f64 type. verification: - v1_object - field_id_non_static @@ -2169,8 +2495,6 @@ groups: field = resolve(field_id) if op == ldobj and size(field) < 32 then acc = extendto32(vs.get(field)) - else if type(field) == f32 then - acc = f32tof64(vs.get(field)) else acc = vs.get(field) end @@ -2178,14 +2502,58 @@ groups: skip instructions: - sig: ldobj v:in:ref, field_id - acc: out:i32 + acc: out:b32 format: [op_v_8_id_16] + opcode_idx: [0x7d] - sig: ldobj.64 v:in:ref, field_id acc: out:b64 format: [op_v_8_id_16] + opcode_idx: [0x7e] - sig: ldobj.obj v:in:ref, field_id acc: out:ref format: [op_v_8_id_16] + opcode_idx: [0x7f] + + - title: Store accumulator content into object field + description: > + Store accumulator content into object field by field_id. For non-object variant the size of actually stored + value is determined by field_id, other accumulator bits are discarded. + If field type size is less than 32, accumulator content will be truncated to storage size before storing. + verification: + - v1_object + - field_id_non_static + - field_id_size + - acc_type + properties: + - acc_read + - field_id + exceptions: + - x_null + pseudo: | + if vs == null then + throw NullPointerException + end + field = resolve(field_id) + if op == stobj and size(field) < 32 then + vs.set(field, truncate(field, acc)) + else + vs.set(field, acc) + end + semantics: |- + skip + instructions: + - sig: stobj v:in:ref, field_id + acc: in:b32 + format: [op_v_8_id_16] + opcode_idx: [0x80] + - sig: stobj.64 v:in:ref, field_id + acc: in:b64 + format: [op_v_8_id_16] + opcode_idx: [0x81] + - sig: stobj.obj v:in:ref, field_id + acc: in:ref + format: [op_v_8_id_16] + opcode_idx: [0x82] - title: Get field from object to register description: > @@ -2195,6 +2563,7 @@ groups: If field type is less than 32, then loaded value is sign or zero extended to i32 depending on field type. If field type is f32, load will implicitly convert value into f64 type. verification: + - v2_object - field_id_non_static - field_id_size properties: @@ -2220,61 +2589,24 @@ groups: - sig: ldobj.v v1:out:i32, v2:in:ref, field_id acc: none format: [op_v1_4_v2_4_id_16] + opcode_idx: [0x83] - sig: ldobj.v.64 v1:out:b64, v2:in:ref, field_id acc: none format: [op_v1_4_v2_4_id_16] + opcode_idx: [0x84] - sig: ldobj.v.obj v1:out:ref, v2:in:ref, field_id acc: none format: [op_v1_4_v2_4_id_16] - - - title: Store accumulator content into object field - description: > - Store accumulator content into object field by field_id. For non-object variant the size of actually stored - value is determined by field_id, and other accumulator bits are discarded. - If field type size is less than 32, accumulator content will be truncated to storage size before storing. - If field type is f32, accumulator content will be implicitly converted from f64 to f32 before storing. - verification: - - v1_object - - field_id_non_static - - field_id_size - - acc_type - properties: - - acc_read - - field_id - exceptions: - - x_null - pseudo: | - if vs == null then - throw NullPointerException - end - field = resolve(field_id) - if op == stobj and size(field) < 32 then - vs.set(field, truncate(field, acc)) - if type(field) == f32 then - vs.set(field, f64tof32(acc)) - else - vs.set(field, acc) - end - semantics: |- - skip - instructions: - - sig: stobj v:in:ref, field_id - acc: in:i32 - format: [op_v_8_id_16] - - sig: stobj.64 v:in:ref, field_id - acc: in:b64 - format: [op_v_8_id_16] - - sig: stobj.obj v:in:ref, field_id - acc: in:ref - format: [op_v_8_id_16] + opcode_idx: [0x85] - title: Store register content into object field description: > Store register content into object field by field_id. For non-object variant the size of actually stored value is determined by field_id, other register bits are discarded. If field type size is less than 32, register content will be truncated to storage size before storing. - If field type is f32, register content will be implicitly converted from f64 to f32 before storing. verification: + - v1_type + - v2_object - field_id_non_static - field_id_size properties: @@ -2289,31 +2621,31 @@ groups: field = resolve(field_id) if op == stobj and size(field) < 32 then v2.set(field, truncate(field, v1)) - if type(field) == f32 then - v2.set(field, f64tof32(v1)) else v2.set(field, v1) end semantics: |- skip instructions: - - sig: stobj.v v1:in:i32, v2:in:ref, field_id + - sig: stobj.v v1:in:b32, v2:in:ref, field_id acc: none format: [op_v1_4_v2_4_id_16] + opcode_idx: [0x86] - sig: stobj.v.64 v1:in:b64, v2:in:ref, field_id acc: none format: [op_v1_4_v2_4_id_16] + opcode_idx: [0x87] - sig: stobj.v.obj v1:in:ref, v2:in:ref, field_id acc: none format: [op_v1_4_v2_4_id_16] + opcode_idx: [0x88] - title: Get static field description: > Get static field value by field_id and put it into accumulator. For non-object variant, the size of the field is determined by the field_id, most significant bits are sign or unsigned extended based on the field type to fit accumulator size. - If field size is less than 32, result will be sign or unsigned extended to i32 depending on field type. - If field type is f32, result will be implicitly converted from f32 to f64. + If field size is less then 32, result will be sign or unsigned extended to i32 depedning on field type. verification: - field_id_static - field_id_size @@ -2326,8 +2658,6 @@ groups: field = resolve(field_id) if op == ldstatic and size(field) < 32 then acc = extendto32(get_static(field)) - else if type(field) == f32 then - acc = f32tof64(get_static(field)) else acc = get_static(field) end @@ -2335,21 +2665,23 @@ groups: skip instructions: - sig: ldstatic field_id - acc: out:i32 + acc: out:b32 format: [op_id_16] + opcode_idx: [0x89] - sig: ldstatic.64 field_id acc: out:b64 format: [op_id_16] + opcode_idx: [0x8a] - sig: ldstatic.obj field_id acc: out:ref format: [op_id_16] + opcode_idx: [0x8b] - title: Store to static field description: > Store accumulator content into static field by field_id. For non-object variant the size of actually stored value is determined by field_id, other accumulator bits are discarded. - If field type size is less than 32, then accumulator content will be truncated to field size before storing. - If field type is f32, accumulator content will be implicitly converted from f64 to f32 before storing. + If field type size is less than 32, then accumulator content will be trunctated to field size before storing. verification: - field_id_static - field_id_size @@ -2363,8 +2695,6 @@ groups: field = resolve(field_id) if op == ststatic and size(field) < 32 then set_static(field, truncate(field, acc)) - else if type(field) == f32 then - set_static(field, f64tof32(acc)) else set_static(field, acc) end @@ -2372,14 +2702,17 @@ groups: skip instructions: - sig: ststatic field_id - acc: in:i32 + acc: in:b32 format: [op_id_16] + opcode_idx: [0x8c] - sig: ststatic.64 field_id acc: in:b64 format: [op_id_16] + opcode_idx: [0x8d] - sig: ststatic.obj field_id acc: in:ref format: [op_id_16] + opcode_idx: [0x8e] - title: Return value from method description: > @@ -2400,12 +2733,15 @@ groups: - sig: return acc: in:i32 format: [op_none] + opcode_idx: [0x8f] - sig: return.64 acc: in:b64 format: [op_none] + opcode_idx: [0x90] - sig: return.obj acc: in:ref format: [op_none] + opcode_idx: [0x91] - title: Return from a void method description: > @@ -2427,6 +2763,7 @@ groups: - sig: return.void acc: none format: [op_none] + opcode_idx: [0x92] - title: Throw exception description: > @@ -2451,6 +2788,7 @@ groups: - sig: throw v:in:ref acc: none format: [op_v_8] + opcode_idx: [0x93] - title: Check cast description: > @@ -2479,6 +2817,7 @@ groups: - sig: checkcast type_id acc: in:ref format: [op_id_16] + opcode_idx: [0x94] - title: Is instance description: > @@ -2509,6 +2848,7 @@ groups: - sig: isinstance type_id acc: inout:ref->i32 format: [op_id_16] + opcode_idx: [0x95] - title: Static call description: > @@ -2551,12 +2891,15 @@ groups: - sig: call.short method_id, v1:in:top, v2:in:top acc: out:top format: [op_v1_4_v2_4_id_16] + opcode_idx: [0x96] - sig: call method_id, v1:in:top, v2:in:top, v3:in:top, v4:in:top acc: out:top format: [op_v1_4_v2_4_v3_4_v4_4_id_16] + opcode_idx: [0x97] - sig: call.range method_id, v:in:top acc: out:top format: [op_v_8_id_16] + opcode_idx: [0x98] - title: Static call with accumulator as input description: > @@ -2603,9 +2946,11 @@ groups: - sig: call.acc.short method_id, v:in:top, imm:u1 acc: inout:top format: [op_v_4_imm_4_id_16] + opcode_idx: [0x99] - sig: call.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 acc: inout:top format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + opcode_idx: [0x9a] - title: Object calls description: > @@ -2651,12 +2996,15 @@ groups: - sig: call.virt.short method_id, v1:in:top, v2:in:top acc: out:top format: [op_v1_4_v2_4_id_16] + opcode_idx: [0x9b] - sig: call.virt method_id, v1:in:top, v2:in:top, v3:in:top, v4:in:top acc: out:top format: [op_v1_4_v2_4_v3_4_v4_4_id_16] + opcode_idx: [0x9c] - sig: call.virt.range method_id, v:in:top acc: out:top format: [op_v_8_id_16] + opcode_idx: [0x9d] - title: Object calls with accumulator as input description: > @@ -2712,9 +3060,11 @@ groups: - sig: call.virt.acc.short method_id, v:in:top, imm:u1 acc: inout:top format: [op_v_4_imm_4_id_16] + opcode_idx: [0x9e] - sig: call.virt.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 acc: inout:top format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + opcode_idx: [0x9f] - title: Dynamic move register-to-register description: > @@ -2734,6 +3084,7 @@ groups: - sig: mov.dyn v1:out:any, v2:in:any acc: none format: [op_v1_8_v2_8, op_v1_16_v2_16] + opcode_idx: [0xa0, 0xa1] - title: Dynamic load accumulator from register description: > @@ -2753,6 +3104,7 @@ groups: - sig: lda.dyn v:in:any acc: out:any format: [op_v_8] + opcode_idx: [0xa2] - title: Dynamic store accumulator description: > @@ -2772,6 +3124,7 @@ groups: - sig: sta.dyn v:out:any acc: in:any format: [op_v_8] + opcode_idx: [0xa3] - title: Dynamic load accumulator from immediate description: > @@ -2791,9 +3144,11 @@ groups: - sig: ldai.dyn imm:i32 acc: out:any format: [op_imm_32] + opcode_idx: [0xa4] - sig: fldai.dyn imm:f64 acc: out:any format: [op_imm_64] + opcode_idx: [0xa5] properties: [acc_write, float, dynamic] - title: Dynamic return from method @@ -2815,6 +3170,7 @@ groups: - sig: return.dyn acc: in:any format: [op_none] + opcode_idx: [0xa6] - title: Dynamic indirect call description: > @@ -2846,9 +3202,12 @@ groups: - sig: calli.dyn.short imm, v1:in:any, v2:in:any, v3:in:any acc: out:any format: [op_imm_4_v1_4_v2_4_v3_4] + opcode_idx: [0xa7] - sig: calli.dyn imm, v1:in:any, v2:in:any, v3:in:any, v4:in:any, v5:in:any acc: out:any format: [op_imm_4_v1_4_v2_4_v3_4_v4_4_v5_4] + opcode_idx: [0xa8] - sig: calli.dyn.range imm, v:in:any acc: out:any format: [op_imm_16_v_16] + opcode_idx: [0xa9] diff --git a/isa/isapi.rb b/isa/isapi.rb index 616d2723b6..e16735ed9a 100755 --- a/isa/isapi.rb +++ b/isa/isapi.rb @@ -14,6 +14,13 @@ require 'delegate' require 'ostruct' require 'digest' +require 'set' + +module Enumerable + def stable_sort_by + sort_by.with_index { |x, idx| [yield(x), idx] } + end +end module Util module_function @@ -88,6 +95,11 @@ class Instruction < SimpleDelegator Panda.prefixes_hash[name] if name end + # Suggested handler name + def handler_name + opcode.upcase + end + def opcode_idx if prefix dig(:opcode_idx) << 8 | prefix.opcode_idx @@ -161,8 +173,8 @@ class Instruction < SimpleDelegator !exceptions.include? 'x_none' end - def public? - !/^builtin\./.match(mnemonic) + def builtin? + /^builtin\./.match(mnemonic) end # Size of source operand @@ -174,6 +186,24 @@ class Instruction < SimpleDelegator cached def dest_op_size dtype[1..-1].to_i end + + def namespace + dig(:namespace) || "core" + end +end + +class Prefix < SimpleDelegator + # Suggested handler name + def handler_name + name.upcase + end +end + +# Dummy class for invalid handlers +class Invalid + def handler_name + 'INVALID' + end end # Methods over format names @@ -238,7 +268,7 @@ class Operand end @srcdst = srcdst.to_sym || :in - types = %i[none u1 u2 i8 u8 i16 u16 i32 u32 f32 i64 u64 b64 f64 ref top any] + types = %i[none u1 u2 i8 u8 i16 u16 i32 u32 b32 f32 i64 u64 b64 f64 ref top any] raise "Incorrect type #{type}" unless types.include?(type.sub('[]', '').to_sym) @type = type @@ -279,33 +309,28 @@ end class DispatchTable # Canonical order of dispatch table consisting of # * non-prefixed instructions handlers + # * invalid handlers # * prefix handlers that re-dispatch to prefixed instruction based on second byte of opcode_idx # * prefixed instructions handlers, in the order of prefixes # Return array with proposed handler names def handler_names - names = Panda.instructions.reject(&:prefix).map { |i| instruction_handler_name(i) } + - Panda.prefixes.map { |p| prefix_hanlder_name(p) } + handlers = Panda.instructions.reject(&:prefix) + + Array.new(invalid_non_prefixed_interval.size, Invalid.new) + + Panda.prefixes.select(&:public?) + + Array.new(invalid_prefixes_interval.size, Invalid.new) + + Panda.prefixes.reject(&:public?) + + Panda.instructions.select(&:prefix).stable_sort_by { |i| Panda.prefixes_hash[i.prefix.name].opcode_idx } - Panda.prefixes.each do |p| - Panda.instructions.select { |i| i.prefix && (i.prefix.name == p.name) }.each do |i| - names << instruction_handler_name(i) - end - end - - names + handlers.map(&:handler_name) end - def instruction_handler_name(insn) - insn.opcode.upcase + def invalid_non_prefixed_interval + (Panda.instructions.reject(&:prefix).map(&:opcode_idx).max + 1)..(Panda.prefixes.map(&:opcode_idx).min - 1) end - def prefix_hanlder_name(prefix) - prefix.name.upcase - end - - # Maximum value for primary dispatch index, i.e. the maximum value of first byte of opcode_idx - def primary_opcode_bound - Panda.prefixes.map(&:opcode_idx).max + def invalid_prefixes_interval + max_invalid_idx = Panda.prefixes.reject(&:public?).map(&:opcode_idx).min || 256 + (Panda.prefixes.select(&:public?).map(&:opcode_idx).max + 1)..(max_invalid_idx - 1) end # Maximum value for secondary dispatch index for given prefix name @@ -317,8 +342,7 @@ class DispatchTable # Offset in dispatch table for handlers of instructions for given prefix name def secondary_opcode_offset(prefix) @prefix_data ||= prefix_data - @first_prefixed_idx ||= first_prefixed_idx - @first_prefixed_idx + @prefix_data[prefix.name][:delta] + 256 + @prefix_data[prefix.name][:delta] end private @@ -331,9 +355,45 @@ class DispatchTable cur_delta += prefix_instructions_num end end +end + +# Auxilary classes for opcode assignment +class OpcodeAssigner + def initialize + @table = Hash.new { |h, k| h[k] = Set.new } + @all_opcodes = Set.new(0..255) + end + + def consume(item) + raise 'Cannot consume instruction without opcode' unless item.opcode_idx + + @table[prefix(item)] << item.opcode_idx + end + + def yield_opcode(item) + return item.opcode_idx if item.opcode_idx + + opcodes = @table[prefix(item)] + choose_opcode(opcodes) + end + + private - def first_prefixed_idx - Panda.instructions.reject(&:prefix).size + Panda.prefixes.size + def choose_opcode(occupied_opcodes) + (@all_opcodes - occupied_opcodes).min + end + + def prefix(item) + item.prefix.nil? ? 'non_prefixed' : item.prefix + end +end + +class PrefixOpcodeAssigner < OpcodeAssigner + private + + # override opcodes assignment for prefixes + def choose_opcode(occupied_opcodes) + (@all_opcodes - occupied_opcodes).max end end @@ -368,37 +428,33 @@ module Panda # Hash from format names to Format instances cached def format_hash - each_data_instruction_with_object([]) do |_, instruction, fmts| - instruction.format.each do |f| - fmts << [f, Format.new(f)] - end + each_data_instruction.with_object([]) do |instruction, fmts| + fmt_name = instruction.format + fmts << [fmt_name, Format.new(fmt_name)] end.to_h end # Array of Instruction instances for every possible instruction - cached def instructions - opcode_idxs = Hash.new(0) - # create separate instance for every instruction format and inherit group properties - each_data_instruction_with_object([]) do |group, instruction, insns| - props = group.to_h - props.delete(:instructions) - insn = props.merge(instruction.to_h) # instruction may override group props - instruction.format.each do |f| - insn[:format] = f - prefix_key = insn[:prefix].nil? ? 'non_prefixed' : insn[:prefix] - insn[:opcode_idx] = opcode_idxs[prefix_key] - opcode_idxs[prefix_key] += 1 - insns << Instruction.new(OpenStruct.new(insn)) - end + def instructions + unless defined? @instructions + opcodes = OpcodeAssigner.new + tmp_public = initialize_instructions(opcodes) { |ins| !ins.opcode_idx.nil? } + tmp_private = initialize_instructions(opcodes) { |ins| ins.opcode_idx.nil? } + tmp = tmp_public + tmp_private + @instructions = tmp.sort_by(&:opcode_idx) end + @instructions end - cached def prefixes - non_prefixed_num = groups.flat_map(&:instructions).reject(&:prefix).flat_map(&:format).size - dig(:prefixes).each_with_index do |p, idx| - p.opcode_idx = idx + non_prefixed_num + def prefixes + unless defined? @prefixes + opcodes = PrefixOpcodeAssigner.new + tmp_public = initialize_prefixes(opcodes) { |p| !p.opcode_idx.nil? } + tmp_private = initialize_prefixes(opcodes) { |p| p.opcode_idx.nil? } + tmp = tmp_public + tmp_private + @prefixes = tmp.sort_by(&:opcode_idx) end - dig(:prefixes) + @prefixes end cached def dispatch_table @@ -410,11 +466,6 @@ module Panda format_hash.values.uniq(&:pretty).sort_by(&:pretty) end - # 32-bit checksum of data YAML file - def checksum - Digest::MD5.hexdigest(@data.to_s).to_i(16) & 0xffffffff - end - # delegating part of module # def wrap_data(data) @@ -441,11 +492,42 @@ module Panda hash end - private_class_method def each_data_instruction_with_object(object) - groups.each_with_object(object) do |g, obj| + private_class_method def each_data_instruction + # create separate instance for every instruction format and inherit group properties + @each_data_instruction ||= groups.each_with_object([]) do |g, obj| g.instructions.each do |i| - yield(g, i, obj) + props = g.to_h + props.delete(:instructions) + data_insn = props.merge(i.to_h) # instruction may override group props + if data_insn[:opcode_idx] && (data_insn[:opcode_idx].size != data_insn[:format].size) + raise 'format and opcode_idx arrays should have equal size' + end + + data_insn[:format].each_with_index do |f, idx| + insn = data_insn.dup + insn[:format] = f + insn[:opcode_idx] = data_insn[:opcode_idx][idx] if data_insn[:opcode_idx] + obj << OpenStruct.new(insn) + end end + end.to_enum + end + + private_class_method def initialize_instructions(opcodes, &block) + each_data_instruction.select(&block).each_with_object([]) do |instruction, insns| + instruction[:public?] = !instruction.opcode_idx.nil? + instruction.opcode_idx = opcodes.yield_opcode(instruction) + opcodes.consume(instruction) + insns << Instruction.new(instruction) + end + end + + private_class_method def initialize_prefixes(opcodes, &block) + dig(:prefixes).select(&block).each_with_object([]) do |p, res| + p[:public?] = !p.opcode_idx.nil? + p.opcode_idx = opcodes.yield_opcode(p) + opcodes.consume(p) + res << Prefix.new(p) end end end diff --git a/ldscripts/panda.ld b/ldscripts/panda.ld index 916a6b2b9a..d677cc936a 100644 --- a/ldscripts/panda.ld +++ b/ldscripts/panda.ld @@ -68,7 +68,7 @@ SECTIONS { .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } - + .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) diff --git a/ldscripts/panda_test_asan.ld b/ldscripts/panda_test_asan.ld index 0e163b5308..e21f6913bc 100644 --- a/ldscripts/panda_test_asan.ld +++ b/ldscripts/panda_test_asan.ld @@ -358,4 +358,3 @@ SECTIONS { /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } - \ No newline at end of file diff --git a/libpandabase/os/filesystem.cpp b/libpandabase/os/filesystem.cpp index c4596cd675..e7f62c17c3 100644 --- a/libpandabase/os/filesystem.cpp +++ b/libpandabase/os/filesystem.cpp @@ -15,7 +15,7 @@ #include "os/filesystem.h" #include "macros.h" -#if defined PANDA_TARGET_MOBILE || defined PANDA_TARGET_LINUX || defined PANDA_TARGET_ARM32 ||\ +#if defined PANDA_TARGET_MOBILE || defined PANDA_TARGET_LINUX || defined PANDA_TARGET_ARM32 || \ defined PANDA_TARGET_ARM64 #include #endif diff --git a/libpandafile/BUILD.gn b/libpandafile/BUILD.gn index 439f0bd7a0..200373ac2a 100644 --- a/libpandafile/BUILD.gn +++ b/libpandafile/BUILD.gn @@ -31,7 +31,7 @@ config("arkfile_public_config") { libarkfile_sources = [ "annotation_data_accessor.cpp", - "ark_version.cpp", + "file_format_version.cpp", "bytecode_emitter.cpp", "class_data_accessor.cpp", "code_data_accessor.cpp", @@ -64,7 +64,7 @@ ohos_shared_library("libarkfile") { ":isa_gen_libarkfile_bytecode_emitter_gen_h", ":isa_gen_libarkfile_bytecode_instruction-inl_gen_h", ":isa_gen_libarkfile_bytecode_instruction_enum_gen_h", - ":isa_gen_libarkfile_isa_checksum_h", + ":isa_gen_libarkfile_file_format_version_h", ":isa_gen_libarkfile_tests_bytecode_emitter_tests_gen_h", ":libarkfile_bytecode_builtin_enum_gen_h", ":libarkfile_type_gen_h", @@ -90,7 +90,7 @@ ohos_static_library("libarkfile_frontend_static") { ":isa_gen_libarkfile_bytecode_emitter_gen_h", ":isa_gen_libarkfile_bytecode_instruction-inl_gen_h", ":isa_gen_libarkfile_bytecode_instruction_enum_gen_h", - ":isa_gen_libarkfile_isa_checksum_h", + ":isa_gen_libarkfile_file_format_version_h", ":isa_gen_libarkfile_tests_bytecode_emitter_tests_gen_h", ":libarkfile_bytecode_builtin_enum_gen_h", ":libarkfile_type_gen_h", @@ -120,7 +120,7 @@ ark_isa_gen("isa_gen_libarkfile") { "bytecode_instruction-inl_gen.h.erb", "bytecode_emitter_def_gen.h.erb", "bytecode_emitter_gen.h.erb", - "isa_checksum.h.erb", + "file_format_version.h.erb", "tests/bytecode_emitter_tests_gen.h.erb", ] sources = "templates" ## ark_root/templates diff --git a/libpandafile/CMakeLists.txt b/libpandafile/CMakeLists.txt index c5c9f6b04a..ebfb611914 100644 --- a/libpandafile/CMakeLists.txt +++ b/libpandafile/CMakeLists.txt @@ -24,7 +24,7 @@ set(TEMPLATES bytecode_instruction-inl_gen.h.erb bytecode_emitter_def_gen.h.erb bytecode_emitter_gen.h.erb - isa_checksum.h.erb + file_format_version.h.erb tests/bytecode_emitter_tests_gen.h.erb ) @@ -69,7 +69,7 @@ set(SOURCES method_handle_data_accessor.cpp debug_info_extractor.cpp literal_data_accessor.cpp - ark_version.cpp + file_format_version.cpp ) add_library(arkfile ${PANDA_DEFAULT_LIB_TYPE} ${SOURCES}) @@ -100,7 +100,7 @@ panda_add_gtest( tests/bytecode_emitter_tests.cpp tests/debug_info_extractor_test.cpp tests/panda_cache_test.cpp - tests/ark_version_test.cpp + tests/file_format_version_test.cpp LIBRARIES arkbase arkfile diff --git a/libpandafile/bytecode_instruction.h b/libpandafile/bytecode_instruction.h index ac57270da5..36051a1fa5 100644 --- a/libpandafile/bytecode_instruction.h +++ b/libpandafile/bytecode_instruction.h @@ -248,6 +248,8 @@ public: return static_cast(GetOpcode()) & std::numeric_limits::max(); } + bool IsPrimaryOpcodeValid() const; + uint8_t GetSecondaryOpcode() const { // NOLINTNEXTLINE(hicpp-signed-bitwise) @@ -255,11 +257,6 @@ public: std::numeric_limits::max(); } - bool IsOpcodeEqual(Opcode opcode) const - { - return GetOpcode() == opcode; - } - template auto JumpTo(int32_t offset) const -> std::enable_if_t { @@ -356,16 +353,7 @@ public: bool IsTerminator() const { - return HasFlag(Flags::RETURN) || HasFlag(Flags::JUMP) || IsOpcodeEqual(Opcode::THROW_V8); - } - - bool IsMonitor() const - { - if (!IsOpcodeEqual(Opcode::BUILTIN_ACC_IMM8)) { - return false; - } - auto sub_opcode = static_cast(GetImm()); - return BUILTIN_ACC::MONITORENTER_IMM8 == sub_opcode || BUILTIN_ACC::MONITOREXIT_IMM8 == sub_opcode; + return HasFlag(Flags::RETURN) || HasFlag(Flags::JUMP) || (GetOpcode() == Opcode::THROW_V8); } static constexpr bool HasId(Format format, size_t idx); diff --git a/libpandafile/file.cpp b/libpandafile/file.cpp index a5138f1ee5..39773442b3 100644 --- a/libpandafile/file.cpp +++ b/libpandafile/file.cpp @@ -13,9 +13,8 @@ * limitations under the License. */ -#include "ark_version.h" +#include "file_format_version.h" #include "file-inl.h" -#include "isa_checksum.h" #include "os/file.h" #include "os/mem.h" #include "mem/mem.h" @@ -36,6 +35,7 @@ #include #include +#include #include #include #include @@ -457,6 +457,19 @@ File::~File() AnonMemSet::GetInstance().Remove(FILENAME); } +inline std::string VersionToString(const std::array &array) +{ + std::stringstream ss; + + for (size_t i = 0; i < File::VERSION_SIZE - 1; ++i) { + ss << static_cast(array[i]); + ss << "."; + } + ss << static_cast(array[File::VERSION_SIZE - 1]); + + return ss.str(); +} + /* static */ std::unique_ptr File::Open(std::string_view filename, OpenMode open_mode) { @@ -490,25 +503,23 @@ std::unique_ptr File::Open(std::string_view filename, OpenMode open_ return nullptr; } - uint32_t isa_checksum = 0; - if (!file.ReadAll(&isa_checksum, sizeof(uint32_t))) { - LOG(ERROR, PANDAFILE) << "Failed to read isa's checksum of panda file '" << filename << "'"; - return nullptr; - } - std::array buf {}; if (!file.ReadAll(&buf[0], buf.size())) { return nullptr; } - std::array min_version_local {0, 0, 0, 1}; - if (buf < min_version_local) { - std::stringstream ss; - ss << "Unable to open file '" << filename << "' with bytecode version " << buf[0U] << "."; - ss << buf[1U] << "." << buf[2U] << "." << buf[3U] << ". Minimum supported version is "; - ss << min_version_local[0U] << "." << min_version_local[1U] << "." << min_version_local[2U] << "." - << min_version_local[3U]; - LOG(ERROR, PANDAFILE) << ss.str(); - + if (buf < minVersion || buf > version) { + LOG(ERROR, PANDAFILE) << "Unable to open file '" << filename + << "' with bytecode version " // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_INDENT_CHECK) + << VersionToString(buf); + if (buf < minVersion) { + LOG(ERROR, PANDAFILE) + << "Minimum supported version is " // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_INDENT_CHECK) + << VersionToString(minVersion); + } else { + LOG(ERROR, PANDAFILE) + << "Maximum supported version is " // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_INDENT_CHECK) + << VersionToString(version); + } return nullptr; } @@ -518,10 +529,6 @@ std::unique_ptr File::Open(std::string_view filename, OpenMode open_ return nullptr; } - if (!CheckHeader(ptr, filename)) { - return nullptr; - } - // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER, CPP_RULE_ID_NO_USE_NEW_UNIQUE_PTR) return std::unique_ptr(new File(filename.data(), std::move(ptr))); } @@ -556,17 +563,13 @@ std::unique_ptr File::OpenUncompressedArchive(int fd, const std::str return std::unique_ptr(new File(filename.data(), std::move(ptr))); } -bool CheckHeader(const os::mem::ConstBytePtr &ptr, const std::string_view &filename, bool check_isa_checksum) +bool CheckHeader(const os::mem::ConstBytePtr &ptr, const std::string_view &filename) { auto header = reinterpret_cast(ptr.Get()); if (header->magic != File::MAGIC) { LOG(ERROR, PANDAFILE) << "Invalid panda file '" << filename << "'"; return false; } - if (check_isa_checksum && header->isa_checksum != ISA_CHECKSUM) { - LOG(ERROR, PANDAFILE) << "Isa checksums mismatch in panda file '" << filename << "'"; - return false; - } return true; } @@ -580,10 +583,6 @@ std::unique_ptr File::OpenFromMemory(os::mem::ConstBytePtr &&ptr) return nullptr; } - if (!CheckHeader(ptr)) { - return nullptr; - } - if (header->file_size < sizeof(File::Header)) { LOG(ERROR, PANDAFILE) << "Invalid panda file"; return nullptr; @@ -604,10 +603,6 @@ std::unique_ptr File::OpenFromMemory(os::mem::ConstBytePtr &&ptr, st return nullptr; } - if (!CheckHeader(ptr, filename)) { - return nullptr; - } - if (header->file_size < sizeof(File::Header)) { LOG(ERROR, PANDAFILE) << "Invalid panda file '" << filename << "'"; return nullptr; diff --git a/libpandafile/file.h b/libpandafile/file.h index 01b7e6b2ee..50a25740bd 100644 --- a/libpandafile/file.h +++ b/libpandafile/file.h @@ -44,7 +44,6 @@ public: struct Header { std::array magic; uint32_t checksum; - uint32_t isa_checksum; std::array version; uint32_t file_size; uint32_t foreign_off; @@ -367,10 +366,9 @@ std::unique_ptr OpenPandaFileFromZipFILE(FILE *inputfile std::string_view archive_filename); /* - * Check ptr point valid panda file: magic/isa_checksum + * Check ptr point valid panda file: magic */ -bool CheckHeader(const os::mem::ConstBytePtr &ptr, const std::string_view &filename = "", - bool check_isa_checksum = true); +bool CheckHeader(const os::mem::ConstBytePtr &ptr, const std::string_view &filename = ""); // NOLINTNEXTLINE(readability-identifier-naming) extern const char *ARCHIVE_FILENAME; diff --git a/libpandafile/file_format_version.cpp b/libpandafile/file_format_version.cpp new file mode 100644 index 0000000000..854da31c1d --- /dev/null +++ b/libpandafile/file_format_version.cpp @@ -0,0 +1,37 @@ +/* + * 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 "file_format_version.h" + +#include +#include + +namespace panda::panda_file { + +std::string GetVersion(const std::array &v) +{ + std::string versionstr; + for (size_t i = 0; i < File::VERSION_SIZE; i++) { + versionstr += std::to_string(v[i]); + if (i == (File::VERSION_SIZE - 1)) { + break; + } + versionstr += "."; + } + + return versionstr; +} + +} // namespace panda::panda_file diff --git a/libpandafile/file_item_container.cpp b/libpandafile/file_item_container.cpp index d6c89ac412..e941008b85 100644 --- a/libpandafile/file_item_container.cpp +++ b/libpandafile/file_item_container.cpp @@ -15,11 +15,10 @@ #include "file_item_container.h" +#include "file_format_version.h" #include "file-inl.h" #include "helpers.h" -#include "isa_checksum.h" #include "macros.h" -#include "ark_version.h" #include @@ -586,11 +585,6 @@ bool ItemContainer::WriteHeader(Writer *writer, ssize_t *checksum_offset) } writer->CountChecksum(true); - uint32_t isa_checksum = ISA_CHECKSUM; - if (!writer->Write(isa_checksum)) { - return false; - } - std::vector versionVec(std::begin(version), std::end(version)); if (!writer->WriteBytes(versionVec)) { return false; diff --git a/libpandafile/file_items.h b/libpandafile/file_items.h index 618c767839..077d7388d7 100644 --- a/libpandafile/file_items.h +++ b/libpandafile/file_items.h @@ -17,11 +17,11 @@ #define PANDA_LIBPANDAFILE_FILE_ITEMS_H_ #include "file.h" +#include "file_format_version.h" #include "file_writer.h" #include "macros.h" #include "modifiers.h" #include "type.h" -#include "ark_version.h" #include #include diff --git a/libpandafile/literal_data_accessor-inl.h b/libpandafile/literal_data_accessor-inl.h index 9c5202e1ef..e79d8d6faf 100644 --- a/libpandafile/literal_data_accessor-inl.h +++ b/libpandafile/literal_data_accessor-inl.h @@ -63,6 +63,9 @@ inline void LiteralDataAccessor::EnumerateLiteralVals(File::EntityId id, const C case LiteralTag::GENERATORMETHOD: value = static_cast(helpers::Read(&sp)); break; + case LiteralTag::METHODAFFILIATE: + value = static_cast(helpers::Read(&sp)); + break; case LiteralTag::ACCESSOR: case LiteralTag::NULLVALUE: value = static_cast(helpers::Read(&sp)); diff --git a/libpandafile/literal_data_accessor.h b/libpandafile/literal_data_accessor.h index 0915527bcf..943c6c3cea 100644 --- a/libpandafile/literal_data_accessor.h +++ b/libpandafile/literal_data_accessor.h @@ -37,14 +37,15 @@ enum class LiteralTag : uint8_t { METHOD = 0x06, GENERATORMETHOD = 0x07, ACCESSOR = 0x08, - NULLVALUE = 0x09, + METHODAFFILIATE = 0x09, ARRAY_I8 = 0x0a, ARRAY_I16 = 0x0b, ARRAY_I32 = 0x0c, ARRAY_I64 = 0x0d, ARRAY_F32 = 0x0e, ARRAY_F64 = 0x0f, - ARRAY_STRING = 0x10 + ARRAY_STRING = 0x10, + NULLVALUE = 0xff }; class LiteralDataAccessor { diff --git a/libpandafile/templates/bytecode_instruction-inl_gen.h.erb b/libpandafile/templates/bytecode_instruction-inl_gen.h.erb index b3577a2534..f498cdb9fd 100644 --- a/libpandafile/templates/bytecode_instruction-inl_gen.h.erb +++ b/libpandafile/templates/bytecode_instruction-inl_gen.h.erb @@ -373,3 +373,21 @@ inline bool BytecodeInst::IsBuiltin() const return false; } } + +template +inline bool BytecodeInst::IsPrimaryOpcodeValid() const +{ + auto opcode = GetPrimaryOpcode(); + // NOLINTNEXTLINE(readability-magic-numbers) + if (((opcode >= <%= Panda::dispatch_table.invalid_non_prefixed_interval.min %>) && + // NOLINTNEXTLINE(readability-magic-numbers) + (opcode <= <%= Panda::dispatch_table.invalid_non_prefixed_interval.max %>)) || + // NOLINTNEXTLINE(readability-magic-numbers) + ((opcode >= <%= Panda::dispatch_table.invalid_prefixes_interval.min %>) && + // NOLINTNEXTLINE(readability-magic-numbers) + (opcode <= <%= Panda::dispatch_table.invalid_prefixes_interval.max %>))) { + // NOLINTNEXTLINE(readability-simplify-boolean-expr) + return false; + } + return true; +} diff --git a/libpandafile/templates/file_format_version.h.erb b/libpandafile/templates/file_format_version.h.erb new file mode 100644 index 0000000000..97dae4903e --- /dev/null +++ b/libpandafile/templates/file_format_version.h.erb @@ -0,0 +1,43 @@ +/* + * 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. + */ + +#ifndef LIBPANDAFILE_FILE_FORMAT_VERSION_H +#define LIBPANDAFILE_FILE_FORMAT_VERSION_H + +#include +#include +#include + +#include "file.h" + +namespace panda::panda_file { +constexpr std::array version {<%= Panda::version.split('.').join(', ') %>}; +constexpr std::array minVersion {<%= Panda::min_version.split('.').join(', ') %>}; + +std::string GetVersion(const std::array &version); + +inline void PrintBytecodeVersion() +{ + std::stringstream ss; + + ss << "Bytecode version " << GetVersion(version) << '\n'; + ss << "Minimum supported bytecode version " << GetVersion(minVersion) << '\n'; + + std::cout << ss.str() << std::endl; +} + +} // namespace panda::panda_file + +#endif diff --git a/libpandafile/tests/bytecode_emitter_tests.cpp b/libpandafile/tests/bytecode_emitter_tests.cpp index e03c22c50c..e610be02eb 100644 --- a/libpandafile/tests/bytecode_emitter_tests.cpp +++ b/libpandafile/tests/bytecode_emitter_tests.cpp @@ -746,4 +746,4 @@ void TestNoneFormat(Opcode opcode, std::function emit) #include -} // namespace panda \ No newline at end of file +} // namespace panda diff --git a/libpandafile/tests/file_format_version_test.cpp b/libpandafile/tests/file_format_version_test.cpp new file mode 100644 index 0000000000..4e3c16d70f --- /dev/null +++ b/libpandafile/tests/file_format_version_test.cpp @@ -0,0 +1,47 @@ +/* + * 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 "file_format_version.h" + +#include + +namespace panda::panda_file::test { +TEST(File, TestGetVersion) +{ + std::string versionstr; + for (size_t i = 0; i < File::VERSION_SIZE; i++) { + versionstr += std::to_string(version[i]); + if (i == (File::VERSION_SIZE - 1)) { + break; + } + versionstr += "."; + } + EXPECT_EQ(GetVersion(version), versionstr); +} + +TEST(File, GetMinVersion) +{ + std::string versionstr; + for (size_t i = 0; i < File::VERSION_SIZE; i++) { + versionstr += std::to_string(minVersion[i]); + if (i == (File::VERSION_SIZE - 1)) { + break; + } + versionstr += "."; + } + EXPECT_EQ(GetVersion(minVersion), versionstr); +} + +} // namespace panda::panda_file::test diff --git a/libpandafile/tests/file_item_container_test.cpp b/libpandafile/tests/file_item_container_test.cpp index 53453b1f01..5f86c7ee99 100644 --- a/libpandafile/tests/file_item_container_test.cpp +++ b/libpandafile/tests/file_item_container_test.cpp @@ -19,9 +19,9 @@ #include "debug_data_accessor-inl.h" #include "field_data_accessor-inl.h" #include "file.h" +#include "file_format_version.h" #include "file_item_container.h" #include "file_writer.h" -#include "isa_checksum.h" #include "helpers.h" #include "method_data_accessor-inl.h" #include "method_handle_data_accessor.h" @@ -95,8 +95,11 @@ TEST(ItemContainer, TestFileFormatVersionTooOld) File::Header header = {}; header.magic = File::MAGIC; - header.isa_checksum = ISA_CHECKSUM; - header.version = {0, 0, 0, 0}; + + auto old = std::array(minVersion); + --old[3]; + + header.version = old; header.file_size = sizeof(File::Header); for (uint8_t b : Span(reinterpret_cast(&header), sizeof(header))) { @@ -107,17 +110,20 @@ TEST(ItemContainer, TestFileFormatVersionTooOld) EXPECT_EQ(File::Open(file_name), nullptr); } -TEST(ItemContainer, TestFileFormatVersionValid) +TEST(ItemContainer, TestFileFormatVersionTooNew) { - const std::string file_name = "test_file_format_version_valid.abc"; + const std::string file_name = "test_file_format_version_too_new.abc"; { ItemContainer container; auto writer = FileWriter(file_name); File::Header header = {}; header.magic = File::MAGIC; - header.isa_checksum = ISA_CHECKSUM; - header.version = {0, 0, 0, 2}; + + auto new_ = std::array(minVersion); + ++new_[3]; + + header.version = new_; header.file_size = sizeof(File::Header); for (uint8_t b : Span(reinterpret_cast(&header), sizeof(header))) { @@ -125,124 +131,28 @@ TEST(ItemContainer, TestFileFormatVersionValid) } } - EXPECT_NE(File::Open(file_name), nullptr); + EXPECT_EQ(File::Open(file_name), nullptr); } -TEST(ItemContainer, TestIsaChecksumMismatch) +TEST(ItemContainer, TestFileFormatVersionValid) { - using panda::os::file::Mode; - using panda::os::file::Open; - - // 1. Write panda file to disk - - // 1.1. Create data members from ItemContainer - - std::unordered_map string_map; - - std::map class_map; - - std::unordered_map i_value_map; - std::unordered_map l_value_map; - std::unordered_map f_value_map; - std::unordered_map d_value_map; - std::unordered_map id_value_map; - - std::vector> items; - std::vector> foreign_items; - - // 1.2 Create a file handler - - const std::string file_name = "test_isa_checksum_mismatch.panda"; - auto writer = FileWriter(file_name); - - // 1.3 Body of function ItemContainer::ComputeLayout - - uint32_t num_classes = class_map.size(); - uint32_t class_idx_offset = sizeof(File::Header); - uint32_t cur_offset = class_idx_offset + num_classes * ID_SIZE; - - for (auto &item : foreign_items) { - cur_offset = RoundUp(cur_offset, item->Alignment()); - item->SetOffset(cur_offset); - item->ComputeLayout(); - cur_offset += item->GetSize(); - } - - for (auto &item : items) { - if (!item->NeedsEmit()) { - continue; - } - - cur_offset = RoundUp(cur_offset, item->Alignment()); - item->SetOffset(cur_offset); - item->ComputeLayout(); - cur_offset += item->GetSize(); - } - - uint32_t offset = cur_offset; - - // 1.4 Body of function ItemContainer::Write - - // Write header - - std::vector magic; - magic.assign(File::MAGIC.cbegin(), File::MAGIC.cend()); - ASSERT_TRUE(writer.WriteBytes(magic)); - - uint32_t checksum = 0; - ASSERT_TRUE(writer.Write(checksum)); - - uint32_t wrong_isa_checksum = 0; - ASSERT_TRUE(writer.Write(wrong_isa_checksum)); - - std::vector version {0, 0, 0, 1}; - ASSERT_TRUE(writer.WriteBytes(version)); - - ASSERT_TRUE(writer.Write(offset)); - - uint32_t foreign_offset = 0; - if (!foreign_items.empty()) { - foreign_offset = foreign_items.front()->GetOffset(); - } - - ASSERT_TRUE(writer.Write(foreign_offset)); - - uint32_t foreign_size = 0; - if (!foreign_items.empty()) { - size_t begin = foreign_items.front()->GetOffset(); - size_t end = foreign_items.back()->GetOffset() + foreign_items.back()->GetSize(); - - foreign_size = end - begin; - } - - ASSERT_TRUE(writer.Write(foreign_size)); - ASSERT_TRUE(writer.Write(class_map.size())); - ASSERT_TRUE(writer.Write(sizeof(File::Header))); - - // Write class idx - - for (auto &entry : class_map) { - ASSERT_TRUE(writer.Write(entry.second->GetOffset())); - } + const std::string file_name = "test_file_format_version_valid.abc"; + { + ItemContainer container; + auto writer = FileWriter(file_name); - for (auto &item : foreign_items) { - ASSERT_TRUE(writer.Align(item->Alignment())); - ASSERT_TRUE(item->Write(&writer)); - } + File::Header header; + memset(&header, 0, sizeof(header)); + header.magic = File::MAGIC; + header.version = {0, 0, 0, 2}; + header.file_size = sizeof(File::Header); - for (auto &item : items) { - if (!item->NeedsEmit()) { - continue; + for (uint8_t b : Span(reinterpret_cast(&header), sizeof(header))) { + writer.WriteByte(b); } - - ASSERT_TRUE(writer.Align(item->Alignment())); - ASSERT_TRUE(item->Write(&writer)); } - // Read panda file from disk - - auto ptr = File::Open(file_name); - EXPECT_EQ(ptr, nullptr); + EXPECT_NE(File::Open(file_name), nullptr); } static std::unique_ptr GetPandaFile(std::vector &data) @@ -315,8 +225,7 @@ TEST(ItemContainer, TestClasses) ASSERT_NE(panda_file, nullptr); - EXPECT_THAT(panda_file->GetHeader()->version, ::testing::ElementsAre(0, 0, 0, 1)); - EXPECT_EQ(panda_file->GetHeader()->isa_checksum, ISA_CHECKSUM); + EXPECT_THAT(panda_file->GetHeader()->version, ::testing::ElementsAre(0, 0, 0, 2)); EXPECT_EQ(panda_file->GetHeader()->file_size, mem_writer.GetData().size()); EXPECT_EQ(panda_file->GetHeader()->foreign_off, 0U); EXPECT_EQ(panda_file->GetHeader()->foreign_size, 0U); diff --git a/libpandafile/type_helper.h b/libpandafile/type_helper.h index b849bac16e..b59fbf49c9 100644 --- a/libpandafile/type_helper.h +++ b/libpandafile/type_helper.h @@ -24,12 +24,7 @@ namespace panda::panda_file { inline panda::panda_file::Type GetEffectiveType(const panda_file::Type &type) { - auto type_id = type.GetId(); - if (type_id == panda_file::Type::TypeId::F32) { - type_id = panda_file::Type::TypeId::F64; - } - - return panda_file::Type {type_id}; + return type; } inline bool IsArrayDescriptor(const uint8_t *descriptor) diff --git a/libziparchive/tests/libziparchive_tests.cpp b/libziparchive/tests/libziparchive_tests.cpp index 1b4198a825..c280d6b361 100644 --- a/libziparchive/tests/libziparchive_tests.cpp +++ b/libziparchive/tests/libziparchive_tests.cpp @@ -17,7 +17,6 @@ #include "libpandafile/file.h" #include "os/file.h" #include "os/mem.h" -#include "isa_checksum.h" #include "assembly-emitter.h" #include "assembly-parser.h" @@ -996,8 +995,6 @@ TEST(LIBZIPARCHIVE, OpenUncompressedArchiveFILE) // Delete the test archive, so it doesn't keep growing as we run this test remove(s_Test_archive_filename); - uint32_t *isa_checksum = reinterpret_cast(&pf_data[offsetof(panda_file::File::Header, isa_checksum)]); - *isa_checksum = ISA_CHECKSUM; // ************* Create Zip file ************* // Append a bunch of text files to the test archive for (i = (N - 1); i >= 0; --i) { diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index a7d688c976..e62d543060 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -333,7 +333,6 @@ template("gen_intrinsics_yaml") { action("$target_name") { script = "$ark_root/runtime/templates/gen_intrinsics_data.rb" - # rerun action when data file or template file update inputs = [ template_file ] inputs += invoker.data_files @@ -389,7 +388,7 @@ ark_isa_gen("isa_gen_libarkruntime") { extra_dependencies = builtin_labels } -isa = "$ark_root/isa/isa.yaml" +isa = "$root_gen_dir/isa/isa.yaml" isa_api = "$ark_root/isa/isapi.rb" bridge_dispatch_template = "templates/bridge_dispatch.S.erb" bridge_archs = [ @@ -411,6 +410,7 @@ foreach(arch, bridge_archs) { "templates/bridge_helpers_${arch}.rb", "templates/bridge_helpers_static.rb", ] + extra_dependencies = [ "$ark_root/isa:isa_combine" ] } ark_gen_file("bridge_dispatch_dyn_${arch}") { @@ -422,6 +422,7 @@ foreach(arch, bridge_archs) { "templates/bridge_helpers_dynamic.rb", "templates/bridge_helpers_${arch}.rb", ] + extra_dependencies = [ "$ark_root/isa:isa_combine" ] } } diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index ea0ce38dff..af45d448b3 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -212,7 +212,7 @@ panda_isa_gen( EXTRA_DEPENDENCIES ${builtin_headers} ) -set(ISA "${PANDA_ROOT}/isa/isa.yaml") +set(ISA "${CMAKE_BINARY_DIR}/isa/isa.yaml") set(ISA_API "${PANDA_ROOT}/isa/isapi.rb") set(BRIDGE_DISPATCH_TEMPLATE "${CMAKE_CURRENT_LIST_DIR}/templates/bridge_dispatch.S.erb") set(BRIDGE_ARCHS aarch64 arm armhf amd64 x86) @@ -224,8 +224,8 @@ foreach(arch ${BRIDGE_ARCHS}) REQUIRES ${ISA_API} ${CMAKE_CURRENT_LIST_DIR}/templates/bridge_helpers_${arch}.rb ${CMAKE_CURRENT_LIST_DIR}/templates/bridge_helpers_static.rb ) - add_custom_target(bridge_dispatch_${arch} DEPENDS ${GEN_INCLUDE_DIR}/bridge_dispatch_${arch}.S) - + add_custom_target(bridge_dispatch_${arch} DEPENDS ${GEN_INCLUDE_DIR}/bridge_dispatch_${arch}.S ${ISA}) + add_dependencies(bridge_dispatch_${arch} isa_assert) panda_gen_file( DATAFILE ${ISA} @@ -233,7 +233,8 @@ foreach(arch ${BRIDGE_ARCHS}) OUTPUTFILE ${GEN_INCLUDE_DIR}/bridge_dispatch_dyn_${arch}.S REQUIRES ${ISA_API} ${CMAKE_CURRENT_LIST_DIR}/templates/bridge_helpers_dynamic.rb ${CMAKE_CURRENT_LIST_DIR}/templates/bridge_helpers_${arch}.rb ) - add_custom_target(bridge_dispatch_dyn_${arch} DEPENDS ${GEN_INCLUDE_DIR}/bridge_dispatch_dyn_${arch}.S) + add_custom_target(bridge_dispatch_dyn_${arch} DEPENDS ${GEN_INCLUDE_DIR}/bridge_dispatch_dyn_${arch}.S ${ISA}) + add_dependencies(bridge_dispatch_${arch} isa_assert) endforeach() diff --git a/runtime/arch/helpers.h b/runtime/arch/helpers.h index c3e0400d37..b8aaf5a04e 100644 --- a/runtime/arch/helpers.h +++ b/runtime/arch/helpers.h @@ -156,32 +156,27 @@ public: template T Read() { - // The runtime alway operates with double so read double instead of float - if constexpr (std::is_same::value) { // NOLINT - return static_cast(*ReadPtr()); - } else { // NOLINT - return *ReadPtr(); - } + return *ReadPtr(); } template const T *ReadPtr() { - static_assert(!std::is_same::value, "float variables are not supported"); - constexpr size_t PTR_SIZE = ArchTraits::POINTER_SIZE; // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) - if constexpr (std::is_same::value) { + if constexpr (std::is_same::value || std::is_same::value) { // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) if constexpr (ExtArchTraits::HARDFP) { - const double *v; + const T *v; + size_t read_bytes = std::max(sizeof(T), ExtArchTraits::FPR_SIZE); + fp_arg_bytes_read_ = RoundUp(fp_arg_bytes_read_, read_bytes); if (fp_arg_bytes_read_ < ExtArchTraits::FP_ARG_NUM_BYTES) { - v = reinterpret_cast(fpr_args_.data() + fp_arg_bytes_read_); - fp_arg_bytes_read_ += sizeof(double); + v = reinterpret_cast(fpr_args_.data() + fp_arg_bytes_read_); + fp_arg_bytes_read_ += read_bytes; } else { - stack_args_ = AlignPtr(stack_args_); - v = reinterpret_cast(stack_args_); - stack_args_ += sizeof(double); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + stack_args_ = AlignPtr(stack_args_); + v = reinterpret_cast(stack_args_); + stack_args_ += read_bytes; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } return v; } diff --git a/runtime/bridge/arch/aarch64/interpreter_to_compiled_code_bridge_dyn_aarch64.S b/runtime/bridge/arch/aarch64/interpreter_to_compiled_code_bridge_dyn_aarch64.S index 4431bb9336..35ebb2e366 100644 --- a/runtime/bridge/arch/aarch64/interpreter_to_compiled_code_bridge_dyn_aarch64.S +++ b/runtime/bridge/arch/aarch64/interpreter_to_compiled_code_bridge_dyn_aarch64.S @@ -160,7 +160,7 @@ InvokeCompiledCodeWithArgArrayDyn: .Linvoke_: // invoke the entrypoint blr lr - + sub sp, fp, 32 ldp x19, THREAD_REG, [sp], 48 CFI_RESTORE(THREAD_REG) diff --git a/runtime/bridge/arch/arm/interpreter_to_compiled_code_bridge_armhf.S b/runtime/bridge/arch/arm/interpreter_to_compiled_code_bridge_armhf.S index 57a4afbbaf..1d46a19782 100644 --- a/runtime/bridge/arch/arm/interpreter_to_compiled_code_bridge_armhf.S +++ b/runtime/bridge/arch/arm/interpreter_to_compiled_code_bridge_armhf.S @@ -86,9 +86,10 @@ strge \tmp1, [\stack_ptr], #4 b \next_label -1: sub r2, r2, #SHORTY_FIRST_FLOAT - cmp r2, #(SHORTY_NUM_FLOAT_TYPES - 1) - bls 2f +1: cmp r2, #SHORTY_F32 + beq 21f + cmp r2, #SHORTY_F64 + beq 22f // it is a 64bit int // align bic \gpr_ptr, \gpr_ptr, #7 @@ -104,10 +105,21 @@ blt \next_label bge 3f -2: // it is a float +21: // it is a float // determine whether there are free fp regs sub \tmp1, \fpr_ptr, r4 cmp \tmp1, #64 + ldr \tmp1, [\arg_ptr] + stmlt \fpr_ptr!, {\tmp1} + stmge \stack_ptr!, {\tmp1} + b \next_label + +22: // it is a double + // determine whether there are free fp regs + add \fpr_ptr, \fpr_ptr, #7 + bic \fpr_ptr, \fpr_ptr, #7 + sub \tmp1, \fpr_ptr, r4 + cmp \tmp1, #64 ldm \arg_ptr, {\tmp1, \tmp2} stmlt \fpr_ptr!, {\tmp1, \tmp2} blt \next_label @@ -261,7 +273,6 @@ PrepareArgStack: bicge sp, sp, #7 subge sp, sp, #8 b .Lloop_shorty - .Lexit: bic sp, sp, #7 // align sp sub r4, sp, r4, lsl #3 @@ -391,25 +402,26 @@ InterpreterToCompiledCodeBridge: bpl .LU16 cmp r2, #SHORTY_I8 beq .LI8 - uxtb r0, r0 + uxtb r0, r0 b .L32 -.LI8: +.LI8: sxtb r0, r0 b .L32 -.LI16: - sxth r0, r0 +.LI16: + sxth r0, r0 b .L32 -.LU16: - uxth r0, r0 +.LU16: + uxth r0, r0 .L32: // it is a 32bit value or reference str r0, [r3] b .Lreturn .L64: - sub r2, #SHORTY_FIRST_FLOAT - cmp r2, #(SHORTY_NUM_FLOAT_TYPES - 1) - vmovls.f64 r0, r1, d0 + cmp r2, #SHORTY_F64 + vmoveq.f64 r0, r1, d0 + cmp r2, #SHORTY_F32 + vmoveq.f32 r0, s0 stm r3, {r0, r1} .Lreturn: @@ -548,19 +560,22 @@ InvokeCompiledCodeWithArgArray: bpl .LU16_ cmp r2, #SHORTY_I8 beq .LI8_ - uxtb r0, r0 + uxtb r0, r0 b .Lstore_result_ -.LI8_: +.LI8_: sxtb r0, r0 b .Lstore_result_ -.LI16_: - sxth r0, r0 +.LI16_: + sxth r0, r0 b .Lstore_result_ -.LU16_: - uxth r0, r0 +.LU16_: + uxth r0, r0 b .Lstore_result_ .LFLOAT_: - vmovls.f64 r0, r1, d0 + cmp r2, #SHORTY_F64 + vmoveq.f64 r0, r1, d0 + cmp r2, #SHORTY_F32 + vmoveq.f32 r0, s0 .Lstore_result_: // store the result r0,r1 into memory [r8] diff --git a/runtime/bridge/arch/x86/interpreter_to_compiled_code_bridge_x86.S b/runtime/bridge/arch/x86/interpreter_to_compiled_code_bridge_x86.S index 0692fc156c..5752bd3386 100644 --- a/runtime/bridge/arch/x86/interpreter_to_compiled_code_bridge_x86.S +++ b/runtime/bridge/arch/x86/interpreter_to_compiled_code_bridge_x86.S @@ -152,7 +152,7 @@ InterpreterToCompiledCodeBridge: PREPARE_ARG_STACK // setup regs and memory as follow - // %eax - SHORTY_PTR_REG, %edx - SHORTY_REG, %ecx - shorty value, (%esp) - insn_ptr, + // %eax - SHORTY_PTR_REG, %edx - SHORTY_REG, %ecx - shorty value, (%esp) - insn_ptr, // 8(%ebp) - iframe, 4(%esp) - iframe->vregs[], %edi - pointer to stack movl METHOD_SHORTY_OFFSET(%ebx), %SHORTY_PTR_REG // method->shorty* INIT_SHORTY_REG @@ -280,7 +280,7 @@ InterpreterToCompiledCodeBridge: .Lreturn: leal -28(%ebp), %esp - + popl %edi popl %esi popl %ebx @@ -334,10 +334,10 @@ InvokeCompiledCodeWithArgArray: movl METHOD_SHORTY_OFFSET(%ebx), %SHORTY_PTR_REG // method->shorty* INIT_SHORTY_REG - PREPARE_ARG_STACK + PREPARE_ARG_STACK // setup regs and memory as follow - // %eax - SHORTY_PTR_REG, %edx - SHORTY_REG, %ecx - shorty value, %esi - args[], + // %eax - SHORTY_PTR_REG, %edx - SHORTY_REG, %ecx - shorty value, %esi - args[], // %edi - pointer to stack movl METHOD_SHORTY_OFFSET(%ebx), %SHORTY_PTR_REG // method->shorty* INIT_SHORTY_REG @@ -379,7 +379,7 @@ InvokeCompiledCodeWithArgArray: movl %eax, (%esp) movl %edx, 4(%esp) // handle the first arg index - PUSH_ARG %esi, %edi, %eax, %edx + PUSH_ARG %esi, %edi, %eax, %edx movl (%esp), %eax movl 4(%esp), %edx @@ -468,7 +468,7 @@ InvokeCompiledCodeWithArgArray: .Lreturn_: leal -28(%ebp), %esp - + popl %edi popl %esi popl %ebx diff --git a/runtime/coretypes/array.cpp b/runtime/coretypes/array.cpp index 2a63122e30..91f769df5f 100644 --- a/runtime/coretypes/array.cpp +++ b/runtime/coretypes/array.cpp @@ -34,7 +34,6 @@ static Array *AllocateArray(panda::BaseClass *array_class, size_t elem_size, arr ThrowOutOfMemoryError("OOM when allocating array"); return nullptr; } - if (LIKELY(space_type == panda::SpaceType::SPACE_TYPE_OBJECT)) { return static_cast( vm->GetHeapManager()->AllocateObject(array_class, size, DEFAULT_ALIGNMENT, MTManagedThread::GetCurrent())); diff --git a/runtime/coretypes/string.cpp b/runtime/coretypes/string.cpp index c645447e65..17efb3b34b 100644 --- a/runtime/coretypes/string.cpp +++ b/runtime/coretypes/string.cpp @@ -128,8 +128,8 @@ String *String::CreateFromUtf16(const uint16_t *utf16_data, uint32_t utf16_lengt if (can_be_compressed) { CopyUtf16AsMUtf8(utf16_data, string->GetDataMUtf8(), utf16_length); } else { - if (memcpy_s(string->GetDataUtf16(), ComputeDataSizeUtf16(string->GetLength()), utf16_data, - utf16_length << 1UL) != EOK) { + if (utf16_length != 0 && memcpy_s(string->GetDataUtf16(), ComputeDataSizeUtf16(string->GetLength()), utf16_data, + utf16_length << 1UL) != EOK) { LOG(FATAL, RUNTIME) << __func__ << " memcpy_s failed"; UNREACHABLE(); } diff --git a/runtime/include/cframe_iterators.h b/runtime/include/cframe_iterators.h index d011b51461..fc5cc78e4b 100644 --- a/runtime/include/cframe_iterators.h +++ b/runtime/include/cframe_iterators.h @@ -22,6 +22,7 @@ #include "runtime/include/cframe.h" #include "runtime/include/method.h" #include "libpandafile/shorty_iterator.h" +#include "utils/bit_utils.h" namespace panda { @@ -227,8 +228,7 @@ public: uint32_t vreg_num = num_args + (is_static ? 1 : 0); return Range( - CFrameJniMethodIterator(0, vreg_num, method->GetShorty(), gpr_begin_slot, GPR_END_SLOT, - FP_BEGIN_SLOT + 2, // 2 + CFrameJniMethodIterator(0, vreg_num, method->GetShorty(), gpr_begin_slot, GPR_END_SLOT, FP_BEGIN_SLOT, FP_END_SLOT, STACK_BEGIN_SLOT), CFrameJniMethodIterator(vreg_num, vreg_num, method->GetShorty(), 0, 0, 0, 0, 0)); } @@ -242,8 +242,7 @@ public: { static_assert(arch::ExtArchTraits::GPR_SIZE == 4); // 4 bytes -- register size on AARCH32 - if (vreg_type == VRegInfo::Type::INT64 || vreg_type == VRegInfo::Type::FLOAT64 || - vreg_type == VRegInfo::Type::FLOAT32) { + if (vreg_type == VRegInfo::Type::INT64 || vreg_type == VRegInfo::Type::FLOAT64) { return 2; // 2 slots } return 1; @@ -263,6 +262,11 @@ public: ptrdiff_t inc = GetSlotsCountForType(vreg_type_); ASSERT(inc == 1 || inc == 2); // 1 or 2 slots if (inc == 1) { + if constexpr (arch::ExtArchTraits::HARDFP) { + if (vreg_type_ == VRegInfo::Type::FLOAT32) { // in this case one takes 1 slots + return HandleHardFloat(); + } + } if ((gpr_current_slot_ - 1) > gpr_end_slot_) { --gpr_current_slot_; current_slot_ = gpr_current_slot_; @@ -274,18 +278,8 @@ public: } } else { if constexpr (arch::ExtArchTraits::HARDFP) { - if (vreg_type_ == VRegInfo::Type::FLOAT32 || - vreg_type_ == VRegInfo::Type::FLOAT64) { // in this case one takes 2 slots - // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_NESTING_LEVEL) - if ((fp_current_slot_ - 2) > fp_end_slot_) { - fp_current_slot_ -= 2; - current_slot_ = fp_current_slot_; - } else { - stack_current_slot_ = RoundUp(stack_current_slot_ - 1, 2) - 1; // 2 - current_slot_ = stack_current_slot_; - stack_current_slot_ -= 1; - } - return *this; + if (vreg_type_ == VRegInfo::Type::FLOAT64) { // in this case one takes 2 slots + return HandleHardDouble(); } } gpr_current_slot_ = RoundUp(gpr_current_slot_ - 1, 2) - 1; // 2 @@ -349,6 +343,7 @@ private: case panda_file::Type::TypeId::U32: return VRegInfo::Type::INT32; case panda_file::Type::TypeId::F32: + return VRegInfo::Type::FLOAT32; case panda_file::Type::TypeId::F64: return VRegInfo::Type::FLOAT64; case panda_file::Type::TypeId::I64: @@ -364,6 +359,34 @@ private: return VRegInfo::Type::INT32; } + CFrameJniMethodIterator &HandleHardFloat() + { + ASSERT(vreg_type_ == VRegInfo::Type::FLOAT32); + if (fp_current_slot_ > fp_end_slot_) { + current_slot_ = fp_current_slot_; + --fp_current_slot_; + } else { + --stack_current_slot_; + current_slot_ = stack_current_slot_; + } + return *this; + } + + CFrameJniMethodIterator &HandleHardDouble() + { + ASSERT(vreg_type_ == VRegInfo::Type::FLOAT64); + fp_current_slot_ = RoundDown(static_cast(fp_current_slot_) + 1, 2U) - 1; + if (fp_current_slot_ > fp_end_slot_) { + current_slot_ = fp_current_slot_; + fp_current_slot_ -= 2U; + } else { + stack_current_slot_ = RoundUp(stack_current_slot_ - 1, 2U) - 1; + current_slot_ = stack_current_slot_; + stack_current_slot_ -= 1; + } + return *this; + } + private: uint32_t vreg_index_; uint32_t vreg_num_; diff --git a/runtime/include/coretypes/tagged_value.h b/runtime/include/coretypes/tagged_value.h index 22db4df565..b50f797a53 100644 --- a/runtime/include/coretypes/tagged_value.h +++ b/runtime/include/coretypes/tagged_value.h @@ -53,7 +53,6 @@ inline TaggedType ReinterpretDoubleToTaggedType(double value) { return bit_cast(value); } - inline double ReinterpretTaggedTypeToDouble(TaggedType value) { return bit_cast(value); diff --git a/runtime/include/language_context.h b/runtime/include/language_context.h index 43ccb5dd37..967b7222fe 100644 --- a/runtime/include/language_context.h +++ b/runtime/include/language_context.h @@ -430,7 +430,6 @@ public: UNREACHABLE(); return stream; } - uint64_t GetTypeTag(interpreter::TypeTag tag) const { // return TypeTag default diff --git a/runtime/include/method-inl.h b/runtime/include/method-inl.h index bb06d27e9d..7fd73cd4f6 100644 --- a/runtime/include/method-inl.h +++ b/runtime/include/method-inl.h @@ -119,6 +119,9 @@ Value Method::InvokeInterpretedCode(ManagedThread *thread, uint32_t num_actual_a } return res; } + + LOG(DEBUG, INTERPRETER) << "Invoke entry: " << GetFullName(); + auto is_compiled = thread->IsCurrentFrameCompiled(); thread->SetCurrentFrameIsCompiled(false); thread->SetCurrentFrame(frame.get()); @@ -152,6 +155,8 @@ Value Method::InvokeInterpretedCode(ManagedThread *thread, uint32_t num_actual_a } thread->SetCurrentFrame(current_frame); res = GetReturnValueFromAcc(ret_type, thread->HasPendingException(), frame->GetAcc()); + + LOG(DEBUG, INTERPRETER) << "Invoke exit: " << GetFullName(); } return res; } diff --git a/runtime/include/object_header.h b/runtime/include/object_header.h index 10f1b4a6d0..87399a247e 100644 --- a/runtime/include/object_header.h +++ b/runtime/include/object_header.h @@ -12,7 +12,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - // All common ObjectHeader methods can be found here: // - Get/Set Mark or Class word // - Get size of the object header and an object itself diff --git a/runtime/interpreter/instruction_handler_base.h b/runtime/interpreter/instruction_handler_base.h index 184478452b..a24b82641d 100644 --- a/runtime/interpreter/instruction_handler_base.h +++ b/runtime/interpreter/instruction_handler_base.h @@ -50,6 +50,11 @@ public: return (static_cast(GetInst().GetOpcode()) >> 8) & 0xff; } + ALWAYS_INLINE bool IsPrimaryOpcodeValid() const + { + return GetInst().IsPrimaryOpcodeValid(); + } + void DumpVRegs() { #ifndef NDEBUG @@ -152,7 +157,7 @@ protected: ALWAYS_INLINE void MoveToExceptionHandler() { - SetOpcodeExtension(NUM_OPS + NUM_PREFIXES - 1); + SetOpcodeExtension(UINT8_MAX + NUM_PREFIXED + 1); SetOpcodeExtension(GetOpcodeExtension() - GetPrimaryOpcode()); } diff --git a/runtime/interpreter/instruction_handler_state.h b/runtime/interpreter/instruction_handler_state.h index 54c0ab7df8..df10d222e0 100644 --- a/runtime/interpreter/instruction_handler_state.h +++ b/runtime/interpreter/instruction_handler_state.h @@ -103,6 +103,11 @@ public: return (static_cast(GetInst().GetOpcode()) >> 8) & 0xff; } + ALWAYS_INLINE bool IsPrimaryOpcodeValid() const + { + return GetInst().IsPrimaryOpcodeValid(); + } + ALWAYS_INLINE BytecodeInstruction GetInst() const { return state_.GetInst(); diff --git a/runtime/interpreter/interpreter-inl.h b/runtime/interpreter/interpreter-inl.h index b9204cc8b4..09b8c94d94 100644 --- a/runtime/interpreter/interpreter-inl.h +++ b/runtime/interpreter/interpreter-inl.h @@ -93,6 +93,13 @@ public: #include "unimplemented_handlers-inl.h" + template + ALWAYS_INLINE void HandleNop() + { + LOG_INST() << "nop"; + this->template MoveToNextInst(); + } + template ALWAYS_INLINE void HandleFldaiDyn() { @@ -177,6 +184,16 @@ public: this->template MoveToNextInst(); } + template + ALWAYS_INLINE void HandleFmovi() + { + auto imm = bit_cast(this->GetInst().template GetImm()); + uint16_t vd = this->GetInst().template GetVReg(); + LOG_INST() << "fmovi v" << vd << ", " << imm; + this->GetFrame()->GetVReg(vd).SetPrimitive(imm); + this->template MoveToNextInst(); + } + template ALWAYS_INLINE void HandleFmoviWide() { @@ -241,6 +258,15 @@ public: this->template MoveToNextInst(); } + template + ALWAYS_INLINE void HandleFldai() + { + auto imm = bit_cast(this->GetInst().template GetImm()); + LOG_INST() << "fldai " << imm; + this->GetAcc().SetPrimitive(imm); + this->template MoveToNextInst(); + } + template ALWAYS_INLINE void HandleFldaiWide() { @@ -384,6 +410,13 @@ public: HandleBinaryOp2(); } + template + ALWAYS_INLINE void HandleFcmpl() + { + LOG_INST() << "fcmpl ->"; + HandleBinaryOp2(); + } + template ALWAYS_INLINE void HandleFcmplWide() { @@ -391,6 +424,13 @@ public: HandleBinaryOp2(); } + template + ALWAYS_INLINE void HandleFcmpg() + { + LOG_INST() << "fcmpg ->"; + HandleBinaryOp2(); + } + template ALWAYS_INLINE void HandleFcmpgWide() { @@ -524,6 +564,13 @@ public: HandleBinaryOp2(); } + template + ALWAYS_INLINE void HandleFadd2() + { + LOG_INST() << "fadd2 ->"; + HandleBinaryOp2(); + } + template ALWAYS_INLINE void HandleFadd2Wide() { @@ -545,6 +592,13 @@ public: HandleBinaryOp2(); } + template + ALWAYS_INLINE void HandleFsub2() + { + LOG_INST() << "fsub2 ->"; + HandleBinaryOp2(); + } + template ALWAYS_INLINE void HandleFsub2Wide() { @@ -566,6 +620,13 @@ public: HandleBinaryOp2(); } + template + ALWAYS_INLINE void HandleFmul2() + { + LOG_INST() << "fmul2 ->"; + HandleBinaryOp2(); + } + template ALWAYS_INLINE void HandleFmul2Wide() { @@ -573,6 +634,13 @@ public: HandleBinaryOp2(); } + template + ALWAYS_INLINE void HandleFdiv2() + { + LOG_INST() << "fdiv2 ->"; + HandleBinaryOp2(); + } + template ALWAYS_INLINE void HandleFdiv2Wide() { @@ -580,6 +648,13 @@ public: HandleBinaryOp2(); } + template + ALWAYS_INLINE void HandleFmod2() + { + LOG_INST() << "fmod2 ->"; + HandleBinaryOp2(); + } + template ALWAYS_INLINE void HandleFmod2Wide() { @@ -2228,174 +2303,6 @@ public: return panda_file::INVALID_OFFSET; } - template - ALWAYS_INLINE void HandleBuiltinI32tof32() - { // builtin: 0x00 (acc) - auto v = static_cast(this->GetAcc().template GetAs()); - - LOG_INST() << "\t" - << "i32tof32"; - - this->GetAcc().Set(static_cast(v)); - this->template MoveToNextInst(); - } - - template - ALWAYS_INLINE void HandleBuiltinI64tof32() - { // builtin: 0x01 (acc) - auto v = static_cast(this->GetAcc().template GetAs()); - - LOG_INST() << "\t" - << "i64tof32"; - - this->GetAcc().Set(static_cast(v)); - this->template MoveToNextInst(); - } - - template - ALWAYS_INLINE void HandleBuiltinF64tof32() - { // builtin: 0x02 (acc) - auto v = static_cast(this->GetAcc().template GetAs()); - - LOG_INST() << "\t" - << "f64tof32"; - - this->GetAcc().Set(static_cast(v)); - this->template MoveToNextInst(); - } - - template - ALWAYS_INLINE void HandleBuiltinMonitorenter() - { // builtin: 0x03 (acc) - - LOG_INST() << "\t" - << "monitorenter"; - - this->GetFrame()->SetAcc(this->GetAcc()); - panda::intrinsics::ObjectMonitorEnter(this->GetAcc().GetReference()); - this->GetAcc() = this->GetFrame()->GetAcc(); - - if (UNLIKELY(this->GetThread()->HasPendingException())) { - this->MoveToExceptionHandler(); - } else { - this->template MoveToNextInst(); - } - } - - template - ALWAYS_INLINE void HandleBuiltinMonitorexit() - { // builtin: 0x04 (acc) - - LOG_INST() << "\t" - << "monitorexit"; - - panda::intrinsics::ObjectMonitorExit(this->GetAcc().GetReference()); - - if (UNLIKELY(this->GetThread()->HasPendingException())) { - this->MoveToExceptionHandler(); - } else { - this->template MoveToNextInst(); - } - } - - template - ALWAYS_INLINE void HandleBuiltinFadd2f32() - { // builtin: 0x00 (bin2) - auto v1 = static_cast(this->GetAcc().template GetAs()); - auto vs = this->GetInst().template GetVReg(); - auto v2 = static_cast(this->GetFrame()->GetVReg(vs).template GetAs()); - - LOG_INST() << "\t" - << "fadd2f32 v" << vs; - - this->GetAcc().Set(static_cast(v1 + v2)); - this->template MoveToNextInst(); - } - - template - ALWAYS_INLINE void HandleBuiltinFsub2f32() - { // builtin: 0x01 (bin2) - auto v1 = static_cast(this->GetAcc().template GetAs()); - auto vs = this->GetInst().template GetVReg(); - auto v2 = static_cast(this->GetFrame()->GetVReg(vs).template GetAs()); - - LOG_INST() << "\t" - << "fsub2f32 v" << vs; - - this->GetAcc().Set(static_cast(v1 - v2)); - this->template MoveToNextInst(); - } - - template - ALWAYS_INLINE void HandleBuiltinFmul2f32() - { // builtin: 0x02 (bin2) - auto v1 = static_cast(this->GetAcc().template GetAs()); - auto vs = this->GetInst().template GetVReg(); - auto v2 = static_cast(this->GetFrame()->GetVReg(vs).template GetAs()); - - LOG_INST() << "\t" - << "fmul2f32 v" << vs; - - this->GetAcc().Set(static_cast(v1 * v2)); - this->template MoveToNextInst(); - } - - template - ALWAYS_INLINE void HandleBuiltinFdiv2f32() - { // builtin: 0x03 (bin2) - auto v1 = static_cast(this->GetAcc().template GetAs()); - auto vs = this->GetInst().template GetVReg(); - auto v2 = static_cast(this->GetFrame()->GetVReg(vs).template GetAs()); - - LOG_INST() << "\t" - << "fdiv2f32 v" << vs; - - this->GetAcc().Set(static_cast(v1 / v2)); - this->template MoveToNextInst(); - } - - template - ALWAYS_INLINE void HandleBuiltinFmod2f32() - { // builtin: 0x04 (bin2) - auto v1 = static_cast(this->GetAcc().template GetAs()); - auto vs = this->GetInst().template GetVReg(); - auto v2 = static_cast(this->GetFrame()->GetVReg(vs).template GetAs()); - - LOG_INST() << "\t" - << "fmod2f32 v" << vs; - - this->GetAcc().Set(static_cast(std::fmod(v1, v2))); - this->template MoveToNextInst(); - } - - template - ALWAYS_INLINE void HandleBuiltinFcmpl2f32() - { // builtin: 0x05 (bin2) - auto v1 = static_cast(this->GetAcc().template GetAs()); - auto vs = this->GetInst().template GetVReg(); - auto v2 = static_cast(this->GetFrame()->GetVReg(vs).template GetAs()); - - LOG_INST() << "\t" - << "fcmplf32 v" << vs; - - this->GetAcc().Set(static_cast(math_helpers::fcmpl()(v1, v2))); - this->template MoveToNextInst(); - } - - template - ALWAYS_INLINE void HandleBuiltinFcmpg2f32() - { // builtin: 0x06 (bin2) - auto v1 = static_cast(this->GetAcc().template GetAs()); - auto vs = this->GetInst().template GetVReg(); - auto v2 = static_cast(this->GetFrame()->GetVReg(vs).template GetAs()); - - LOG_INST() << "\t" - << "fcmpgf32 v" << vs; - - this->GetAcc().Set(static_cast(math_helpers::fcmpg()(v1, v2))); - this->template MoveToNextInst(); - } - ALWAYS_INLINE static bool IsCompilerEnableJit() { return !enable_instrumentation && RuntimeIfaceT::IsCompilerEnableJit(); diff --git a/runtime/interpreter/templates/builtin_insn_handlers.h.erb b/runtime/interpreter/templates/builtin_insn_handlers.h.erb index 839e7917e8..b709ffca03 100644 --- a/runtime/interpreter/templates/builtin_insn_handlers.h.erb +++ b/runtime/interpreter/templates/builtin_insn_handlers.h.erb @@ -21,10 +21,9 @@ HANDLE_<%= insn.opcode.upcase %>: { const auto builtin_id = state.GetInst().template GetImm>(); LOG(DEBUG, INTERPRETER) << "Subdispatch: " << "<%= insn.mnemonic %>, " << builtin_id - << " (NUM_OPS=" << NUM_OPS << ", NUM_PREFIXES=" << NUM_PREFIXES + << " (NUM_PREFIXED=" << NUM_PREFIXED << ", delta=" << <%= insn.delta %> << ")"; - - DISPATCH(GetDispatchTable(dispatch_table), NUM_OPS + NUM_PREFIXES + <%= insn.delta %> + builtin_id, label); + DISPATCH(GetDispatchTable(dispatch_table), 256 + NUM_PREFIXED + 1 + <%= insn.delta %> + builtin_id, label); } % end diff --git a/runtime/interpreter/templates/interpreter-inl_gen.h.erb b/runtime/interpreter/templates/interpreter-inl_gen.h.erb index 29dcf08ff6..db8b3de0f0 100644 --- a/runtime/interpreter/templates/interpreter-inl_gen.h.erb +++ b/runtime/interpreter/templates/interpreter-inl_gen.h.erb @@ -45,7 +45,7 @@ void ExecuteImpl(ManagedThread* thread, const uint8_t *pc, Frame* frame) { PandaUniquePtr method_exit(&method_exit_event, method_exit_event); #endif - static std::array dispatch_table{ + static std::array dispatch_table{ % Panda::dispatch_table.handler_names.each do |name| &&HANDLE_<%= name %>, % end @@ -56,19 +56,22 @@ void ExecuteImpl(ManagedThread* thread, const uint8_t *pc, Frame* frame) { SetDispatchTable(dispatch_table); InstructionHandlerState state(thread, pc, frame); - if constexpr (jump_to_eh) { goto EXCEPTION_HANDLER; } - ASSERT(state.GetPrimaryOpcode() <= <%= Panda::dispatch_table.primary_opcode_bound %>); + ASSERT(state.IsPrimaryOpcodeValid()); const void *label; DISPATCH(GetDispatchTable(dispatch_table), state.GetPrimaryOpcode(), label); -% Panda::instructions.select(&:public?).each do |i| +% Panda::instructions.reject(&:builtin?).each do |i| % mnemonic = i.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join -HANDLE_<%= Panda::dispatch_table.instruction_handler_name(i) %>: { - InstructionHandler handler(&state); +HANDLE_<%= i.handler_name %>: { +% namespace = i.namespace == 'core' ? '' : "#{i.namespace}::" +% if i.namespace != 'core' +#ifdef PANDA_WITH_<%= i.namespace.upcase %> +% end + <%= namespace %>InstructionHandler handler(&state); INSTRUMENT_FRAME(); handler.DumpVRegs(); handler.InstrumentInstruction(); @@ -79,25 +82,30 @@ HANDLE_<%= Panda::dispatch_table.instruction_handler_name(i) %>: { % if i.properties.include?('return') if (handler.GetFrame()->IsStackless()) { handler.HandleReturnStackless(); - ASSERT(handler.GetExceptionOpcode() < NUM_OPS + NUM_PREFIXES); + ASSERT(handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1)); DISPATCH(GetDispatchTable(dispatch_table), handler.GetExceptionOpcode(), label); } else { return; } % else % if !i.exceptions.include?('x_none') || i.properties.include?("call") || ['ststatic', 'ldstatic', 'throw', 'lda'].include?(i.stripped_mnemonic) - ASSERT(handler.GetExceptionOpcode() < NUM_OPS + NUM_PREFIXES); + ASSERT(handler.IsPrimaryOpcodeValid() || (handler.GetExceptionOpcode() == UINT8_MAX + NUM_PREFIXED + 1)); DISPATCH(GetDispatchTable(dispatch_table), handler.GetExceptionOpcode(), label); % else - ASSERT(handler.GetPrimaryOpcode() <= <%= Panda::dispatch_table.primary_opcode_bound %>); + ASSERT(handler.IsPrimaryOpcodeValid()); DISPATCH(GetDispatchTable(dispatch_table), handler.GetPrimaryOpcode(), label); % end % end +% if i.namespace != 'core' +#endif // PANDA_WITH_<%= i.namespace.upcase %> +% end } % end - +HANDLE_INVALID: { + LOG(FATAL,INTERPRETER) << "Incorrect opcode"; +} % Panda::prefixes.each do |p| -HANDLE_<%= Panda::dispatch_table.prefix_hanlder_name(p) %>: { +HANDLE_<%= p.handler_name %>: { const auto secondary_opcode = state.GetSecondaryOpcode(); LOG(DEBUG, INTERPRETER) << "Prefix subdispatch: " << "<%= p.name %>, " << secondary_opcode; @@ -123,7 +131,7 @@ INSTRUMENT_FRAME_HANDLER: { handler.InstrumentForceReturn(); if (handler.GetFrame()->IsStackless()) { handler.HandleInstrumentForceReturn(); - ASSERT(handler.GetPrimaryOpcode() <= <%= Panda::dispatch_table.primary_opcode_bound %>); + ASSERT(handler.IsPrimaryOpcodeValid()); DISPATCH(GetDispatchTable(dispatch_table), handler.GetPrimaryOpcode(), label); } else { return; @@ -133,8 +141,7 @@ INSTRUMENT_FRAME_HANDLER: { handler.GetFrame()->ClearRetryInstruction(); auto* method = handler.GetFrame()->GetMethod(); state = InstructionHandlerState(thread, method->GetInstructions() + handler.GetFrame()->GetBytecodeOffset(), handler.GetFrame()); - - ASSERT(state.GetPrimaryOpcode() <= <%= Panda::dispatch_table.primary_opcode_bound %>); + ASSERT(state.IsPrimaryOpcodeValid()); goto* dispatch_table[state.GetPrimaryOpcode()]; } @@ -167,7 +174,7 @@ EXCEPTION_HANDLER: { Span sp(handler.GetFrame()->GetMethod()->GetInstructions(), pc_offset); state = InstructionHandlerState(thread, sp.cend(), handler.GetFrame()); - ASSERT(state.GetPrimaryOpcode() <= <%= Panda::dispatch_table.primary_opcode_bound %>); + ASSERT(state.IsPrimaryOpcodeValid()); goto* dispatch_table[state.GetPrimaryOpcode()]; } diff --git a/runtime/interpreter/templates/isa_constants_gen.h.erb b/runtime/interpreter/templates/isa_constants_gen.h.erb index 2bcdeda3cb..093dafd813 100644 --- a/runtime/interpreter/templates/isa_constants_gen.h.erb +++ b/runtime/interpreter/templates/isa_constants_gen.h.erb @@ -17,12 +17,10 @@ #define PANDA_RUNTIME_INCLUDE_ISA_CONSTANTS_GEN_H_ namespace panda::interpreter { - -constexpr auto NUM_OPS = <%= Panda::instructions.size %> + 1; // +1 is for EXCEPTION_HANDLER -constexpr auto NUM_PREFIXES = <%= Panda::prefixes.size %>; -constexpr auto NUM_PREFIXED = <%= Panda::instructions.select(&:prefix).size %>; -static_assert(NUM_OPS - NUM_PREFIXED + NUM_PREFIXES <= 210, "Too many first-level-dispatch opcodes in use, please review the ISA"); - + constexpr auto NUM_PREFIXED = <%= Panda::instructions.select(&:prefix).size %>; + constexpr auto NUM_NON_PREFIXED_OPS = <%= Panda::instructions.size %> - NUM_PREFIXED + 1; // +1 is for EXCEPTION_HANDLER + constexpr auto NUM_PREFIXES = <%= Panda::prefixes.size %>; + static_assert(NUM_NON_PREFIXED_OPS + NUM_PREFIXES <= 210, "Too many first-level-dispatch opcodes in use, please review the ISA"); } // namespace panda::interpreter #endif // PANDA_RUNTIME_INCLUDE_ISA_CONSTANTS_GEN_H_ diff --git a/runtime/interpreter/vregister.h b/runtime/interpreter/vregister.h index 2845dd2c74..e178034801 100644 --- a/runtime/interpreter/vregister.h +++ b/runtime/interpreter/vregister.h @@ -146,6 +146,13 @@ public: SetValue(v); } + ALWAYS_INLINE inline void Set(float value) + { + ASSERT(!HasObject()); + auto v = bit_cast(value); + SetValue(v); + } + ALWAYS_INLINE inline void Set(double value) { ASSERT(!HasObject()); @@ -172,6 +179,13 @@ public: MarkAsPrimitive(); } + ALWAYS_INLINE inline void SetPrimitive(float value) + { + auto v = bit_cast(value); + SetValue(v); + MarkAsPrimitive(); + } + ALWAYS_INLINE inline void SetPrimitive(double value) { auto v = bit_cast(value); @@ -188,7 +202,7 @@ public: ALWAYS_INLINE inline float GetFloat() const { ASSERT(!HasObject()); - return static_cast(bit_cast(GetValue())); + return bit_cast(Get()); } ALWAYS_INLINE inline int64_t GetLong() const @@ -245,6 +259,7 @@ public: values << "obj = " << std::hex << GetValue(); } else { values << "pri = (i64) " << GetValue() << " | " + << "(f32) " << GetFloat() << " | " << "(f64) " << GetDouble() << " | " << "(hex) " << std::hex << GetValue(); } diff --git a/runtime/mark_word.h b/runtime/mark_word.h index 0925ca42ee..a2dbf7c575 100644 --- a/runtime/mark_word.h +++ b/runtime/mark_word.h @@ -12,7 +12,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - // Our main goal is to have similar interface for two different platforms - high-end and low-end. // // 64 bits object header for high-end devices: (64 bits pointer) @@ -80,7 +79,6 @@ // |-----------------------------------------------------|--------------------------------|--------------------| // | Forwarding address:14 | state:11 | OOP to metadata object | GC | // |-----------------------------------------------------|--------------------------------|--------------------| - #ifndef PANDA_RUNTIME_MARK_WORD_H_ #define PANDA_RUNTIME_MARK_WORD_H_ diff --git a/runtime/mem/allocator.cpp b/runtime/mem/allocator.cpp index 5dd8661453..03f1ba8015 100644 --- a/runtime/mem/allocator.cpp +++ b/runtime/mem/allocator.cpp @@ -446,7 +446,6 @@ ObjectAllocatorGen::~ObjectAllocatorGen() delete non_movable_object_allocator_; delete large_non_movable_object_allocator_; } - template size_t ObjectAllocatorGen::GetRegularObjectMaxSize() { diff --git a/runtime/mem/frame_allocator-inl.h b/runtime/mem/frame_allocator-inl.h index 8277bf3abd..8afbdd1f9b 100644 --- a/runtime/mem/frame_allocator-inl.h +++ b/runtime/mem/frame_allocator-inl.h @@ -206,5 +206,4 @@ inline bool FrameAllocator::Contains(void *mem) #undef LOG_FRAME_ALLOCATOR } // namespace panda::mem - #endif // PANDA_RUNTIME_MEM_FRAME_ALLOCATOR_INL_H_ diff --git a/runtime/mem/gc/gc.cpp b/runtime/mem/gc/gc.cpp index 6b488979f0..c1920af15c 100644 --- a/runtime/mem/gc/gc.cpp +++ b/runtime/mem/gc/gc.cpp @@ -429,7 +429,7 @@ void GC::PreStartup() // Add a delay GCTask. if ((!Runtime::GetCurrent()->IsZygote()) && (!gc_settings_.run_gc_in_place)) { // divide 2 to temporarily set target footprint to a high value to disable GC during App startup. - GetPandaVm()->GetGCTrigger()->SetMinTargetFootprint(Runtime::GetOptions().GetObjectPoolSize() / 2); + GetPandaVm()->GetGCTrigger()->SetMinTargetFootprint(Runtime::GetOptions().GetHeapSizeLimit() / 2); PreStartupImp(); constexpr uint64_t DISABLE_GC_DURATION_NS = 2000 * 1000 * 1000; auto task = MakePandaUnique(GCTaskCause::STARTUP_COMPLETE_CAUSE, diff --git a/runtime/mem/gc/gc.h b/runtime/mem/gc/gc.h index f4c76f559f..6bc3618e46 100644 --- a/runtime/mem/gc/gc.h +++ b/runtime/mem/gc/gc.h @@ -44,7 +44,6 @@ #include "runtime/timing.h" namespace panda { - class BaseClass; class Class; class HClass; diff --git a/runtime/mem/gc/gc_stats.h b/runtime/mem/gc/gc_stats.h index 68335832eb..9b54978144 100644 --- a/runtime/mem/gc/gc_stats.h +++ b/runtime/mem/gc/gc_stats.h @@ -230,4 +230,4 @@ private: } // namespace panda::mem -#endif // PANDA_RUNTIME_MEM_GC_GC_STATS_H_ +#endif // PANDA_RUNTIME_MEM_GC_GC_STATS_H diff --git a/runtime/mem/mem_stats.h b/runtime/mem/mem_stats.h index b6809fb74a..31b442140c 100644 --- a/runtime/mem/mem_stats.h +++ b/runtime/mem/mem_stats.h @@ -27,7 +27,6 @@ #include "runtime/mem/gc/gc_phase.h" namespace panda { - class BaseClass; } // namespace panda diff --git a/runtime/mem/mem_stats_additional_info.h b/runtime/mem/mem_stats_additional_info.h index 9e2f4807e9..6ed7b55554 100644 --- a/runtime/mem/mem_stats_additional_info.h +++ b/runtime/mem/mem_stats_additional_info.h @@ -22,7 +22,6 @@ #include "runtime/mem/mem_stats.h" namespace panda { - class Class; } // namespace panda diff --git a/runtime/mem/mem_stats_default.cpp b/runtime/mem/mem_stats_default.cpp index e0f38d6bab..ae28e89dcd 100644 --- a/runtime/mem/mem_stats_default.cpp +++ b/runtime/mem/mem_stats_default.cpp @@ -46,5 +46,4 @@ double MemStatsDefault::GetTotalGCPhaseTime([[maybe_unused]] GCPhase phase) cons { return 0; } - } // namespace panda::mem diff --git a/runtime/mem/mem_stats_default.h b/runtime/mem/mem_stats_default.h index 0a19d5e940..24b4931c9e 100644 --- a/runtime/mem/mem_stats_default.h +++ b/runtime/mem/mem_stats_default.h @@ -21,7 +21,6 @@ #include "runtime/mem/mem_stats.h" namespace panda { - class Class; } // namespace panda diff --git a/runtime/mem/object_helpers.cpp b/runtime/mem/object_helpers.cpp index 6661e26251..2e4afa233f 100644 --- a/runtime/mem/object_helpers.cpp +++ b/runtime/mem/object_helpers.cpp @@ -12,7 +12,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include #include "runtime/mem/object_helpers-inl.h" diff --git a/runtime/mem/panda_string.cpp b/runtime/mem/panda_string.cpp index 74ed682a1f..48b8a1acbf 100644 --- a/runtime/mem/panda_string.cpp +++ b/runtime/mem/panda_string.cpp @@ -59,13 +59,22 @@ double PandaStringToD(const PandaString &str) return result; } -PandaString ConvertToString(Span sp) +template +PandaString ConvertToString(T sp) { PandaString res; res.reserve(sp.size()); + + // Also support ascii that great than 127, so using unsigned char here + constexpr size_t MAX_CHAR = std::numeric_limits::max(); + for (auto c : sp) { + if (c > MAX_CHAR) { + return ""; + } res.push_back(c); } + return res; } diff --git a/runtime/mem/pygote_space_allocator.h b/runtime/mem/pygote_space_allocator.h index 1c0e94ba02..55dac74bb7 100644 --- a/runtime/mem/pygote_space_allocator.h +++ b/runtime/mem/pygote_space_allocator.h @@ -28,7 +28,6 @@ #include "runtime/mem/gc/bitmap.h" namespace panda { - class ObjectHeader; } // namespace panda diff --git a/runtime/mem/refstorage/global_object_storage.cpp b/runtime/mem/refstorage/global_object_storage.cpp index 263a42cd8c..4b5d7d1a2a 100644 --- a/runtime/mem/refstorage/global_object_storage.cpp +++ b/runtime/mem/refstorage/global_object_storage.cpp @@ -12,7 +12,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include "global_object_storage.h" #include diff --git a/runtime/mem/refstorage/ref_block.cpp b/runtime/mem/refstorage/ref_block.cpp index 392845ac4f..2ca3ab00a6 100644 --- a/runtime/mem/refstorage/ref_block.cpp +++ b/runtime/mem/refstorage/ref_block.cpp @@ -12,7 +12,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include "ref_block.h" namespace panda::mem { diff --git a/runtime/mem/region_allocator.h b/runtime/mem/region_allocator.h index 229620f9b5..9637f7e59c 100644 --- a/runtime/mem/region_allocator.h +++ b/runtime/mem/region_allocator.h @@ -22,7 +22,6 @@ #include "runtime/mem/region_space.h" namespace panda { - class ManagedThread; } // namespace panda diff --git a/runtime/mem/region_space.cpp b/runtime/mem/region_space.cpp index 0dbbfc992a..b80b7233ef 100644 --- a/runtime/mem/region_space.cpp +++ b/runtime/mem/region_space.cpp @@ -12,7 +12,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #include "runtime/mem/region_space-inl.h" #include "runtime/mem/rem_set-inl.h" diff --git a/runtime/mem/runslots_allocator-inl.h b/runtime/mem/runslots_allocator-inl.h index 8e4d6b8c9b..de303de5e2 100644 --- a/runtime/mem/runslots_allocator-inl.h +++ b/runtime/mem/runslots_allocator-inl.h @@ -887,5 +887,4 @@ bool RunSlotsAllocator::MemPoolManager::PoolListEleme #undef LOG_RUNSLOTS_ALLOCATOR } // namespace panda::mem - #endif // PANDA_RUNTIME_MEM_RUNSLOTS_ALLOCATOR_INL_H_ diff --git a/runtime/object_accessor-impl.cpp b/runtime/object_accessor-impl.cpp index 807d62d923..6e4a9c8685 100644 --- a/runtime/object_accessor-impl.cpp +++ b/runtime/object_accessor-impl.cpp @@ -12,6 +12,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #ifndef PANDA_RUNTIME_OBJECT_ACCESSOR_IMPL_CPP_ #define PANDA_RUNTIME_OBJECT_ACCESSOR_IMPL_CPP_ // This file is included by interpreter to inline methods that defined in it. diff --git a/runtime/options.yaml b/runtime/options.yaml index dd02924199..44a03eba71 100644 --- a/runtime/options.yaml +++ b/runtime/options.yaml @@ -314,25 +314,25 @@ options: default: true description: Enable/disable TLAB using for object allocations. Now, it is ignored for all GCs except GenGC. Temporary option for quick switch between modes. -- name: object-pool-size +- name: heap-size-limit type: uint32_t default: 536870912 - description: Size of pool used for objects + description: Max heap size -- name: internal-pool-size +- name: internal-memory-size-limit type: uint64_t default: 2147483648 - description: Size of pool used for internal memory. + description: Max internal memory used by the VM -- name: code-pool-size - type: uint32_t +- name: code-cache-size-limit + type: uint64_t default: 33554432 - description: Size of pool used for compiled code memory + description: The limit for compiled code size. -- name: compiler-pool-size - type: uint32_t +- name: compiler-memory-size-limit + type: uint64_t default: 268435456 - description: Size of pool used for internal compiler memory + description: Max memory used by the compiler - name: print-memory-statistics type: bool @@ -547,3 +547,8 @@ options: type: bool default: false description: Print backtrace each time a thread gets suspended + +- name: icu-data-path + type: std::string + default: "default" + description: Path to generated icu data file diff --git a/runtime/runtime.cpp b/runtime/runtime.cpp index 4a2058d19a..893adc8d42 100644 --- a/runtime/runtime.cpp +++ b/runtime/runtime.cpp @@ -251,8 +251,8 @@ bool Runtime::Create(const RuntimeOptions &options, const std::vector 'void', - 'u1' => 'uint8_t', - 'i8' => 'int8_t', - 'u8' => 'uint8_t', - 'i16' => 'int16_t', - 'u16' => 'uint16_t', - 'i32' => 'int32_t', - 'u32' => 'uint32_t', - 'i64' => 'int64_t', - 'u64' => 'uint64_t', - 'f32' => 'double', - 'f64' => 'double', - 'any' => ['int64_t', 'int64_t'], - 'acc' => ['int64_t', 'int64_t'], - 'string_id' => 'uint32_t', - 'method_id' => 'uint32_t', - } - @effective_type_map[type] || get_object_type(type) + get_type(type) end def get_ret_effective_type(type) - @ret_effective_type_map ||= { - 'void' => 'void', - 'u1' => 'uint8_t', - 'i8' => 'int8_t', - 'u8' => 'uint8_t', - 'i16' => 'int16_t', - 'u16' => 'uint16_t', - 'i32' => 'int32_t', - 'u32' => 'uint32_t', - 'i64' => 'int64_t', - 'u64' => 'uint64_t', - 'f32' => 'double', - 'f64' => 'double', - 'any' => 'DecodedTaggedValue', - 'string_id' => 'uint32_t', - 'method_id' => 'uint32_t', - 'acc' => 'DecodedTaggedValue', - } - @ret_effective_type_map[type] || get_object_type(type) + get_ret_type(type) end class Intrinsic < SimpleDelegator def need_abi_wrapper? - signature.ret == 'f32' || signature.args.include?('f32') + Object.send(:get_ret_type, signature.ret) != Object.send(:get_ret_effective_type, signature.ret) || + signature.args.any? { |arg| Object.send(:get_ret_type, arg) != Object.send(:get_ret_effective_type, arg) } end def enum_name diff --git a/runtime/templates/shorty_values.h.erb b/runtime/templates/shorty_values.h.erb index c8ad1b3aaa..ce7f36109f 100644 --- a/runtime/templates/shorty_values.h.erb +++ b/runtime/templates/shorty_values.h.erb @@ -25,12 +25,12 @@ % first_nonvoid = PandaFile::types.select {|type| type.name != "void"}.first.code % first_32 = PandaFile::types.select {|type| type.width && type.width == 32}.first.code -% last_int32 = PandaFile::types.select {|type| type.width && type.width == 32 && type.properties.include?("integral") }.last.code -% first_64 = PandaFile::types.select {|type| (type.width && type.width == 64) || type.properties.include?("float") }.first.code +% last_int32 = PandaFile::types.select {|type| type.width && type.width == 32 && type.properties.include?("integral")}.last.code +% first_64 = PandaFile::types.select {|type| (type.width && type.width == 64)}.first.code % first_float = PandaFile::types.select {|type| type.properties.include?("float") }.first.code -% num_32_and_larger = PandaFile::types.select {|type| type.width && type.width >= 32 || type.properties.include?("float") || type.name == "reference" || type.name == "tagged" }.length +% num_32_and_larger = PandaFile::types.select {|type| type.width && type.width >= 32 || type.name == "reference" || type.name == "tagged" }.length % num_float_types = PandaFile::types.select {|type| type.properties.include?("float") }.length -% num_64bit_types = PandaFile::types.select {|type| (type.width && type.width == 64) || type.properties.include?("float") }.length +% num_64bit_types = PandaFile::types.select {|type| (type.width && type.width == 64)}.length // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define SHORTY_FIRST_NONVOID 0x<%= first_nonvoid.to_s(16) %> // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) @@ -38,7 +38,7 @@ // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define SHORTY_LAST_INT32 0x<%= last_int32.to_s(16) %> // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define SHORTY_FIRST_64 0x<%= first_64.to_s(16) %> // in the runtime all 32bit floats extends to doubles +#define SHORTY_FIRST_64 0x<%= first_64.to_s(16) %> // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define SHORTY_FIRST_FLOAT 0x<%= first_float.to_s(16) %> // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) diff --git a/runtime/templates/unimplemented_intrinsics-inl.cpp.erb b/runtime/templates/unimplemented_intrinsics-inl.cpp.erb index 4fa70c5f7a..bf46e2a8f9 100644 --- a/runtime/templates/unimplemented_intrinsics-inl.cpp.erb +++ b/runtime/templates/unimplemented_intrinsics-inl.cpp.erb @@ -15,6 +15,9 @@ // Autogenerated file -- DO NOT EDIT! +#ifndef PANDA_RUNTIME_UNIMPLEMENTED_INTRINSICS_INL_H_ +#define PANDA_RUNTIME_UNIMPLEMENTED_INTRINSICS_INL_H_ + % unimplemented = %w( % ) % intrinsics_hash = Runtime::intrinsics.map { |i| [i.name, i] }.to_h @@ -32,3 +35,5 @@ <%= body %> } % end + +#endif // PANDA_RUNTIME_UNIMPLEMENTED_INTRINSICS_INL_H_ diff --git a/runtime/tests/arch/arm/invokation_helper_hf.S b/runtime/tests/arch/arm/invokation_helper_hf.S index 83ee374643..52d9755211 100644 --- a/runtime/tests/arch/arm/invokation_helper_hf.S +++ b/runtime/tests/arch/arm/invokation_helper_hf.S @@ -19,4 +19,54 @@ .global InvokeHelper .type InvokeHelper, %function InvokeHelper: + CFI_STARTPROC + CFI_DEF_CFA(sp, 0) + + // setup regs as follow + // r4 - gprs, r5 - fprs, r6 - stack args, r7 - number of stack args, r8 - thread + + push {r4 - r8, fp, lr} + CFI_ADJUST_CFA_OFFSET(28) + CFI_REL_OFFSET(lr, 24) + CFI_REL_OFFSET(fp, 20) + mov fp, sp + CFI_DEF_CFA_REGISTER(fp) + + mov r4, r0 + mov r5, r1 + mov r6, r2 + mov r7, r3 + ldr r8, [sp, #28] + + sub sp, sp, #4 + push {THREAD_REG} + CFI_ADJUST_CFA_OFFSET(8) + CFI_REL_OFFSET(THREAD_REG, 0) + mov THREAD_REG, r8 + + ldmia r4!, {r0 - r3} + vldmia r5!, {d0 - d7} + + sub sp, sp, r7, lsl #2 + bic sp, sp, #7 + mov r8, sp +1: cmp r7, #0 + beq .Linvoke + ldr r4, [r6], #4 + str r4, [r8], #4 + sub r7, r7, #1 + b 1b + +.Linvoke: + ldr lr, [r0, #METHOD_COMPILED_ENTRY_POINT_OFFSET] + blx lr + + mov sp, fp + ldr THREAD_REG, [sp, #-8] + CFI_RESTORE(THREAD_REG) + pop {r4 - r8, fp, lr} + CFI_ADJUST_CFA_OFFSET(-28) + CFI_RESTORE(lr) + CFI_RESTORE(fp) bx lr + CFI_ENDPROC diff --git a/runtime/tests/card_table_test.cpp b/runtime/tests/card_table_test.cpp index b43141b6a5..fc16344544 100644 --- a/runtime/tests/card_table_test.cpp +++ b/runtime/tests/card_table_test.cpp @@ -46,7 +46,7 @@ protected: seed_ = 123456U; #endif RuntimeOptions options; - options.SetObjectPoolSize(64_MB); + options.SetHeapSizeLimit(64_MB); options.SetShouldLoadBootPandaFiles(false); options.SetShouldInitializeIntrinsics(false); options.SetGcType("epsilon"); diff --git a/runtime/tests/class_linker_test.cpp b/runtime/tests/class_linker_test.cpp index dfc0cae1fb..bfd99e28cd 100644 --- a/runtime/tests/class_linker_test.cpp +++ b/runtime/tests/class_linker_test.cpp @@ -45,7 +45,7 @@ public: options.SetShouldLoadBootPandaFiles(false); options.SetShouldInitializeIntrinsics(false); options.SetGcType("epsilon"); - options.SetObjectPoolSize(64_MB); + options.SetHeapSizeLimit(64_MB); Runtime::Create(options); thread_ = panda::MTManagedThread::GetCurrent(); thread_->ManagedCodeBegin(); diff --git a/runtime/tests/interpreter_test.cpp b/runtime/tests/interpreter_test.cpp index a26891f377..e3aa8b0dcd 100644 --- a/runtime/tests/interpreter_test.cpp +++ b/runtime/tests/interpreter_test.cpp @@ -1346,7 +1346,7 @@ static void TestArray() if constexpr (component_type_id == panda_file::Type::TypeId::REFERENCE) { emitter.LdaObj(4); } else if constexpr (component_type_id == panda_file::Type::TypeId::F32) { - emitter.FldaiWide(bit_cast(static_cast(STORE_VALUE))); + emitter.Fldai(bit_cast(STORE_VALUE)); } else if constexpr (component_type_id == panda_file::Type::TypeId::F64) { emitter.FldaiWide(bit_cast(STORE_VALUE)); } else { diff --git a/runtime/tests/invokation_helper.h b/runtime/tests/invokation_helper.h index 872417fd2e..191843325a 100644 --- a/runtime/tests/invokation_helper.h +++ b/runtime/tests/invokation_helper.h @@ -17,6 +17,7 @@ #define PANDA_RUNTIME_TESTS_INVOKATION_HELPER_H_ #include +#include #include "bridge/bridge.h" #include "include/thread.h" @@ -34,13 +35,50 @@ auto GetInvokeHelper() return reinterpret_cast(const_cast(GetInvokeHelperImpl())); } -inline void WriteArg(arch::ArgWriter *) {} +inline void WriteArgImpl(arch::ArgWriter *, size_t) {} template -inline void WriteArg(arch::ArgWriter *writer, T arg, Args... args) +inline void WriteArgImpl(arch::ArgWriter *writer, size_t nfloats, T arg, Args... args); + +template +inline void WriteArgImpl(arch::ArgWriter *writer, size_t nfloats, float arg, Args... args) +{ + writer->Write(arg); + WriteArgImpl(writer, nfloats + 1, args...); +} + +template +inline void WriteArgImpl(arch::ArgWriter *writer, size_t nfloats, T arg, Args... args) { + if (RUNTIME_ARCH == Arch::AARCH32 && std::is_same_v) { + // JIT compiler doesn't pack floats according armhf ABI. So in the following case: + // + // void foo(f32 a0, f64 a1, f32 a2) + // + // Arguments will be passed in the following registers: + // a0 - s0 + // a1 - d1 + // a2 - s4 + // + // But according to armhf ABI a0 and a2 should be packed into d0: + // a0 - s0 + // a1 - d1 + // a2 - s1 + // + // So write additional float if necessary to prevent packing + if ((nfloats & 0x1) != 0) { + nfloats += 1; + writer->Write(0.0f); + } + } writer->Write(arg); - WriteArg(writer, args...); + WriteArgImpl(writer, nfloats, args...); +} + +template +inline void WriteArg(arch::ArgWriter *writer, T arg, Args... args) +{ + WriteArgImpl(writer, 0, arg, args...); } template diff --git a/runtime/tests/method_test.cpp b/runtime/tests/method_test.cpp index 902235c89d..ec4fcc7177 100644 --- a/runtime/tests/method_test.cpp +++ b/runtime/tests/method_test.cpp @@ -31,7 +31,7 @@ public: MethodTest() { RuntimeOptions options; - options.SetObjectPoolSize(128_MB); + options.SetHeapSizeLimit(128_MB); options.SetShouldLoadBootPandaFiles(false); options.SetShouldInitializeIntrinsics(false); options.SetGcType("epsilon"); diff --git a/runtime/tests/region_allocator_test.cpp b/runtime/tests/region_allocator_test.cpp index 3755b731c7..26dab9940f 100644 --- a/runtime/tests/region_allocator_test.cpp +++ b/runtime/tests/region_allocator_test.cpp @@ -38,7 +38,7 @@ public: { options_.SetShouldLoadBootPandaFiles(false); options_.SetShouldInitializeIntrinsics(false); - options_.SetObjectPoolSize(256_MB); + options_.SetHeapSizeLimit(256_MB); Runtime::Create(options_); thread_ = panda::MTManagedThread::GetCurrent(); thread_->ManagedCodeBegin(); diff --git a/scripts/install-third-party b/scripts/install-third-party index d50b11d6df..c77f339228 100755 --- a/scripts/install-third-party +++ b/scripts/install-third-party @@ -51,7 +51,7 @@ echo "$MSG_PREFIX Cloning googletest from $GOOGLETEST_URL" git clone --verbose "$GOOGLETEST_URL" "$PANDA_THIRD_PARTY_DIR/googletest" -MINIZ_URL="https://gitee.com/OHOS_STD/third_party_miniz.git" +MINIZ_URL="https://gitee.com/openharmony/third_party_miniz.git" echo "$MSG_PREFIX Cloning miniz from $MINIZ_URL" git clone --verbose "$MINIZ_URL" "$PANDA_THIRD_PARTY_DIR/miniz" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5d3eff4d0b..7395cca14a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -737,8 +737,6 @@ add_test_file(FILE "${CMAKE_CURRENT_SOURCE_DIR}/cts-assembly/initobj-bad-02.pa" add_test_file(FILE "${CMAKE_CURRENT_SOURCE_DIR}/cts-assembly/big_ark_option_value.pa" RUNTIME_OPTIONS --code-pool-size=3221225472 CTS_TEST) -add_test_file(FILE "${CMAKE_CURRENT_SOURCE_DIR}/cts-assembly/compiler_effective_types.pa" CTS_TEST) - if (TARGET verifier-tests) # Verifier regression tests # Negative (must fail) diff --git a/tests/cts-assembly/arrays-04.pa b/tests/cts-assembly/arrays-04.pa index 7cd668ed25..ac76453757 100644 --- a/tests/cts-assembly/arrays-04.pa +++ b/tests/cts-assembly/arrays-04.pa @@ -10,10 +10,10 @@ # 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. -# -# The following comment until the empty line must be a valid YAML document +# +# The following comment until the empty line must be a valid YAML document # containing exact copies of ISA specification assertions relevant to this test. -#--- +#--- # - title: Load from array # description: > # Load an element from array using accumulator as an index and puts it into accumulator. @@ -21,7 +21,7 @@ # - sig: fldarr.32 vs # format: [op_vs_8] # type: obj -# dtype: f64 +# dtype: f32 # etype: f32 # properties: [acc_read, acc_write, float] # - title: Store to array @@ -30,7 +30,7 @@ # instructions: # - sig: fstarr.32 vs1, vs2 # format: [op_vs1_4_vs2_4] -# type: f64 +# type: f32 # dtype: none # etype: f32 # properties: [acc_read, float] @@ -47,7 +47,7 @@ ldai 0 loop: jeq v0, loop_exit - i32tof64 + i32tof32 fstarr.32 v1, v2 inci v2, 1 lda v2 @@ -58,16 +58,16 @@ loop_exit: loop2: jltz loop2_exit lda v2 - i32tof64 - sta.64 v3 + i32tof32 + sta v3 lda v2 fldarr.32 v1 - fsub2.64 v3 - sta.64 v3 - call.short abs, v3 - sta.64 v3 - fldai.64 1e-6 - fcmpl.64 v3 + fsub2 v3 + sta v3 + call.short abs, v3, v3 + sta v3 + fldai 1e-6 + fcmpl v3 jlez exit_failure inci v2, -1 lda v2 @@ -80,15 +80,15 @@ exit_failure: return } -.function f64 abs(f64 a0){ - fldai.64 0.0 - fcmpl.64 a0 +.function f32 abs(f32 a0){ + fldai 0.0 + fcmpl a0 jlez label - lda.64 a0 - fneg.64 - return.64 + lda a0 + fneg + return label: - lda.64 a0 - return.64 + lda a0 + return } diff --git a/tests/cts-assembly/big_ark_option_value.pa b/tests/cts-assembly/big_ark_option_value.pa index a722cfb309..cec537085d 100644 --- a/tests/cts-assembly/big_ark_option_value.pa +++ b/tests/cts-assembly/big_ark_option_value.pa @@ -11,25 +11,25 @@ # See the License for the specific language governing permissions and # limitations under the License. -# Running this test asserts correct usage of runtime option (e.g. object-pool-size) with value > 2 GB +# Running this test asserts correct usage of runtime option (e.g. heap-size-limit) with value > 2 GB # Test content copies compiler_effective_types.pa .function f32 foo(f32 a0) { - fmovi.64 v0, 1.0 - lda.64 a0 - fcmpg.64 v0 + fmovi v0, 1.0 + lda a0 + fcmpg v0 jnez exit_failure - fldai.64 1.0 - return.64 + fldai 1.0 + return exit_failure: - fldai.64 99.0 - return.64 + fldai 99.0 + return } .function u1 main() { - fmovi.64 v1, 1.0 + fmovi v1, 1.0 call.short foo, v1, v1 - fcmpg.64 v1 + fcmpg v1 jnez exit_failure ldai 0 return diff --git a/tests/cts-assembly/intrinsics-03.pa b/tests/cts-assembly/intrinsics-03.pa index 4e8b097730..341ded09fc 100644 --- a/tests/cts-assembly/intrinsics-03.pa +++ b/tests/cts-assembly/intrinsics-03.pa @@ -15,20 +15,20 @@ .record Math .function f32 Math.absF32(f32 a0) .function u1 main(){ - fmovi.64 v0, 2.0 - fmovi.64 v1, 1e-13 + fmovi v0, 2.0 + fmovi v1, 1e-13 call.short Math.absF32, v0, v0 - fsub2.64 v0 - sta.64 v2 + fsub2 v0 + sta v2 call.short abs, v2, v2 - fcmpl.64 v1 + fcmpl v1 jgtz exit_failure - fmovi.64 v0, -2.0 + fmovi v0, -2.0 call.short Math.absF32, v0, v0 - fadd2.64 v0 - sta.64 v2 + fadd2 v0 + sta v2 call.short abs, v2, v2 - fcmpl.64 v1 + fcmpl v1 jgtz exit_failure ldai 0 return @@ -38,14 +38,14 @@ exit_failure: } .function f32 abs(f32 a0){ - fldai.64 0.0 - fcmpl.64 a0 + fldai 0.0 + fcmpl a0 jlez label - lda.64 a0 - fneg.64 - return.64 + lda a0 + fneg + return label: lda.64 a0 - return.64 + return } diff --git a/tests/cts-assembly/intrinsics-05.pa b/tests/cts-assembly/intrinsics-05.pa index 61aa3960d1..079109ff07 100644 --- a/tests/cts-assembly/intrinsics-05.pa +++ b/tests/cts-assembly/intrinsics-05.pa @@ -14,17 +14,17 @@ #Assert that intrinsic Math.sin works fine .record Math .function f32 Math.fsin (f32 a0) -.function f64 Math.absF64 (f64 a0) +.function f32 Math.absF32 (f32 a0) .function u1 main(){ - fmovi.64 v0, 1.0 - fmovi.64 v1, 0.8414709848 - fmovi.64 v2, 1e-6 + fmovi v0, 1.0 + fmovi v1, 0.8414709848 + fmovi v2, 1e-6 call.short Math.fsin, v0, v0 - fsub2.64 v1 - sta.64 v1 - call.short Math.absF64, v1, v1 - fcmpl.64 v2 + fsub2 v1 + sta v1 + call.short Math.absF32, v1, v1 + fcmpl v2 jgez exit_failure ldai 0 return diff --git a/tests/cts-assembly/intrinsics-07.pa b/tests/cts-assembly/intrinsics-07.pa index fdc64d5566..ad01dfbe23 100644 --- a/tests/cts-assembly/intrinsics-07.pa +++ b/tests/cts-assembly/intrinsics-07.pa @@ -14,17 +14,17 @@ #Assert that intrinsic Math.cos works fine .record Math .function f32 Math.fcos (f32 a0) -.function f64 Math.absF64 (f64 a0) +.function f32 Math.absF32 (f32 a0) .function u1 main(){ - fmovi.64 v0, 1.0 - fmovi.64 v1, 0.5403023059 - fmovi.64 v2, 1e-6 + fmovi v0, 1.0 + fmovi v1, 0.5403023059 + fmovi v2, 1e-6 call.short Math.fcos, v0, v0 - fsub2.64 v1 - sta.64 v1 - call.short Math.absF64, v1, v1 - fcmpl.64 v2 + fsub2 v1 + sta v1 + call.short Math.absF32, v1, v1 + fcmpl v2 jgez exit_failure ldai 0 return diff --git a/tests/cts-assembly/intrinsics-09.pa b/tests/cts-assembly/intrinsics-09.pa index 72faf74188..3783d2b6ae 100644 --- a/tests/cts-assembly/intrinsics-09.pa +++ b/tests/cts-assembly/intrinsics-09.pa @@ -14,18 +14,18 @@ #Assert that intrinsic Math.pow works fine .record Math .function f32 Math.fpow (f32 a0, f32 a1) -.function f64 Math.absF64 (f64 a0) +.function f32 Math.absF32 (f32 a0) .function u1 main(){ - fmovi.64 v0, 2.5 - fmovi.64 v1, 24.7052942201 - fmovi.64 v2, 1e-6 - fmovi.64 v3, 3.5 + fmovi v0, 2.5 + fmovi v1, 24.7052942201 + fmovi v2, 1e-6 + fmovi v3, 3.5 call.short Math.fpow, v0, v3 - fsub2.64 v1 - sta.64 v1 - call.short Math.absF64, v1, v1 - fcmpl.64 v2 + fsub2 v1 + sta v1 + call.short Math.absF32, v1, v1 + fcmpl v2 jgez exit_failure ldai 0 return diff --git a/tests/cts-assembly/intrinsics-11.pa b/tests/cts-assembly/intrinsics-11.pa index 604b6ce151..ff1aece456 100644 --- a/tests/cts-assembly/intrinsics-11.pa +++ b/tests/cts-assembly/intrinsics-11.pa @@ -14,17 +14,17 @@ #Assert that intrinsic Math.sqrt works fine .record Math .function f32 Math.fsqrt (f32 a0) -.function f64 Math.absF64 (f64 a0) +.function f32 Math.absF32 (f32 a0) .function u1 main(){ - fmovi.64 v0, 2.5 - fmovi.64 v1, 1.5811388301 - fmovi.64 v2, 1e-6 + fmovi v0, 2.5 + fmovi v1, 1.5811388301 + fmovi v2, 1e-6 call.short Math.fsqrt, v0, v0 - fsub2.64 v1 - sta.64 v1 - call.short Math.absF64, v1, v1 - fcmpl.64 v2 + fsub2 v1 + sta v1 + call.short Math.absF32, v1, v1 + fcmpl v2 jgez exit_failure ldai 0 return diff --git a/tests/cts-assembly/intrinsics-15.pa b/tests/cts-assembly/intrinsics-15.pa index 718bd63732..4c98bec323 100644 --- a/tests/cts-assembly/intrinsics-15.pa +++ b/tests/cts-assembly/intrinsics-15.pa @@ -15,7 +15,7 @@ .function void IO.printF32(f32 a0) .function u1 main(){ - fmovi.64 v0, 26.6 + fmovi v0, 26.6 call.short IO.printF32, v0, v0 ldai 0 return diff --git a/tests/cts-assembly/intrinsics-f32-01.pa b/tests/cts-assembly/intrinsics-f32-01.pa index e2df3ec8f9..60201665ef 100644 --- a/tests/cts-assembly/intrinsics-f32-01.pa +++ b/tests/cts-assembly/intrinsics-f32-01.pa @@ -16,10 +16,10 @@ .function f32 Math.fsqrt (f32 a0) .function u1 main(){ - fmovi.64 v0, 0.78539816339744828 # Pi / 4 - fmovi.64 v1, 0.88622695207595825 # Expected result + fmovi v0, 0.78539816339744828 # Pi / 4 + fmovi v1, 0.88622695207595825 # Expected result call.short Math.fsqrt, v0 - fcmpl.64 v1 + fcmpl v1 jnez exit_failure ldai 0 return diff --git a/tests/cts-coverage-tool/CMakeLists.txt b/tests/cts-coverage-tool/CMakeLists.txt index ea27ac7a71..16006d490b 100644 --- a/tests/cts-coverage-tool/CMakeLists.txt +++ b/tests/cts-coverage-tool/CMakeLists.txt @@ -18,7 +18,7 @@ project(cts_coverage_tool) # Coverage reports generation # Source files: -set(ISA_FILE "${isa_SOURCE_DIR}/isa.yaml") +set(ISA_FILE "${CMAKE_BINARY_DIR}/isa/isa.yaml") set(NON_TESTABLE "${PROJECT_SOURCE_DIR}/non_testable.yaml") set(TESTS_DIR "${PROJECT_BINARY_DIR}/../cts-generator") set(TESTS_GLOB_ASSEMBLY "cts-assembly/**/*.pa") diff --git a/tests/cts-generator/cts-template/call.acc.short.yaml b/tests/cts-generator/cts-template/call.acc.short.yaml new file mode 100644 index 0000000000..43fb7804d3 --- /dev/null +++ b/tests/cts-generator/cts-template/call.acc.short.yaml @@ -0,0 +1,2296 @@ +# 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. +--- +definitions: + - name: java + template: > + .language Java + +tests: + - file-name: call.acc.short + isa: + title: Static call with accumulator as input + description: > + Call indicated static method, i.e. create new frame, pass values of arguments and + continue execution from the first instruction of a method. + Callee should treat accumulator value as undefined and cannot use it until accumulator + definition in the new frame. + Result (if any) is returned in accumulator (see 'Calling sequence' chapter for more details). + Method, its class and the number of argument is resolved by given method_id in + runtime constant-pool. + Arguments are passed in source registers in the same order as in method signature. + Non-range instructions can be used to pass up to 4 arguments (unused register slot values will + be discarded and corresponding registers will not be passed to the callee). + In dynamically-typed language context accept 'any' values in source registers. + Immediate operand encodes a position starting from 0 on which accumulator is passed. + exceptions: + - x_none + verification: + - method_id_static + - compatible_arguments + - method_id_non_abstract + instructions: + - sig: call.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + commands: + + - file-name: op_v_4_imm_4_id_16 + description: Check that compiler reports an error on invalid instruction format. + isa: + instructions: + - sig: call.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + header-template: [] + check-type: exit-positive + runner-options: [compile-failure] + code-template: | + .function void f0() { + return.void + } + .function void f1(i32 a0) { + return.void + } + .function void f2(i32 a0, i32 a1) { + return.void + } + .function void f3(i32 a0, i32 a1, i32 a2) { + return.void + } + .function i32 main() { + call.acc.short %s + cases: + - values: ['foo, v0, 0'] + - values: ['foo, v1, 1'] + - values: ['f0'] + - values: ['f1, v0'] + - values: ['f2, v0, 0'] + runner-options: [compile-only] + - values: ['f2, v16, 0'] + - values: ['f2, v255, 1'] + - values: ['f2, v32767, 1'] + - values: ['f2, v65536, 0'] + - values: ['f2, v255, 1'] + - values: ['f2, a0, 1'] + - values: ['f3, v0, 0'] + + + - file-name: reg_v_valid + description: Check with all valid 'v' register numbers. + isa: + instructions: + - sig: call.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .function i32 foo(i32 a0, i32 a1) { + lda a0 + return + } + .function i32 main() { + ldai 0 + movi v0, 0 + movi v1, 1 + movi v2, 2 + movi v3, 3 + movi v4, 4 + movi v5, 5 + movi v6, 6 + movi v7, 7 + movi v8, 8 + movi v9, 9 + movi v10, 10 + movi v11, 11 + movi v12, 12 + movi v13, 13 + movi v14, 14 + movi v15, 15 + call.acc.short foo, v0, 1 + call.acc.short foo, v1, 1 + call.acc.short foo, v2, 1 + call.acc.short foo, v3, 1 + call.acc.short foo, v4, 1 + call.acc.short foo, v5, 1 + call.acc.short foo, v6, 1 + call.acc.short foo, v7, 1 + call.acc.short foo, v8, 1 + call.acc.short foo, v9, 1 + call.acc.short foo, v10, 1 + call.acc.short foo, v11, 1 + call.acc.short foo, v12, 1 + call.acc.short foo, v13, 1 + call.acc.short foo, v14, 1 + call.acc.short foo, v15, 1 + + + - file-name: reg_a_valid + description: Check with all valid 'a' register numbers. + isa: + instructions: + - sig: call.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .function i32 foo(i32 a0, i32 a1) { + lda a0 + return + } + .function void f(i32 a0, i32 a1, i32 a2, i32 a3, i32 a4, i32 a5, i32 a6, i32 a7, i32 a8, i32 a9, i32 a10, i32 a11, i32 a12, i32 a13, i32 a14, i32 a15) { + ldai 0 + call.acc.short foo, a0, 1 + call.acc.short foo, a1, 1 + call.acc.short foo, a2, 1 + call.acc.short foo, a3, 1 + call.acc.short foo, a4, 1 + call.acc.short foo, a5, 1 + call.acc.short foo, a6, 1 + call.acc.short foo, a7, 1 + call.acc.short foo, a8, 1 + call.acc.short foo, a9, 1 + call.acc.short foo, a10, 1 + call.acc.short foo, a11, 1 + call.acc.short foo, a12, 1 + call.acc.short foo, a13, 1 + call.acc.short foo, a14, 1 + call.acc.short foo, a15, 1 + return.void + } + .function i32 main() { + movi v0, 0 + movi v1, 1 + movi v2, 2 + movi v3, 3 + movi v4, 4 + movi v5, 5 + movi v6, 6 + movi v7, 7 + movi v8, 8 + movi v9, 9 + movi v10, 10 + movi v11, 11 + movi v12, 12 + movi v13, 13 + movi v14, 14 + movi v15, 15 + call.range f, v0 + + + - file-name: uninitialized_regs + description: Check that verifier reports an error on uninitialized registers. + isa: + instructions: + - sig: call.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .function i32 foo(%s) { + %s + return + } + .function i32 main() { + %s + call.acc.short foo, %s + cases: + - description: Register v0 is not initialized. + values: + - i32 a0, i32 a1 + - lda a0 + - ldai 0 + - v0, 0 + - description: Register v0 is not initialized. + values: + - i32 a0, i32 a1 + - lda a1 + - ldai 0 + - v0, 1 + - description: Register v0 is not initialized, but it's not used. + values: + - i32 a0 + - lda a0 + - ldai 0 + - v0, 0 + runner-options: [verifier-only, verifier-debug-config] + - description: Accumulator is not initialized. + values: + - i32 a0, i32 a1 + - lda a1 + - movi v0, 0 + - v0, 0 + - description: Accumulator is not initialized. + values: + - i32 a0, i32 a1 + - lda a0 + - movi v0, 0 + - v0, 1 + - description: Accumulator is not initialized, but it's not used. + values: + - i32 a0 + - lda a0 + - movi v0, 0 + - v0, 1 + runner-options: [verifier-only, verifier-debug-config] + - description: Accumulator and v0 are both not initialized. + values: + - i32 a0, i32 a1 + - ldai 0 + - '' + - v0, 0 + - description: Accumulator and v0 are both not initialized, but they are not used. + values: + - '' + - ldai 0 + - '' + - v0, 0 + runner-options: [verifier-only, verifier-debug-config] + - description: Accumulator is not initialized in function. + values: + - i32 a0, i32 a1 + - call.acc.short foo, a0, 0 + - | + # + ldai 0 + movi v0, 0 + - v0, 0 + + + - file-name: not_static_method + description: Check that verifier reports an error on non-static method. + isa: + verification: + - method_id_static + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .record R {} + .function void %s { + return.void + } + .function i32 main() { + newobj v0, R + ldai 0 + call.acc.short %s + cases: + - values: + - R.foo(R a0, i32 a1) + - R.foo, v0, 1 + bugid: ['5542'] + ignore: true + - values: + - R.foo(R a0) + - R.foo, v0, 1 + bugid: ['5542'] + ignore: true + - values: + - R.foo(i32 a0, R a1) + - R.foo, v0, 0 + runner-options: [verifier-only, verifier-debug-config] + - values: + - R.foo(R a0, i32 a1) + - R.foo, v0, 1 + bugid: ['5542'] + ignore: true + - values: + - R.foo(R a0) + - R.foo, v0, 1 + bugid: ['5542'] + ignore: true + - values: + - R.foo() + - R.foo, v0, 1 + runner-options: [verifier-only, verifier-debug-config] + - values: + - R.foo(R a0, i32 a1) + - R.foo, v0, 1 + runner-options: [verifier-only, verifier-debug-config] + - values: + - R.foo(R a0, i32 a1) + - R.foo, v0, 1 + runner-options: [verifier-only, verifier-debug-config] + - values: + - foo(R a0, i32 a1) + - foo, v0, 1 + runner-options: [verifier-only, verifier-debug-config] + + + - file-name: abstract_method + description: Check that verifier reports an error on abstract method. + isa: + verification: + - method_id_non_abstract + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + bugid: ['5544'] + ignore: true + code-template: | + .record R {} + .function void %s + .function i32 main() { + newobj v0, R + ldai 0 + call.acc.short %s + cases: + - values: + - R.foo(R a0, i32 a1) + - R.foo, v0, 1 + - values: + - foo(R a0, i32 a1) + - foo, v0, 1 + + + - file-name: invalid_method + description: Check that verifier reports an error on invalid method. + isa: + verification: + - method_id_static + - method_id_non_abstract + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .record R {} + %s + .function i32 main() { + newobj v0, R + ldai 0 + call.acc.short %s + cases: + - description: No return in function. + values: + - .function void R.foo(R a0, i32 a1) {} + - R.foo, v0, 1 + bugid: ['5607'] + ignore: true + - description: No return in function. + values: + - | + # + .function void R.foo(i32 a0, R a1) { + ldai 0 + } + - R.foo, v0, 0 + - description: No return in cctor. + values: + - | + # + .function i32 R.foo(R a0) {} + - R.foo, v0, 0 + bugid: ['5607'] + ignore: true + + + - file-name: incompatible_v_p + description: Check 'call.acc.short' instruction called with incompatible register argument in PandaAssembly context. + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record R {} + .function void R.foo(i32 a0, %s a1) { + return.void + } + .function i32 main() { + *s + ldai 0 + call.acc.short R.foo, v1, 0 + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - u8 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - u32 + exclude: [i32] + - values: + - u64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - u32[] + exclude: [u32a, nul] + - values: + - u64[] + exclude: [u64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - u32[][] + exclude: [u32aa, nul] + - values: + - u64[][] + exclude: [u64aa, nul] + - values: + - f32[][] + exclude: [f32aa, nul] + - values: + - R + exclude: [nul] + - values: + - panda.String + exclude: [str, nul] + - values: + - panda.Class + exclude: [typ, nul] + - values: + - panda.Object + exclude: [u32a, u64a, f32a, u32aa, u64aa, f32aa, str, typ, ra, stra, typa, obja, raa, straa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - panda.String[] + exclude: [stra, nul] + - values: + - panda.Class[] + exclude: [typa, nul] + - values: + - panda.Object[] + exclude: [obja, u32aa, u64aa, f32aa, ra, stra, typa, raa, straa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - panda.String[][] + exclude: [straa, nul] + - values: + - panda.Class[][] + exclude: [typaa, nul] + - values: + - panda.Object[][] + exclude: [objaa, raa, straa, typaa, nul] + cases: + - values: + - movi v1, 1 + id: i32 + - values: + - movi.64 v1, 1 + id: i64 + - values: + - fmovi.64 v1, 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[] + id: u32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[] + id: u64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[][] + id: u32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[][] + id: u64aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[][] + id: f32aa + - values: + - | + # + lda.str "test message" + sta.obj v1 + id: str + - values: + - | + # + lda.type R + sta.obj v1 + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[] + id: stra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[] + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[] + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[][] + id: straa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[][] + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[][] + id: objaa + - values: + - mov.null v1 + id: nul + + + - file-name: incompatible_acc_p + description: Check 'call.acc.short' instruction called with incompatible accumulator argument in PandaAssembly context. + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record R {} + .function void R.foo(i32 a0, %s a1) { + return.void + } + .function i32 main() { + *s + movi v1, 0 + call.acc.short R.foo, v1, 1 + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - u8 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - u32 + exclude: [i32] + - values: + - u64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - u32[] + exclude: [u32a, nul] + - values: + - u64[] + exclude: [u64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - u32[][] + exclude: [u32aa, nul] + - values: + - u64[][] + exclude: [u64aa, nul] + - values: + - f32[][] + exclude: [f32aa, nul] + - values: + - R + exclude: [nul] + - values: + - panda.String + exclude: [str, nul] + - values: + - panda.Class + exclude: [typ, nul] + - values: + - panda.Object + exclude: [u32a, u64a, f32a, u32aa, u64aa, f32aa, str, typ, ra, stra, typa, obja, raa, straa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - panda.String[] + exclude: [stra, nul] + - values: + - panda.Class[] + exclude: [typa, nul] + - values: + - panda.Object[] + exclude: [obja, u32aa, u64aa, f32aa, ra, stra, typa, raa, straa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - panda.String[][] + exclude: [straa, nul] + - values: + - panda.Class[][] + exclude: [typaa, nul] + - values: + - panda.Object[][] + exclude: [objaa, raa, straa, typaa, nul] + cases: + - values: + - ldai 1 + id: i32 + - values: + - ldai.64 1 + id: i64 + - values: + - fldai.64 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[] + lda.obj v1 + id: u32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[] + lda.obj v1 + id: u64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + lda.obj v1 + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[][] + lda.obj v1 + id: u32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[][] + lda.obj v1 + id: u64aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[][] + lda.obj v1 + id: f32aa + - values: + - | + # + lda.str "test message" + id: str + - values: + - | + # + lda.type R + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + lda.obj v1 + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[] + lda.obj v1 + id: stra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[] + lda.obj v1 + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[] + lda.obj v1 + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + lda.obj v1 + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[][] + lda.obj v1 + id: straa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[][] + lda.obj v1 + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[][] + lda.obj v1 + id: objaa + - values: + - lda.null + id: nul + + + - file-name: incompatible_v_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc.short' instruction with incompatible register in Java context. + header-template: [java] + code-template: | + .record java.lang.Object + .record java.lang.Class + .record R {} + .function void R.foo(i32 a0, %s a1) { + return.void + } + .function i32 main() { + *s + ldai 0 + call.acc.short R.foo, v1, 0 + check-type: exit-positive + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - i32 + exclude: [i32] + - values: + - i64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - f64 + exclude: [f64] + - values: + - u1[] + exclude: [u1a, nul] + - values: + - i8[] + exclude: [i8a, nul] + - values: + - u16[] + exclude: [u1a, u16a, nul] + - values: + - i16[] + exclude: [i8a, i16a, nul] + - values: + - i32[] + exclude: [i8a, i16a, i32a, nul] + - values: + - i64[] + exclude: [i64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - f64[] + exclude: [f32a, f64a, nul] + - values: + - i32[][] + exclude: [i32aa, nul] + - values: + - f64[][] + exclude: [f64aa, nul] + - values: + - R + exclude: [nul] + - values: + - java.lang.Class + exclude: [typ, nul] + - values: + - java.lang.Object + exclude: [u1a, i8a, u16a, i16a, i32a, i64a, f32a, f64a, i32aa, f64aa, typ, ra, typa, obja, raa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - java.lang.Class[] + exclude: [typa, nul] + - values: + - java.lang.Object[] + exclude: [obja, i32aa, f64aa, ra, typa, raa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - java.lang.Class[][] + exclude: [typaa, nul] + - values: + - java.lang.Object[][] + exclude: [objaa, raa, typaa, nul] + cases: + - values: + - movi v1, 1 + id: i32 + - values: + - movi.64 v1, 1 + id: i64 + - values: + - fmovi.64 v1, 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u1[] + id: u1a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i8[] + id: i8a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u16[] + id: u16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i16[] + id: i16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[] + id: i32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i64[] + id: i64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[] + id: f64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[][] + id: i32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[][] + id: f64aa + - values: + - | + # + lda.type R + sta.obj v1 + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[] + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[] + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[][] + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[][] + id: objaa + - values: + - mov.null v1 + id: nul + + + - file-name: incompatible_acc_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc.short' instruction with incompatible accumulator in Java context. + header-template: [java] + check-type: exit-positive + code-template: | + .record java.lang.Object + .record java.lang.Class + .record R {} + .function void R.foo(%s a0, i32 a1) { + return.void + } + .function i32 main() { + *s + movi v1, 0 + call.acc.short R.foo, v1, 0 + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - i32 + exclude: [i32] + - values: + - i64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - f64 + exclude: [f64] + - values: + - u1[] + exclude: [u1a, nul] + - values: + - i8[] + exclude: [i8a, nul] + - values: + - u16[] + exclude: [u1a, u16a, nul] + - values: + - i16[] + exclude: [i8a, i16a, nul] + - values: + - i32[] + exclude: [i8a, i16a, i32a, nul] + - values: + - i64[] + exclude: [i64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - f64[] + exclude: [f32a, f64a, nul] + - values: + - i32[][] + exclude: [i32aa, nul] + - values: + - f64[][] + exclude: [f64aa, nul] + - values: + - R + exclude: [nul] + - values: + - java.lang.Class + exclude: [typ, nul] + - values: + - java.lang.Object + exclude: [u1a, i8a, u16a, i16a, i32a, i64a, f32a, f64a, i32aa, f64aa, typ, ra, typa, obja, raa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - java.lang.Class[] + exclude: [typa, nul] + - values: + - java.lang.Object[] + exclude: [obja, i32aa, f64aa, ra, typa, raa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - java.lang.Class[][] + exclude: [typaa, nul] + - values: + - java.lang.Object[][] + exclude: [objaa, raa, typaa, nul] + cases: + - values: + - ldai 1 + id: i32 + - values: + - ldai.64 1 + id: i64 + - values: + - fldai.64 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u1[] + lda.obj v1 + id: u1a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i8[] + lda.obj v1 + id: i8a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u16[] + lda.obj v1 + id: u16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i16[] + lda.obj v1 + id: i16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[] + lda.obj v1 + id: i32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i64[] + lda.obj v1 + id: i64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + lda.obj v1 + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[] + lda.obj v1 + id: f64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[][] + lda.obj v1 + id: i32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[][] + lda.obj v1 + id: f64aa + - values: + - | + # + lda.type R + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + lda.obj v1 + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[] + lda.obj v1 + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[] + lda.obj v1 + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + lda.obj v1 + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[][] + lda.obj v1 + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[][] + lda.obj v1 + id: objaa + - values: + - lda.null + id: nul + + + - file-name: compatible_primitive_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc.short' instruction with compatible primitive arguments in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record R {} + .function void R.foo(%s a0, %s a1) { + return.void + } + .function i32 main() { + %s + %s + call.acc.short R.foo, v1, 0 + cases: + - values: + - u1 + - u8 + - ldai 1 + - movi v1, 1 + - values: + - i8 + - u16 + - ldai 1 + - movi v1, 1 + - values: + - i16 + - u32 + - ldai 1 + - movi v1, 1 + - values: + - i64 + - i32 + - ldai.64 1 + - movi v1, 1 + - values: + - u64 + - f32 + - ldai.64 1 + - fmovi.64 v1, 1.1 + - values: + - f64 + - i64 + - fldai.64 1.1 + - movi.64 v1, 1 + + + - file-name: compatible_primitive_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc.short' instruction with compatible primitive arguments in Java context. + header-template: [java] + code-template: | + .record R {} + .function void R.foo(%s a0, %s a1) { + return.void + } + .function i32 main() { + %s + %s + call.acc.short R.foo, v1, 1 + check-type: exit-positive + cases: + - values: + - u1 + - f64 + - movi v1, 1 + - fldai.64 1.1 + - values: + - u16 + - i16 + - movi v1, 1 + - ldai 1 + - values: + - i32 + - i64 + - movi v1, 1 + - ldai.64 1 + - values: + - f32 + - i8 + - fmovi.64 v1, 1.1 + - ldai 1 + + + - file-name: compatible_prim_array_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc.short' instruction called with compatible primitive array arguments in PandaAssembly context. + header-template: [] + code-template: | + .function void foo(%s a0, %s a1) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v1, v0, %s + lda.obj v1 + movi v0, 10 + newarr v1, v0, %s + call.acc.short foo, v1, 0 + check-type: exit-positive + cases: + - values: + - u1[] + - u8[] + - u1[] + - u8[] + - values: + - i8[] + - u16[] + - i8[] + - u16[] + - values: + - i16[] + - u32[] + - i16[] + - u32[] + - values: + - f32[][] + - u64[] + - f32[][] + - u64[] + - values: + - i64[] + - f32[] + - i64[] + - f32[] + - values: + - f64[] + - u1[][] + - f64[] + - u1[][] + - values: + - u8[][] + - i8[][] + - u8[][] + - i8[][] + - values: + - u16[][] + - i16[][] + - u16[][] + - i16[][] + - values: + - u32[][] + - i32[][] + - u32[][] + - i32[][] + - values: + - u64[][] + - i64[][] + - u64[][] + - i64[][] + - values: + - i32[] + - f64[][] + - i32[] + - f64[][] + + + - file-name: compatible_prim_array_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java] + tags: [verifier] + description: Check 'call.acc.short' instruction called with compatible primitive array arguments in Java context. + header-template: [java] + code-template: | + .function void foo(%s a0, %s a1) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v1, v0, %s + movi v0, 10 + newarr v0, v0, %s + lda.obj v0 + call.acc.short foo, v1, 1 + check-type: exit-positive + cases: + - values: + - u1[] + - f64[][] + - u1[] + - f64[][] + - values: + - u16[] + - i16[] + - u16[] + - i16[] + - values: + - i32[] + - i64[] + - i32[] + - i64[] + - values: + - f32[] + - f64[] + - f32[] + - f64[] + - values: + - u1[][] + - i8[][] + - u1[][] + - i8[][] + - values: + - u16[][] + - i16[][] + - u16[][] + - i16[][] + - values: + - i32[][] + - i64[][] + - i32[][] + - i64[][] + - values: + - f32[][] + - i8[] + - f32[][] + - i8[] + + + - file-name: compatible_obj_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc.short' instruction called with compatible object arguments in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record Q {} + .record R {} + .function void foo(%s a0, %s a1) { + return.void + } + .function i32 main() { + %s + call.acc.short foo, v1, 0 + cases: + # Object of type O is instance of type T if O is the same as T ... + - values: + - Q + - panda.String + - | + # + lda.str "test" + sta.obj v1 + newobj v0, Q + lda.obj v0 + - values: + - panda.Class + - R + - | + # + lda.type Q + newobj v1, R + # ... or is subtype of T + - values: + - panda.Object + - panda.Object + - | + # + newobj v1, Q + lda.str "test" + - values: + - panda.Object + - panda.Object + - | + # + lda.type Q + newobj v1, R + bugid: ['3594'] + ignore: true + # For arrays T should be a root type in type hierarchy ... + - values: + - panda.Object + - panda.Object + - | + # + movi v0, 10 + newarr v1, v0, i32[] + lda.obj v1 + newarr v1, v0, f64[][] + - values: + - panda.Object + - panda.Object + - | + # + movi v0, 10 + newarr v1, v0, Q[] + lda.obj v1 + newarr v1, v0, panda.Object[] + - values: + - panda.Object + - panda.Object + - | + # + movi v0, 10 + newarr v1, v0, panda.String[] + lda.obj v1 + newarr v1, v0, panda.Class[] + + + - file-name: compatible_obj_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc.short' instruction called with compatible object arguments in Java context. + header-template: [java] + check-type: exit-positive + code-template: | + .record java.lang.Object + .record java.lang.Class + .record java.lang.String + .record java.io.Serializable + .record I {} + .record E {} + .record Q {} + .record R {} + .function void foo(%s a0, %s a1) { + return.void + } + .function i32 main() { + %s + call.acc.short foo, v1, 1 + cases: + # Object of type O is instance of type T if O is the same as T ... + - values: + - Q + - java.lang.String + - | + # + newobj v1, Q + lda.str "test" + - values: + - java.lang.Class + - E + - | + # + lda.type Q + sta.obj v1 + newobj v0, E + lda.obj v0 + # ... or is subtype of T + - values: + - E + - I + - | + # + newobj v1, Q + newobj v0, Q + lda.obj v0 + - values: + - java.lang.Object + - java.lang.Object + - | + # + newobj v1, Q + lda.str "test" + - values: + - java.io.Serializable + - java.lang.Object + - | + # + lda.type java.lang.String + sta.obj v1 + lda.type Q + bugid: ['3594'] + ignore: true + # For arrays T should be a root type in type hierarchy ... + - values: + - java.lang.Object + - java.lang.Object + - | + # + movi v0, 10 + newarr v1, v0, i32[] + lda.obj v1 + newarr v1, v0, f64[][] + - values: + - java.lang.Object + - java.lang.Object + - | + # + movi v0, 10 + newarr v1, v0, Q[] + lda.obj v1 + newarr v1, v0, java.lang.Object[] + - values: + - java.lang.Object + - java.lang.Object + - | + # + movi v0, 10 + newarr v1, v0, java.lang.String[] + lda.obj v1 + newarr v1, v0, java.lang.Class[] + + + - file-name: compatible_obj_array_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc.short' instruction called with compatible object array arguments in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record Q {} + .record R {} + .function void foo(%s a0, %s a1) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v1, v0, %s + lda.obj v1 + newarr v1, v0, %s + call.acc.short foo, v1, 0 + cases: + # T is such array that O array elements are the same as T array elements + - values: + - Q[] + - Q[][] + - Q[] + - Q[][] + - values: + - panda.Object[] + - panda.Object[][] + - panda.Object[] + - panda.Object[][] + - values: + - panda.String[] + - panda.String[][] + - panda.String[] + - panda.String[][] + - values: + - panda.Class[] + - panda.Class[][] + - panda.Class[] + - panda.Class[][] + # T is such array that O array elements are subtypes of T array elements + - values: + - panda.Object[] + - panda.Object[] + - panda.Object[][] + - Q[] + - values: + - panda.Object[] + - panda.Object[] + - Q[][] + - panda.Class[] + - values: + - panda.Object[] + - panda.Object[] + - panda.Class[][] + - panda.String[] + - values: + - panda.Object[] + - panda.Object[] + - panda.String[][] + - i32[][] + - values: + - panda.Object[] + - panda.Object[][] + - f64[][][] + - panda.Object[][][] + - values: + - panda.Object[][] + - panda.Object[][] + - panda.Class[][] + - panda.Class[][][] + - values: + - panda.Object[][] + - panda.Object[][] + - i32[][][] + - f64[][][][] + + + - file-name: compatible_obj_array_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc.short' instruction called with compatible object array arguments in Java context. + header-template: [java] + code-template: | + .record java.lang.Object + .record java.lang.Class + .record java.lang.String + .record I {} + .record E {} + .record Q {} + .record R {} + .function void foo(%s a0, %s a1) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v1, v0, %s + newarr v0, v0, %s + lda.obj v0 + call.acc.short foo, v1, 1 + check-type: exit-positive + cases: + # T is such array that O array elements are the same as T array elements + - values: + - Q[] + - java.lang.String[] + - Q[] + - java.lang.String[] + - values: + - Q[][] + - java.lang.String[][] + - Q[][] + - java.lang.String[][] + - values: + - java.lang.Object[] + - java.lang.Class[][] + - java.lang.Object[] + - java.lang.Class[][] + - values: + - java.lang.Class[] + - java.lang.Object[][] + - java.lang.Class[] + - java.lang.Object[][] + # T is such array that O array elements are subtypes of T array elements + - values: + - E[] + - java.lang.Object[] + - Q[] + - Q[][] + - values: + - I[] + - java.lang.Object[] + - Q[] + - java.lang.Class[] + - values: + - java.lang.Object[] + - java.lang.Object[] + - java.lang.Object[][] + - Q[] + - values: + - java.lang.Object[] + - java.lang.Object[] + - java.lang.String[] + - f64[][][] + - values: + - java.lang.Object[] + - java.lang.Object[] + - java.lang.String[][] + - i32[][] + # inherited types from object[][] + - values: + - E[][] + - java.lang.Object[][] + - Q[][] + - java.lang.Object[][][] + - values: + - I[][] + - java.lang.Object[][] + - Q[][] + - java.lang.Class[][][] + - values: + - java.lang.Object[][] + - java.lang.Object[][] + - java.lang.Class[][] + - i32[][][] + + + - file-name: compatible_obj_null_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc.short' instruction called with null object ref in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record Q {} + .function void foo(%s a0, %s a1) { + return.void + } + .function i32 main() { + mov.null v1 + lda.null + call.acc.short foo, v1, 0 + cases: + - values: ['i32[]', 'f64[][]'] + - values: ['panda.Object', 'panda.Object[]'] + - values: ['panda.Object[][]', 'Q'] + - values: ['Q[][]', 'panda.String'] + - values: ['panda.String[]', 'panda.Class'] + - values: ['panda.Class[]', 'u32[][][]'] + + + - file-name: compatible_obj_null_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc.short' instruction called with null object ref in Java context. + header-template: [java] + code-template: | + .record java.lang.Object + .record java.lang.Class + .record java.lang.String + .record Q {} + .function void foo(%s a0, %s a1) { + return.void + } + .function i32 main() { + mov.null v1 + lda.null + call.acc.short foo, v1, 1 + check-type: exit-positive + cases: + - values: ['i32[]', 'f64[][]'] + - values: ['java.lang.Object', 'java.lang.Object[]'] + - values: ['java.lang.Object[][]', 'Q'] + - values: ['Q[][]', 'java.lang.String'] + - values: ['java.lang.String[]', 'java.lang.Class'] + - values: ['java.lang.Class[]', 'u1[][][]'] + + + - file-name: values_signed + isa: + instructions: + - sig: call.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + runner-options: [] + description: Check 'call.acc.short' instruction called with integer values. + header-template: [] + check-type: empty + code-template: | + .function i32 foo(i32 a0, i64 a1) { + ldai %s + jeq a0, ok1 + ldai 1 + return + ok1: + ldai.64 %s + cmp.64 a1 + return + } + .function i32 main() { + movi v1, %s + movi.64 v2, %s + lda v1 + call.acc.short foo, v2, 0 + jeqz pass1 + return + pass1: + lda.64 v2 + call.acc.short foo, v1, 1 + return + } + cases: + - values: [0, -1, 0, -1] + - values: [-1, 0, -1, 0] + - values: [0x5a5a5a5a, 0xa5a5a5a5cafebabe, 0x5a5a5a5a, 0xa5a5a5a5cafebabe] + - values: [0x11111111, 0xe1e1e1e1e1e1e1e1, 0x11111111, 0xe1e1e1e1e1e1e1e1] + + + - file-name: values_unsigned + isa: + instructions: + - sig: call.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + runner-options: [] + description: Check 'call.acc.short' instruction called with unsigned values. + header-template: [] + check-type: empty + code-template: | + .function i32 foo(u32 a0, u64 a1) { + ldai %s + ucmp a0 + jeqz ok1 + return + ok1: + ldai.64 %s + ucmp.64 a1 + return + } + .function i32 main() { + movi v1, %s + movi.64 v2, %s + lda v1 + call.acc.short foo, v2, 0 + jeqz pass1 + return + pass1: + lda.64 v2 + call.acc.short foo, v1, 1 + return + } + cases: + - values: [0xffffffff, 0xefffffffffffffff, 0xffffffff, 0xefffffffffffffff] + - values: [123456789, 0, 123456789, 0] + - values: [0x5a5a5a5a, 0xa5a5a5a5a5a5a5a5, 0x5a5a5a5a, 0xa5a5a5a5a5a5a5a5] + - values: [0x1111eeee, 0xeeee1111ffffdddd, 0x1111eeee, 0xeeee1111ffffdddd] + + + - file-name: values_float + isa: + instructions: + - sig: call.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + runner-options: [] + description: Check 'call.acc.short' instruction called with float values. + header-template: [] + check-type: empty + code-template: | + .function i32 foo(f32 a0, f64 a1) { + fldai %s + fcmpg a0 + jeqz ok1 + return + ok1: + fldai.64 %s + fcmpg.64 a1 + return + } + .function i32 main() { + fmovi v1, %s + fmovi.64 v2, %s + lda v1 + call.acc.short foo, v2, 0 + jeqz pass1 + return + pass1: + lda.64 v2 + call.acc.short foo, v1, 1 + return + } + cases: + - values: [0, -1.1, 0, -1.1] + - values: [-1.1, 0.12345678, -1.1, 0.12345678] + - values: [1.98765e14, -0.000000019e19, 1.98765e14, -0.000000019e19] + - values: [0.717171717171717171717171e71, 0.373737373737373737e37, 0.717171717171717171717171e71, 0.373737373737373737e37] + - values: [0xff800000, 0x7ff0000000000000, 0xff800000, 0x7ff0000000000000] + + + - file-name: values_obj_p + isa: + instructions: + - sig: call.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + runner-options: [] + description: Check 'call.acc.short' instruction called with object values in PandaAssembly context. + header-template: [] + check-type: empty + code-template: | + .record panda.Object + .record panda.String + .record R {} + # put objects into array + .function panda.Object foo(panda.Object a0, panda.Object a1) { + movi v0, 2 + newarr v0, v0, panda.Object[] + lda.obj a0 + movi v2, 0 + starr.obj v0, v2 + lda.obj a1 + movi v2, 1 + starr.obj v0, v2 + lda.obj v0 + return.obj + } + # check that array contains correct obj refs + .function i32 check(panda.Object a0, panda.Object a1, panda.Object[] a2) { + ldai 0 + ldarr.obj a2 + jeq.obj a0, ok1 + ldai 1 + return + ok1: + ldai 1 + ldarr.obj a2 + jeq.obj a1, ok2 + ldai 2 + return + ok2: + ldai 0 + return + } + .function i32 main() { + %s + lda.obj v1 + call.acc.short foo, v2, 0 # acc, v2 + sta.obj v7 + call check, v1, v2, v7 + jeqz pass1 + return + pass1: + lda.obj v2 + call.acc.short foo, v1, 1 # v1, acc + sta.obj v7 + call check, v1, v2, v7 + return + } + cases: + - values: + - | + # + newobj v1, R + newobj v2, panda.Object + - values: + - | + # + lda.str "test" + sta.obj v1 + lda.type panda.String + sta.obj v2 + - values: + - | + # + mov.null v1 + newobj v2, R + - values: + - | + # + newobj v1, panda.Object + mov.null v2 + - values: + - | + # + movi v0, 0 + newarr v1, v0, panda.String[] + lda.str "" + sta.obj v2 + - values: + - | + # + movi v0, 1 + newarr v1, v0, R[][] + newarr v2, v0, i32[] + + + - file-name: regs_restored + isa: + description: > + Call indicated static method, i.e. create new frame, pass values of arguments and + continue execution from the first instruction of a method. + Callee should treat accumulator value as undefined and cannot use it until accumulator + definition in the new frame. + description: Check 'call.acc.short' that registers are restored after the call. + tags: [tsan] + header-template: [] + code-template: | + .function void foo(i32 a0) { + movi a0, -100 + movi v0, 100 + movi v1, 200 + movi v2, 300 + movi v3, 400 + movi v4, 500 + movi v5, 600 + movi v6, 700 + movi v7, 800 + movi v8, 900 + movi v9, 1000 + movi v10, 1100 + movi v11, 1200 + movi v12, 1300 + movi v13, 1400 + movi v14, 1500 + movi v15, 1600 + ldai 9999 + return.void + } + .function i32 main() { + movi v0, 1 + movi v1, 2 + movi v2, 3 + movi v3, 4 + movi v4, 5 + movi v5, 6 + movi v6, 7 + movi v7, 8 + movi v8, 9 + movi v9, 10 + movi v10, 11 + movi v11, 12 + movi v12, 13 + movi v13, 14 + movi v14, 15 + movi v15, 16 + call.acc.short foo, v0, 1 + call.acc.short foo, v1, 1 + call.acc.short foo, v2, 1 + call.acc.short foo, v3, 1 + call.acc.short foo, v4, 1 + call.acc.short foo, v5, 1 + call.acc.short foo, v6, 1 + call.acc.short foo, v7, 1 + call.acc.short foo, v8, 1 + call.acc.short foo, v9, 1 + call.acc.short foo, v10, 1 + call.acc.short foo, v11, 1 + call.acc.short foo, v12, 1 + call.acc.short foo, v13, 1 + call.acc.short foo, v14, 1 + call.acc.short foo, v15, 1 + ldai 1 + jeq v0, ok1 + return + ok1: + ldai 2 + jeq v1, ok2 + return + ok2: + ldai 3 + jeq v2, ok3 + return + ok3: + ldai 4 + jeq v3, ok4 + return + ok4: + ldai 5 + jeq v4, ok5 + return + ok5: + ldai 6 + jeq v5, ok6 + return + ok6: + ldai 7 + jeq v6, ok7 + return + ok7: + ldai 8 + jeq v7, ok8 + return + ok8: + ldai 9 + jeq v8, ok9 + return + ok9: + ldai 10 + jeq v9, ok10 + return + ok10: + ldai 11 + jeq v10, ok11 + return + ok11: + ldai 12 + jeq v11, ok12 + return + ok12: + ldai 13 + jeq v12, ok13 + return + ok13: + ldai 14 + jeq v13, ok14 + return + ok14: + ldai 15 + jeq v14, ok15 + return + ok15: + ldai 16 + jeq v15, ok16 + return + ok16: + check-type: exit-positive diff --git a/tests/cts-generator/cts-template/call.acc.yaml b/tests/cts-generator/cts-template/call.acc.yaml new file mode 100644 index 0000000000..19e36ab3a5 --- /dev/null +++ b/tests/cts-generator/cts-template/call.acc.yaml @@ -0,0 +1,2272 @@ +# 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. +--- +definitions: + - name: java + template: > + .language Java + +tests: + - file-name: call.acc + isa: + title: Static call with accumulator as input + description: > + Call indicated static method, i.e. create new frame, pass values of arguments and + continue execution from the first instruction of a method. + Callee should treat accumulator value as undefined and cannot use it until accumulator + definition in the new frame. + Result (if any) is returned in accumulator (see 'Calling sequence' chapter for more details). + Method, its class and the number of argument is resolved by given method_id in + runtime constant-pool. + Arguments are passed in source registers in the same order as in method signature. + Non-range instructions can be used to pass up to 4 arguments (unused register slot values will + be discarded and corresponding registers will not be passed to the callee). + In dynamically-typed language context accept 'any' values in source registers. + Immediate operand encodes a position starting from 0 on which accumulator is passed. + exceptions: + - x_none + verification: + - method_id_static + - compatible_arguments + - method_id_non_abstract + instructions: + - sig: call.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + commands: + + - file-name: op_v1_4_v2_4_v3_4_imm_4_id_16 + description: Check that compiler reports an error on invalid instruction format. + isa: + instructions: + - sig: call.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + header-template: [] + check-type: exit-positive + runner-options: [compile-failure] + code-template: | + .function void f0() { + return.void + } + .function void f1(i32 a0) { + return.void + } + .function void f2(i32 a0, i32 a1) { + return.void + } + .function void f3(i32 a0, i32 a1, i32 a2) { + return.void + } + .function void f4(i32 a0, i32 a1, i32 a2, i32 a3) { + return.void + } + .function void f5(i32 a0, i32 a1, i32 a2, i32 a3, i32 a4) { + return.void + } + .function i32 main() { + call.acc %s + cases: + - values: ['foo, v0, v0, v0, 0'] + - values: ['main'] + - values: ['f0, 0'] + - values: ['f1, 1'] + - values: ['f1, v0, 0'] + - values: ['f2, v0, 0'] + - values: ['f2, v0, v0, 1'] + - values: ['f3, v0, v0, 0'] + - values: ['f3, v0, v0, v0, 1'] + runner-options: [compile-only] + - values: ['f4, v0, v0, v0, 0'] + runner-options: [compile-only] + - values: ['f4, v0, v0, v0, v0, 1'] + - values: ['f5, v0, v0, v0, v0, 0'] + - values: ['f5, v0, v0, v0, v0, v0, 1'] + - values: ['f4, v0, v0, v0, 4'] + bugid: ['5554'] + ignore: true + - values: ['f4, v0, v0, v0, 5'] + bugid: ['5554'] + ignore: true + - values: ['f4, v16, v0, v0, 0'] + - values: ['f4, v0, v255, v0, 0'] + - values: ['f4, v0, v0, v32767, 0'] + - values: ['f4, v65536, v0, v0, 0'] + - values: ['f4, a0, a0, a0, 0'] + + + - file-name: reg_v_valid + description: Check with all valid 'v' register numbers. + isa: + instructions: + - sig: call.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .function i32 foo(i32 a0, i32 a1, i32 a2, i32 a3) { + lda a3 + return + } + .function i32 main() { + ldai 0 + movi v0, 0 + movi v1, 1 + movi v2, 2 + movi v3, 3 + movi v4, 4 + movi v5, 5 + movi v6, 6 + movi v7, 7 + movi v8, 8 + movi v9, 9 + movi v10, 10 + movi v11, 11 + movi v12, 12 + movi v13, 13 + movi v14, 14 + movi v15, 15 + call.acc foo, v0, v1, v2, 0 + call.acc foo, v3, v4, v5, 1 + call.acc foo, v6, v7, v8, 2 + call.acc foo, v9, v10, v11, 3 + call.acc foo, v12, v13, v14, 0 + call.acc foo, v15, v15, v15, 1 + + + - file-name: reg_a_valid + description: Check with all valid 'a' register numbers. + isa: + instructions: + - sig: call.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .function i32 foo(i32 a0, i32 a1, i32 a2, i32 a3) { + lda a0 + return + } + .function void f(i32 a0, i32 a1, i32 a2, i32 a3, i32 a4, i32 a5, i32 a6, i32 a7, i32 a8, i32 a9, i32 a10, i32 a11, i32 a12, i32 a13, i32 a14, i32 a15) { + ldai 0 + call.acc foo, a0, a1, a2, 0 + call.acc foo, a3, a4, a5, 1 + call.acc foo, a6, a7, a8, 2 + call.acc foo, a9, a10, a11, 3 + call.acc foo, a12, a13, a14, 0 + call.acc foo, a15, a15, a15, 1 + return.void + } + .function i32 main() { + movi v0, 0 + movi v1, 1 + movi v2, 2 + movi v3, 3 + movi v4, 4 + movi v5, 5 + movi v6, 6 + movi v7, 7 + movi v8, 8 + movi v9, 9 + movi v10, 10 + movi v11, 11 + movi v12, 12 + movi v13, 13 + movi v14, 14 + movi v15, 15 + call.range f, v0 + + + - file-name: uninitialized_regs + description: Check that verifier reports an error on uninitialized registers. + isa: + instructions: + - sig: call.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .function i32 foo(%s) { + %s + return + } + .function i32 main() { + %s + call.acc foo, %s + cases: + - description: Register v0 is not initialized. + values: + - i32 a0, i32 a1, i32 a2, i32 a3 + - lda a1 + - | + # + ldai 0 + movi v1, 0 + movi v2, 0 + - v0, v1, v2, 0 + - description: Register v1 is not initialized. + values: + - i32 a0, i32 a1, i32 a2, i32 a3 + - lda a2 + - | + # + ldai 0 + movi v0, 0 + movi v2, 0 + - v0, v1, v2, 0 + - description: Register v2 is not initialized. + values: + - i32 a0, i32 a1, i32 a2, i32 a3 + - lda a3 + - | + # + ldai 0 + movi v0, 0 + movi v1, 0 + - v0, v1, v2, 0 + - description: Registers v1, v2 are not initialized, but they arent used. + values: + - i32 a0, i32 a1 + - lda a0 + - | + # + ldai 0 + movi v0, 0 + - v0, v1, v2, 0 + runner-options: [verifier-only, verifier-debug-config] + - description: Accumulator is not initialized. + values: + - i32 a0, i32 a1 + - lda a1 + - | + # + movi v0, 0 + movi v1, 0 + movi v2, 0 + - v0, v1, v2, 1 + - description: Accumulator is not initialized. + values: + - i32 a0, i32 a1, i32 a2 + - lda a0 + - | + # + movi v0, 0 + movi v1, 0 + movi v2, 0 + - v0, v1, v2, 0 + - description: Accumulator is not initialized, but its not used. + values: + - i32 a0 + - lda a0 + - | + # + movi v0, 0 + movi v1, 0 + movi v2, 0 + - v0, v1, v2, 1 + runner-options: [verifier-only, verifier-debug-config] + - description: Accumulator is not initialized, but its not used. + values: + - i32 a0, i32 a1, i32 a2 + - lda a0 + - | + # + movi v0, 0 + movi v1, 0 + movi v2, 0 + - v0, v1, v2, 3 + runner-options: [verifier-only, verifier-debug-config] + - description: Accumulator and all regs are not initialized. + values: + - i32 a0, i32 a1, i32 a2, i32 a3 + - ldai 0 + - + - v15, v14, v13, 0 + - description: Accumulator and all regs not initialized, but they are not used. + values: + - + - ldai 0 + - + - v12, v11, v10, 2 + runner-options: [verifier-only, verifier-debug-config] + - description: Accumulator is not initialized in function. + values: + - i32 a0, i32 a1, i32 a2 + - call.acc foo, a0, a1, a2, 0 + - | + # + ldai 0 + movi v0, 0 + movi v1, 0 + movi v2, 0 + - v0, v1, v2, 0 + + + - file-name: not_static_method + description: Check that verifier reports an error on non-static method. + isa: + verification: + - method_id_static + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .record R {} + .function void %s { + return.void + } + .function i32 main() { + newobj v0, R + movi v1, 0 + movi v2, 0 + ldai 0 + call.acc %s + cases: + - values: + - R.foo(R a0, i32 a1, i32 a2, i32 a3) + - R.foo, v0, v1, v2, 1 + bugid: ['5542'] + ignore: true + - values: + - R.foo(R a0) + - R.foo, v0, v1, v2, 1 + bugid: ['5542'] + ignore: true + - values: + - R.foo(i32 a0, R a1, i32 a2, i32 a3) + - R.foo, v0, v1, v2, 0 + runner-options: [verifier-only, verifier-debug-config] + - values: + - R.foo(R a0, i32 a1) + - R.foo, v0, v1, v2, 1 + bugid: ['5542'] + ignore: true + - values: + - R.foo(R a0) + - R.foo, v0, v0, v0, 1 + bugid: ['5542'] + ignore: true + - values: + - R.foo() + - R.foo, v1, v1, v1, 1 + runner-options: [verifier-only, verifier-debug-config] + - values: + - R.foo(R a0, i32 a1) + - R.foo, v0, v1, v2, 2 + runner-options: [verifier-only, verifier-debug-config] + - values: + - R.foo(R a0, i32 a1, i32 a2) + - R.foo, v0, v1, v2, 3 + runner-options: [verifier-only, verifier-debug-config] + - values: + - foo(R a0, i32 a1, i32 a2, i32 a3) + - foo, v0, v1, v2, 2 + runner-options: [verifier-only, verifier-debug-config] + + + - file-name: abstract_method + description: Check that verifier reports an error on abstract method. + isa: + verification: + - method_id_non_abstract + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + bugid: ['5544'] + ignore: true + code-template: | + .record R {} + .function void %s + .function i32 main() { + newobj v0, R + lda.obj v0 + call.acc %s + cases: + - values: + - R.foo(R a0, R a1) + - R.foo, v0, v0, v0, 1 + - values: + - foo(R a0, R a1) + - foo, v0, v0, v0, 0 + + + - file-name: invalid_method + description: Check that verifier reports an error on invalid method. + isa: + verification: + - method_id_static + - method_id_non_abstract + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .record R {} + %s + .function i32 main() { + newobj v0, R + lda.obj v0 + call.acc %s + cases: + - description: No return in function. + values: + - .function void R.foo(R a0, R a1, R a2, R a3) {} + - R.foo, v0, v0, v0, 1 + bugid: ['5607'] + ignore: true + - description: No return in function. + values: + - | + # + .function void foo(R a0, R a1) { + ldai 0 + } + - foo, v0, v0, v0, 0 + - description: No return in cctor. + values: + - | + # + .function i32 R.foo(R a0) {} + - R.foo, v0, v0, v0, 0 + bugid: ['5607'] + ignore: true + + + - file-name: incompatible_v_p + description: Check 'call.acc' instruction called with incompatible register arguments in PandaAssembly context. + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record R {} + .function void R.foo(i32 a0, i32 a1, i32 a2, %s a3) { + return.void + } + .function i32 main() { + *s + movi v2, 2 + movi v3, 3 + ldai 0 + call.acc R.foo, v3, v2, v1, 0 + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - u8 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - u32 + exclude: [i32] + - values: + - u64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - u32[] + exclude: [u32a, nul] + - values: + - u64[] + exclude: [u64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - u32[][] + exclude: [u32aa, nul] + - values: + - u64[][] + exclude: [u64aa, nul] + - values: + - f32[][] + exclude: [f32aa, nul] + - values: + - R + exclude: [nul] + - values: + - panda.String + exclude: [str, nul] + - values: + - panda.Class + exclude: [typ, nul] + - values: + - panda.Object + exclude: [u32a, u64a, f32a, u32aa, u64aa, f32aa, str, typ, ra, stra, typa, obja, raa, straa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - panda.String[] + exclude: [stra, nul] + - values: + - panda.Class[] + exclude: [typa, nul] + - values: + - panda.Object[] + exclude: [obja, u32aa, u64aa, f32aa, ra, stra, typa, raa, straa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - panda.String[][] + exclude: [straa, nul] + - values: + - panda.Class[][] + exclude: [typaa, nul] + - values: + - panda.Object[][] + exclude: [objaa, raa, straa, typaa, nul] + cases: + - values: + - movi v1, 1 + id: i32 + - values: + - movi.64 v1, 1 + id: i64 + - values: + - fmovi.64 v1, 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[] + id: u32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[] + id: u64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[][] + id: u32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[][] + id: u64aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[][] + id: f32aa + - values: + - | + # + lda.str "test message" + sta.obj v1 + id: str + - values: + - | + # + lda.type R + sta.obj v1 + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[] + id: stra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[] + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[] + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[][] + id: straa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[][] + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[][] + id: objaa + - values: + - mov.null v1 + id: nul + + + - file-name: incompatible_acc_p + description: Check 'call.acc' instruction called with incompatible accumulator argument in PandaAssembly context. + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record R {} + .function void R.foo(i32 a0, i32 a1, %s a2, i32 a3) { + return.void + } + .function i32 main() { + *s + movi v1, 0 + call.acc R.foo, v1, v1, v1, 2 + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - u8 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - u32 + exclude: [i32] + - values: + - u64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - u32[] + exclude: [u32a, nul] + - values: + - u64[] + exclude: [u64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - u32[][] + exclude: [u32aa, nul] + - values: + - u64[][] + exclude: [u64aa, nul] + - values: + - f32[][] + exclude: [f32aa, nul] + - values: + - R + exclude: [nul] + - values: + - panda.String + exclude: [str, nul] + - values: + - panda.Class + exclude: [typ, nul] + - values: + - panda.Object + exclude: [u32a, u64a, f32a, u32aa, u64aa, f32aa, str, typ, ra, stra, typa, obja, raa, straa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - panda.String[] + exclude: [stra, nul] + - values: + - panda.Class[] + exclude: [typa, nul] + - values: + - panda.Object[] + exclude: [obja, u32aa, u64aa, f32aa, ra, stra, typa, raa, straa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - panda.String[][] + exclude: [straa, nul] + - values: + - panda.Class[][] + exclude: [typaa, nul] + - values: + - panda.Object[][] + exclude: [objaa, raa, straa, typaa, nul] + cases: + - values: + - ldai 1 + id: i32 + - values: + - ldai.64 1 + id: i64 + - values: + - fldai.64 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[] + lda.obj v1 + id: u32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[] + lda.obj v1 + id: u64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + lda.obj v1 + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[][] + lda.obj v1 + id: u32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[][] + lda.obj v1 + id: u64aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[][] + lda.obj v1 + id: f32aa + - values: + - | + # + lda.str "test message" + id: str + - values: + - | + # + lda.type R + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + lda.obj v1 + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[] + lda.obj v1 + id: stra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[] + lda.obj v1 + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[] + lda.obj v1 + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + lda.obj v1 + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[][] + lda.obj v1 + id: straa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[][] + lda.obj v1 + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[][] + lda.obj v1 + id: objaa + - values: + - lda.null + id: nul + + + - file-name: incompatible_v_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc' instruction with incompatible register in Java context. + header-template: [java] + code-template: | + .record java.lang.Object + .record java.lang.Class + .record R {} + .function void R.foo(R a0, %s a1, i32 a2, R a3) { + return.void + } + .function i32 main() { + *s + ldai 0 + newobj v2, R + newobj v3, R + call.acc R.foo, v2, v1, v3, 2 + check-type: exit-positive + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - i32 + exclude: [i32] + - values: + - i64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - f64 + exclude: [f64] + - values: + - u1[] + exclude: [u1a, nul] + - values: + - i8[] + exclude: [i8a, nul] + - values: + - u16[] + exclude: [u1a, u16a, nul] + - values: + - i16[] + exclude: [i8a, i16a, nul] + - values: + - i32[] + exclude: [i8a, i16a, i32a, nul] + - values: + - i64[] + exclude: [i64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - f64[] + exclude: [f32a, f64a, nul] + - values: + - i32[][] + exclude: [i32aa, nul] + - values: + - f64[][] + exclude: [f64aa, nul] + - values: + - R + exclude: [nul] + - values: + - java.lang.Class + exclude: [typ, nul] + - values: + - java.lang.Object + exclude: [u1a, i8a, u16a, i16a, i32a, i64a, f32a, f64a, i32aa, f64aa, typ, ra, typa, obja, raa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - java.lang.Class[] + exclude: [typa, nul] + - values: + - java.lang.Object[] + exclude: [obja, i32aa, f64aa, ra, typa, raa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - java.lang.Class[][] + exclude: [typaa, nul] + - values: + - java.lang.Object[][] + exclude: [objaa, raa, typaa, nul] + cases: + - values: + - movi v1, 1 + id: i32 + - values: + - movi.64 v1, 1 + id: i64 + - values: + - fmovi.64 v1, 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u1[] + id: u1a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i8[] + id: i8a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u16[] + id: u16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i16[] + id: i16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[] + id: i32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i64[] + id: i64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[] + id: f64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[][] + id: i32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[][] + id: f64aa + - values: + - | + # + lda.type R + sta.obj v1 + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[] + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[] + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[][] + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[][] + id: objaa + - values: + - mov.null v1 + id: nul + + + - file-name: incompatible_acc_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc' instruction with incompatible accumulator in Java context. + header-template: [java] + check-type: exit-positive + code-template: | + .record java.lang.Object + .record java.lang.Class + .record R {} + .function void R.foo(%s a0, i32 a1, i32 a2, R a3) { + return.void + } + .function i32 main() { + *s + movi v1, 0 + newobj v2, R + call.acc R.foo, v1, v1, v2, 0 + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - i32 + exclude: [i32] + - values: + - i64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - f64 + exclude: [f64] + - values: + - u1[] + exclude: [u1a, nul] + - values: + - i8[] + exclude: [i8a, nul] + - values: + - u16[] + exclude: [u1a, u16a, nul] + - values: + - i16[] + exclude: [i8a, i16a, nul] + - values: + - i32[] + exclude: [i8a, i16a, i32a, nul] + - values: + - i64[] + exclude: [i64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - f64[] + exclude: [f32a, f64a, nul] + - values: + - i32[][] + exclude: [i32aa, nul] + - values: + - f64[][] + exclude: [f64aa, nul] + - values: + - R + exclude: [nul] + - values: + - java.lang.Class + exclude: [typ, nul] + - values: + - java.lang.Object + exclude: [u1a, i8a, u16a, i16a, i32a, i64a, f32a, f64a, i32aa, f64aa, typ, ra, typa, obja, raa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - java.lang.Class[] + exclude: [typa, nul] + - values: + - java.lang.Object[] + exclude: [obja, i32aa, f64aa, ra, typa, raa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - java.lang.Class[][] + exclude: [typaa, nul] + - values: + - java.lang.Object[][] + exclude: [objaa, raa, typaa, nul] + cases: + - values: + - ldai 1 + id: i32 + - values: + - ldai.64 1 + id: i64 + - values: + - fldai.64 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u1[] + lda.obj v1 + id: u1a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i8[] + lda.obj v1 + id: i8a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u16[] + lda.obj v1 + id: u16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i16[] + lda.obj v1 + id: i16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[] + lda.obj v1 + id: i32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i64[] + lda.obj v1 + id: i64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + lda.obj v1 + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[] + lda.obj v1 + id: f64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[][] + lda.obj v1 + id: i32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[][] + lda.obj v1 + id: f64aa + - values: + - | + # + lda.type R + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + lda.obj v1 + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[] + lda.obj v1 + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[] + lda.obj v1 + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + lda.obj v1 + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[][] + lda.obj v1 + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[][] + lda.obj v1 + id: objaa + - values: + - lda.null + id: nul + + + - file-name: compatible_primitive_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc' instruction with compatible primitive arguments in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record R {} + .function void R.foo(%s) { + return.void + } + .function i32 main() { + %s + call.acc R.foo, v1, v2, v3, 0 + cases: + - values: + - u1 a0, u8 a1, i8 a2, u16 a3 + - | + # + ldai 1 + movi v1, 1 + movi v2, 1 + movi v3, 1 + - values: + - i16 a0, u32 a1, i64 a2, i32 a3 + - | + # + ldai 1 + movi v1, 1 + movi.64 v2, 1 + movi v3, 1 + - values: + - u64 a0, f32 a1, f64 a2, i64 a3 + - | + # + ldai.64 1 + fmovi.64 v1, 1.1 + fmovi.64 v2, 1.1 + movi.64 v3, 1 + + + - file-name: compatible_primitive_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc' instruction with compatible primitive arguments in Java context. + header-template: [java] + code-template: | + .record R {} + .function void R.foo(%s) { + return.void + } + .function i32 main() { + %s + call.acc R.foo, v1, v2, v3, 3 + check-type: exit-positive + cases: + - values: + - u1 a0, f64 a1, u16 a2, i16 a3 + - | + # + movi v1, 1 + fmovi.64 v2, 1.1 + movi v3, 1 + ldai 1 + - values: + - i32 a0, i64 a1, f32 a2, i8 a3 + - | + # + movi v1, 1 + movi.64 v2, 1 + fmovi.64 v3, 1.1 + ldai 1 + + + - file-name: compatible_prim_array_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc' instruction called with compatible primitive array arguments in PandaAssembly context. + header-template: [] + code-template: | + .function void foo(%s) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v1, v0, %s[] + newarr v2, v0, %s[] + newarr v3, v0, %s[] + newarr v4, v0, %s[] + lda.obj v4 + call.acc foo, v1, v2, v3, 3 + check-type: exit-positive + cases: + - values: + - u1[] a0, u8[] a1, i8[] a2, u16[] a3 + - u1 + - u8 + - i8 + - u16 + - values: + - i16[] a0, u32[] a1, f32[][] a2, u64[] a3 + - i16 + - u32 + - f32[] + - u64 + - values: + - i64[] a0, f32[] a1, f64[] a2, u1[][] a3 + - i64 + - f32 + - f64 + - u1[] + - values: + - u8[][] a0, i8[][] a1, u16[][] a2, i16[][] a3 + - u8[] + - i8[] + - u16[] + - i16[] + - values: + - u32[][] a0, i32[][] a1, u64[][] a2, i64[][] a3 + - u32[] + - i32[] + - u64[] + - i64[] + - values: + - i32[] a0, f64[][] a1 + - i32 + - f64[] + - f64[][] + - f64[][][] + + + - file-name: compatible_prim_array_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java] + tags: [verifier] + description: Check 'call.acc' instruction called with compatible primitive array arguments in Java context. + header-template: [java] + code-template: | + .function void foo(%s) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v1, v0, %s[] + newarr v2, v0, %s[] + newarr v3, v0, %s[] + lda.obj v3 + newarr v4, v0, %s[] + call.acc foo, v1, v2, v4, 2 + check-type: exit-positive + cases: + - values: + - u1[] a0, f64[][] a1, u16[] a2, i16[] a3 + - u1 + - f64[] + - u16 + - i16 + - values: + - i32[] a0, i64[] a1, f32[] a2, f64[] a3 + - i32 + - i64 + - f32 + - f64 + - values: + - u1[][] a0, i8[][] a1, u16[][] a2, i16[][] a3 + - u1[] + - i8[] + - u16[] + - i16[] + - values: + - i32[][] a0, i64[][] a1, f32[][] a2, i8[] a3 + - i32[] + - i64[] + - f32[] + - i8 + + + - file-name: compatible_obj_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc' instruction called with compatible object arguments in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record Q {} + .record R {} + .function void foo(%s) { + return.void + } + .function i32 main() { + %s + call.acc foo, v1, v2, v3, 3 + cases: + # Object of type O is instance of type T if O is the same as T ... + - values: + - Q a0, R a1, panda.Class a2, panda.String a3 + - | + # + newobj v1, Q + newobj v2, R + lda.type Q + sta.obj v3 + lda.str "test" + # ... or is subtype of T + - values: + - panda.Object a0, panda.Object a1, panda.Object a2, panda.Object a3 + - | + # + newobj v1, Q + lda.str "test" + sta.obj v2 + lda.type Q + sta.obj v3 + newobj v4, R + lda.obj v4 + bugid: ['3594'] + ignore: true + # For arrays T should be a root type in type hierarchy ... + - values: + - panda.Object a0, panda.Object a1, panda.Object a2, panda.Object a3 + - | + # + movi v0, 10 + newarr v1, v0, i32[] + newarr v2, v0, f64[][] + newarr v3, v0, Q[] + newarr v4, v0, panda.Object[] + lda.obj v4 + - values: + - panda.Object a0, panda.Object a1, panda.Object a2, panda.Object a3 + - | + # + movi v0, 10 + newarr v1, v0, panda.String[] + newarr v2, v0, panda.Class[] + newarr v3, v0, Q[][] + newarr v4, v0, R[] + lda.obj v4 + + + - file-name: compatible_obj_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc' instruction called with compatible object arguments in Java context. + header-template: [java] + check-type: exit-positive + code-template: | + .record java.lang.Object + .record java.lang.Class + .record java.lang.String + .record java.io.Serializable + .record I {} + .record E {} + .record Q {} + .record R {} + .function void foo(%s) { + return.void + } + .function i32 main() { + %s + call.acc foo, v1, v2, v3, 0 + cases: + # Object of type O is instance of type T if O is the same as T ... + - values: + - Q a0, java.lang.String a1, java.lang.Class a2, E a3 + - | + # + newobj v0, Q + lda.str "test" + sta.obj v1 + lda.type Q + sta.obj v2 + newobj v3, E + lda.obj v0 + # ... or is subtype of T + - values: + - E a0, I a1, java.lang.Object a2, java.lang.Object a3 + - | + # + newobj v0, Q + newobj v1, Q + newobj v2, Q + lda.str "test" + sta.obj v3 + lda.obj v0 + - values: + - java.io.Serializable a0, java.lang.Object a1, java.lang.Object a2 + - | + # + lda.type Q + sta.obj v1 + newobj v2, R + lda.type java.lang.String + bugid: ['3594'] + ignore: true + # For arrays T should be a root type in type hierarchy ... + - values: + - java.lang.Object a0, java.lang.Object a1, java.lang.Object a2, java.lang.Object a3 + - | + # + movi v0, 10 + newarr v1, v0, i32[] + newarr v2, v0, f64[][] + newarr v3, v0, Q[] + newarr v4, v0, java.lang.Object[] + lda.obj v4 + - values: + - java.lang.Object a0, java.lang.Object a1, java.lang.Object a2, java.lang.Object a3 + - | + # + movi v0, 10 + newarr v1, v0, java.lang.String[] + newarr v2, v0, java.lang.Class[] + newarr v3, v0, I[] + newarr v4, v0, java.lang.Object[][] + lda.obj v4 + + + - file-name: compatible_obj_array_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc' instruction called with compatible object array arguments in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record Q {} + .record R {} + .function void foo(%s) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v1, v0, %s + newarr v2, v0, %s + newarr v3, v0, %s + newarr v4, v0, %s + lda.obj v4 + call.acc foo, v1, v2, v3, 3 + cases: + # T is such array that O array elements are the same as T array elements + - values: + - Q[] a0, Q[][] a1, panda.Object[] a2, panda.Object[][] a3 + - Q[] + - Q[][] + - panda.Object[] + - panda.Object[][] + - values: + - panda.String[] a0, panda.String[][] a1, panda.Class[] a2, panda.Class[][] a3 + - panda.String[] + - panda.String[][] + - panda.Class[] + - panda.Class[][] + # T is such array that O array elements are subtypes of T array elements + - values: + - panda.Object[] a0, panda.Object[] a1, panda.Object[] a2, panda.Object[] a3 + - panda.Object[][] + - Q[] + - Q[][] + - panda.Class[] + - values: + - panda.Object[] a0, panda.Object[] a1, panda.Object[] a2, panda.Object[] a3 + - panda.Class[][] + - panda.String[] + - panda.String[][] + - i32[][] + - values: + - panda.Object[] a0, panda.Object[][] a1, panda.Object[][] a2, panda.Object[][] a3 + - f64[][][] + - panda.Object[][][] + - panda.Class[][] + - panda.Class[][][] + - values: + - panda.Object[][] a0, panda.Object[][] a1 + - i32[][][] + - f64[][][][] + - i32[][][] + - f64[][][][] + + + - file-name: compatible_obj_array_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc' instruction called with compatible object array arguments in Java context. + header-template: [java] + code-template: | + .record java.lang.Object + .record java.lang.Class + .record java.lang.String + .record I {} + .record E {} + .record Q {} + .record R {} + .function void foo(%s) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v1, v0, %s + newarr v2, v0, %s + newarr v3, v0, %s + newarr v4, v0, %s + lda.obj v2 + call.acc foo, v1, v3, v4, 1 + check-type: exit-positive + cases: + # T is such array that O array elements are the same as T array elements + - values: + - Q[] a0, java.lang.String[] a1, Q[][] a2, java.lang.String[][] a3 + - Q[] + - java.lang.String[] + - Q[][] + - java.lang.String[][] + - values: + - java.lang.Object[] a0, java.lang.Class[][] a1, java.lang.Class[] a2, java.lang.Object[][] a3 + - java.lang.Object[] + - java.lang.Class[][] + - java.lang.Class[] + - java.lang.Object[][] + # T is such array that O array elements are subtypes of T array elements + - values: + - E[] a0, java.lang.Object[] a1, I[] a2, java.lang.Object[] a3 + - Q[] + - Q[][] + - Q[] + - java.lang.Class[] + - values: + - java.lang.Object[] a0, java.lang.Object[] a1, java.lang.Object[] a2, java.lang.Object[] a3 + - java.lang.Object[][] + - Q[] + - java.lang.String[] + - f64[][][] + - values: + - java.lang.Object[] a0, java.lang.Object[] a1, java.lang.Object[] a2, java.lang.Object[] a3 + - java.lang.String[][] + - i32[][] + - I[][] + - u16[][] + # inherited types from object[][] + - values: + - E[][] a0, java.lang.Object[][] a1, I[][] a2, java.lang.Object[][] a3 + - Q[][] + - java.lang.Object[][][] + - Q[][] + - java.lang.Class[][][] + - values: + - java.lang.Object[][] a0, java.lang.Object[][] a1 + - java.lang.Class[][] + - i32[][][] + - u1[] + - u1[][] + + + - file-name: compatible_obj_null_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc' instruction called with null object ref in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record Q {} + .function void foo(%s) { + return.void + } + .function i32 main() { + mov.null v1 + mov.null v2 + mov.null v3 + lda.null + call.acc foo, v1, v2, v3, 0 + cases: + - values: ['i32[] a0, f64[][] a1, panda.Object a2, panda.Object[] a3'] + - values: ['panda.Object[][] a0, Q a1, Q[][] a2, panda.String a3'] + - values: ['panda.String[] a0, panda.Class a1, panda.Class[] a2, u32[][][] a3'] + + + - file-name: compatible_obj_null_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.acc' instruction called with null object ref in Java context. + header-template: [java] + code-template: | + .record java.lang.Object + .record java.lang.Class + .record java.lang.String + .record Q {} + .function void foo(%s) { + return.void + } + .function i32 main() { + mov.null v1 + mov.null v2 + mov.null v3 + lda.null + call.acc foo, v1, v2, v3, 1 + check-type: exit-positive + cases: + - values: ['i32[] a0, f64[][] a1, java.lang.Object a2, java.lang.Object[] a3'] + - values: ['java.lang.Object[][] a0, Q a1, Q[][] a2, java.lang.String a3'] + - values: ['java.lang.String[] a0, java.lang.Class a1, java.lang.Class[] a2, u1[][][] a3'] + + + - file-name: values_signed + isa: + instructions: + - sig: call.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + runner-options: [] + description: Check 'call.acc' instruction called with integer values. + header-template: [] + check-type: empty + code-template: | + .function i32 foo(i32 a0, i64 a1, i32 a2, i64 a3) { + ldai %s + jeq a0, ok1 + ldai 1 + return + ok1: + ldai.64 %s + cmp.64 a1 + jeqz ok2 + ldai 2 + return + ok2: + ldai %s + jeq a2, ok3 + ldai 3 + return + ok3: + ldai.64 %s + cmp.64 a3 + return + } + .function i32 main() { + movi v0, %s + movi.64 v1, %s + movi v2, %s + movi.64 v3, %s + lda v0 + call.acc foo, v1, v2, v3, 0 + return + } + cases: + - values: [0, -1, 0x5a5a5a5a, 0xa5a5a5a5cafebabe, 0, -1, 0x5a5a5a5a, 0xa5a5a5a5cafebabe] + - values: [0x11111111, 0xe1e1e1e1e1e1e1e1, 0x7ffffffe, 0x8000000000000001, 0x11111111, 0xe1e1e1e1e1e1e1e1, 0x7ffffffe, 0x8000000000000001] + + + - file-name: values_unsigned + isa: + instructions: + - sig: call.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + runner-options: [] + description: Check 'call.acc' instruction called with unsigned values. + header-template: [] + check-type: empty + code-template: | + .function i32 foo(u32 a0, u64 a1, u32 a2, u64 a3) { + ldai %s + ucmp a0 + jeqz ok1 + ldai 1 + return + ok1: + ldai.64 %s + ucmp.64 a1 + jeqz ok2 + ldai 2 + return + ok2: + ldai %s + ucmp a2 + jeqz ok3 + ldai 3 + return + ok3: + ldai.64 %s + ucmp.64 a3 + return + } + .function i32 main() { + movi v0, %s + movi.64 v1, %s + movi v2, %s + movi.64 v3, %s + lda.64 v3 + call.acc foo, v0, v1, v2, 3 + return + } + cases: + - values: [123456789, 0, 0xffffffff, 0xefffffffffffffff, 123456789, 0, 0xffffffff, 0xefffffffffffffff] + - values: [0x1111eeee, 0xeeee1111ffffdddd, 0x5a5a5a5a, 0xa5a5a5a5a5a5a5a5, 0x1111eeee, 0xeeee1111ffffdddd, 0x5a5a5a5a, 0xa5a5a5a5a5a5a5a5] + + + - file-name: values_float + isa: + instructions: + - sig: call.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + runner-options: [] + description: Check 'call.acc' instruction called with float values. + header-template: [] + check-type: empty + code-template: | + .function i32 foo(f32 a0, f64 a1, f32 a2, f64 a3) { + fldai %s + fcmpg a0 + jeqz ok1 + ldai 1 + return + ok1: + fldai.64 %s + fcmpg.64 a1 + jeqz ok2 + ldai 2 + return + ok2: + fldai %s + fcmpg a2 + jeqz ok3 + ldai 3 + return + ok3: + fldai.64 %s + fcmpg.64 a3 + return + } + .function i32 main() { + fmovi v0, %s + fmovi.64 v1, %s + fmovi v2, %s + fmovi.64 v3, %s + lda.64 v1 + call.acc foo, v0, v2, v3, 1 + return + } + cases: + - values: [0, -1.1, -1.1, 0.12345678, 0, -1.1, -1.1, 0.12345678] + - values: [0.717171717171717171717171e71, 0.373737373737373737e37, 1.98765e14, -0.000000019e19, 0.717171717171717171717171e71, 0.373737373737373737e37, 1.98765e14, -0.000000019e19] + - values: [0xff800000, 0x7ff0000000000000, 0x7f800000, 0xfff0000000000000, 0xff800000, 0x7ff0000000000000, 0x7f800000, 0xfff0000000000000] + + + - file-name: values_obj_p + isa: + instructions: + - sig: call.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + runner-options: [] + description: Check 'call.acc' instruction called with object values in PandaAssembly context. + header-template: [] + check-type: empty + code-template: | + .record panda.Object + .record panda.String + .record R {} + # put objects into array + .function panda.Object foo(panda.Object a0, panda.Object a1, panda.Object a2, panda.Object a3) { + movi v0, 4 + newarr v0, v0, panda.Object[] + lda.obj a0 + movi v7, 0 + starr.obj v0, v7 + lda.obj a1 + movi v7, 1 + starr.obj v0, v7 + lda.obj a2 + movi v7, 2 + starr.obj v0, v7 + lda.obj a3 + movi v7, 3 + starr.obj v0, v7 + lda.obj v0 + return.obj + } + # check that array contains correct obj refs + .function i32 check(panda.Object a0, panda.Object a1, panda.Object a2, panda.Object a3, panda.Object[] a4) { + ldai 0 + ldarr.obj a4 + jeq.obj a0, ok1 + ldai 1 + return + ok1: + ldai 1 + ldarr.obj a4 + jeq.obj a1, ok2 + ldai 2 + return + ok2: + ldai 2 + ldarr.obj a4 + jeq.obj a2, ok3 + ldai 3 + return + ok3: + ldai 3 + ldarr.obj a4 + jeq.obj a3, ok4 + ldai 4 + return + ok4: + ldai 0 + return + } + .function i32 main() { + %s + lda.obj v0 + call.acc foo, v1, v2, v3, 0 # acc, v1, v2, v3 + sta.obj v4 + call.range check, v0 + jeqz pass1 + return + pass1: + lda.obj v1 + call.acc foo, v0, v2, v3, 1 # v0, acc, v2, v3 + sta.obj v4 + call.range check, v0 + jeqz pass2 + return + pass2: + lda.obj v2 + call.acc foo, v0, v1, v3, 2 # v0, v1, acc, v3 + sta.obj v4 + call.range check, v0 + jeqz pass3 + return + pass3: + lda.obj v3 + call.acc foo, v0, v1, v2, 3 # v0, v1, v2, acc + sta.obj v4 + call.range check, v0 + return + } + cases: + - values: + - | + # + newobj v0, R + newobj v1, panda.Object + lda.str "test" + sta.obj v2 + lda.type panda.String + sta.obj v3 + - values: + - | + # + mov.null v0 + newobj v1, R + newobj v2, panda.Object + mov.null v3 + - values: + - | + # + movi v5, 0 + newarr v0, v5, panda.String[] + lda.str "" + sta.obj v1 + newarr v2, v5, R[][] + newarr v3, v5, i32[] + + + - file-name: regs_restored + isa: + description: > + Call indicated static method, i.e. create new frame, pass values of arguments and + continue execution from the first instruction of a method. + Callee should treat accumulator value as undefined and cannot use it until accumulator + definition in the new frame. + description: Check 'call.acc' that registers are restored after the call. + tags: [tsan] + header-template: [] + code-template: | + .function i32 foo(i32 a0, i32 a1, i32 a2, i32 a3) { + movi a0, -100 + movi a1, -200 + movi a2, -300 + movi a3, -400 + movi v0, 100 + movi v1, 200 + movi v2, 300 + movi v3, 400 + movi v4, 500 + movi v5, 600 + movi v6, 700 + movi v7, 800 + movi v8, 900 + movi v9, 1000 + movi v10, 1100 + movi v11, 1200 + movi v12, 1300 + movi v13, 1400 + movi v14, 1500 + movi v15, 1600 + ldai 9999 + return + } + .function i32 main() { + movi v0, 1 + movi v1, 2 + movi v2, 3 + movi v3, 4 + movi v4, 5 + movi v5, 6 + movi v6, 7 + movi v7, 8 + movi v8, 9 + movi v9, 10 + movi v10, 11 + movi v11, 12 + movi v12, 13 + movi v13, 14 + movi v14, 15 + movi v15, 16 + ldai 0 + call.acc foo, v0, v1, v2, 3 + call.acc foo, v3, v4, v5, 3 + call.acc foo, v6, v7, v8, 3 + call.acc foo, v9, v10, v11, 3 + call.acc foo, v12, v13, v14, 3 + call.acc foo, v15, v15, v15, 3 + ldai 1 + jeq v0, ok1 + return + ok1: + ldai 2 + jeq v1, ok2 + return + ok2: + ldai 3 + jeq v2, ok3 + return + ok3: + ldai 4 + jeq v3, ok4 + return + ok4: + ldai 5 + jeq v4, ok5 + return + ok5: + ldai 6 + jeq v5, ok6 + return + ok6: + ldai 7 + jeq v6, ok7 + return + ok7: + ldai 8 + jeq v7, ok8 + return + ok8: + ldai 9 + jeq v8, ok9 + return + ok9: + ldai 10 + jeq v9, ok10 + return + ok10: + ldai 11 + jeq v10, ok11 + return + ok11: + ldai 12 + jeq v11, ok12 + return + ok12: + ldai 13 + jeq v12, ok13 + return + ok13: + ldai 14 + jeq v13, ok14 + return + ok14: + ldai 15 + jeq v14, ok15 + return + ok15: + ldai 16 + jeq v15, ok16 + return + ok16: + check-type: exit-positive diff --git a/tests/cts-generator/cts-template/call.virt.acc.short.yaml b/tests/cts-generator/cts-template/call.virt.acc.short.yaml new file mode 100644 index 0000000000..9df4e7ff0f --- /dev/null +++ b/tests/cts-generator/cts-template/call.virt.acc.short.yaml @@ -0,0 +1,2638 @@ +# 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. +--- +definitions: + - name: java + template: > + .language Java + +tests: + - file-name: call.virt.acc.short + isa: + title: Object calls with accumulator as input + description: > + Call indicated object method, i.e. create new frame, pass values of arguments and + continue execution from the first instruction of a method. + Callee should treat accumulator value as undefined and cannot use it until accumulator + definition in the new frame. + Result (if any) is returned in accumulator (see 'Calling sequence' chapter for more details). + Method, its class and the number of argument is resolved by given method_id in runtime + constant-pool based on object reference using language-specific semantics (currently only Java + virtual methods are supported, further extensions are TBD). + Object reference is passed in the first source register, arguments are passed starting from + the second source register in the same order as in method signature. + Non-range instructions can be used to pass up to 4 arguments (including object reference). + Immediate operand encodes a position starting from 0 on which accumulator is passed. + instructions: + - sig: call.virt.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + commands: + + - file-name: op_v_4_imm_4_id_16 + description: Check that compiler reports an error on invalid instruction format. + isa: + instructions: + - sig: call.virt.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + header-template: [] + check-type: exit-positive + runner-options: [compile-failure] + code-template: | + .record R {} + .function void R.f1(R a0) { + return.void + } + .function void R.f2(R a0, i32 a1) { + return.void + } + .function void R.f3(R a0, i32 a1, i32 a2) { + return.void + } + .function void R.sf0() { + return.void + } + .function void R.sf1(i32 a0) { + return.void + } + .function void R.sf2(i32 a0, i32 a1) { + return.void + } + .function void R.sf3(i32 a0, i32 a1, i32 a2) { + return.void + } + .function void sf0() { + return.void + } + .function void sf1(i32 a0) { + return.void + } + .function void sf2(i32 a0, i32 a1) { + return.void + } + .function void sf3(i32 a0, i32 a1, i32 a2) { + return.void + } + .function i32 main() { + newobj v0, R + ldai 0 + call.virt.acc.short %s + cases: + - values: ['R.f1, v0, 0'] + runner-options: [verifier-failure, verifier-debug-config] + - values: ['R.f2, v0, 1'] + runner-options: [verifier-only, verifier-debug-config] + - values: ['R.f3, v0, 1'] + bugid: ['5593'] + ignore: true + - values: ['R.sf1, v0, 0'] + runner-options: [verifier-failure, verifier-debug-config] + - values: ['R.sf2, v0, 1'] + runner-options: [verifier-failure, verifier-debug-config] + - values: ['R.sf3, v0, 1'] + bugid: ['5593'] + ignore: true + - values: ['sf1, v0, 0'] + runner-options: [verifier-failure, verifier-debug-config] + - values: ['sf2, v0, 1'] + runner-options: [verifier-failure, verifier-debug-config] + - values: ['sf3, v0, 1'] + bugid: ['5593'] + ignore: true + - values: ['R.foo, v0, 0'] + - values: ['foo, v0, 1'] + - values: ['R.sf0'] + - values: ['sf0'] + - values: ['R.f2, v16, 0'] + - values: ['R.f2, v255, 1'] + - values: ['R.f2, v32767, 1'] + - values: ['R.f2, v65536, 0'] + - values: ['R.f2, v255, 1'] + - values: ['R.f2, a0, 1'] + - values: ['R.f3, v0, 0'] + bugid: ['5593'] + ignore: true + + + - file-name: reg_v_valid + description: Check with all valid 'v' register numbers. + isa: + instructions: + - sig: call.virt.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .record R {} + .function R R.foo(R a0, i32 a1) { + lda.obj a0 + return.obj + } + .function i32 main() { + newobj v0, R + lda.obj v0 + movi v0, 0 + movi v1, 1 + movi v2, 2 + movi v3, 3 + movi v4, 4 + movi v5, 5 + movi v6, 6 + movi v7, 7 + movi v8, 8 + movi v9, 9 + movi v10, 10 + movi v11, 11 + movi v12, 12 + movi v13, 13 + movi v14, 14 + movi v15, 15 + call.virt.acc.short R.foo, v0, 0 + call.virt.acc.short R.foo, v1, 0 + call.virt.acc.short R.foo, v2, 0 + call.virt.acc.short R.foo, v3, 0 + call.virt.acc.short R.foo, v4, 0 + call.virt.acc.short R.foo, v5, 0 + call.virt.acc.short R.foo, v6, 0 + call.virt.acc.short R.foo, v7, 0 + call.virt.acc.short R.foo, v8, 0 + call.virt.acc.short R.foo, v9, 0 + call.virt.acc.short R.foo, v10, 0 + call.virt.acc.short R.foo, v11, 0 + call.virt.acc.short R.foo, v12, 0 + call.virt.acc.short R.foo, v13, 0 + call.virt.acc.short R.foo, v14, 0 + call.virt.acc.short R.foo, v15, 0 + + + - file-name: reg_a_valid + description: Check with all valid 'a' register numbers. + isa: + instructions: + - sig: call.virt.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .record R {} + .function R R.foo(R a0, i32 a1) { + lda.obj a0 + return.obj + } + .function void f(i32 a0, i32 a1, i32 a2, i32 a3, i32 a4, i32 a5, i32 a6, i32 a7, i32 a8, i32 a9, i32 a10, i32 a11, i32 a12, i32 a13, i32 a14, R a15) { + lda.obj a15 + call.virt.acc.short R.foo, a0, 0 + call.virt.acc.short R.foo, a1, 0 + call.virt.acc.short R.foo, a2, 0 + call.virt.acc.short R.foo, a3, 0 + call.virt.acc.short R.foo, a4, 0 + call.virt.acc.short R.foo, a5, 0 + call.virt.acc.short R.foo, a6, 0 + call.virt.acc.short R.foo, a7, 0 + call.virt.acc.short R.foo, a8, 0 + call.virt.acc.short R.foo, a9, 0 + call.virt.acc.short R.foo, a10, 0 + call.virt.acc.short R.foo, a11, 0 + call.virt.acc.short R.foo, a12, 0 + call.virt.acc.short R.foo, a13, 0 + call.virt.acc.short R.foo, a14, 0 + return.void + } + .function i32 main() { + movi v0, 0 + movi v1, 1 + movi v2, 2 + movi v3, 3 + movi v4, 4 + movi v5, 5 + movi v6, 6 + movi v7, 7 + movi v8, 8 + movi v9, 9 + movi v10, 10 + movi v11, 11 + movi v12, 12 + movi v13, 13 + movi v14, 14 + newobj v15, R + call.range f, v0 + + + - file-name: uninitialized_regs + description: Check that verifier reports an error on uninitialized registers. + isa: + description: > + Unused register slot values will be discarded and corresponding registers will not be + passed to the callee). + instructions: + - sig: call.virt.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .record R {} + .function i32 R.foo(%s) { + %s + return + } + .function i32 main() { + %s + call.virt.acc.short R.foo, %s + cases: + - description: Register v0 (obj ref) is not initialized. + values: + - R a0, i32 a1 + - lda a1 + - ldai 0 + - v0, 1 + - description: Register v0 (i32) is not initialized. + values: + - R a0, i32 a1 + - lda a1 + - | + # + newobj v1, R + lda.obj v1 + - v0, 0 + - description: Register v0 is not initialized, but it's not used. + values: + - R a0 + - ldai 0 + - | + # + newobj v1, R + lda.obj v1 + - v0, 0 + runner-options: [verifier-only, verifier-debug-config] + - description: Accumulator (obj ref) is not initialized. + values: + - R a0, i32 a1 + - lda a1 + - movi v0, 0 + - v0, 0 + - description: Accumulator (i32) is not initialized. + values: + - R a0, i32 a1 + - lda a1 + - newobj v0, R + - v0, 1 + - description: Accumulator is not initialized, but it's not used. + values: + - R a0 + - ldai 0 + - newobj v0, R + - v0, 1 + runner-options: [verifier-only, verifier-debug-config] + - description: Accumulator and v0 are both not initialized. + values: + - R a0, i32 a1 + - ldai 0 + - '' + - v0, 0 + - description: Accumulator is not initialized in function. + values: + - R a0, i32 a1 + - call.virt.acc.short R.foo, a0, 1 + - | + # + ldai 0 + newobj v0, R + - v0, 1 + - description: v0 is not initialized in function. + values: + - R a0, i32 a1 + - call.virt.acc.short R.foo, a1, 0 + - | + # + ldai 0 + newobj v0, R + - v0, 1 + + + - file-name: static_method + description: Check that verifier reports an error on static method. + isa: + verification: + - method_id_non_static + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .record R {} + .function void %s { + return.void + } + .function i32 main() { + newobj v0, R + ldai 0 + call.virt.acc.short %s + cases: + - values: + - R.foo(R a0, i32 a1) + - R.foo, v0, 1 + - values: + - R.foo(R a0) + - R.foo, v0, 1 + - values: + - R.foo(i32 a0, R a1) + - R.foo, v0, 0 + - values: + - R.foo(R a0, i32 a1) + - R.foo, v0, 1 + bugid: ['5583'] + ignore: true + - values: + - R.foo(R a0) + - R.foo, v0, 1 + bugid: ['5583'] + ignore: true + - values: + - foo(R a0, i32 a1) + - foo, v0, 1 + + + - file-name: non_accessible_method_p + description: Check that verifier reports an error on non-accessible method. + isa: + verification: + - method_id_accessible + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .record R {} + .function void %s + .function i32 main() { + newobj v0, R + ldai 0 + call.virt.acc.short R.foo, v0, 1 + cases: + - values: + - R.foo(R a0, i32 a1) + - values: + - R.foo(R a0, i32 a1) + + + - file-name: non_accessible_method_j + description: Check that verifier reports an error on non-accessible method. + isa: + verification: + - method_id_accessible + header-template: [java] + runner-options: [verifier-failure, verifier-debug-config, use-java] + tags: [verifier] + check-type: exit-positive + code-template: | + %s + .function i32 main() { + newobj v0, %s + ldai 0 + call.virt.acc.short %s, v0, 1 + cases: + - values: + - | + .record R {} + .function void R.foo(R a0, i32 a1) + - R + - R.foo + - values: + - | + .record R {} + .function void R.foo(R a0, i32 a1) + .record Q {} + - Q + - R.foo + + + - file-name: invalid_method + description: Check that verifier reports an error on invalid method. + isa: + verification: + - method_id_non_static + - method_id_accessible + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .record R {} + %s + .function i32 main() { + newobj v0, R + ldai 0 + call.virt.acc.short %s + cases: + - description: No return in function. + values: + - .function void R.foo(R a0, i32 a1) {} + - R.foo, v0, 1 + bugid: ['5607'] + ignore: true + - description: No return in function. + values: + - | + # + .function i32 R.foo(R a0) { + ldai 0 + } + - R.foo, v0, 1 + + + - file-name: incompatible_v_p + description: Check 'call.virt.acc.short' instruction called with incompatible register argument in PandaAssembly context. + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record R {} + .function void R.foo(R a0, %s a1) { + return.void + } + .function i32 main() { + *s + newobj v0, R + lda.obj v0 + call.virt.acc.short R.foo, v1, 0 + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - u8 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - u32 + exclude: [i32] + - values: + - u64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - u32[] + exclude: [u32a, nul] + - values: + - u64[] + exclude: [u64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - u32[][] + exclude: [u32aa, nul] + - values: + - u64[][] + exclude: [u64aa, nul] + - values: + - f32[][] + exclude: [f32aa, nul] + - values: + - R + exclude: [nul] + - values: + - panda.String + exclude: [str, nul] + - values: + - panda.Class + exclude: [typ, nul] + - values: + - panda.Object + exclude: [u32a, u64a, f32a, u32aa, u64aa, f32aa, str, typ, ra, stra, typa, obja, raa, straa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - panda.String[] + exclude: [stra, nul] + - values: + - panda.Class[] + exclude: [typa, nul] + - values: + - panda.Object[] + exclude: [obja, u32aa, u64aa, f32aa, ra, stra, typa, raa, straa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - panda.String[][] + exclude: [straa, nul] + - values: + - panda.Class[][] + exclude: [typaa, nul] + - values: + - panda.Object[][] + exclude: [objaa, raa, straa, typaa, nul] + cases: + - values: + - movi v1, 1 + id: i32 + - values: + - movi.64 v1, 1 + id: i64 + - values: + - fmovi.64 v1, 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[] + id: u32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[] + id: u64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[][] + id: u32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[][] + id: u64aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[][] + id: f32aa + - values: + - | + # + lda.str "test message" + sta.obj v1 + id: str + - values: + - | + # + lda.type R + sta.obj v1 + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[] + id: stra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[] + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[] + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[][] + id: straa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[][] + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[][] + id: objaa + - values: + - mov.null v1 + id: nul + + + - file-name: incompatible_acc_p + description: Check 'call.virt.acc.short' instruction called with incompatible accumulator argument in PandaAssembly context. + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record R {} + .function void R.foo(R a0, %s a1) { + return.void + } + .function i32 main() { + *s + newobj v2, R + call.virt.acc.short R.foo, v2, 1 + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - u8 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - u32 + exclude: [i32] + - values: + - u64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - u32[] + exclude: [u32a, nul] + - values: + - u64[] + exclude: [u64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - u32[][] + exclude: [u32aa, nul] + - values: + - u64[][] + exclude: [u64aa, nul] + - values: + - f32[][] + exclude: [f32aa, nul] + - values: + - R + exclude: [nul] + - values: + - panda.String + exclude: [str, nul] + - values: + - panda.Class + exclude: [typ, nul] + - values: + - panda.Object + exclude: [u32a, u64a, f32a, u32aa, u64aa, f32aa, str, typ, ra, stra, typa, obja, raa, straa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - panda.String[] + exclude: [stra, nul] + - values: + - panda.Class[] + exclude: [typa, nul] + - values: + - panda.Object[] + exclude: [obja, u32aa, u64aa, f32aa, ra, stra, typa, raa, straa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - panda.String[][] + exclude: [straa, nul] + - values: + - panda.Class[][] + exclude: [typaa, nul] + - values: + - panda.Object[][] + exclude: [objaa, raa, straa, typaa, nul] + cases: + - values: + - ldai 1 + id: i32 + - values: + - ldai.64 1 + id: i64 + - values: + - fldai.64 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[] + lda.obj v1 + id: u32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[] + lda.obj v1 + id: u64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + lda.obj v1 + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[][] + lda.obj v1 + id: u32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[][] + lda.obj v1 + id: u64aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[][] + lda.obj v1 + id: f32aa + - values: + - | + # + lda.str "test message" + id: str + - values: + - | + # + lda.type R + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + lda.obj v1 + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[] + lda.obj v1 + id: stra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[] + lda.obj v1 + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[] + lda.obj v1 + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + lda.obj v1 + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[][] + lda.obj v1 + id: straa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[][] + lda.obj v1 + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[][] + lda.obj v1 + id: objaa + - values: + - lda.null + id: nul + + + - file-name: incompatible_v_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc.short' instruction with incompatible register in Java context. + header-template: [java] + code-template: | + .record java.lang.Object + .record java.lang.Class + .record R {} + .function void R.foo(R a0, %s a1) { + return.void + } + .function i32 main() { + *s + newobj v2, R + lda.obj v2 + call.virt.acc.short R.foo, v1, 0 + check-type: exit-positive + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - i32 + exclude: [i32] + - values: + - i64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - f64 + exclude: [f64] + - values: + - u1[] + exclude: [u1a, nul] + - values: + - i8[] + exclude: [i8a, nul] + - values: + - u16[] + exclude: [u1a, u16a, nul] + - values: + - i16[] + exclude: [i8a, i16a, nul] + - values: + - i32[] + exclude: [i8a, i16a, i32a, nul] + - values: + - i64[] + exclude: [i64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - f64[] + exclude: [f32a, f64a, nul] + - values: + - i32[][] + exclude: [i32aa, nul] + - values: + - f64[][] + exclude: [f64aa, nul] + - values: + - R + exclude: [nul] + - values: + - java.lang.Class + exclude: [typ, nul] + - values: + - java.lang.Object + exclude: [u1a, i8a, u16a, i16a, i32a, i64a, f32a, f64a, i32aa, f64aa, typ, ra, typa, obja, raa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - java.lang.Class[] + exclude: [typa, nul] + - values: + - java.lang.Object[] + exclude: [obja, i32aa, f64aa, ra, typa, raa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - java.lang.Class[][] + exclude: [typaa, nul] + - values: + - java.lang.Object[][] + exclude: [objaa, raa, typaa, nul] + cases: + - values: + - movi v1, 1 + id: i32 + - values: + - movi.64 v1, 1 + id: i64 + - values: + - fmovi.64 v1, 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u1[] + id: u1a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i8[] + id: i8a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u16[] + id: u16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i16[] + id: i16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[] + id: i32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i64[] + id: i64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[] + id: f64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[][] + id: i32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[][] + id: f64aa + - values: + - | + # + lda.type R + sta.obj v1 + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[] + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[] + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[][] + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[][] + id: objaa + - values: + - mov.null v1 + id: nul + + + - file-name: incompatible_acc_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc.short' instruction with incompatible accumulator in Java context. + header-template: [java] + check-type: exit-positive + code-template: | + .record java.lang.Object + .record java.lang.Class + .record R {} + .function void R.foo(R a0, %s a1) { + return.void + } + .function i32 main() { + *s + newobj v2, R + call.virt.acc.short R.foo, v2, 1 + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - i32 + exclude: [i32] + - values: + - i64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - f64 + exclude: [f64] + - values: + - u1[] + exclude: [u1a, nul] + - values: + - i8[] + exclude: [i8a, nul] + - values: + - u16[] + exclude: [u1a, u16a, nul] + - values: + - i16[] + exclude: [i8a, i16a, nul] + - values: + - i32[] + exclude: [i8a, i16a, i32a, nul] + - values: + - i64[] + exclude: [i64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - f64[] + exclude: [f32a, f64a, nul] + - values: + - i32[][] + exclude: [i32aa, nul] + - values: + - f64[][] + exclude: [f64aa, nul] + - values: + - R + exclude: [nul] + - values: + - java.lang.Class + exclude: [typ, nul] + - values: + - java.lang.Object + exclude: [u1a, i8a, u16a, i16a, i32a, i64a, f32a, f64a, i32aa, f64aa, typ, ra, typa, obja, raa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - java.lang.Class[] + exclude: [typa, nul] + - values: + - java.lang.Object[] + exclude: [obja, i32aa, f64aa, ra, typa, raa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - java.lang.Class[][] + exclude: [typaa, nul] + - values: + - java.lang.Object[][] + exclude: [objaa, raa, typaa, nul] + cases: + - values: + - ldai 1 + id: i32 + - values: + - ldai.64 1 + id: i64 + - values: + - fldai.64 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u1[] + lda.obj v1 + id: u1a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i8[] + lda.obj v1 + id: i8a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u16[] + lda.obj v1 + id: u16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i16[] + lda.obj v1 + id: i16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[] + lda.obj v1 + id: i32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i64[] + lda.obj v1 + id: i64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + lda.obj v1 + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[] + lda.obj v1 + id: f64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[][] + lda.obj v1 + id: i32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[][] + lda.obj v1 + id: f64aa + - values: + - | + # + lda.type R + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + lda.obj v1 + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[] + lda.obj v1 + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[] + lda.obj v1 + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + lda.obj v1 + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[][] + lda.obj v1 + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[][] + lda.obj v1 + id: objaa + - values: + - lda.null + id: nul + + + - file-name: compatible_primitive_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc.short' instruction with compatible primitive arguments in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record R {} + .function void R.foo(R a0, %s a1) { + return.void + } + .function i32 main() { + newobj v0, R + lda.obj v0 + %s + call.virt.acc.short R.foo, v1, 0 + cases: + - values: + - u1 + - movi v1, 1 + - values: + - u8 + - movi v1, 1 + - values: + - i8 + - movi v1, 1 + - values: + - u16 + - movi v1, 1 + - values: + - i16 + - movi v1, 1 + - values: + - u32 + - movi v1, 1 + - values: + - i32 + - movi v1, 1 + - values: + - u64 + - movi.64 v1, 1 + - values: + - i64 + - movi.64 v1, 1 + - values: + - f32 + - fmovi.64 v1, 1.1 + - values: + - f64 + - fmovi.64 v1, 1.1 + + + - file-name: compatible_primitive_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc.short' instruction with compatible primitive arguments in Java context. + header-template: [java] + code-template: | + .record R {} + .function void R.foo(R a0, %s a1) { + return.void + } + .function i32 main() { + %s + newobj v1, R + call.virt.acc.short R.foo, v1, 1 + check-type: exit-positive + cases: + - values: + - u1 + - ldai 1 + - values: + - i8 + - ldai 1 + - values: + - u16 + - ldai 1 + - values: + - i16 + - ldai 1 + - values: + - i32 + - ldai 1 + - values: + - i64 + - ldai.64 1 + - values: + - f32 + - fldai.64 1.1 + - values: + - f64 + - fldai.64 1.1 + + + - file-name: compatible_prim_array_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc.short' instruction called with compatible primitive array arguments in PandaAssembly context. + header-template: [] + code-template: | + .record R {} + .function void R.foo(R a0, %s a1) { + return.void + } + .function i32 main() { + newobj v1, R + lda.obj v1 + movi v1, 10 + newarr v1, v1, %s + call.virt.acc.short R.foo, v1, 0 + check-type: exit-positive + cases: + - values: + - u1[] + - u1[] + - values: + - u8[] + - u8[] + - values: + - i8[] + - i8[] + - values: + - u16[] + - u16[] + - values: + - i16[] + - i16[] + - values: + - u32[] + - u32[] + - values: + - i32[] + - i32[] + - values: + - u64[] + - u64[] + - values: + - i64[] + - i64[] + - values: + - f32[] + - f32[] + - values: + - f64[] + - f64[] + - values: + - u1[][] + - u1[][] + - values: + - u8[][] + - u8[][] + - values: + - i8[][] + - i8[][] + - values: + - u16[][] + - u16[][] + - values: + - i16[][] + - i16[][] + - values: + - u32[][] + - u32[][] + - values: + - i32[][] + - i32[][] + - values: + - u64[][] + - u64[][] + - values: + - i64[][] + - i64[][] + - values: + - f32[][] + - f32[][] + - values: + - f64[][] + - f64[][] + + + - file-name: compatible_prim_array_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java] + tags: [verifier] + description: Check 'call.virt.acc.short' instruction called with compatible primitive array arguments in Java context. + header-template: [java] + code-template: | + .record R {} + .function void foo(R a0, %s a1) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v0, v0, %s + lda.obj v0 + newobj v1, R + call.virt.acc.short foo, v1, 1 + check-type: exit-positive + cases: + - values: + - u1[] + - u1[] + - values: + - i8[] + - i8[] + - values: + - u16[] + - u16[] + - values: + - i16[] + - i16[] + - values: + - i32[] + - i32[] + - values: + - i64[] + - i64[] + - values: + - f32[] + - f32[] + - values: + - f64[] + - f64[] + - values: + - u1[][] + - u1[][] + - values: + - i8[][] + - i8[][] + - values: + - u16[][] + - u16[][] + - values: + - i16[][] + - i16[][] + - values: + - i32[][] + - i32[][] + - values: + - i64[][] + - i64[][] + - values: + - f32[][] + - f32[][] + - values: + - f64[][] + - f64[][] + + + - file-name: compatible_obj_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc.short' instruction called with compatible object arguments in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record Q {} + .record R {} + .function void R.foo(R a0, %s a1) { + return.void + } + .function i32 main() { + %s + newobj v7, R + lda.obj v7 + call.virt.acc.short R.foo, v1, 0 + cases: + # Object of type O is instance of type T if O is the same as T ... + - values: + - Q + - newobj v1, Q + - values: + - panda.String + - | + # + lda.str "test" + sta.obj v1 + - values: + - panda.Class + - | + # + lda.type Q + sta.obj v1 + # ... or is subtype of T + - values: + - panda.Object + - newobj v1, Q + - values: + - panda.Object + - | + # + lda.str "test" + sta.obj v1 + - values: + - panda.Object + - | + # + lda.type Q + sta.obj v1 + bugid: ['3594'] + ignore: true + # For arrays T should be a root type in type hierarchy ... + - values: + - panda.Object + - | + # + movi v0, 10 + newarr v1, v0, i32[] + - values: + - panda.Object + - | + # + movi v0, 10 + newarr v1, v0, f64[][] + - values: + - panda.Object + - | + # + movi v0, 10 + newarr v1, v0, Q[] + - values: + - panda.Object + - | + # + movi v0, 10 + newarr v1, v0, panda.Object[] + - values: + - panda.Object + - | + # + movi v0, 10 + newarr v1, v0, panda.String[] + - values: + - panda.Object + - | + # + movi v0, 10 + newarr v1, v0, panda.Class[] + + + - file-name: compatible_obj_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc.short' instruction called with compatible object arguments in Java context. + header-template: [java] + check-type: exit-positive + code-template: | + .record java.lang.Object + .record java.lang.Class + .record java.lang.String + .record java.io.Serializable + .record I {} + .record E {} + .record Q {} + .record R {} + .function void R.foo(R a0, %s a1) { + return.void + } + .function i32 main() { + %s + newobj v1, R + call.virt.acc.short R.foo, v1, 1 + cases: + # Object of type O is instance of type T if O is the same as T ... + - values: + - Q + - | + # + newobj v1, Q + lda.obj v1 + - values: + - java.lang.String + - lda.str "test" + - values: + - java.lang.Class + - lda.type Q + - values: + - E + - | + # + newobj v0, E + lda.obj v0 + # ... or is subtype of T + - values: + - E + - | + # + newobj v0, Q + lda.obj v0 + - values: + - I + - | + # + newobj v0, Q + lda.obj v0 + - values: + - java.lang.Object + - | + # + newobj v0, Q + lda.obj v0 + - values: + - java.lang.Object + - lda.str "test" + - values: + - java.lang.Object + - lda.type java.lang.String + bugid: ['3594'] + ignore: true + - values: + - java.io.Serializable + - lda.type Q + bugid: ['3594'] + ignore: true + # For arrays T should be a root type in type hierarchy ... + - values: + - java.lang.Object + - | + # + movi v0, 10 + newarr v1, v0, i32[] + lda.obj v1 + - values: + - java.lang.Object + - | + # + movi v0, 10 + newarr v1, v0, f64[][] + lda.obj v1 + - values: + - java.lang.Object + - | + # + movi v0, 10 + newarr v1, v0, Q[] + lda.obj v1 + - values: + - java.lang.Object + - | + # + movi v0, 10 + newarr v1, v0, java.lang.Object[] + lda.obj v1 + - values: + - java.lang.Object + - | + # + movi v0, 10 + newarr v1, v0, java.lang.String[] + lda.obj v1 + - values: + - java.lang.Object + - | + # + movi v0, 10 + newarr v1, v0, java.lang.Class[] + lda.obj v1 + + + - file-name: compatible_obj_array_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc.short' instruction called with compatible object array arguments in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record Q {} + .record R {} + .function void R.foo(R a0, %s a1) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v1, v0, %s + newobj v0, R + lda.obj v0 + call.virt.acc.short R.foo, v1, 0 + cases: + # T is such array that O array elements are the same as T array elements + - values: + - Q[] + - Q[] + - values: + - Q[][] + - Q[][] + - values: + - panda.Object[] + - panda.Object[] + - values: + - panda.Object[][] + - panda.Object[][] + - values: + - panda.String[] + - panda.String[] + - values: + - panda.String[][] + - panda.String[][] + - values: + - panda.Class[] + - panda.Class[] + - values: + - panda.Class[][] + - panda.Class[][] + # T is such array that O array elements are subtypes of T array elements + - values: + - panda.Object[] + - panda.Object[][] + - values: + - panda.Object[] + - Q[] + - values: + - panda.Object[] + - Q[][] + - values: + - panda.Object[] + - panda.Class[] + - values: + - panda.Object[] + - panda.Class[][] + - values: + - panda.Object[] + - panda.String[] + - values: + - panda.Object[] + - panda.String[][] + - values: + - panda.Object[] + - i32[][] + - values: + - panda.Object[] + - f64[][][] + - values: + - panda.Object[][] + - panda.Object[][][] + - values: + - panda.Object[][] + - panda.Class[][] + - values: + - panda.Object[][] + - panda.Class[][][] + - values: + - panda.Object[][] + - i32[][][] + - values: + - panda.Object[][] + - f64[][][][] + + + - file-name: compatible_obj_array_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc.short' instruction called with compatible object array arguments in Java context. + header-template: [java] + code-template: | + .record java.lang.Object + .record java.lang.Class + .record java.lang.String + .record I {} + .record E {} + .record Q {} + .record R {} + .function void R.foo(R a0, %s a1) { + return.void + } + .function i32 main() { + movi v1, 10 + newarr v1, v1, %s + lda.obj v1 + newobj v1, R + call.virt.acc.short R.foo, v1, 1 + check-type: exit-positive + cases: + # T is such array that O array elements are the same as T array elements + - values: + - Q[] + - Q[] + - values: + - java.lang.String[] + - java.lang.String[] + - values: + - Q[][] + - Q[][] + - values: + - java.lang.String[][] + - java.lang.String[][] + - values: + - java.lang.Object[] + - java.lang.Object[] + - values: + - java.lang.Class[][] + - java.lang.Class[][] + - values: + - java.lang.Class[] + - java.lang.Class[] + - values: + - java.lang.Object[][] + - java.lang.Object[][] + # T is such array that O array elements are subtypes of T array elements + - values: + - E[] + - Q[] + - values: + - java.lang.Object[] + - Q[][] + - values: + - I[] + - Q[] + - values: + - java.lang.Object[] + - java.lang.Class[] + - values: + - java.lang.Object[] + - java.lang.Object[][] + - values: + - java.lang.Object[] + - Q[] + - values: + - java.lang.Object[] + - java.lang.String[] + - values: + - java.lang.Object[] + - f64[][][] + - values: + - java.lang.Object[] + - java.lang.String[][] + - values: + - java.lang.Object[] + - i32[][] + # inherited types from object[][] + - values: + - E[][] + - Q[][] + - values: + - java.lang.Object[][] + - java.lang.Object[][][] + - values: + - I[][] + - Q[][] + - values: + - java.lang.Object[][] + - java.lang.Class[][][] + - values: + - java.lang.Object[][] + - java.lang.Class[][] + - values: + - java.lang.Object[][] + - i32[][][] + + + - file-name: compatible_obj_null_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc.short' instruction called with null object ref in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record R {} + .function void R.foo(R a0, %s a1) { + return.void + } + .function i32 main() { + newobj v1, R + lda.null + call.virt.acc.short R.foo, v1, 1 + cases: + - values: ['i32[]'] + - values: ['f64[][]'] + - values: ['panda.Object'] + - values: ['panda.Object[]'] + - values: ['panda.Object[][]'] + - values: ['R'] + - values: ['R[][]'] + - values: ['panda.String'] + - values: ['panda.String[]'] + - values: ['panda.Class'] + - values: ['panda.Class[]'] + - values: ['u32[][][]'] + + + - file-name: compatible_obj_null_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc.short' instruction called with null object ref in Java context. + header-template: [java] + code-template: | + .record java.lang.Object + .record java.lang.Class + .record java.lang.String + .record R {} + .function void R.foo(R a0, %s a1) { + return.void + } + .function i32 main() { + newobj v1, R + lda.obj v1 + mov.null v1 + call.virt.acc.short R.foo, v1, 0 + check-type: exit-positive + cases: + - values: ['i32[]'] + - values: ['f64[][]'] + - values: ['java.lang.Object'] + - values: ['java.lang.Object[]'] + - values: ['java.lang.Object[][]'] + - values: ['R'] + - values: ['R[][]'] + - values: ['java.lang.String'] + - values: ['java.lang.String[]'] + - values: ['java.lang.Class'] + - values: ['java.lang.Class[]'] + - values: ['u1[][][]'] + + + - file-name: values_p + isa: + instructions: + - sig: call.virt.acc.short method_id, v:in:top, imm:u1 + acc: inout:top + format: [op_v_4_imm_4_id_16] + runner-options: [] + description: Check 'call.virt.acc.short' instruction called with various values in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.String + .record R {} + .function i32 R.fooi32(R a0, i32 a1) { + lda a1 + return + } + .function i64 R.fooi64(R a0, i64 a1) { + lda.64 a1 + return.64 + } + .function u32 R.foou32(R a0, u32 a1) { + lda a1 + return + } + .function u64 R.foou64(R a0, u64 a1) { + lda.64 a1 + return.64 + } + .function f32 R.foof32(R a0, f32 a1) { + lda a1 + return + } + .function f64 R.foof64(R a0, f64 a1) { + lda.64 a1 + return.64 + } + .function panda.Object R.fooobj(R a0, panda.Object a1) { + lda.obj a1 + return.obj + } + .function i32 main() { + %s + newobj v0, R + lda.obj v0 + call.virt.acc.short R.foo%s, v1, 0 + call.virt.acc.short R.foo%s, v0, 1 + %s + ldai 1 + return + ok: + cases: + # signed i32 + - values: + - movi v1, 0 + - i32 + - i32 + - jeq v1, ok + - values: + - movi v1, -1 + - i32 + - i32 + - jeq v1, ok + - values: + - movi v1, 0x5a5a5a5a + - i32 + - i32 + - jeq v1, ok + - values: + - movi v1, 0x11111111 + - i32 + - i32 + - jeq v1, ok + # signed i64 + - values: + - movi.64 v1, 0 + - i64 + - i64 + - | + # + cmp.64 v1 + jeqz ok + - values: + - movi.64 v1, -1 + - i64 + - i64 + - | + # + cmp.64 v1 + jeqz ok + - values: + - movi.64 v1, 0xa5a5a5a5cafebabe + - i64 + - i64 + - | + # + cmp.64 v1 + jeqz ok + - values: + - movi.64 v1, 0xe1e1e1e1e1e1e1e1 + - i64 + - i64 + - | + # + cmp.64 v1 + jeqz ok + # unsigned u32 + - values: + - movi v1, 0 + - u32 + - u32 + - | + # + ucmp v1 + jeqz ok + - values: + - movi v1, 0xffffffff + - u32 + - u32 + - | + # + ucmp v1 + jeqz ok + - values: + - movi v1, 123456789 + - u32 + - u32 + - | + # + ucmp v1 + jeqz ok + - values: + - movi v1, 0x1111eeee + - u32 + - u32 + - | + # + ucmp v1 + jeqz ok + # unsigned u64 + - values: + - movi.64 v1, 0 + - u64 + - u64 + - | + # + ucmp.64 v1 + jeqz ok + - values: + - movi.64 v1, 0xefffffffffffffff + - u64 + - u64 + - | + # + ucmp.64 v1 + jeqz ok + - values: + - movi.64 v1, 0xa5a5a5a5a5a5a5a5 + - u64 + - u64 + - | + # + ucmp.64 v1 + jeqz ok + - values: + - movi.64 v1, 0xeeee1111ffffdddd + - u64 + - u64 + - | + # + ucmp.64 v1 + jeqz ok + # f32 + - values: + - fmovi v1, 0.0 + - f32 + - f32 + - | + # + fcmpg v1 + jeqz ok + - values: + - fmovi v1, -1.1 + - f32 + - f32 + - | + # + fcmpg v1 + jeqz ok + - values: + - fmovi v1, 1.98765e14 + - f32 + - f32 + - | + # + fcmpg v1 + jeqz ok + - values: + - fmovi v1, 0.717171717171717171717171e71 + - f32 + - f32 + - | + # + fcmpg v1 + jeqz ok + - values: + - fmovi v1, 0xff800000 + - f32 + - f32 + - | + # + fcmpg v1 + jeqz ok + # f64 + - values: + - fmovi.64 v1, 0.0 + - f64 + - f64 + - | + # + fcmpg.64 v1 + jeqz ok + - values: + - fmovi.64 v1, -1.1 + - f64 + - f64 + - | + # + fcmpg.64 v1 + jeqz ok + - values: + - fmovi.64 v1, -0.000000019e19 + - f64 + - f64 + - | + # + fcmpg.64 v1 + jeqz ok + - values: + - fmovi.64 v1, 0.373737373737373737e37 + - f64 + - f64 + - | + # + fcmpg.64 v1 + jeqz ok + - values: + - fmovi.64 v1, 0x7ff0000000000000 + - f64 + - f64 + - | + # + fcmpg.64 v1 + jeqz ok + # object + - values: + - newobj v1, R + - obj + - obj + - jeq.obj v1, ok + - values: + - newobj v1, panda.Object + - obj + - obj + - jeq.obj v1, ok + - values: + - | + # + lda.str "test" + sta.obj v1 + - obj + - obj + - jeq.obj v1, ok + - values: + - | + # + lda.type panda.String + sta.obj v1 + - obj + - obj + - jeq.obj v1, ok + - values: + - mov.null v1 + - obj + - obj + - jeq.obj v1, ok + - values: + - | + # + movi v3, 10 + newarr v1, v3, panda.String[] + - obj + - obj + - jeq.obj v1, ok + - values: + - | + # + movi v3, 10 + newarr v1, v3, i32[][] + - obj + - obj + - jeq.obj v1, ok + + + - file-name: regs_restored + isa: + description: > + Call indicated object method, i.e. create new frame, pass values of arguments and + continue execution from the first instruction of a method. + Callee should treat accumulator value as undefined and cannot use it until accumulator + definition in the new frame. + description: Check 'call.virt.acc.short' that registers are restored after the call. + tags: [tsan] + header-template: [] + code-template: | + .record R {} + .function R R.foo(R a0, i32 a1) { + movi v0, 100 + movi v1, 200 + movi v2, 300 + movi v3, 400 + movi v4, 500 + movi v5, 600 + movi v6, 700 + movi v7, 800 + movi v8, 900 + movi v9, 1000 + movi v10, 1100 + movi v11, 1200 + movi v12, 1300 + movi v13, 1400 + movi v14, 1500 + movi v15, 1600 + lda.obj a0 + return.obj + } + .function i32 main() { + newobj v0, R + lda.obj v0 + movi v0, 1 + movi v1, 2 + movi v2, 3 + movi v3, 4 + movi v4, 5 + movi v5, 6 + movi v6, 7 + movi v7, 8 + movi v8, 9 + movi v9, 10 + movi v10, 11 + movi v11, 12 + movi v12, 13 + movi v13, 14 + movi v14, 15 + movi v15, 16 + call.virt.acc.short R.foo, v0, 0 + call.virt.acc.short R.foo, v1, 0 + call.virt.acc.short R.foo, v2, 0 + call.virt.acc.short R.foo, v3, 0 + call.virt.acc.short R.foo, v4, 0 + call.virt.acc.short R.foo, v5, 0 + call.virt.acc.short R.foo, v6, 0 + call.virt.acc.short R.foo, v7, 0 + call.virt.acc.short R.foo, v8, 0 + call.virt.acc.short R.foo, v9, 0 + call.virt.acc.short R.foo, v10, 0 + call.virt.acc.short R.foo, v11, 0 + call.virt.acc.short R.foo, v12, 0 + call.virt.acc.short R.foo, v13, 0 + call.virt.acc.short R.foo, v14, 0 + call.virt.acc.short R.foo, v15, 0 + ok0: + ldai 1 + jeq v0, ok1 + return + ok1: + ldai 2 + jeq v1, ok2 + return + ok2: + ldai 3 + jeq v2, ok3 + return + ok3: + ldai 4 + jeq v3, ok4 + return + ok4: + ldai 5 + jeq v4, ok5 + return + ok5: + ldai 6 + jeq v5, ok6 + return + ok6: + ldai 7 + jeq v6, ok7 + return + ok7: + ldai 8 + jeq v7, ok8 + return + ok8: + ldai 9 + jeq v8, ok9 + return + ok9: + ldai 10 + jeq v9, ok10 + return + ok10: + ldai 11 + jeq v10, ok11 + return + ok11: + ldai 12 + jeq v11, ok12 + return + ok12: + ldai 13 + jeq v12, ok13 + return + ok13: + ldai 14 + jeq v13, ok14 + return + ok14: + ldai 15 + jeq v14, ok15 + return + ok15: + ldai 16 + jeq v15, ok16 + return + ok16: + check-type: exit-positive + + + - file-name: ame_p + isa: + exceptions: + - x_abstract + description: Check that AbstractMethodError is thrown in PandaAssembly context. + header-template: [] + code-template: | + .record panda.AbstractMethodError + .record R {} + .function void R.foo1(R a0) + .function void R.foo2(R a0, R a1) + .function i32 main() { + begin: + newobj v0, R + lda.obj v0 + call.virt.acc.short %s + end: + ldai 1 # Should not reach this line + return + + catch_AME: + ldai 0 # Expected panda.AbstractMethodError + return + + catch_all: + ldai 2 # Unexpected exception, test failed + return + + .catch panda.AbstractMethodError, begin, end, catch_AME + .catchall begin, end, catch_all + check-type: none + cases: + - values: + - R.foo1, v0, 1 + tags: ['tsan'] + - values: + - R.foo2, v0, 0 + + + - file-name: npe_p + isa: + exceptions: + - x_null + description: Check that NullPointerException is thrown in PandaAssembly context. + header-template: [] + code-template: | + .record panda.NullPointerException + .record R {} + .function void R.foo(R a0, R a1) { + return.void + } + .function R get_null() { + lda.null + return.obj + } + .function i32 main() { + call.short get_null + %s + begin: + call.virt.acc.short R.foo, %s + end: + ldai 1 # Should not reach this line + return + + catch_NPE: + ldai 0 # Expected panda.NullPointerException + return + + catch_all: + ldai 2 # Unexpected exception, test failed + return + + .catch panda.NullPointerException, begin, end, catch_NPE + .catchall begin, end, catch_all + check-type: none + cases: + - values: + - newobj v0, R + - v0, 0 + - values: + - | + # + sta.obj v0 + newobj v1, R + lda.obj v1 + - v0, 1 + - values: + - sta.obj v0 + - v0, 1 + - values: + - sta.obj v0 + - v0, 0 + - values: + - newobj v0, R + - v0, 1 + runner-options: [run-failure] diff --git a/tests/cts-generator/cts-template/call.virt.acc.yaml b/tests/cts-generator/cts-template/call.virt.acc.yaml new file mode 100644 index 0000000000..f4e46ef564 --- /dev/null +++ b/tests/cts-generator/cts-template/call.virt.acc.yaml @@ -0,0 +1,2387 @@ +# 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. +--- +definitions: + - name: java + template: > + .language Java + +tests: + - file-name: call.virt.acc + isa: + title: Object calls with accumulator as input + description: > + Call indicated object method, i.e. create new frame, pass values of arguments and + continue execution from the first instruction of a method. + Callee should treat accumulator value as undefined and cannot use it until accumulator + definition in the new frame. + Result (if any) is returned in accumulator (see 'Calling sequence' chapter for more details). + Method, its class and the number of argument is resolved by given method_id in runtime + constant-pool based on object reference using language-specific semantics (currently only Java + virtual methods are supported, further extensions are TBD). + Object reference is passed in the first source register, arguments are passed starting from + the second source register in the same order as in method signature. + Non-range instructions can be used to pass up to 4 arguments (including object reference). + Unused register slot values will be discarded and corresponding registers will not be + passed to the callee). + Immediate operand encodes a position starting from 0 on which accumulator is passed. + instructions: + - sig: call.virt.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + commands: + + - file-name: op_v1_4_v2_4_v3_4_imm_4_id_16 + description: Check that compiler reports an error on invalid instruction format. + isa: + instructions: + - sig: call.virt.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + header-template: [] + check-type: exit-positive + runner-options: [compile-failure] + code-template: | + .record R {} + .function void R.f1(R a0) { + return.void + } + .function void R.f2(R a0, i32 a1) { + return.void + } + .function void R.f3(R a0, i32 a1, i32 a2) { + return.void + } + .function void R.f4(R a0, i32 a1, i32 a2, i32 a3) { + return.void + } + .function void R.f5(R a0, i32 a1, i32 a2, i32 a3, i32 a4) { + return.void + } + .function void R.sf1(i32 a0) { + return.void + } + .function void R.sf2(i32 a0, i32 a1) { + return.void + } + .function void R.sf3(i32 a0, i32 a1, i32 a2) { + return.void + } + .function void R.sf4(i32 a0, i32 a1, i32 a2, i32 a3) { + return.void + } + .function void R.sf5(i32 a0, i32 a1, i32 a2, i32 a3, i32 a4) { + return.void + } + .function void sf1(i32 a0) { + return.void + } + .function void sf2(i32 a0, i32 a1) { + return.void + } + .function void sf3(i32 a0, i32 a1, i32 a2) { + return.void + } + .function void sf4(i32 a0, i32 a1, i32 a2, i32 a3) { + return.void + } + .function void sf5(i32 a0, i32 a1, i32 a2, i32 a3, i32 a4) { + return.void + } + .function i32 main() { + newobj v0, R + movi v1, 1 + movi v2, 2 + movi v3, 3 + movi v4, 4 + ldai 0 + call.virt.acc %s + cases: + - values: ['R.f1, v0, 1'] + - values: ['R.f1, v0, v1, 2'] + - values: ['R.f1, v0, v1, v2, 3'] + runner-options: [compile-only] + - values: ['R.f2, v0, 1'] + - values: ['R.f2, v0, v1, 2'] + - values: ['R.f2, v0, v1, v2, 3'] + runner-options: [compile-only] + - values: ['R.f3, v0, 1'] + - values: ['R.f3, v0, v1, 2'] + - values: ['R.f3, v0, v1, v2, 3'] + runner-options: [compile-only] + - values: ['R.f4, v0, 1'] + - values: ['R.f4, v0, v1, 2'] + - values: ['R.f4, v0, v1, v2, 3'] + runner-options: [compile-only] + - values: ['R.f5, v0, 1'] + - values: ['R.f5, v0, v1, 2'] + - values: ['R.f5, v0, v1, v2, 3'] + bugid: ['5601'] + ignore: true + - values: ['R.sf1, v1, 1'] + - values: ['R.sf1, v2, v1, 2'] + - values: ['R.sf1, v3, v2, v1, 3'] + runner-options: [verifier-failure, verifier-debug-config] + - values: ['R.sf2, v1, 1'] + - values: ['R.sf2, v2, v1, 2'] + - values: ['R.sf2, v3, v2, v1, 3'] + runner-options: [verifier-failure, verifier-debug-config] + - values: ['R.sf3, v1, 1'] + - values: ['R.sf3, v2, v1, 2'] + - values: ['R.sf3, v3, v2, v1, 3'] + runner-options: [verifier-failure, verifier-debug-config] + - values: ['R.sf4, v1, 1'] + - values: ['R.sf4, v2, v1, 2'] + - values: ['R.sf4, v3, v2, v1, 3'] + runner-options: [verifier-failure, verifier-debug-config] + - values: ['R.sf5, v1, 1'] + - values: ['R.sf5, v2, v1, 2'] + - values: ['R.sf5, v3, v2, v1, 3'] + bugid: ['5601'] + ignore: true + - values: ['sf1, v1, 1'] + - values: ['sf1, v2, v1, 2'] + - values: ['sf1, v3, v2, v1, 3'] + runner-options: [verifier-failure, verifier-debug-config] + - values: ['sf2, v1, 1'] + - values: ['sf2, v2, v1, 2'] + - values: ['sf2, v3, v2, v1, 3'] + runner-options: [verifier-failure, verifier-debug-config] + - values: ['sf3, v1, 1'] + - values: ['sf3, v2, v1, 2'] + - values: ['sf3, v3, v2, v1, 3'] + runner-options: [verifier-failure, verifier-debug-config] + - values: ['sf4, v1, 1'] + - values: ['sf4, v2, v1, 2'] + - values: ['sf4, v3, v2, v1, 3'] + runner-options: [verifier-failure, verifier-debug-config] + - values: ['sf5, v1, 1'] + - values: ['sf5, v2, v1, 2'] + - values: ['sf5, v3, v2, v1, 3'] + bugid: ['5601'] + ignore: true + + + - file-name: reg_v_valid + description: Check with all valid 'v' register numbers. + isa: + instructions: + - sig: call.virt.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .record R {} + .function R R.foo(R a0, i32 a1, i32 a2, i32 a3) { + lda.obj a0 + return.obj + } + .function i32 main() { + newobj v0, R + lda.obj v0 + movi v0, 0 + movi v1, 1 + movi v2, 2 + movi v3, 3 + movi v4, 4 + movi v5, 5 + movi v6, 6 + movi v7, 7 + movi v8, 8 + movi v9, 9 + movi v10, 10 + movi v11, 11 + movi v12, 12 + movi v13, 13 + movi v14, 14 + movi v15, 15 + call.virt.acc R.foo, v0, v1, v2, 0 + call.virt.acc R.foo, v3, v4, v5, 0 + call.virt.acc R.foo, v6, v7, v8, 0 + call.virt.acc R.foo, v9, v10, v11, 0 + call.virt.acc R.foo, v12, v13, v14, 0 + call.virt.acc R.foo, v15, v15, v15, 0 + + + - file-name: reg_a_valid + description: Check with all valid 'a' register numbers. + isa: + instructions: + - sig: call.virt.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .record R {} + .function R R.foo(R a0, i32 a1, i32 a2, i32 a3) { + lda.obj a0 + return.obj + } + .function void f(i32 a0, i32 a1, i32 a2, i32 a3, i32 a4, i32 a5, i32 a6, i32 a7, i32 a8, i32 a9, i32 a10, i32 a11, i32 a12, i32 a13, i32 a14, R a15) { + lda.obj a15 + call.virt.acc R.foo, a0, a1, a2, 0 + call.virt.acc R.foo, a3, a4, a5, 0 + call.virt.acc R.foo, a6, a7, a8, 0 + call.virt.acc R.foo, a9, a10, a11, 0 + call.virt.acc R.foo, a12, a13, a14, 0 + return.void + } + .function i32 main() { + movi v0, 0 + movi v1, 1 + movi v2, 2 + movi v3, 3 + movi v4, 4 + movi v5, 5 + movi v6, 6 + movi v7, 7 + movi v8, 8 + movi v9, 9 + movi v10, 10 + movi v11, 11 + movi v12, 12 + movi v13, 13 + movi v14, 14 + newobj v15, R + call.range f, v0 + + + - file-name: uninitialized_regs + description: Check that verifier reports an error on uninitialized registers. + isa: + instructions: + - sig: call.virt.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .record R {} + .function i32 R.foo(%s) { + %s + return + } + .function i32 main() { + %s + call.virt.acc R.foo, %s + cases: + - description: Register v0 is not initialized. + values: + - R a0, i32 a1, i32 a2, i32 a3 + - lda a1 + - | + # + movi v1, 0 + movi v2, 0 + newobj v7, R + lda.obj v7 + - v0, v1, v2, 0 + - description: Register v1 is not initialized. + values: + - R a0, i32 a1, i32 a2, i32 a3 + - lda a2 + - | + # + movi v0, 0 + movi v2, 0 + newobj v7, R + lda.obj v7 + - v0, v1, v2, 0 + - description: Register v2 is not initialized. + values: + - R a0, i32 a1, i32 a2, i32 a3 + - lda a3 + - | + # + movi v0, 0 + movi v1, 0 + newobj v7, R + lda.obj v7 + - v0, v1, v2, 0 + - description: Registers v1, v2 are not initialized, but they arent used. + values: + - R a0, i32 a1 + - lda a1 + - | + # + movi v0, 0 + newobj v7, R + lda.obj v7 + - v0, v1, v2, 0 + runner-options: [verifier-only, verifier-debug-config] + - description: Accumulator (i32) is not initialized. + values: + - R a0, i32 a1 + - lda a1 + - | + # + newobj v0, R + movi v1, 0 + movi v2, 0 + - v0, v1, v2, 1 + - description: Accumulator (obj ref) is not initialized. + values: + - R a0, i32 a1, i32 a2 + - lda a1 + - | + # + movi v0, 0 + movi v1, 0 + movi v2, 0 + - v0, v1, v2, 0 + - description: Accumulator (i32) is not initialized, but its not used. + values: + - R a0 + - ldai 0 + - | + # + newobj v0, R + movi v1, 0 + movi v2, 0 + - v0, v1, v2, 1 + runner-options: [verifier-only, verifier-debug-config] + - description: Accumulator (i32) is not initialized, but its not used. + values: + - R a0, i32 a1, i32 a2 + - lda a1 + - | + # + newobj v0, R + movi v1, 0 + movi v2, 0 + - v0, v1, v2, 3 + runner-options: [verifier-only, verifier-debug-config] + - description: Accumulator and all regs are not initialized. + values: + - R a0, i32 a1, i32 a2, i32 a3 + - ldai 0 + - + - v15, v14, v13, 0 + - description: Regs not initialized, but they are not used. + values: + - 'R a0' + - ldai 0 + - | + # + newobj v15, R + lda.obj v15 + - v0, v1, v2, 0 + runner-options: [verifier-only, verifier-debug-config] + - description: Accumulator is not initialized in function. + values: + - R a0, i32 a1, i32 a2, i32 a3 + - call.virt.acc R.foo, a1, a2, a3, 0 + - | + # + newobj v7, R + lda.obj v7 + movi v0, 0 + movi v1, 0 + movi v2, 0 + - v0, v1, v2, 0 + + + - file-name: static_method + description: Check that verifier reports an error on a static method. + isa: + verification: + - method_id_non_static + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .record R {} + .function void %s { + return.void + } + .function i32 main() { + newobj v0, R + movi v1, 0 + movi v2, 0 + ldai 0 + call.virt.acc %s + cases: + - values: + - R.foo(R a0, i32 a1, i32 a2, i32 a3) + - R.foo, v0, v1, v2, 3 + - values: + - R.foo(R a0) + - R.foo, v0, v1, v2, 2 + - values: + - R.foo(i32 a0, R a1) + - R.foo, v0, v1, v2, 0 + - values: + - R.foo(R a0, i32 a1) + - R.foo, v0, v1, v2, 3 + bugid: ['5583'] + ignore: true + - values: + - R.foo(R a0) + - R.foo, v0, v1, v2, 1 + bugid: ['5583'] + ignore: true + - values: + - foo(R a0, i32 a1) + - foo, v0, v1, v2, 3 + + + - file-name: non_accessible_method_p + description: Check that verifier reports an error on non-accessible method. + isa: + verification: + - method_id_accessible + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .record R {} + .function void %s + .function i32 main() { + newobj v0, R + ldai 0 + movi v1, 1 + movi v2, 2 + call.virt.acc R.foo, v0, v1, v2, 1 + cases: + - values: + - R.foo(R a0, i32 a1, i32 a2, i32 a3) + - values: + - R.foo(R a0, i32 a1, i32 a2) + + + - file-name: non_accessible_method_j + description: Check that verifier reports an error on non-accessible method. + isa: + verification: + - method_id_accessible + header-template: [java] + runner-options: [verifier-failure, verifier-debug-config, use-java] + tags: [verifier] + check-type: exit-positive + code-template: | + %s + .function i32 main() { + newobj v0, %s + ldai 0 + movi v1, 1 + movi v2, 2 + call.virt.acc %s.foo, v0, v1, v2, 1 + cases: + - values: + - | + .record R {} + .function void R.foo(R a0, i32 a1, i32 a2, i32 a3) + - R + - R + - values: + - | + .record R {} + .function void R.foo(R a0, i32 a1, i32 a2, i32 a3) + .record Q {} + .function void Q.foo(R a0, i32 a1, i32 a2, i32 a3) { + return.void + } + - Q + - R + - values: + - | + .record R {} + .function void R.foo(R a0, i32 a1, i32 a2, i32 a3) + .record Q {} + .function void Q.foo(Q a0, i32 a1, i32 a2, i32 a3) { + return.void + } + - Q + - Q + runner-options: [verifier-only, verifier-debug-config, use-java] + + + - file-name: invalid_method + description: Check that verifier reports an error on invalid method. + isa: + verification: + - method_id_non_static + - method_id_accessible + header-template: [] + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + check-type: exit-positive + code-template: | + .record R {} + %s + .function i32 main() { + newobj v0, R + lda.obj v0 + call.virt.acc %s + cases: + - description: No return in function. + values: + - .function void R.foo(R a0, R a1, R a2, R a3) {} + - R.foo, v0, v0, v0, 1 + bugid: ['5607'] + ignore: true + - description: No return in function. + values: + - | + # + .function i32 R.foo(R a0, R a1, R a2, R a3) { + ldai 0 + } + - R.foo, v0, v0, v0, 0 + + + - file-name: incompatible_v_p + description: Check 'call.virt.acc' instruction called with incompatible register arguments in PandaAssembly context. + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record R {} + .function void R.foo(R a0, i32 a1, i32 a2, %s a3) { + return.void + } + .function i32 main() { + *s + movi v2, 2 + movi v3, 3 + newobj v0, R + lda.obj v0 + call.virt.acc R.foo, v3, v2, v1, 0 + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - u8 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - u32 + exclude: [i32] + - values: + - u64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - u32[] + exclude: [u32a, nul] + - values: + - u64[] + exclude: [u64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - u32[][] + exclude: [u32aa, nul] + - values: + - u64[][] + exclude: [u64aa, nul] + - values: + - f32[][] + exclude: [f32aa, nul] + - values: + - R + exclude: [nul] + - values: + - panda.String + exclude: [str, nul] + - values: + - panda.Class + exclude: [typ, nul] + - values: + - panda.Object + exclude: [u32a, u64a, f32a, u32aa, u64aa, f32aa, str, typ, ra, stra, typa, obja, raa, straa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - panda.String[] + exclude: [stra, nul] + - values: + - panda.Class[] + exclude: [typa, nul] + - values: + - panda.Object[] + exclude: [obja, u32aa, u64aa, f32aa, ra, stra, typa, raa, straa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - panda.String[][] + exclude: [straa, nul] + - values: + - panda.Class[][] + exclude: [typaa, nul] + - values: + - panda.Object[][] + exclude: [objaa, raa, straa, typaa, nul] + cases: + - values: + - movi v1, 1 + id: i32 + - values: + - movi.64 v1, 1 + id: i64 + - values: + - fmovi.64 v1, 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[] + id: u32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[] + id: u64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[][] + id: u32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[][] + id: u64aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[][] + id: f32aa + - values: + - | + # + lda.str "test message" + sta.obj v1 + id: str + - values: + - | + # + lda.type R + sta.obj v1 + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[] + id: stra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[] + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[] + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[][] + id: straa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[][] + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[][] + id: objaa + - values: + - mov.null v1 + id: nul + + + - file-name: incompatible_acc_p + description: Check 'call.virt.acc' instruction called with incompatible accumulator argument in PandaAssembly context. + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, verifier-debug-config] + tags: [verifier] + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record R {} + .function void R.foo(R a0, i32 a1, %s a2, i32 a3) { + return.void + } + .function i32 main() { + *s + newobj v2, R + movi v1, 0 + call.virt.acc R.foo, v2, v1, v1, 2 + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - u8 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - u32 + exclude: [i32] + - values: + - u64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - u32[] + exclude: [u32a, nul] + - values: + - u64[] + exclude: [u64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - u32[][] + exclude: [u32aa, nul] + - values: + - u64[][] + exclude: [u64aa, nul] + - values: + - f32[][] + exclude: [f32aa, nul] + - values: + - R + exclude: [nul] + - values: + - panda.String + exclude: [str, nul] + - values: + - panda.Class + exclude: [typ, nul] + - values: + - panda.Object + exclude: [u32a, u64a, f32a, u32aa, u64aa, f32aa, str, typ, ra, stra, typa, obja, raa, straa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - panda.String[] + exclude: [stra, nul] + - values: + - panda.Class[] + exclude: [typa, nul] + - values: + - panda.Object[] + exclude: [obja, u32aa, u64aa, f32aa, ra, stra, typa, raa, straa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - panda.String[][] + exclude: [straa, nul] + - values: + - panda.Class[][] + exclude: [typaa, nul] + - values: + - panda.Object[][] + exclude: [objaa, raa, straa, typaa, nul] + cases: + - values: + - ldai 1 + id: i32 + - values: + - ldai.64 1 + id: i64 + - values: + - fldai.64 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[] + lda.obj v1 + id: u32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[] + lda.obj v1 + id: u64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + lda.obj v1 + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u32[][] + lda.obj v1 + id: u32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, u64[][] + lda.obj v1 + id: u64aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[][] + lda.obj v1 + id: f32aa + - values: + - | + # + lda.str "test message" + id: str + - values: + - | + # + lda.type R + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + lda.obj v1 + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[] + lda.obj v1 + id: stra + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[] + lda.obj v1 + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[] + lda.obj v1 + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + lda.obj v1 + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.String[][] + lda.obj v1 + id: straa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Class[][] + lda.obj v1 + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[][] + lda.obj v1 + id: objaa + - values: + - lda.null + id: nul + + + - file-name: incompatible_v_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc' instruction with incompatible register in Java context. + header-template: [java] + code-template: | + .record java.lang.Object + .record java.lang.Class + .record R {} + .function void R.foo(R a0, %s a1, i32 a2, R a3) { + return.void + } + .function i32 main() { + *s + ldai 0 + newobj v2, R + newobj v3, R + call.virt.acc R.foo, v3, v1, v2, 2 + check-type: exit-positive + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - i32 + exclude: [i32] + - values: + - i64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - f64 + exclude: [f64] + - values: + - u1[] + exclude: [u1a, nul] + - values: + - i8[] + exclude: [i8a, nul] + - values: + - u16[] + exclude: [u1a, u16a, nul] + - values: + - i16[] + exclude: [i8a, i16a, nul] + - values: + - i32[] + exclude: [i8a, i16a, i32a, nul] + - values: + - i64[] + exclude: [i64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - f64[] + exclude: [f32a, f64a, nul] + - values: + - i32[][] + exclude: [i32aa, nul] + - values: + - f64[][] + exclude: [f64aa, nul] + - values: + - R + exclude: [nul] + - values: + - java.lang.Class + exclude: [typ, nul] + - values: + - java.lang.Object + exclude: [u1a, i8a, u16a, i16a, i32a, i64a, f32a, f64a, i32aa, f64aa, typ, ra, typa, obja, raa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - java.lang.Class[] + exclude: [typa, nul] + - values: + - java.lang.Object[] + exclude: [obja, i32aa, f64aa, ra, typa, raa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - java.lang.Class[][] + exclude: [typaa, nul] + - values: + - java.lang.Object[][] + exclude: [objaa, raa, typaa, nul] + cases: + - values: + - movi v1, 1 + id: i32 + - values: + - movi.64 v1, 1 + id: i64 + - values: + - fmovi.64 v1, 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u1[] + id: u1a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i8[] + id: i8a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u16[] + id: u16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i16[] + id: i16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[] + id: i32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i64[] + id: i64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[] + id: f64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[][] + id: i32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[][] + id: f64aa + - values: + - | + # + lda.type R + sta.obj v1 + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[] + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[] + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[][] + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[][] + id: objaa + - values: + - mov.null v1 + id: nul + + + - file-name: incompatible_acc_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-failure, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc' instruction with incompatible accumulator in Java context. + header-template: [java] + check-type: exit-positive + code-template: | + .record java.lang.Object + .record java.lang.Class + .record R {} + .function void R.foo(R a0, %s a1, i32 a2, R a3) { + return.void + } + .function i32 main() { + *s + movi v1, 0 + newobj v2, R + call.virt.acc R.foo, v2, v1, v2, 1 + template-cases: + - values: + - u1 + exclude: [i32] + - values: + - i8 + exclude: [i32] + - values: + - u16 + exclude: [i32] + - values: + - i16 + exclude: [i32] + - values: + - i32 + exclude: [i32] + - values: + - i64 + exclude: [i64] + - values: + - f32 + exclude: [f64] + - values: + - f64 + exclude: [f64] + - values: + - u1[] + exclude: [u1a, nul] + - values: + - i8[] + exclude: [i8a, nul] + - values: + - u16[] + exclude: [u1a, u16a, nul] + - values: + - i16[] + exclude: [i8a, i16a, nul] + - values: + - i32[] + exclude: [i8a, i16a, i32a, nul] + - values: + - i64[] + exclude: [i64a, nul] + - values: + - f32[] + exclude: [f32a, nul] + - values: + - f64[] + exclude: [f32a, f64a, nul] + - values: + - i32[][] + exclude: [i32aa, nul] + - values: + - f64[][] + exclude: [f64aa, nul] + - values: + - R + exclude: [nul] + - values: + - java.lang.Class + exclude: [typ, nul] + - values: + - java.lang.Object + exclude: [u1a, i8a, u16a, i16a, i32a, i64a, f32a, f64a, i32aa, f64aa, typ, ra, typa, obja, raa, typaa, objaa, nul] + - values: + - R[] + exclude: [ra, nul] + - values: + - java.lang.Class[] + exclude: [typa, nul] + - values: + - java.lang.Object[] + exclude: [obja, i32aa, f64aa, ra, typa, raa, typaa, objaa, nul] + - values: + - R[][] + exclude: [raa, nul] + - values: + - java.lang.Class[][] + exclude: [typaa, nul] + - values: + - java.lang.Object[][] + exclude: [objaa, raa, typaa, nul] + cases: + - values: + - ldai 1 + id: i32 + - values: + - ldai.64 1 + id: i64 + - values: + - fldai.64 1.0 + id: f64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, u1[] + lda.obj v1 + id: u1a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i8[] + lda.obj v1 + id: i8a + - values: + - | + # + movi v1, 10 + newarr v1, v1, u16[] + lda.obj v1 + id: u16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i16[] + lda.obj v1 + id: i16a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[] + lda.obj v1 + id: i32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i64[] + lda.obj v1 + id: i64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f32[] + lda.obj v1 + id: f32a + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[] + lda.obj v1 + id: f64a + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[][] + lda.obj v1 + id: i32aa + - values: + - | + # + movi v1, 10 + newarr v1, v1, f64[][] + lda.obj v1 + id: f64aa + - values: + - | + # + lda.type R + id: typ + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[] + lda.obj v1 + id: ra + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[] + lda.obj v1 + id: typa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[] + lda.obj v1 + id: obja + - values: + - | + # + movi v1, 10 + newarr v1, v1, R[][] + lda.obj v1 + id: raa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Class[][] + lda.obj v1 + id: typaa + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[][] + lda.obj v1 + id: objaa + - values: + - lda.null + id: nul + + + - file-name: compatible_primitive_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc' instruction with compatible primitive arguments in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record R {} + .function void R.foo(R a0, %s) { + return.void + } + .function i32 main() { + newobj v0, R + lda.obj v0 + %s + call.virt.acc R.foo, v1, v2, v3, 0 + cases: + - values: + - u1 a1, u8 a2, i8 a3 + - | + # + movi v1, 1 + movi v2, 1 + movi v3, 1 + - values: + - u16 a1, i16 a2, u32 a3 + - | + # + movi v1, 1 + movi v2, 1 + movi v3, 1 + - values: + - i32 a1, i64 a2, u64 a3 + - | + # + movi v1, 1 + movi.64 v2, 1 + movi.64 v3, 1 + - values: + - f32 a1, f64 a2 + - | + # + fmovi.64 v1, 1.1 + fmovi.64 v2, 1.1 + + + - file-name: compatible_primitive_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc' instruction with compatible primitive arguments in Java context. + header-template: [java] + code-template: | + .record R {} + .function void R.foo(R a0, %s) { + return.void + } + .function i32 main() { + %s + newobj v0, R + call.virt.acc R.foo, v0, v1, v2, 3 + check-type: exit-positive + cases: + - values: + - u1 a1, f64 a2, u16 a3 + - | + # + movi v1, 1 + fmovi.64 v2, 1.1 + ldai 1 + - values: + - i32 a1, i64 a2, f32 a3 + - | + # + movi v1, 1 + movi.64 v2, 1 + fldai.64 1.1 + - values: + - i16 a1, i8 a2 + - | + # + movi v1, 1 + movi v2, 1 + + + - file-name: compatible_prim_array_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc' instruction called with compatible primitive array arguments in PandaAssembly context. + header-template: [] + code-template: | + .record R {} + .function void R.foo(R a0, %s) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v1, v0, %s[] + newarr v2, v0, %s[] + newarr v3, v0, %s[] + lda.obj v3 + newobj v0, R + call.virt.acc R.foo, v0, v1, v2, 3 + check-type: exit-positive + cases: + - values: + - u8[] a1, i8[] a2, u16[] a3 + - u8 + - i8 + - u16 + - values: + - u32[] a1, f32[][] a2, u64[] a3 + - u32 + - f32[] + - u64 + - values: + - f32[] a1, f64[] a2, u1[][] a3 + - f32 + - f64 + - u1[] + - values: + - i8[][] a1, u16[][] a2, i16[][] a3 + - i8[] + - u16[] + - i16[] + - values: + - i32[][] a1, u64[][] a2, i64[][] a3 + - i32[] + - u64[] + - i64[] + - values: + - i32[] a1, f64[][] a2 + - i32 + - f64[] + - f64[][] + - values: + - u1[] a1, i16[] a2, i64[] a3 + - u1 + - i16 + - i64 + - values: + - u8[][] a1, u32[][] a2 + - u8[] + - u32[] + - u32[][] + + + - file-name: compatible_prim_array_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java] + tags: [verifier] + description: Check 'call.virt.acc' instruction called with compatible primitive array arguments in Java context. + header-template: [java] + code-template: | + .record R {} + .function void R.foo(R a0, %s) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v1, v0, %s[] + newarr v2, v0, %s[] + newarr v3, v0, %s[] + newobj v0, R + lda.obj v0 + call.virt.acc R.foo, v1, v2, v3, 0 + check-type: exit-positive + cases: + - values: + - f64[][] a1, u16[] a2, i16[] a3 + - f64[] + - u16 + - i16 + - values: + - i64[] a1, f32[] a2, f64[] a3 + - i64 + - f32 + - f64 + - values: + - i8[][] a1, u16[][] a2, i16[][] a3 + - i8[] + - u16[] + - i16[] + - values: + - i32[][] a1, i64[][] a2, f32[][] a3 + - i32[] + - i64[] + - f32[] + - values: + - u1[] a1, i32[] a2, u1[][] a3 + - u1 + - i32 + - u1[] + + + - file-name: compatible_obj_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc' instruction called with compatible object arguments in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record Q {} + .record R {} + .function void R.foo(R a0, %s) { + return.void + } + .function i32 main() { + %s + newobj v7, R + lda.obj v7 + call.virt.acc R.foo, v1, v2, v3, 0 + cases: + # Object of type O is instance of type T if O is the same as T ... + - values: + - R a1, panda.Class a2, panda.String a3 + - | + # + newobj v1, R + lda.type Q + sta.obj v2 + lda.str "test" + sta.obj v3 + # ... or is subtype of T + - values: + - panda.Object a1, panda.Object a2, panda.Object a3 + - | + # + newobj v1, Q + lda.str "test" + sta.obj v2 + lda.type Q + sta.obj v3 + bugid: ['3594'] + ignore: true + # For arrays T should be a root type in type hierarchy ... + - values: + - panda.Object a1, panda.Object a2, panda.Object a3 + - | + # + movi v0, 10 + newarr v1, v0, i32[] + newarr v2, v0, f64[][] + newarr v3, v0, Q[] + - values: + - panda.Object a1, panda.Object a2, panda.Object a3 + - | + # + movi v0, 10 + newarr v1, v0, panda.String[] + newarr v2, v0, panda.Class[] + newarr v3, v0, Q[][] + + + - file-name: compatible_obj_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc' instruction called with compatible object arguments in Java context. + header-template: [java] + check-type: exit-positive + code-template: | + .record java.lang.Object + .record java.lang.Class + .record java.lang.String + .record java.io.Serializable + .record I {} + .record E {} + .record Q {} + .record R {} + .function void R.foo(R a0, %s) { + return.void + } + .function i32 main() { + %s + newobj v0, R + call.virt.acc R.foo, v0, v1, v2, 3 + cases: + # Object of type O is instance of type T if O is the same as T ... + - values: + - Q a1, java.lang.String a2, java.lang.Class a3 + - | + # + newobj v1, Q + lda.str "test" + sta.obj v2 + lda.type Q + # ... or is subtype of T + - values: + - E a1, I a2, java.lang.Object a3 + - | + # + newobj v1, Q + newobj v2, Q + lda.str "test" + - values: + - java.io.Serializable a1, java.lang.Object a2, java.lang.Object a3 + - | + # + lda.type Q + sta.obj v1 + newobj v2, R + lda.type java.lang.String + bugid: ['3594'] + ignore: true + # For arrays T should be a root type in type hierarchy ... + - values: + - java.lang.Object a1, java.lang.Object a2, java.lang.Object a3 + - | + # + movi v0, 10 + newarr v1, v0, i32[] + newarr v2, v0, Q[] + newarr v3, v0, java.lang.Object[] + lda.obj v3 + - values: + - java.lang.Object a1, java.lang.Object a2, java.lang.Object a3 + - | + # + movi v0, 10 + newarr v1, v0, java.lang.String[] + newarr v2, v0, java.lang.Class[] + newarr v3, v0, I[][] + lda.obj v3 + + + - file-name: compatible_obj_array_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc' instruction called with compatible object array arguments in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record Q {} + .record R {} + .function void R.foo(R a0, %s) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v1, v0, %s + newarr v2, v0, %s + newarr v3, v0, %s + lda.obj v3 + newobj v0, R + call.virt.acc R.foo, v0, v1, v2, 3 + cases: + # T is such array that O array elements are the same as T array elements + - values: + - Q[][] a1, panda.Object[] a2, panda.Object[][] a3 + - Q[][] + - panda.Object[] + - panda.Object[][] + - values: + - panda.String[] a1, panda.Class[] a2, panda.Class[][] a3 + - panda.String[] + - panda.Class[] + - panda.Class[][] + # T is such array that O array elements are subtypes of T array elements + - values: + - panda.Object[] a1, panda.Object[] a2, panda.Object[] a3 + - Q[] + - Q[][] + - panda.Class[] + - values: + - panda.Object[] a1, panda.Object[] a2, panda.Object[] a3 + - panda.String[] + - panda.String[][] + - i32[][] + - values: + - panda.Object[][] a1, panda.Object[][] a2, panda.Object[][] a3 + - panda.Object[][][] + - panda.Class[][] + - panda.Class[][][] + - values: + - panda.Object[][] a1, panda.Object[][] a2, panda.Object[][] a3 + - i32[][][] + - f64[][][][] + - Q[][] + + + - file-name: compatible_obj_array_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc' instruction called with compatible object array arguments in Java context. + header-template: [java] + code-template: | + .record java.lang.Object + .record java.lang.Class + .record java.lang.String + .record I {} + .record E {} + .record Q {} + .record R {} + .function void R.foo(R a0, %s) { + return.void + } + .function i32 main() { + movi v0, 10 + newarr v1, v0, %s + newarr v2, v0, %s + newarr v3, v0, %s + newobj v0, R + lda.obj v0 + call.virt.acc R.foo, v1, v2, v3, 0 + check-type: exit-positive + cases: + # T is such array that O array elements are the same as T array elements + - values: + - java.lang.String[] a1, Q[][] a2, java.lang.String[][] a3 + - java.lang.String[] + - Q[][] + - java.lang.String[][] + - values: + - java.lang.Class[][] a1, java.lang.Class[] a2, java.lang.Object[][] a3 + - java.lang.Class[][] + - java.lang.Class[] + - java.lang.Object[][] + - values: + - Q[] a1, R[] a2, I[] a3 + - Q[] + - R[] + - I[] + # T is such array that O array elements are subtypes of T array elements + - values: + - java.lang.Object[] a1, I[] a2, java.lang.Object[] a3 + - Q[][] + - Q[] + - java.lang.Class[] + - values: + - java.lang.Object[] a1, java.lang.Object[] a2, java.lang.Object[] a3 + - Q[] + - java.lang.String[] + - f64[][][] + - values: + - java.lang.Object[] a1, java.lang.Object[] a2, java.lang.Object[] a3 + - i32[][] + - I[][] + - u16[][] + # inherited types from object[][] + - values: + - java.lang.Object[][] a1, I[][] a2, java.lang.Object[][] a3 + - java.lang.Object[][][] + - Q[][] + - java.lang.Class[][][] + - values: + - java.lang.Object[][] a1, java.lang.Object[][] a2, java.lang.Object[][] a3 + - java.lang.Class[][] + - i32[][][] + - I[][][] + + + - file-name: compatible_obj_null_args_p + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc' instruction called with null object ref in PandaAssembly context. + header-template: [] + check-type: exit-positive + code-template: | + .record panda.Object + .record panda.Class + .record panda.String + .record Q {} + .function void Q.foo(Q a0, %s) { + return.void + } + .function i32 main() { + mov.null v1 + mov.null v2 + mov.null v3 + lda.null + call.virt.acc Q.foo, v1, v2, v3, 0 + cases: + - values: ['f64[][] a1, panda.Object a2, panda.Object[] a3'] + - values: ['Q a1, Q[][] a2, panda.String a3'] + - values: ['panda.Class a1, panda.Class[] a2, u32[][][] a3'] + + + - file-name: compatible_obj_null_args_j + isa: + verification: + - compatible_arguments + runner-options: [verifier-only, use-java, verifier-debug-config] + tags: [verifier] + description: Check 'call.virt.acc' instruction called with null object ref in Java context. + header-template: [java] + code-template: | + .record java.lang.Object + .record java.lang.Class + .record java.lang.String + .record Q {} + .function void Q.foo(Q a0, %s) { + return.void + } + .function i32 main() { + mov.null v1 + mov.null v2 + mov.null v3 + lda.null + call.virt.acc Q.foo, v1, v2, v3, 1 + check-type: exit-positive + cases: + - values: ['i32[] a1, java.lang.Object a2, java.lang.Object[] a3'] + - values: ['java.lang.Object[][] a1, Q a2, java.lang.String a3'] + - values: ['java.lang.String[] a1, java.lang.Class a2, u1[][][] a3'] + + + - file-name: values_signed + isa: + instructions: + - sig: call.virt.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + runner-options: [] + description: Check 'call.virt.acc' instruction called with integer values. + header-template: [] + check-type: empty + code-template: | + .record R {} + .function i32 R.foo(R a0, i32 a1, i64 a2, i32 a3) { + ldai %s + jeq a1, ok1 + ldai 1 + return + ok1: + ldai.64 %s + cmp.64 a2 + jeqz ok2 + ldai 2 + return + ok2: + ldai %s + jeq a3, ok3 + ldai 3 + return + ok3: + ldai 0 + return + } + .function i32 main() { + movi v1, %s + movi.64 v2, %s + movi v3, %s + newobj v0, R + lda.obj v0 + call.virt.acc R.foo, v1, v2, v3, 0 + return + } + cases: + - values: [0, -1, 0x5a5a5a5a, 0, -1, 0x5a5a5a5a] + - values: [0x11111111, 0xe1e1e1e1e1e1e1e1, 0x7ffffffe, 0x11111111, 0xe1e1e1e1e1e1e1e1, 0x7ffffffe] + - values: [0xeeee0000, 0x8000000000000001, 0x80000001, 0xeeee0000, 0x8000000000000001, 0x80000001] + + + - file-name: values_unsigned + isa: + instructions: + - sig: call.virt.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + runner-options: [] + description: Check 'call.virt.acc' instruction called with unsigned values. + header-template: [] + check-type: empty + code-template: | + .record R {} + .function i32 R.foo(R a0, u64 a1, u32 a2, u64 a3) { + ldai.64 %s + ucmp.64 a1 + jeqz ok1 + ldai 1 + return + ok1: + ldai %s + ucmp a2 + jeqz ok2 + ldai 2 + return + ok2: + ldai.64 %s + ucmp.64 a3 + return + } + .function i32 main() { + ldai.64 %s + movi v2, %s + movi.64 v3, %s + newobj v0, R + call.virt.acc R.foo, v0, v2, v3, 1 + return + } + cases: + - values: [0, 0xffffffff, 0xefffffffffffffff, 0, 0xffffffff, 0xefffffffffffffff] + - values: [0xeeee1111ffffdddd, 0x5a5a5a5a, 0xa5a5a5a5a5a5a5a5, 0xeeee1111ffffdddd, 0x5a5a5a5a, 0xa5a5a5a5a5a5a5a5] + - values: [1234567890123456789, 0, 0xffffffffffffffff, 1234567890123456789, 0, 0xffffffffffffffff] + + + - file-name: values_float + isa: + instructions: + - sig: call.virt.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + runner-options: [] + description: Check 'call.virt.acc' instruction called with float values. + header-template: [] + check-type: empty + code-template: | + .record R {} + .function i32 R.foo(R a0, f64 a1, f32 a2, f64 a3) { + fldai.64 %s + fcmpg.64 a1 + jeqz ok1 + ldai 1 + return + ok1: + fldai %s + fcmpg a2 + jeqz ok2 + ldai 3 + return + ok2: + fldai.64 %s + fcmpg.64 a3 + return + } + .function i32 main() { + fldai.64 %s + fmovi v2, %s + fmovi.64 v3, %s + newobj v0, R + call.virt.acc R.foo, v0, v2, v3, 1 + return + } + cases: + - values: [-1.1, -1.1, 0.12345678, -1.1, -1.1, 0.12345678] + - values: [0.373737373737373737e37, 1.98765e14, -0.000000019e19, 0.373737373737373737e37, 1.98765e14, -0.000000019e19] + - values: [0.717171717171717171717171e71, 0, 0.373737373737373737e37, 0.717171717171717171717171e71, 0, 0.373737373737373737e37] + - values: [0x7ff0000000000000, 0x7f800000, 0xfff0000000000000, 0x7ff0000000000000, 0x7f800000, 0xfff0000000000000] + + + - file-name: values_obj_p + isa: + instructions: + - sig: call.virt.acc method_id, v1:in:top, v2:in:top, v3:in:top, imm:u2 + acc: inout:top + format: [op_v1_4_v2_4_v3_4_imm_4_id_16] + runner-options: [] + description: Check 'call.virt.acc' instruction called with object values in PandaAssembly context. + header-template: [] + check-type: empty + code-template: | + .record panda.Object + .record panda.String + .record R {} + # put objects into array + .function panda.Object R.foo(R a0, panda.Object a1, panda.Object a2, panda.Object a3) { + movi v0, 3 + newarr v0, v0, panda.Object[] + lda.obj a1 + movi v7, 0 + starr.obj v0, v7 + lda.obj a2 + movi v7, 1 + starr.obj v0, v7 + lda.obj a3 + movi v7, 2 + starr.obj v0, v7 + lda.obj v0 + return.obj + } + # check that array contains correct obj refs + .function i32 check(panda.Object a0, panda.Object a1, panda.Object a2, panda.Object[] a3) { + ldai 0 + ldarr.obj a3 + jeq.obj a0, ok1 + ldai 1 + return + ok1: + ldai 1 + ldarr.obj a3 + jeq.obj a1, ok2 + ldai 2 + return + ok2: + ldai 2 + ldarr.obj a3 + jeq.obj a2, ok3 + ldai 3 + return + ok3: + ldai 0 + return + } + .function i32 main() { + newobj v7, R + %s + lda.obj v1 + call.virt.acc R.foo, v7, v2, v3, 1 # R, acc, v2, v3 + sta.obj v4 + call check, v1, v2, v3, v4 + jeqz pass1 + return + pass1: + lda.obj v2 + call.virt.acc R.foo, v7, v1, v3, 2 # R, v1, acc, v3 + sta.obj v4 + call check, v1, v2, v3, v4 + jeqz pass2 + return + pass2: + lda.obj v3 + call.virt.acc R.foo, v7, v1, v2, 3 # R, v1, v2, acc + sta.obj v4 + call check, v1, v2, v3, v4 + return + } + cases: + - values: + - | + # + newobj v1, panda.Object + lda.str "test" + sta.obj v2 + lda.type panda.String + sta.obj v3 + - values: + - | + # + newobj v1, R + newobj v2, panda.Object + mov.null v3 + - values: + - | + # + lda.str "" + sta.obj v1 + movi v5, 0 + newarr v2, v5, R[][] + newarr v3, v5, i32[] + - values: + - | + # + movi v5, 0 + newarr v1, v5, panda.String[] + lda.type R + sta.obj v2 + newarr v3, v5, panda.Object[][] + + + - file-name: regs_restored + isa: + description: > + Call indicated object method, i.e. create new frame, pass values of arguments and + continue execution from the first instruction of a method. + Callee should treat accumulator value as undefined and cannot use it until accumulator + definition in the new frame. + description: Check 'call.virt.acc' that registers are restored after the call. + tags: [tsan] + header-template: [] + code-template: | + .record R {} + .function R R.foo(R a0, i32 a1, i32 a2, i32 a3) { + movi v0, 100 + movi v1, 200 + movi v2, 300 + movi v3, 400 + movi v4, 500 + movi v5, 600 + movi v6, 700 + movi v7, 800 + movi v8, 900 + movi v9, 1000 + movi v10, 1100 + movi v11, 1200 + movi v12, 1300 + movi v13, 1400 + movi v14, 1500 + movi v15, 1600 + lda.obj a0 + return.obj + } + .function i32 main() { + newobj v0, R + lda.obj v0 + movi v0, 1 + movi v1, 2 + movi v2, 3 + movi v3, 4 + movi v4, 5 + movi v5, 6 + movi v6, 7 + movi v7, 8 + movi v8, 9 + movi v9, 10 + movi v10, 11 + movi v11, 12 + movi v12, 13 + movi v13, 14 + movi v14, 15 + movi v15, 16 + call.virt.acc R.foo, v0, v1, v2, 0 + call.virt.acc R.foo, v3, v4, v5, 0 + call.virt.acc R.foo, v6, v7, v8, 0 + call.virt.acc R.foo, v9, v10, v11, 0 + call.virt.acc R.foo, v12, v13, v14, 0 + call.virt.acc R.foo, v15, v15, v15, 0 + ldai 1 + jeq v0, ok1 + return + ok1: + ldai 2 + jeq v1, ok2 + return + ok2: + ldai 3 + jeq v2, ok3 + return + ok3: + ldai 4 + jeq v3, ok4 + return + ok4: + ldai 5 + jeq v4, ok5 + return + ok5: + ldai 6 + jeq v5, ok6 + return + ok6: + ldai 7 + jeq v6, ok7 + return + ok7: + ldai 8 + jeq v7, ok8 + return + ok8: + ldai 9 + jeq v8, ok9 + return + ok9: + ldai 10 + jeq v9, ok10 + return + ok10: + ldai 11 + jeq v10, ok11 + return + ok11: + ldai 12 + jeq v11, ok12 + return + ok12: + ldai 13 + jeq v12, ok13 + return + ok13: + ldai 14 + jeq v13, ok14 + return + ok14: + ldai 15 + jeq v14, ok15 + return + ok15: + ldai 16 + jeq v15, ok16 + return + ok16: + check-type: exit-positive + + + - file-name: ame_p + isa: + exceptions: + - x_abstract + description: Check that AbstractMethodError is thrown in PandaAssembly context. + header-template: [] + code-template: | + .record panda.AbstractMethodError + .record R {} + .function void R.foo1(R a0) + .function void R.foo2(R a0, R a1, R a2, R a3) + .function i32 main() { + begin: + newobj v0, R + lda.obj v0 + call.virt.acc %s + end: + ldai 1 # Should not reach this line + return + + catch_AME: + ldai 0 # Expected panda.AbstractMethodError + return + + catch_all: + ldai 2 # Unexpected exception, test failed + return + + .catch panda.AbstractMethodError, begin, end, catch_AME + .catchall begin, end, catch_all + check-type: none + cases: + - values: + - R.foo1, v0, v1, v2, 1 + tags: ['tsan'] + - values: + - R.foo2, v0, v0, v0, 0 diff --git a/tests/cts-generator/cts-template/fldarr.32.yaml b/tests/cts-generator/cts-template/fldarr.32.yaml index 1d2685b192..4bef5c1616 100644 --- a/tests/cts-generator/cts-template/fldarr.32.yaml +++ b/tests/cts-generator/cts-template/fldarr.32.yaml @@ -38,7 +38,7 @@ tests: isa: instructions: - sig: fldarr.32 v:in:f32[] - acc: inout:i32->f64 + acc: inout:i32->f32 format: [op_v_8] properties: [acc_read, acc_write, float] description: Check fldarr.32 reads items from array of different size and type in Panda Assembly context. @@ -59,7 +59,7 @@ tests: isa: instructions: - sig: fldarr.32 v:in:f32[] - acc: inout:i32->f64 + acc: inout:i32->f32 format: [op_v_8] properties: [acc_read, acc_write, float] tags: ['tsan', 'verifier'] @@ -77,7 +77,7 @@ tests: isa: instructions: - sig: fldarr.32 v:in:f32[] - acc: inout:i32->f64 + acc: inout:i32->f32 format: [op_v_8] properties: [acc_read, acc_write, float] description: Check rejectable array of primitive types for fldarr.32 instruction in Panda Assembly context. @@ -107,7 +107,7 @@ tests: isa: instructions: - sig: fldarr.32 v:in:f32[] - acc: inout:i32->f64 + acc: inout:i32->f32 format: [op_v_8] properties: [acc_read, acc_write, float] description: Check fldarr.32 reads correct items from array of primitives. @@ -126,12 +126,12 @@ tests: call.short nextRand, v0 sta v0 # v0 - next random number andi 0xFFFFFF # Limit amount of digit in number to fit in f32 primitive without loss of precision - i32tof64 - sta.64 v5 + i32tof32 + sta v5 fstarr.32 v1, v2 # save random number v1[v2] = acc lda v2 fldarr.32 v1 # acc = v1[v2] - fcmpl.64 v5 # Compare random number and stored value from array + fcmpl v5 # Compare random number and stored value from array jeqz passed ldai 1 return @@ -152,7 +152,7 @@ tests: isa: instructions: - sig: fldarr.32 v:in:f32[] - acc: inout:i32->f64 + acc: inout:i32->f32 format: [op_v_8] properties: [acc_read, acc_write, float] description: Check fldarr.32 reads correct items from array of primitives. Inspect different indexes and values. @@ -165,7 +165,7 @@ tests: newarr v0, v0, f32[] # v0 - testable array fill_array: lda v1 - i32tof64 # acc = (f32)v1 + i32tof32 # acc = (f32)v1 fstarr.32 v0, v1 # v0[v1] = acc inci v1, 1 # v1 = v1 + 1 lda v1 @@ -175,10 +175,10 @@ tests: check_array: lda v1 fldarr.32 v0 - sta.64 v3 + sta v3 lda v1 - i32tof64 - fcmpl.64 v3 + i32tof32 + fcmpl v3 jeqz ok ldai 1 return @@ -198,7 +198,7 @@ tests: isa: instructions: - sig: fldarr.32 v:in:f32[] - acc: inout:i32->f64 + acc: inout:i32->f32 format: [op_v_8] properties: [acc_read, acc_write, float] check-type: empty @@ -257,7 +257,7 @@ tests: isa: instructions: - sig: fldarr.32 v:in:f32[] - acc: inout:i32->f64 + acc: inout:i32->f32 format: [op_v_8] properties: [acc_read, acc_write, float] verification: @@ -333,7 +333,7 @@ tests: isa: instructions: - sig: fldarr.32 v:in:f32[] - acc: inout:i32->f64 + acc: inout:i32->f32 format: [op_v_8] properties: [acc_read, acc_write, float] verification: @@ -404,7 +404,7 @@ tests: isa: instructions: - sig: fldarr.32 v:in:f32[] - acc: inout:i32->f64 + acc: inout:i32->f32 format: [op_v_8] properties: [acc_read, acc_write, float] verification: @@ -527,7 +527,7 @@ tests: isa: instructions: - sig: fldarr.32 v:in:f32[] - acc: inout:i32->f64 + acc: inout:i32->f32 format: [op_v_8] properties: [acc_read, acc_write, float] description: Check 'fldarr.32' with uninitialized register and accumulator. @@ -548,7 +548,7 @@ tests: isa: instructions: - sig: fldarr.32 v:in:f32[] - acc: inout:i32->f64 + acc: inout:i32->f32 format: [op_v_8] properties: [acc_read, acc_write, float] exceptions: @@ -603,7 +603,7 @@ tests: isa: instructions: - sig: fldarr.32 v:in:f32[] - acc: inout:i32->f64 + acc: inout:i32->f32 format: [op_v_8] properties: [acc_read, acc_write, float] exceptions: diff --git a/tests/cts-generator/cts-template/fstarr.32.yaml b/tests/cts-generator/cts-template/fstarr.32.yaml index 9ce4a4a9c7..667109999f 100644 --- a/tests/cts-generator/cts-template/fstarr.32.yaml +++ b/tests/cts-generator/cts-template/fstarr.32.yaml @@ -36,7 +36,7 @@ tests: Store accumulator content into array slot pointed by index. instructions: - sig: fstarr.32 v1:in:f32[], v2:in:i32 - acc: in:f64 + acc: in:f32 format: [op_v1_4_v2_4] properties: [acc_read, float] commands: @@ -46,7 +46,7 @@ tests: isa: instructions: - sig: fstarr.32 v1:in:f32[], v2:in:i32 - acc: in:f64 + acc: in:f32 format: [op_v1_4_v2_4] properties: [acc_read, float] check-type: empty @@ -82,7 +82,7 @@ tests: isa: instructions: - sig: fstarr.32 v1:in:f32[], v2:in:i32 - acc: in:f64 + acc: in:f32 format: [op_v1_4_v2_4] properties: [acc_read, float] runner-options: [compile-failure] @@ -121,7 +121,7 @@ tests: isa: instructions: - sig: fstarr.32 v1:in:f32[], v2:in:i32 - acc: in:f64 + acc: in:f32 format: [op_v1_4_v2_4] properties: [acc_read, float] runner-options: [compile-failure] @@ -160,7 +160,7 @@ tests: call.short get_null sta.obj v0 movi v1, %s - fldai.64 0 + fldai 0 begin: fstarr.32 v0, v1 end: @@ -204,7 +204,7 @@ tests: movi v0, %s newarr v0, v0, f32[] movi v1, %s - fldai.64 0 + fldai 0 begin: fstarr.32 v0, v1 end: @@ -298,7 +298,7 @@ tests: movi v0, 1 newarr v1, v0, f32[] movi v2, 0 - fldai.64 0 + fldai 0 fstarr.32 v1, v2 check-type: exit-positive @@ -316,7 +316,7 @@ tests: movi v0, 1 newarr v1, v0, %s movi v2, 0 - fldai.64 0 + fldai 0 fstarr.32 v1, v2 check-type: exit-positive cases: @@ -351,7 +351,7 @@ tests: .function i32 main() { %s movi v1, 0 - fldai.64 0 + fldai 0 fstarr.32 v0, v1 check-type: exit-positive cases: @@ -438,7 +438,7 @@ tests: movi v0, 1 newarr v1, v0, *s %s - fldai.64 0 + fldai 0 fstarr.32 v1, v2 check-type: exit-positive cases: @@ -638,7 +638,7 @@ tests: isa: instructions: - sig: fstarr.32 v1:in:f32[], v2:in:i32 - acc: in:f64 + acc: in:f32 format: [op_v1_4_v2_4] properties: [acc_read, float] description: Check fstarr.32 stores items to array of different size and type in Panda Assembly context. @@ -647,7 +647,7 @@ tests: movi v0, *s newarr v1, v0, %s movi v2, *s - fldai.64 1234567890.0 + fldai 1234567890.0 fstarr.32 v1, v2 check-type: exit-positive template-cases: @@ -673,7 +673,7 @@ tests: movi v2, 0 # array index fill_array: lda v2 - i32tof64 + i32tof32 fstarr.32 v1, v2 # v1[v2] = acc inci v2, 1 # v2 = v2 + 1 lda v2 @@ -681,11 +681,11 @@ tests: inci v2, -1 check_array: lda v2 - i32tof64 - sta.64 v3 # value to compare with + i32tof32 + sta v3 # value to compare with lda v2 fldarr.32 v1 - fcmpg.64 v3 + fcmpg v3 jeqz ok ldai 2 return diff --git a/tests/cts-generator/cts-template/initobj.range.yaml b/tests/cts-generator/cts-template/initobj.range.yaml index 9ea7060a9c..3cb324e671 100644 --- a/tests/cts-generator/cts-template/initobj.range.yaml +++ b/tests/cts-generator/cts-template/initobj.range.yaml @@ -1713,12 +1713,12 @@ tests: header-template: [] code-template: | .record Z { - %s f + f64 f } - .function void Z.ctor1(Z a0, f32 a1) { + .function void Z.ctor1(Z a0, f64 a1) { return.void } - .function void Z.ctor2(Z a0, %s a1) { + .function void Z.ctor2(Z a0, f64 a1) { lda.64 a1 stobj.64 a0, Z.f return.void @@ -1745,28 +1745,70 @@ tests: ok: check-type: exit-positive cases: - - values: [f64, f64, 0.0] - - values: [f64, f64, 4.625] - - values: [f64, f64, -4.625] - - values: [f64, f64, 0xfff0000000000000] # -Inf - - values: [f64, f64, 0x7ff0000000000000] # +Inf + - values: [0.0] + - values: [4.625] + - values: [-4.625] + - values: [0xfff0000000000000] # -Inf + - values: [0x7ff0000000000000] # +Inf tags: ['tsan'] - - values: [f64, f64, 0x7ff8000000000000] - - values: [f64, f64, 0x7ff8000000000010] - - values: [f64, f64, 0x7fffffffffffffff] - - values: [f64, f64, 0xffffffffffffffff] + - values: [0x7ff8000000000000] + - values: [0x7ff8000000000010] + - values: [0x7fffffffffffffff] + - values: [0xffffffffffffffff] tags: ['tsan'] - - values: [f32, f32, 0.0] - - values: [f32, f32, 4.625] - - values: [f32, f32, -4.625] - - values: [f32, f32, 0xfff0000000000000] # -Inf - - values: [f32, f32, 0x7ff0000000000000] # +Inf - - values: [f32, f32, 0x7ff8000000000000] - - values: [f32, f32, 0x7ff8000000000010] - tags: ['tsan'] - - values: [f32, f32, 0x7fffffffffffffff] - - values: [f32, f32, 0xffffffffffffffff] + - file-name: "check_float32_type_p" + isa: + instructions: + - sig: initobj.range method_id, v:in:none + acc: out:ref + format: [op_v_8_id_16] + description: Check 'initobj.range' constructor behavior with primitive float argument types in PandaAssembly context. + header-template: [] + code-template: | + .record Z { + f32 f + } + .function void Z.ctor1(Z a0, f32 a1) { + return.void + } + .function void Z.ctor2(Z a0, f32 a1) { + lda.64 a1 + stobj a0, Z.f + return.void + } + .function i32 main() { + fmovi v1, -1.0 + initobj.range Z.ctor1, v1 + sta.obj v0 + ldobj v0, Z.f + fmovi v1, 0.0 + fcmpg v1 + jeqz chk2 + ldai 1 + return + chk2: + fmovi v1, %s + initobj.range Z.ctor2, v1 + sta.obj v0 + ldobj v0, Z.f + fcmpg v1 + jeqz ok + ldai 2 + return + ok: + check-type: exit-positive + cases: + - values: [0.0] + - values: [4.625] + - values: [-4.625] + - values: [0xff800000] # -Inf + - values: [0x7f800000] # +Inf + - values: [0x7fc00000] + - values: [0x7fc00010] + tags: ['tsan'] + - values: [0x7fffffff] + - values: [0xffffffff] - file-name: "check_obj_types_p" isa: @@ -1891,7 +1933,7 @@ tests: - x_oom description: Create objects with 'initobj.range' instruction until OutOfMemoryError in PandaAssembly context header-template: [] - panda-options: "--object-pool-size=67108864" + panda-options: "--heap-size-limit=67108864" bugid: ['3578', '4170', '4171'] ignore: true code-template: | diff --git a/tests/cts-generator/cts-template/initobj.short.yaml b/tests/cts-generator/cts-template/initobj.short.yaml index 4074a0e401..b29049e4dc 100644 --- a/tests/cts-generator/cts-template/initobj.short.yaml +++ b/tests/cts-generator/cts-template/initobj.short.yaml @@ -1466,12 +1466,12 @@ tests: header-template: [] code-template: | .record Z { - %s f + f64 f } .function void Z.ctor1(Z a0) { return.void } - .function void Z.ctor2(Z a0, %s a1) { + .function void Z.ctor2(Z a0, f64 a1) { lda.64 a1 stobj.64 a0, Z.f return.void @@ -1497,27 +1497,68 @@ tests: ok: check-type: exit-positive cases: - - values: [f64, f64, 0.0] - - values: [f64, f64, 4.625] - - values: [f64, f64, -4.625] - - values: [f64, f64, 0xfff0000000000000] # -Inf + - values: [0.0] + - values: [4.625] + - values: [-4.625] + - values: [0xfff0000000000000] # -Inf tags: ['tsan'] - - values: [f64, f64, 0x7ff0000000000000] # +Inf - - values: [f64, f64, 0x7ff8000000000000] - - values: [f64, f64, 0x7ff8000000000010] - - values: [f64, f64, 0x7fffffffffffffff] - - values: [f64, f64, 0xffffffffffffffff] + - values: [0x7ff0000000000000] # +Inf + - values: [0x7ff8000000000000] + - values: [0x7ff8000000000010] + - values: [0x7fffffffffffffff] + - values: [0xffffffffffffffff] tags: ['tsan'] - - values: [f32, f32, 0.0] - - values: [f32, f32, 4.625] - - values: [f32, f32, -4.625] - - values: [f32, f32, 0xfff0000000000000] # -Inf - - values: [f32, f32, 0x7ff0000000000000] # +Inf - - values: [f32, f32, 0x7ff8000000000000] - - values: [f32, f32, 0x7ff8000000000010] - - values: [f32, f32, 0x7fffffffffffffff] - - values: [f32, f32, 0xffffffffffffffff] + - file-name: "check_float32_type_p" + isa: + instructions: + - sig: initobj.short method_id, v1:in:none, v2:in:none + acc: out:ref + format: [op_v1_4_v2_4_id_16] + description: Check 'initobj.short' constructor behavior with primitive float argument types in PandaAssembly context. + header-template: [] + code-template: | + .record Z { + f32 f + } + .function void Z.ctor1(Z a0) { + return.void + } + .function void Z.ctor2(Z a0, f32 a1) { + lda a1 + stobj a0, Z.f + return.void + } + .function i32 main() { + initobj.short Z.ctor1 + sta.obj v0 + ldobj v0, Z.f + fmovi v1, 0.0 + fcmpg v1 + jeqz chk2 + ldai 1 + return + chk2: + fmovi v1, %s + initobj.short Z.ctor2, v1 + sta.obj v0 + ldobj v0, Z.f + fcmpg v1 + jeqz ok + ldai 2 + return + ok: + check-type: exit-positive + cases: + - values: [0.0] + - values: [4.625] + - values: [-4.625] + - values: [0xff800000] # -Inf + - values: [0x7f800000] # +Inf + - values: [0x7fc00000] + - values: [0x7fc00010] + - values: [0x7fffffff] + - values: [0xffffffff] - file-name: "check_obj_types_p" isa: @@ -1642,7 +1683,7 @@ tests: - x_oom description: Create objects with 'initobj.short' instruction until OutOfMemoryError in PandaAssembly context header-template: [] - panda-options: "--object-pool-size=67108864" + panda-options: "--heap-size-limit=67108864" bugid: ['3578', '4170', '4171'] ignore: true code-template: | diff --git a/tests/cts-generator/cts-template/initobj.yaml b/tests/cts-generator/cts-template/initobj.yaml index a9a81e7eef..b9848d1295 100644 --- a/tests/cts-generator/cts-template/initobj.yaml +++ b/tests/cts-generator/cts-template/initobj.yaml @@ -1553,12 +1553,12 @@ tests: header-template: [] code-template: | .record Z { - %s f + f64 f } .function void Z.ctor1(Z a0) { return.void } - .function void Z.ctor2(Z a0, %s a1) { + .function void Z.ctor2(Z a0, f64 a1) { lda.64 a1 stobj.64 a0, Z.f return.void @@ -1584,27 +1584,69 @@ tests: ok: check-type: exit-positive cases: - - values: [f64, f64, 0.0] - - values: [f64, f64, 4.625] - - values: [f64, f64, -4.625] - - values: [f64, f64, 0xfff0000000000000] # -Inf + - values: [0.0] + - values: [4.625] + - values: [-4.625] + - values: [0xfff0000000000000] # -Inf tags: ['tsan'] - - values: [f64, f64, 0x7ff0000000000000] # +Inf - - values: [f64, f64, 0x7ff8000000000000] - - values: [f64, f64, 0x7ff8000000000010] - - values: [f64, f64, 0x7fffffffffffffff] - - values: [f64, f64, 0xffffffffffffffff] - - values: [f32, f32, 0.0] - - values: [f32, f32, 4.625] - - values: [f32, f32, -4.625] - - values: [f32, f32, 0xfff0000000000000] # -Inf - - values: [f32, f32, 0x7ff0000000000000] # +Inf - - values: [f32, f32, 0x7ff8000000000000] - - values: [f32, f32, 0x7ff8000000000010] - - values: [f32, f32, 0x7fffffffffffffff] - - values: [f32, f32, 0xffffffffffffffff] + - values: [0x7ff0000000000000] # +Inf + - values: [0x7ff8000000000000] + - values: [0x7ff8000000000010] + - values: [0x7fffffffffffffff] + - values: [0xffffffffffffffff] tags: ['tsan'] + - file-name: "check_float32_type_p" + isa: + instructions: + - sig: initobj method_id, v1:in:none, v2:in:none, v3:in:none, v4:in:none + acc: out:ref + format: [op_v1_4_v2_4_v3_4_v4_4_id_16] + description: Check 'initobj' constructor behavior with primitive float argument types in PandaAssembly context. + header-template: [] + code-template: | + .record Z { + f32 f + } + .function void Z.ctor1(Z a0) { + return.void + } + .function void Z.ctor2(Z a0, f32 a1) { + lda a1 + stobj a0, Z.f + return.void + } + .function i32 main() { + initobj Z.ctor1 + sta.obj v0 + ldobj v0, Z.f + fmovi v1, 0.0 + fcmpg v1 + jeqz chk2 + ldai 1 + return + chk2: + fmovi v1, %s + initobj Z.ctor2, v1 + sta.obj v0 + ldobj v0, Z.f + fcmpg v1 + jeqz ok + ldai 2 + return + ok: + check-type: exit-positive + cases: + - values: [0.0] + - values: [4.625] + - values: [-4.625] + - values: [0xff800000] # -Inf + - values: [0x7f800000] # +Inf + - values: [0x7fc00000] + - values: [0x7fc00010] + - values: [0x7fffffff] + - values: [0xffffffff] + tags: ['tsan'] - file-name: "check_obj_types_p" isa: @@ -1729,7 +1771,7 @@ tests: - x_oom description: Create objects with 'initobj' instruction until OutOfMemoryError in PandaAssembly context header-template: [] - panda-options: "--object-pool-size=67108864" + panda-options: "--heap-size-limit=67108864" bugid: ['3578', '4170', '4171'] ignore: true code-template: | diff --git a/tests/cts-generator/cts-template/ldobj.64.yaml b/tests/cts-generator/cts-template/ldobj.64.yaml index 32a9b5a539..f2dcec1294 100644 --- a/tests/cts-generator/cts-template/ldobj.64.yaml +++ b/tests/cts-generator/cts-template/ldobj.64.yaml @@ -315,7 +315,10 @@ tests: - file-name: "from_all_int_field_types" description: Check that accumulator value is loaded from field into accumulator. More tests on ldobj.64 can be found in stobj.64 tests isa: - description: If field type is f32, load will implicitly convert value into f64 type. + instructions: + - sig: ldobj.64 v:in:ref, field_id + acc: out:b64 + format: [op_v_8_id_16] header-template: ['pandasm_header'] check-type: exit-positive tags: ['tsan'] @@ -343,10 +346,13 @@ tests: - values: [-1, 'i64', -1, 'i64', 'cmp.64'] - values: [-6510615555426900571, 'i64', -6510615555426900571, 'i64', 'cmp.64'] - - file-name: "from_all_float_field_types" + - file-name: "from_float_field_type" description: Check that accumulator value is loaded from field into accumulator. More tests on ldobj.64 can be found in stobj.64 tests isa: - description: If field type is f32, load will implicitly convert value into f64 type. + instructions: + - sig: ldobj.64 v:in:ref, field_id + acc: out:b64 + format: [op_v_8_id_16] header-template: ['pandasm_header'] bugid: ['3292'] check-type: exit-positive @@ -356,10 +362,10 @@ tests: initobj.short R.ctor sta.obj v0 %s - stobj.64 v0, R.f%s + stobj.64 v0, R.ff64 lda.null %s - ldobj.64 v0, R.f%s + ldobj.64 v0, R.ff64 fcmpg.64 v15 %s jeqz success @@ -367,15 +373,9 @@ tests: return success: cases: - # f32 - - values: ['fldai.64 0.0', 'f32', 'fmovi.64 v15, 0.0', 'f32', ''] - - values: ['fldai.64 -6510615.0', 'f32', 'fmovi.64 v15, -6510615.0', 'f32', ''] - - values: ['fldai.64 0x7FFFFFFFFFFFFFFF', 'f32', 'fmovi.64 v15, 0x7FFFFFFFFFFFFFFF', 'f32', 'subi 1'] # NaN - - values: ['fldai.64 0x7ff0000000000000', 'f32', 'fmovi.64 v15, 0x7ff0000000000000', 'f32', ''] # + Inf - - values: ['fldai.64 0xfff0000000000000', 'f32', 'fmovi.64 v15, 0xfff0000000000000', 'f32', ''] # - Inf # f64 - - values: ['fldai.64 0.0', 'f64', 'fmovi.64 v15, 0.0', 'f64', ''] - - values: ['fldai.64 -6510615555426900571.0', 'f64', 'fmovi.64 v15, -6510615555426900571.0', 'f64', ''] - - values: ['fldai.64 0x7FFFFFFFFFFFFFFF', 'f64', 'fmovi.64 v15, 0x7FFFFFFFFFFFFFFF', 'f64', 'subi 1'] # NaN - - values: ['fldai.64 0x7ff0000000000000', 'f64', 'fmovi.64 v15, 0x7ff0000000000000', 'f64', ''] # + Inf - - values: ['fldai.64 0xfff0000000000000', 'f64', 'fmovi.64 v15, 0xfff0000000000000', 'f64', ''] # - Inf + - values: ['fldai.64 0.0', 'fmovi.64 v15, 0.0', ''] + - values: ['fldai.64 -6510615555426900571.0', 'fmovi.64 v15, -6510615555426900571.0', ''] + - values: ['fldai.64 0x7FFFFFFFFFFFFFFF', 'fmovi.64 v15, 0x7FFFFFFFFFFFFFFF', 'subi 1'] # NaN + - values: ['fldai.64 0x7ff0000000000000', 'fmovi.64 v15, 0x7ff0000000000000', ''] # + Inf + - values: ['fldai.64 0xfff0000000000000', 'fmovi.64 v15, 0xfff0000000000000', ''] # - Inf diff --git a/tests/cts-generator/cts-template/ldobj.v.64.yaml b/tests/cts-generator/cts-template/ldobj.v.64.yaml new file mode 100644 index 0000000000..300c407568 --- /dev/null +++ b/tests/cts-generator/cts-template/ldobj.v.64.yaml @@ -0,0 +1,539 @@ +# 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. + +definitions: + - name: java_header + template: | + .language Java + + .record java.lang.Object + + .record Q {} + .function void Q.ctor(Q a0) { + return.void + } + + .record R { + u1 fu1 + i8 fi8 + i16 fi16 + u16 fu16 + i32 fi32 + i64 fi64 + f32 ff32 + f64 ff64 + + i32[] fi32Array + Q fQ + Q[] fQArray + java.lang.Object fObj + java.lang.Object[] fObjArray + } + .function void R.ctor(R a0) { + return.void + } + - name: pandasm_header + template: | + .language PandaAssembly + + .record panda.Object + + .record Q {} + .function void Q.ctor(Q a0) { + return.void + } + + .record R { + u1 fu1 + u8 fu8 + i8 fi8 + u16 fu16 + i16 fi16 + u32 fu32 + i32 fi32 + u64 fu64 + i64 fi64 + f32 ff32 + f64 ff64 + + i32[] fi32Array + Q fQ + Q[] fQArray + panda.Object fObj + panda.Object[] fObjArray + } + .function void R.ctor(R a0) { + return.void + } + - name: get_null_R + template: | + .function R get_null_R() { + lda.null + return.obj + } + +tests: + - file-name: "ldobj.v.64" + isa: + title: Get field from object to register + description: > + Get field value from an object by field id and put it into register. + instructions: + - sig: ldobj.v.64 v1:out:b64, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + commands: + + - file-name: "check_if_v2_initialized_p" + description: Check that verifier reports error if source registers are not initialized in Panda context. + isa: + instructions: + - sig: ldobj.v.64 v1:out:b64, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['verifier'] + bugid: ['1324', '2084', '3257'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + code-template: | + + .function i32 main() { + %s # verifier error expected, because v2 is not initialized + cases: + - values: + - 'ldobj.v.64 v0, v0, R.fu64' + - values: + - 'ldobj.v.64 v0, v1, R.fi64' + - values: + - 'ldobj.v.64 v0, v15, R.ff32' + + + - file-name: "check_if_v2_initialized_j" + description: Check that verifier reports error if source registers are not initialized in Java context. + isa: + instructions: + - sig: ldobj.v.64 v1:out:b64, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + header-template: ['java_header'] + check-type: exit-positive + tags: ['verifier'] + bugid: ['1324', '2084', '3257', '3293'] + runner-options: ['verifier-failure', 'verifier-debug-config', 'use-java'] + code-template: | + + .function i32 main() { + %s # verifier error expected, because v2 is not initialized + cases: + - values: + - 'ldobj.v.64 v15, v0, R.fi32' + - values: + - 'ldobj.v.64 v15, v1, R.fi64' + - values: + - 'ldobj.v.64 v15, v15, R.ff32' + + + - file-name: "with_null_ref_p" + description: Check that NullPointerException is thrown if object ref is null in Panda context. + isa: + exceptions: + - x_null + header-template: ['pandasm_header', 'get_null_R'] + check-type: empty + tags: ['tsan'] + code-template: | + .record panda.NullPointerException + + .function i32 main() { + call.short get_null_R + sta.obj v0 + try_begin: + ldobj.v.64 v1, v0, %s + ldai 1 + return + try_end: + ldai 0 + return + .catch panda.NullPointerException, try_begin, try_end, try_end + } + cases: + - values: + - R.fi64 + - values: + - R.fu64 + - values: + - R.ff64 + - values: + - R.ff32 + + + - file-name: "with_non_object_ref_p" + description: Check that verifier reports an error when the 2nd operand is not a ref to an object (other than array) in Panda context. + isa: + verification: + - v2_object + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['verifier'] + bugid: ['2085'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + code-template: | + .function i32 main() { + %s + ldobj.v.64 v1, v0, R.fi64 + cases: + - values: + - movi v0, 0 + tags: ['release', 'clang_release_sanitizer'] + bugid: ['1324', '1826'] + - values: + - movi v0, 1 + - values: + - movi.64 v0, 0x00 + tags: ['release', 'clang_release_sanitizer'] + bugid: ['1324', '1826'] + - values: + - movi.64 v0, 0xCAFECAFECAFECAFE + - values: + - fmovi.64 v0, 0.0 + tags: ['release', 'clang_release_sanitizer'] + bugid: ['1324', '1826'] + - values: + - fmovi.64 v0, 6.62607015 + - values: + - | + # + movi v1, 10 + newarr v0, v1, R[] + bugid: ['1827'] + + + - file-name: "with_non_object_ref_j" + description: Check that verifier reports an error when the 2nd operand is not a ref to an object (other than array) in Java context. + isa: + verification: + - v2_object + header-template: ['java_header'] + check-type: exit-positive + tags: ['verifier'] + bugid: ['3293'] + runner-options: ['verifier-failure', 'verifier-debug-config', 'use-java'] + code-template: | + .function i32 main() { + %s + ldobj.v.64 v15, v0, R.fi64 + cases: + - values: + - movi v0, 0 + - values: + - movi v0, 1 + - values: + - movi.64 v0, 0x00 + - values: + - movi.64 v0, 0xCAFECAFECAFECAFE + - values: + - fmovi.64 v0, 0.0 + - values: + - fmovi.64 v0, 6.62607015 + - values: + - | + # + movi v1, 10 + newarr v0, v1, R[] + + + - file-name: "with_static_field_id_p" + description: | + Check that verifier reports an error when the field doesn't resolve to a non-static valid object field in Panda context. + Incorrect usage cannot be compiled. + isa: + verification: + - field_id_non_static + header-template: [] + runner-options: ['compile-failure'] + bugid: ['1324', '1828', '1833', '2086'] + check-type: exit-positive + code-template: | + .record W { + i64 static_field + } + .function void W.ctor(W a0) { + return.void + } + .record random_record_name { + i64 random_field_name + } + .function void random_function_name() { + return.void + } + + .function i32 main() { + initobj W.ctor + sta.obj v0 + ldobj.v.64 v1, v0, %s + cases: + - values: + - W.static_field + runner-options: ['verifier-failure', 'verifier-debug-config'] + tags: ['verifier'] + - values: + - random_record_name + - values: + - random_function_name + - values: + - W.field_not_exists + - values: + - random_record_name.random_field_name + runner-options: ['verifier-failure', 'verifier-debug-config'] + tags: ['verifier'] + bugid: ['3536'] + - values: + - 0 + - values: + - -1.1 + - values: + - "null" + - values: + - "\"abc\"" + + + - file-name: "with_static_field_id_j" + description: | + Check that verifier reports an error when the field doesn't resolve to a non-static valid object field in Java context. + Incorrect usage cannot be compiled. + isa: + verification: + - field_id_non_static + header-template: [] + runner-options: ['compile-failure', 'use-java'] + tags: ['verifier'] + bugid: ['1324', '1828', '1833', '2086', '3293'] + check-type: exit-positive + code-template: | + .language Java + .record W { + i64 static_field + } + .function void W.ctor(W a0) { + return.void + } + .record random_record_name { + i64 random_field_name + } + .function void random_function_name() { + return.void + } + + .function i32 main() { + initobj W.ctor + sta.obj v0 + ldobj.v.64 v15, v0, %s + cases: + - values: + - W.static_field + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config', 'use-java'] + - values: + - random_record_name + - values: + - random_function_name + - values: + - W.field_not_exists + - values: + - random_record_name.random_field_name + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config', 'use-java'] + bugid: ['3536'] + - values: + - 0 + - values: + - -1.1 + - values: + - "null" + - values: + - "\"abc\"" + + + - file-name: "with_wrong_field_size_or_type_p" + description: Check that verifier reports an error when the field resolves to a field with size or type that is not corresponding to bytecode + isa: + verification: + - field_id_size + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + bugid: ['1834', '2088'] + code-template: | + + .function i32 main() { + initobj R.ctor + sta.obj v0 + ldobj.v.64 v1, v0, %s + cases: + - values: + - R.fu1 + - values: + - R.fu8 + - values: + - R.fi8 + - values: + - R.fu16 + - values: + - R.fi16 + - values: + - R.fu32 + - values: + - R.fi32 + - values: + - R.fObj + - values: + - R.fObjArray + - values: + - R.fi32Array + + + - file-name: "with_wrong_field_size_or_type_j" + description: Check that verifier reports an error when the field resolves to a field with size or type that is not corresponding to bytecode + isa: + verification: + - field_id_size + header-template: ['java_header'] + check-type: exit-positive + tags: ['verifier'] + bugid: ['1834', '2088', '3293'] + runner-options: ['verifier-failure', 'verifier-debug-config', 'use-java'] + code-template: | + + .function i32 main() { + initobj R.ctor + sta.obj v0 + ldobj.v.64 v15, v0, %s + cases: + - values: + - R.fu1 + - values: + - R.fi8 + - values: + - R.fi16 + - values: + - R.fu16 + - values: + - R.fi32 + - values: + - R.fObj + - values: + - R.fObjArray + - values: + - R.fi32Array + + + - file-name: "op_v1_4_v2_4_id_16" + description: Check that compiler reports an error when the register number is incorrect + isa: + instructions: + - sig: ldobj.v.64 v1:out:b64, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + header-template: ['pandasm_header'] + check-type: exit-positive + runner-options: ['compile-failure'] + code-template: | + + .function i32 main() { + ldobj.v.64 %s, R.fi64 + cases: + - values: ['v15, v15'] + runner-options: ['compile-only'] + - values: ['v0, v16'] + - values: ['v16, v0'] + - values: ['v256, v0'] + - values: ['v1, v256'] + - values: ['v32567, v32567'] + - values: ['a0, v1'] + - values: ['v0, a1'] + - values: ['v0'] + - values: ['1'] + - values: ['"0"'] + + + - file-name: "from_all_int_field_types" + description: Check that accumulator value is loaded from field into accumulator. More tests on ldobj.v.64 can be found in stobj.v.64 tests + isa: + instructions: + - sig: ldobj.v.64 v1:out:b64, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['tsan'] + code-template: | + + .function i32 main() { + initobj.short R.ctor + sta.obj v0 + ldai.64 %s + stobj.64 v0, R.f%s + movi.64 v15, %s + ldobj.v.64 v1, v0, R.f%s + lda.64 v1 + %s v15 + jeqz success + ldai 1 + return + success: + cases: + # u64 + - values: [0, 'u64', 0, 'u64', 'ucmp.64'] + - values: [0xffffffffffffffff, 'u64', 0xffffffffffffffff, 'u64', 'ucmp.64'] + - values: [0xa5a5a5a5a5a5a5a5, 'u64', 0xa5a5a5a5a5a5a5a5, 'u64', 'ucmp.64'] + # i64 + - values: [0, 'i64', 0, 'i64', 'cmp.64'] + - values: [-1, 'i64', -1, 'i64', 'cmp.64'] + - values: [-6510615555426900571, 'i64', -6510615555426900571, 'i64', 'cmp.64'] + + - file-name: "from_float_field_type" + description: Check that accumulator value is loaded from field into accumulator. More tests on ldobj.v.64 can be found in stobj.v.64 tests + isa: + instructions: + - sig: ldobj.v.64 v1:out:b64, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + header-template: ['pandasm_header'] + bugid: ['3292'] + check-type: exit-positive + code-template: | + + .function i32 main() { + initobj.short R.ctor + sta.obj v0 + %s + stobj.64 v0, R.ff64 + lda.null + %s + ldobj.v.64 v1, v0, R.ff64 + lda.64 v1 + fcmpg.64 v15 + %s + jeqz success + ldai 1 + return + success: + cases: + # f64 + - values: ['fldai.64 0.0', 'fmovi.64 v15, 0.0', ''] + - values: ['fldai.64 -6510615555426900571.0', 'fmovi.64 v15, -6510615555426900571.0', ''] + - values: ['fldai.64 0x7FFFFFFFFFFFFFFF', 'fmovi.64 v15, 0x7FFFFFFFFFFFFFFF', 'subi 1'] # NaN + - values: ['fldai.64 0x7ff0000000000000', 'fmovi.64 v15, 0x7ff0000000000000', ''] # + Inf + - values: ['fldai.64 0xfff0000000000000', 'fmovi.64 v15, 0xfff0000000000000', ''] # - Inf diff --git a/tests/cts-generator/cts-template/ldobj.v.yaml b/tests/cts-generator/cts-template/ldobj.v.yaml new file mode 100644 index 0000000000..96ed16573c --- /dev/null +++ b/tests/cts-generator/cts-template/ldobj.v.yaml @@ -0,0 +1,451 @@ +# 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. + +definitions: + - name: pandasm_header + template: | + .language PandaAssembly + + .record panda.Object + + .record Q {} + .function void Q.ctor(Q a0) { + return.void + } + + .record R { + u1 fu1 + u8 fu8 + i8 fi8 + u16 fu16 + i16 fi16 + u32 fu32 + i32 fi32 + u64 fu64 + i64 fi64 + f32 ff32 + f64 ff64 + # objects: + i32[] fi32Array + Q fQ + Q[] fQArray + panda.Object fObj + panda.Object[] fObjArray + } + .function void R.ctor(R a0) { + return.void + } + + - name: java_header + template: | + .language Java + + .record java.lang.Object + + .record Q {} + .function void Q.ctor(Q a0) { + return.void + } + + .record R { + u1 fu1 + i8 fi8 + u16 fu16 + i16 fi16 + i32 fi32 + i64 fi64 + f32 ff32 + f64 ff64 + # objects: + i32[] fi32Array + Q fQ + Q[] fQArray + java.lang.Object fObj + java.lang.Object[] fObjArray + } + .function void R.ctor(R a0) { + return.void + } + - name: get_null_R + template: | + .function R get_null_R() { + lda.null + return.obj + } + +tests: + - file-name: "ldobj.v" + isa: + title: Get field from object to register + description: > + Get field value from an object by field id and put it into register. + instructions: + - sig: ldobj.v v1:out:i32, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + commands: + + - file-name: "check_if_v2_initialized" + description: Check that verifier reports error if source registers are not initialized + isa: + instructions: + - sig: ldobj.v v1:out:i32, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['verifier'] + bugid: ['1324', '2084'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + code-template: | + + .function i32 main() { + %s # verifier error expected, because v2 is not initialized + cases: + - values: + - 'ldobj.v v0, v0, R.fu1' + - values: + - 'ldobj.v v0, v1, R.fu8' + - values: + - 'ldobj.v v0, v15, R.fi8' + + + - file-name: "with_null_ref_p" + description: Check that NullPointerException is thrown if object ref is null in Panda context. + isa: + exceptions: + - x_null + header-template: ['pandasm_header', 'get_null_R'] + check-type: empty + tags: ['tsan'] + code-template: | + .record panda.NullPointerException + + .function i32 main() { + call.short get_null_R + sta.obj v0 + try_begin: + ldobj.v v1, v0, %s + ldai 1 + return + try_end: + ldai 0 + return + .catch panda.NullPointerException, try_begin, try_end, try_end + } + cases: + - values: + - R.fu1 + - values: + - R.fu8 + - values: + - R.fi8 + - values: + - R.fu16 + - values: + - R.fi16 + - values: + - R.fu32 + - values: + - R.fi32 + + + - file-name: "with_non_object_ref" + description: Check that verifier reports an error when the 2nd operand is not a ref to an object (other than array) + isa: + verification: + - v2_object + header-template: ['pandasm_header'] + check-type: empty + tags: ['verifier'] + bugid: ['2085'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + code-template: | + + .function i32 main() { + %s + try_begin: + ldobj.v v1, v0, R.fu1 + try_end: + ldai 0 + return + .catchall try_begin, try_end, try_end + } + cases: + - values: + - movi v0, 0 + tags: ['release', 'clang_release_sanitizer'] + bugid: ['1324', '1826'] + - values: + - movi v0, 1 + - values: + - movi.64 v0, 0x00 + tags: ['release', 'clang_release_sanitizer'] + bugid: ['1324', '1826'] + - values: + - movi.64 v0, 0xCAFECAFECAFECAFE + - values: + - fmovi.64 v0, 0.0 + tags: ['release', 'clang_release_sanitizer'] + bugid: ['1324', '1826'] + - values: + - fmovi.64 v0, 6.62607015 + - values: + - | + # + movi v1, 10 + newarr v0, v1, R[] + bugid: ['1827'] + + + - file-name: "with_static_field_id" + description: Check that verifier reports an error if the field doesn't resolve to a non-static valid object field + isa: + verification: + - field_id_non_static + header-template: [] + check-type: exit-positive + code-template: | + .record W { + i32 static_field + } + .function void W.ctor(W a0) { + return.void + } + .record random_record_name { + i32 random_field_name + } + .function void random_function_name() { + return.void + } + + .function i32 main() { + initobj W.ctor + sta.obj v0 + ldobj.v v1, v0, %s + cases: + - values: + - W.static_field + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + bugid: ['1324', '1828', '2086'] + - values: + - random_record_name + runner-options: ['compile-failure'] + - values: + - random_function_name + runner-options: ['compile-failure'] + - values: + - W.field_not_exists + runner-options: ['compile-failure'] + - values: + - random_record_name.random_field_name + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + bugid: ['1833', '2086', '3536'] + - values: + - 0 + runner-options: ['compile-failure'] + - values: + - -1.1 + runner-options: ['compile-failure'] + - values: + - "null" + runner-options: ['compile-failure'] + - values: + - "\"abc\"" + runner-options: ['compile-failure'] + + + - file-name: "with_wrong_field_size_or_type" + description: Check that verifier reports an error when the field resolves to a field with size or type that is not corresponding to bytecode + isa: + verification: + - field_id_size + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + bugid: ['1834', '2088'] + code-template: | + + .function i32 main() { + initobj R.ctor + sta.obj v0 + ldobj.v v1, v0, %s + cases: + - values: + - R.fi64 + - values: + - R.fu64 + - values: + - R.ff64 + - values: + - R.ff32 + - values: + - R.fObj + - values: + - R.fObjArray + - values: + - R.fi32Array + + + - file-name: "op_v1_4_v2_4_id_16" + description: Check that compiler reports an error when the register number is out of 4 bit size + isa: + instructions: + - sig: ldobj.v v1:out:i32, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + header-template: ['pandasm_header'] + runner-options: ['compile-failure'] + check-type: exit-positive + code-template: | + + .function i32 main() { + ldobj.v %s, R.fi32 + cases: + - values: ['v15, v15'] + runner-options: ['compile-only'] + - values: ['v0, v16'] + - values: ['v16, v0'] + - values: ['v256, v0'] + - values: ['v1, v256'] + - values: ['v32567, v32567'] + - values: ['a0, v1'] + - values: ['v0, a1'] + - values: ['v0'] + - values: ['1'] + - values: ['"0"'] + + + - file-name: "from_all_field_types" + description: Check that field value is loaded into accumulator. More tests on ldobj.v can be found in stobj.v tests + isa: + description: > + For non-object variant, the size of the field is determined by the field_id, + most significant bits are sign or unsigned extended based on the field type to fit register size. + If field type is less than 32, then loaded value is sign or zero extended to i32 depending on field type. + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['tsan'] + code-template: | + + .function i32 main() { + initobj.short R.ctor + sta.obj v0 + ldai %s + stobj v0, R.f%s + lda.null + movi v15, %s + ldobj.v v1, v0, R.f%s + lda v1 + %s v15 + jeqz success + ldai 1 + return + success: + cases: + # u1 + - values: [0, 'u1', 0, 'u1', 'ucmp'] + - values: [1, 'u1', 1, 'u1', 'ucmp'] + # u8 + - values: [0, 'u8', 0, 'u8', 'ucmp'] + - values: [0x000000ff, 'u8', 0x000000ff, 'u8', 'ucmp'] + - values: [0x000000a5, 'u8', 0x000000a5, 'u8', 'ucmp'] + # u16 + - values: [0, 'u16', 0, 'u16', 'ucmp'] + - values: [0x0000ffff, 'u16', 0x0000ffff, 'u16', 'ucmp'] + - values: [0x0000a5a5, 'u16', 0x0000a5a5, 'u16', 'ucmp'] + # u32 + - values: [0, 'u32', 0, 'u32', 'ucmp'] + - values: [0xffffffff, 'u32', 0xffffffff, 'u32', 'ucmp'] + - values: [0xa5a5a5a5, 'u32', 0xa5a5a5a5, 'u32', 'ucmp'] + + + - file-name: "from_all_field_types_int" + description: Check that field value is loaded into accumulator. Version for signed integer types. More tests on ldobj.v can be found in stobj.v tests. + isa: + description: > + For non-object variant, the size of the field is determined by the field_id, + most significant bits are sign or unsigned extended based on the field type to fit register size. + If field type is less than 32, then loaded value is sign or zero extended to i32 depending on field type. + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['tsan'] + code-template: | + + .function i32 main() { + initobj.short R.ctor + sta.obj v0 + ldai %s + stobj v0, R.f%s + lda.null + movi v15, %s + ldobj.v v1, v0, R.f%s + lda v1 + jeq v15, success + ldai 1 + return + success: + cases: + # i8 + - values: [0, 'i8', 0, 'i8'] + - values: [0x000000ff, 'i8', 0xffffffff, 'i8'] + - values: [0x000000a5, 'i8', 0xffffffa5, 'i8'] + - values: [0x0000005a, 'i8', 0x0000005a, 'i8'] + # i16 + - values: [0, 'i16', 0, 'i16'] + - values: [0x0000ffff, 'i16', 0xffffffff, 'i16'] + - values: [0x0000a5a5, 'i16', 0xffffa5a5, 'i16'] + - values: [0x00005a5a, 'i16', 0x00005a5a, 'i16'] + # i32 + - values: [0, 'i32', 0, 'i32'] + - values: [0xffffffff, 'i32', 0xffffffff, 'i32'] + - values: [0xa5a5a5a5, 'i32', 0xa5a5a5a5, 'i32'] + - values: [0x5a5a5a5a, 'i32', 0x5a5a5a5a, 'i32'] + + - file-name: "from_float_field_type" + description: Check that accumulator value is loaded from field into accumulator. More tests on ldobj.v can be found in stobj.v tests + isa: + instructions: + - sig: ldobj.v v1:out:b32, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + header-template: ['pandasm_header'] + bugid: ['3292'] + check-type: exit-positive + code-template: | + + .function i32 main() { + initobj.short R.ctor + sta.obj v0 + %s + stobj v0, R.ff32 + lda.null + %s + ldobj.v v1, v0, R.ff32 + lda v1 + fcmpg v15 + %s + jeqz success + ldai 1 + return + success: + cases: + # f32 + - values: ['fldai 0.0', 'fmovi v15, 0.0', ''] + - values: ['fldai -6510615.0', 'fmovi v15, -6510615.0', ''] + - values: ['fldai 0x7FFFFFFF', 'fmovi v15, 0x7FFFFFFF', 'subi 1'] # NaN + - values: ['fldai 0x7f800000', 'fmovi v15, 0x7f800000', ''] # + Inf + - values: ['fldai 0xff800000', 'fmovi v15, 0xff800000', ''] # - Inf diff --git a/tests/cts-generator/cts-template/ldobj.yaml b/tests/cts-generator/cts-template/ldobj.yaml index c220378b13..37d2122a23 100644 --- a/tests/cts-generator/cts-template/ldobj.yaml +++ b/tests/cts-generator/cts-template/ldobj.yaml @@ -91,7 +91,7 @@ tests: Get field value from an object by field id and put it into accumulator. instructions: - sig: ldobj v:in:ref, field_id - acc: out:i32 + acc: out:b32 format: [op_v_8_id_16] commands: @@ -100,7 +100,7 @@ tests: isa: instructions: - sig: ldobj v:in:ref, field_id - acc: out:i32 + acc: out:b32 format: [op_v_8_id_16] header-template: ['pandasm_header'] check-type: exit-positive @@ -308,7 +308,7 @@ tests: isa: instructions: - sig: ldobj v:in:ref, field_id - acc: out:i32 + acc: out:b32 format: [op_v_8_id_16] header-template: ['pandasm_header'] runner-options: ['compile-failure'] @@ -411,3 +411,36 @@ tests: - values: [0xa5a5a5a5, 'i32', 0xa5a5a5a5, 'i32'] - values: [0x5a5a5a5a, 'i32', 0x5a5a5a5a, 'i32'] + - file-name: "from_float_field_type" + description: Check that accumulator value is loaded from field into accumulator. More tests on ldobj can be found in stobj tests + isa: + instructions: + - sig: ldobj v:in:ref, field_id + acc: out:b32 + format: [op_v_8_id_16] + header-template: ['pandasm_header'] + bugid: ['3292'] + check-type: exit-positive + code-template: | + + .function i32 main() { + initobj.short R.ctor + sta.obj v0 + %s + stobj v0, R.ff32 + lda.null + %s + ldobj v0, R.ff32 + fcmpg v15 + %s + jeqz success + ldai 1 + return + success: + cases: + # f32 + - values: ['fldai 0.0', 'fmovi v15, 0.0', ''] + - values: ['fldai -6510615.0', 'fmovi v15, -6510615.0', ''] + - values: ['fldai 0x7FFFFFFF', 'fmovi v15, 0x7FFFFFFF', 'subi 1'] # NaN + - values: ['fldai 0x7f800000', 'fmovi v15, 0x7f800000', ''] # + Inf + - values: ['fldai 0xff800000', 'fmovi v15, 0xff800000', ''] # - Inf diff --git a/tests/cts-generator/cts-template/ldstatic.64.yaml b/tests/cts-generator/cts-template/ldstatic.64.yaml index 451c0613e1..da5d726d9c 100644 --- a/tests/cts-generator/cts-template/ldstatic.64.yaml +++ b/tests/cts-generator/cts-template/ldstatic.64.yaml @@ -251,17 +251,20 @@ tests: - file-name: "from_all_float_field_types_p" description: Check that accumulator value is loaded from field into accumulator in PandaAssembly context. More tests on ldstatic.64 can be found in ststatic.64 tests. isa: - description: If field type is f32, result will be implicitly converted from f32 to f64. + instructions: + - sig: ldstatic.64 field_id + acc: out:b64 + format: [op_id_16] header-template: [pandasm_header] check-type: exit-positive code-template: | .function i32 main() { fldai.64 %s - ststatic.64 R.f%s + ststatic.64 R.ff64 lda.null fmovi.64 v15, %s - ldstatic.64 R.f%s + ldstatic.64 R.ff64 fcmpg.64 v15 %s jeqz success @@ -269,19 +272,12 @@ tests: return success: cases: - # f32 - - values: ['0.0', 'f32', '0.0', 'f32', ''] - - values: ['-6510615.0', 'f32', '-6510615.0', 'f32', ''] - - values: ['0x7FFFFFFFFFFFFFFF', 'f32', '0x7FFFFFFFFFFFFFFF', 'f32', 'subi 1'] # NaN - - values: ['0x7ff0000000000000', 'f32', '0x7ff0000000000000', 'f32', ''] # + Inf - - values: ['0xfff0000000000000', 'f32', '0xfff0000000000000', 'f32', ''] # - Inf # f64 - - values: ['0.0', 'f64', '0.0', 'f64', ''] - - values: ['-6510615555426900571.0', 'f64', '-6510615555426900571.0', 'f64', ''] - - values: ['0x7FFFFFFFFFFFFFFF', 'f64', '0x7FFFFFFFFFFFFFFF', 'f64', 'subi 1'] # NaN - - values: ['0x7ff0000000000000', 'f64', '0x7ff0000000000000', 'f64', ''] # + Inf - - values: ['0xfff0000000000000', 'f64', '0xfff0000000000000', 'f64', ''] # - Inf - + - values: ['0.0', '0.0', ''] + - values: ['-6510615555426900571.0', '-6510615555426900571.0', ''] + - values: ['0x7FFFFFFFFFFFFFFF', '0x7FFFFFFFFFFFFFFF', 'subi 1'] # NaN + - values: ['0x7ff0000000000000', '0x7ff0000000000000', ''] # + Inf + - values: ['0xfff0000000000000', '0xfff0000000000000', ''] # - Inf - file-name: "x_init_p" description: Check that ExceptionInInitializerError is thrown if an unexpected exception occurs in static initializer. diff --git a/tests/cts-generator/cts-template/ldstatic.yaml b/tests/cts-generator/cts-template/ldstatic.yaml index eb51f6402f..b2cf2e96dc 100644 --- a/tests/cts-generator/cts-template/ldstatic.yaml +++ b/tests/cts-generator/cts-template/ldstatic.yaml @@ -201,8 +201,6 @@ tests: - R.fu64 - values: - R.ff64 - - values: - - R.ff32 - values: - R.fObj - values: diff --git a/tests/cts-generator/cts-template/newarr.yaml b/tests/cts-generator/cts-template/newarr.yaml index dfaff445f2..a63c2c8b44 100644 --- a/tests/cts-generator/cts-template/newarr.yaml +++ b/tests/cts-generator/cts-template/newarr.yaml @@ -525,8 +525,8 @@ tests: - | # fldarr.32 v0 - fmovi.64 v3, 0 - fcmpg.64 v3 + fmovi v3, 0 + fcmpg v3 - values: - 'f64[]' - | diff --git a/tests/cts-generator/cts-template/newobj.yaml b/tests/cts-generator/cts-template/newobj.yaml index 7183507c00..da8a9c6997 100644 --- a/tests/cts-generator/cts-template/newobj.yaml +++ b/tests/cts-generator/cts-template/newobj.yaml @@ -398,9 +398,9 @@ tests: return label_f32: ldai 111 - ldobj.64 v1, Z.ff32 - fmovi.64 v2, 0.0 - fcmpg.64 v2 + ldobj v1, Z.ff32 + fmovi v2, 0.0 + fcmpg v2 jeqz label_f64 ldai 10 return @@ -625,7 +625,7 @@ tests: - x_oom description: Create objects with newobj instruction until OutOfMemoryError in PandaAssembly context header-template: [] - panda-options: "--object-pool-size=67108864" + panda-options: "--heap-size-limit=67108864" bugid: ["3578", "4170", "4171"] ignore: true code-template: | diff --git a/tests/cts-generator/cts-template/stobj.64.yaml b/tests/cts-generator/cts-template/stobj.64.yaml index 64a1a05d5c..2002c01321 100644 --- a/tests/cts-generator/cts-template/stobj.64.yaml +++ b/tests/cts-generator/cts-template/stobj.64.yaml @@ -138,10 +138,6 @@ tests: - fldai.64 1.1 - R.ff64 bugid: ['1882'] - - values: - - fldai.64 1.1 - - R.ff32 - bugid: ['1882'] - file-name: "with_non_object_ref" description: Check that verifier reports error when the 1st operand is not a ref to an object (other than array) @@ -477,48 +473,6 @@ tests: - | movi.64 v1, -6510615555426900571 cmp.64 v1 - # f32 - - values: - - fldai.64 0.0 - - ff32 - - ff32 - - | - fmovi.64 v1, 0.0 - fcmpg.64 v1 - bugid: ['3292'] - - values: - - fldai.64 -6510615.0 - - ff32 - - ff32 - - | - fmovi.64 v1, -6510615.0 - fcmpg.64 v1 - bugid: ['3292'] - - values: - - fldai.64 0x7FFFFFFFFFFFFFFF # NaN - - ff32 - - ff32 - - | - fmovi.64 v1, 0.0 - fcmpg.64 v1 - subi 1 - bugid: ['3292'] - - values: - - fldai.64 0x7ff0000000000000 # + Inf - - ff32 - - ff32 - - | - fmovi.64 v1, 0x7ff0000000000000 - fcmpg.64 v1 - bugid: ['3292'] - - values: - - fldai.64 0xfff0000000000000 # - Inf - - ff32 - - ff32 - - | - fmovi.64 v1, 0xfff0000000000000 - fcmpg.64 v1 - bugid: ['3292'] # f64 - values: - fldai.64 0.0 diff --git a/tests/cts-generator/cts-template/stobj.v.64.yaml b/tests/cts-generator/cts-template/stobj.v.64.yaml new file mode 100644 index 0000000000..a9f9897145 --- /dev/null +++ b/tests/cts-generator/cts-template/stobj.v.64.yaml @@ -0,0 +1,848 @@ +# 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. + +definitions: + - name: pandasm_header + template: | + .language PandaAssembly + .record panda.Object + .record Q {} + .record R { + u1 fu1 + u8 fu8 + i8 fi8 + u16 fu16 + i16 fi16 + u32 fu32 + i32 fi32 + u64 fu64 + i64 fi64 + f32 ff32 + f64 ff64 + i32[] fi32Array + Q fQ + Q[] fQArray + panda.Object fObj + panda.Object[] fObjArray + } + + - name: java_header + template: | + .language Java + .record java.lang.Object + .record I {} + .record Q {} + .record R { + u1 fu1 + i8 fi8 + u16 fu16 + i16 fi16 + i32 fi32 + i64 fi64 + f32 ff32 + f64 ff64 + # objects + i32[] fi32Array + Q fQ + Q[] fQArray + R fR + R[] fRArray + I fI + I[] fIArray + java.lang.Object fObj + java.lang.Object[] fObjArray + } + + +tests: + - file-name: "stobj.v.64" + isa: + title: Store register content into object field + description: > + Store register content into object field by field_id. For non-object variant the size of actually stored + value is determined by field_id, other register bits are discarded. + instructions: + - sig: stobj.v.64 v1:in:b64, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + commands: + + - file-name: "check_if_regs_initialized_p" + description: Check that verifier reports error if a register is not initialized in PandaAssembly context. + isa: + description: Store register content into object field by field_id. + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + code-template: | + + %s + + .function i32 main() { + newobj v0, R + fmovi.64 v1, 1.1 + %s + cases: + - values: + - "" + - stobj.v.64 v2, v0, R.ff64 + - values: + - "" + - stobj.v.64 v1, v2, R.ff64 + - values: + - | + # v0 (value) not initialized in the frame + .function void check(R a0) { + stobj.v.64 v0, a0, R.ff64 + return.void + } + - call.short check, v0 + - values: + - | + # v0 (object) not initialized in the frame + .function void check(f64 a0) { + stobj.v.64 a0, v0, R.ff64 + return.void + } + - call.short check, v1 + + + - file-name: "check_if_regs_initialized_j" + description: Check that verifier reports error if a register is not initialized in Java context. + isa: + description: Store register content into object field by field_id. + header-template: ['java_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['use-java', 'verifier-failure', 'verifier-debug-config'] + code-template: | + + %s + + .function i32 main() { + newobj v0, R + fmovi.64 v1, 1.1 + %s + cases: + - values: + - "" + - stobj.v.64 v2, v0, R.ff64 + - values: + - "" + - stobj.v.64 v1, v2, R.ff64 + - values: + - | + # v0 (value) not initialized in the frame + .function void check(R a0) { + stobj.v.64 v0, a0, R.ff64 + return.void + } + - call.short check, v0 + - values: + - | + # v0 (object) not initialized in the frame + .function void check(f64 a0) { + stobj.v.64 a0, v0, R.ff64 + return.void + } + - call.short check, v1 + + + - file-name: "with_null_ref_p" + description: Check that NullPointerException is thrown if object ref is null in PandaAssembly context. + isa: + exceptions: + - x_null + header-template: ['pandasm_header'] + check-type: empty + code-template: | + .record panda.NullPointerException + + .function R get_null() { + lda.null + return.obj + } + + .function i32 main() { + call.short get_null + sta.obj v0 + %s + try_begin: + stobj.v.64 v1, v0, %s + ldai 1 + return + try_end: + ldai 0 + return + .catch panda.NullPointerException, try_begin, try_end, try_end + } + cases: + - values: + - movi.64 v1, -1 + - R.fi64 + - values: + - movi.64 v1, 1 + - R.fu64 + - values: + - fmovi.64 v1, 1.1 + - R.ff64 + + + - file-name: "with_null_ref_j" + description: Check that NullPointerException is thrown if object ref is null in Java context. + isa: + exceptions: + - x_null + header-template: ['java_header'] + runner-options: ['use-java'] + check-type: empty + code-template: | + .record java.lang.NullPointerException + + .function R get_null() { + lda.null + return.obj + } + + .function i32 main() { + call.short get_null + sta.obj v0 + %s + try_begin: + stobj.v.64 v1, v0, %s + ldai 1 + return + try_end: + ldai 0 + return + .catch java.lang.NullPointerException, try_begin, try_end, try_end + } + cases: + - values: + - movi.64 v1, -1 + - R.fi64 + - values: + - fmovi.64 v1, 1.1 + - R.ff64 + + + - file-name: "with_non_object_ref_p" + description: > + Check that verifier reports error when the 2nd operand is not a ref to an + object (other than array) in PandaAssembly context. + isa: + verification: + - v2_object + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + code-template: | + .function i32 main() { + *s + movi.64 v1, 1 + stobj.v.64 v1, v0, %s + template-cases: + - values: ['R.fi64'] + - values: ['R.fu64'] + bugid: ['5502'] + ignore: true + - values: ['R.ff32'] + - values: ['R.ff64'] + cases: + - values: + - movi v0, 0 + - values: + - movi v0, 1 + - values: + - movi.64 v0, 0x00 + - values: + - movi.64 v0, 0xCAFECAFECAFECAFE + - values: + - fmovi.64 v0, 0.0 + - values: + - fmovi.64 v0, 6.62607015 + - values: + - | + # + movi v1, 10 + newarr v0, v1, panda.Object[] + + + - file-name: "with_non_object_ref_j" + description: > + Check that verifier reports error when the 2nd operand is not a ref to an + object (other than array) in Java context. + isa: + verification: + - v2_object + header-template: ['java_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + code-template: | + .function i32 main() { + *s + fmovi.64 v1, 3.1415 + stobj.v.64 v1, v0, %s + template-cases: + - values: ['R.fi64'] + bugid: ['5502'] + ignore: true + - values: ['R.ff32'] + bugid: ['5502'] + ignore: true + - values: ['R.ff64'] + bugid: ['5502'] + ignore: true + cases: + - values: + - movi v0, 0 + - values: + - movi v0, 1 + - values: + - movi.64 v0, 0x00 + - values: + - movi.64 v0, 0xCAFECAFECAFECAFE + - values: + - fmovi.64 v0, 0.0 + - values: + - fmovi.64 v0, 6.62607015 + - values: + - | + # + movi v1, 10 + newarr v0, v1, java.lang.Object[] + + + - file-name: "with_static_field_id_p" + description: > + Check that verifier reports error when the field doesn't resolve to a non-static + valid object field in PandaAssembly context. + isa: + verification: + - field_id_non_static + header-template: [] + check-type: exit-positive + runner-options: ['compile-failure'] + code-template: | + .record W { + i64 static_field + } + .record random_record { + i64 random_field + i64 random_static_field + } + .function void random_function() { + return.void + } + + .function i32 main() { + newobj v0, W + movi.64 v1, 1 + stobj.v.64 v1, v0, %s + cases: + - values: + - W.static_field + runner-options: ['verifier-failure', 'verifier-debug-config'] + tags: ['verifier'] + - values: + - random_record + - values: + - random_function + - values: + - W.field_not_exists + - values: + - random_record.random_field + runner-options: ['verifier-failure', 'verifier-debug-config'] + tags: ['verifier'] + - values: + - random_record.random_static_field + runner-options: ['verifier-failure', 'verifier-debug-config'] + tags: ['verifier'] + - values: + - 0 + - values: + - -1.1 + - values: + - "null" + - values: + - "\"abc\"" + + + - file-name: "with_static_field_id_j" + description: > + Check that verifier reports error when the field doesn't resolve to a non-static + valid object field in Java context. + isa: + verification: + - field_id_non_static + header-template: [] + check-type: exit-positive + runner-options: ['use-java', 'verifier-failure', 'verifier-debug-config'] + tags: ['verifier'] + code-template: | + .language Java + .record A { + i64 a_field + } + .record B { + i64 b_field + } + .record C { + i64 c_field + } + + .function i32 main() { + newobj v0, %s + movi.64 v2, 1 + stobj.v.64 v2, v0, %s + cases: + - values: + - C + - C.c_field + - values: + - C + - B.b_field + - values: + - C + - A.a_field + - values: + - B + - B.a_field + runner-options: ['compile-failure'] + - values: + - B + - B.c_field + runner-options: ['compile-failure'] + + + - file-name: "with_wrong_field_size_p" + description: > + Check that verifier reports error when the field resolves to a field with size + that is not corresponding to bytecode in PandaAssembly context. + isa: + verification: + - field_id_size + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + code-template: | + + .function i32 main() { + newobj v0, R + movi.64 v1, 0 + stobj.v.64 v1, v0, %s + cases: + - values: + - R.fu1 + - values: + - R.fu8 + - values: + - R.fi8 + - values: + - R.fu16 + - values: + - R.fi16 + - values: + - R.fu32 + - values: + - R.fi32 + - values: + - R.fObj + - values: + - R.fObjArray + - values: + - R.fi32Array + + + - file-name: "with_wrong_field_size_j" + description: > + Check that verifier reports error when the field resolves to a field with size + that is not corresponding to bytecode in Java context. + isa: + verification: + - field_id_size + header-template: ['java_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['use-java', 'verifier-failure', 'verifier-debug-config'] + code-template: | + + .function i32 main() { + newobj v0, R + fmovi.64 v1, 0.1 + stobj.v.64 v1, v0, %s + cases: + - values: + - R.fu1 + - values: + - R.fi8 + - values: + - R.fu16 + - values: + - R.fi16 + - values: + - R.fi32 + - values: + - R.fObj + - values: + - R.fObjArray + - values: + - R.fi32Array + - values: + - R.fI + - values: + - R.fIArray + + + - file-name: "with_wrong_reg_type_p" + description: > + Check that verifier reports error when the register contains a value of type not corresponding + to the bytecode in PandaAssembly context. + isa: + verification: + - v1_type + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + code-template: | + .function i32 main() { + newobj v0, R + %s + stobj.v.64 v1, v0, %s + cases: + # u64 + - values: + - movi v1, 0 + - R.fu64 + - values: + - movi v1, 0xCAFECAFE + - R.fu64 + - values: + - fmovi.64 v1, 1.1 + - R.fu64 + - values: + - mov.null v1 + - R.fu64 + - values: + - newobj v1, Q + - R.fu64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[] + - R.fu64 + # i64 + - values: + - movi v1, 0 + - R.fi64 + - values: + - movi v1, 0xCAFECAFE + - R.fi64 + - values: + - fmovi.64 v1, 1.1 + - R.fi64 + - values: + - mov.null v1 + - R.fi64 + - values: + - newobj v1, Q + - R.fi64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[] + - R.fi64 + # f64 + - values: + - movi v1, 0 + - R.ff64 + - values: + - movi v1, 0xCAFECAFE + - R.ff64 + - values: + - movi.64 v1, 1 + - R.ff64 + - values: + - mov.null v1 + - R.ff64 + - values: + - newobj v1, Q + - R.ff64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[] + - R.ff64 + # f32 + - values: + - movi v1, 0 + - R.ff32 + - values: + - movi v1, 0xCAFECAFE + - R.ff32 + - values: + - movi.64 v1, 1 + - R.ff32 + - values: + - mov.null v1 + - R.ff32 + - values: + - newobj v1, Q + - R.ff32 + - values: + - | + # + movi v1, 10 + newarr v1, v1, panda.Object[] + - R.ff32 + + + - file-name: "with_wrong_reg_type_j" + description: > + Check that verifier reports error when the register contains + a value of type not corresponding to the bytecode in Java context. + isa: + verification: + - v1_type + header-template: ['java_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['use-java', 'verifier-failure', 'verifier-debug-config'] + code-template: | + .function i32 main() { + newobj v0, R + %s + stobj.v.64 v1, v0, %s + cases: + # i64 + - values: + - movi v1, 0 + - R.fi64 + - values: + - movi v1, 0xCAFECAFE + - R.fi64 + - values: + - fmovi.64 v1, 1.1 + - R.fi64 + - values: + - mov.null v1 + - R.fi64 + - values: + - newobj v1, Q + - R.fi64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[] + - R.fi64 + # f64 + - values: + - movi v1, 0 + - R.ff64 + - values: + - movi v1, 0xCAFECAFE + - R.ff64 + - values: + - movi.64 v1, 1 + - R.ff64 + - values: + - mov.null v1 + - R.ff64 + - values: + - newobj v1, Q + - R.ff64 + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[] + - R.ff64 + # f32 + - values: + - movi v1, 0 + - R.ff32 + - values: + - movi v1, 0xCAFECAFE + - R.ff32 + - values: + - movi.64 v1, 1 + - R.ff32 + - values: + - mov.null v1 + - R.ff32 + - values: + - newobj v1, Q + - R.ff32 + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[] + - R.ff32 + + + - file-name: "op_v1_4_v2_4_id_16" + description: Check that compiler reports error when the register number is out of 4 bit size + isa: + instructions: + - sig: stobj.v.64 v1:in:b64, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + header-template: ['pandasm_header'] + runner-options: ['compile-failure'] + check-type: exit-positive + code-template: | + + .function i32 main() { + stobj.v.64 %s, R.ff64 + cases: + - values: ['v15, v15'] + runner-options: ['compile-only'] + - values: ['v16, v15'] + - values: ['v15, v16'] + - values: ['v255, v0'] + - values: ['v15, v256'] + - values: ['v65535, v65535'] + - values: ['v32767, v0'] + + + - file-name: "into_all_field_types" + description: Check that register value is stored in field. + isa: + instructions: + - sig: stobj.64 v:in:ref, field_id + acc: in:b64 + format: [op_v_8_id_16] + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['tsan'] + code-template: | + .function i32 main() { + movi v7, 5151515 + newobj v0, R + %s + ldai 5151515 + stobj.v.64 v1, v0, R.%s + jeq v7, cont # check acc_none + ldai 2 + return + cont: + ldobj.v.64 v2, v0, R.%s + lda.64 v2 + %s + jeqz success + ldai 1 + return + success: + cases: + # u64 + - values: + - movi.64 v1, 0x0000000000000000 + - fu64 + - fu64 + - | + # + movi.64 v1, 0x0000000000000000 + ucmp.64 v1 + - values: + - movi.64 v1, 0xffffffffffffffff + - fu64 + - fu64 + - | + # + movi.64 v1, 0xffffffffffffffff + ucmp.64 v1 + - values: + - movi.64 v1, 0xa5a5a5a5a5a5a5a5 + - fu64 + - fu64 + - | + # + movi.64 v1, 0xa5a5a5a5a5a5a5a5 + ucmp.64 v1 + # i64 + - values: + - movi.64 v1, 0 + - fi64 + - fi64 + - | + # + movi.64 v1, 0 + cmp.64 v1 + - values: + - movi.64 v1, -1 + - fi64 + - fi64 + - | + # + movi.64 v1, -1 + cmp.64 v1 + - values: + - movi.64 v1, -6510615555426900571 + - fi64 + - fi64 + - | + # + movi.64 v1, -6510615555426900571 + cmp.64 v1 + # f64 + - values: + - fmovi.64 v1, 0.0 + - ff64 + - ff64 + - | + # + fmovi.64 v1, 0.0 + fcmpg.64 v1 + - values: + - fmovi.64 v1, -6510615555426900571.0 + - ff64 + - ff64 + - | + # + fmovi.64 v1, -6510615555426900571.0 + fcmpg.64 v1 + - values: + - fmovi.64 v1, 0x7FFFFFFFFFFFFFFF # NaN + - ff64 + - ff64 + - | + # + fmovi.64 v1, 0.0 + fcmpg.64 v1 + subi 1 + - values: + - fmovi.64 v1, 0x7ff0000000000000 # + Inf + - ff64 + - ff64 + - | + # + fmovi.64 v1, 0x7ff0000000000000 + fcmpg.64 v1 + - values: + - fmovi.64 v1, 0xfff0000000000000 # - Inf + - ff64 + - ff64 + - | + # + fmovi.64 v1, 0xfff0000000000000 + fcmpg.64 v1 diff --git a/tests/cts-generator/cts-template/stobj.v.yaml b/tests/cts-generator/cts-template/stobj.v.yaml new file mode 100644 index 0000000000..93531f25b6 --- /dev/null +++ b/tests/cts-generator/cts-template/stobj.v.yaml @@ -0,0 +1,897 @@ +# 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. + +definitions: + - name: pandasm_header + template: | + .language PandaAssembly + .record panda.Object + .record Q {} + .record R { + u1 fu1 + u8 fu8 + i8 fi8 + u16 fu16 + i16 fi16 + u32 fu32 + i32 fi32 + u64 fu64 + i64 fi64 + f32 ff32 + f64 ff64 + # objects: + i32[] fi32Array + Q fQ + Q[] fQArray + panda.Object fObj + panda.Object[] fObjArray + } + + - name: java_header + template: | + .language Java + .record java.lang.Object + .record I {} + .record Q {} + .record R { + u1 fu1 + i8 fi8 + u16 fu16 + i16 fi16 + i32 fi32 + i64 fi64 + f32 ff32 + f64 ff64 + # objects + i32[] fi32Array + Q fQ + Q[] fQArray + R fR + R[] fRArray + I fI + I[] fIArray + java.lang.Object fObj + java.lang.Object[] fObjArray + } + + +tests: + - file-name: "stobj.v" + isa: + title: Store register content into object field + description: > + Store register content into object field by field_id. For non-object variant the size of actually stored + value is determined by field_id, other register bits are discarded. + instructions: + - sig: stobj.v v1:in:i32, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + commands: + + - file-name: "check_if_regs_initialized_p" + description: Check that verifier reports error if a register is not initialized in PandaAssembly context. + isa: + description: Store register content into object field by field_id. + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + code-template: | + + %s + + .function i32 main() { + newobj v0, R + movi v1, 1 + %s + cases: + - values: + - "" + - stobj.v v2, v0, R.fi32 + - values: + - "" + - stobj.v v1, v2, R.fi32 + - values: + - | + # v0 (value) not initialized in the frame + .function void check(R a0) { + stobj.v v0, a0, R.fi32 + return.void + } + - call.short check, v0 + - values: + - | + # v0 (object) not initialized in the frame + .function void check(i32 a0) { + stobj.v a0, v0, R.fi32 + return.void + } + - call.short check, v1 + + + - file-name: "check_if_regs_initialized_j" + description: Check that verifier reports error if a register is not initialized in Java context + isa: + description: Store register content into object field by field_id. + header-template: ['java_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['use-java', 'verifier-failure', 'verifier-debug-config'] + code-template: | + + %s + + .function i32 main() { + newobj v0, R + movi v1, 1 + %s + cases: + - values: + - "" + - stobj.v v2, v0, R.fi32 + - values: + - "" + - stobj.v v1, v2, R.fi32 + - values: + - | + # v0 (value) not initialized in the frame + .function void check(R a0) { + stobj.v v0, a0, R.fi32 + return.void + } + - call.short check, v0 + - values: + - | + # v0 (object) not initialized in the frame + .function void check(i32 a0) { + stobj.v a0, v0, R.fi32 + return.void + } + - call.short check, v1 + + + - file-name: "with_null_ref_p" + description: Check that NullPointerException is thrown if object ref is null in PandaAssembly context + isa: + exceptions: + - x_null + header-template: ['pandasm_header'] + check-type: empty + code-template: | + .record panda.NullPointerException + + .function R get_null() { + lda.null + return.obj + } + + .function i32 main() { + call.short get_null + sta.obj v0 + %s + try_begin: + stobj.v v1, v0, %s + ldai 1 + return + try_end: + ldai 0 + return + .catch panda.NullPointerException, try_begin, try_end, try_end + } + cases: + - values: + - movi v1, 1 + - R.fu1 + - values: + - movi v1, 1 + - R.fu8 + - values: + - movi v1, 1 + - R.fi8 + - values: + - movi v1, 1 + - R.fu16 + - values: + - movi v1, 1 + - R.fi16 + - values: + - movi v1, 1 + - R.fu32 + - values: + - movi v1, 1 + - R.fi32 + - values: + - fmovi v1, -1.1 + - R.ff32 + + + - file-name: "with_null_ref_j" + description: Check that NullPointerException is thrown if object ref is null in Java context + isa: + exceptions: + - x_null + header-template: ['java_header'] + runner-options: ['use-java'] + check-type: empty + code-template: | + .record java.lang.NullPointerException + + .function R get_null() { + lda.null + return.obj + } + + .function i32 main() { + call.short get_null + sta.obj v0 + %s + try_begin: + stobj.v v1, v0, %s + ldai 1 + return + try_end: + ldai 0 + return + .catch java.lang.NullPointerException, try_begin, try_end, try_end + } + cases: + - values: + - movi v1, 1 + - R.fu1 + - values: + - movi v1, 1 + - R.fi8 + - values: + - movi v1, 1 + - R.fu16 + - values: + - movi v1, 1 + - R.fi16 + - values: + - movi v1, 1 + - R.fi32 + - values: + - fmovi v1, -1.1 + - R.ff32 + + + - file-name: "with_non_object_ref_p" + description: Check that verifier reports error when the 2nd register is not a ref to an object (other than array) in PandaAssembly context + isa: + verification: + - v2_object + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + code-template: | + + .function i32 main() { + *s + movi v1, 1 + stobj.v v1, v0, %s + template-cases: + - values: ['R.fu1'] + bugid: ['5502'] + ignore: true + - values: ['R.fi8'] + bugid: ['5502'] + ignore: true + - values: ['R.fu8'] + bugid: ['5502'] + ignore: true + - values: ['R.fi16'] + bugid: ['5502'] + ignore: true + - values: ['R.fu16'] + bugid: ['5502'] + ignore: true + - values: ['R.fi32'] + - values: ['R.fu32'] + bugid: ['5502'] + ignore: true + cases: + - values: + - movi v0, 0 + - values: + - movi v0, 1 + - values: + - movi.64 v0, 0x00 + - values: + - movi.64 v0, 0xCAFECAFECAFECAFE + - values: + - fmovi.64 v0, 0.0 + - values: + - fmovi.64 v0, 6.62607015 + - values: + - | + # + movi v1, 10 + newarr v0, v1, panda.Object[] + + + - file-name: "with_non_object_ref_j" + description: Check that verifier reports error when the 2nd register is not a ref to an object (other than array) in Java context + isa: + verification: + - v2_object + header-template: ['java_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['use-java', 'verifier-failure', 'verifier-debug-config'] + code-template: | + + .function i32 main() { + *s + movi v1, 1 + stobj.v v1, v0, %s + template-cases: + - values: ['R.fu1'] + bugid: ['5502'] + ignore: true + - values: ['R.fi8'] + bugid: ['5502'] + ignore: true + - values: ['R.fi16'] + bugid: ['5502'] + ignore: true + - values: ['R.fu16'] + bugid: ['5502'] + ignore: true + - values: ['R.fi32'] + cases: + - values: + - movi v0, 0 + - values: + - movi v0, 1 + - values: + - movi.64 v0, 0x00 + - values: + - movi.64 v0, 0xCAFECAFECAFECAFE + - values: + - fmovi.64 v0, 0.0 + - values: + - fmovi.64 v0, 6.62607015 + - values: + - | + # + movi v1, 10 + newarr v0, v1, java.lang.Object[] + + + - file-name: "with_static_field_id_p" + description: > + Check that verifier reports error if the field doesn't resolve to + a non-static valid object field in PandaAssembly context + isa: + verification: + - field_id_non_static + header-template: [] + check-type: exit-positive + runner-options: ['compile-failure'] + code-template: | + .record W { + i32 static_field + } + .record random_record { + i32 random_field + i32 random_static_field + } + .function void random_function() { + return.void + } + + .function i32 main() { + newobj v0, W + movi v2, 1 + stobj.v v2, v0, %s + cases: + - values: + - W.static_field + runner-options: ['verifier-failure', 'verifier-debug-config'] + tags: ['verifier'] + - values: + - random_record + - values: + - random_function + - values: + - W.field_not_exists + - values: + - random_record.random_field + runner-options: ['verifier-failure', 'verifier-debug-config'] + tags: ['verifier'] + - values: + - random_record.random_static_field + runner-options: ['verifier-failure', 'verifier-debug-config'] + tags: ['verifier'] + - values: + - 0 + - values: + - -1.1 + - values: + - "null" + - values: + - "\"abc\"" + + + - file-name: "with_static_field_id_j" + description: > + Check that verifier reports error if the field doesn't resolve to + a non-static valid object field in Java context + isa: + verification: + - field_id_non_static + header-template: [] + check-type: exit-positive + runner-options: ['use-java', 'verifier-failure', 'verifier-debug-config'] + tags: ['verifier'] + code-template: | + .language Java + .record A { + i32 a_field + } + .record B { + i32 b_field + } + .record C { + i32 c_field + } + + .function i32 main() { + newobj v0, %s + movi v2, 1 + stobj.v v2, v0, %s + cases: + - values: + - C + - C.c_field + - values: + - C + - B.b_field + - values: + - C + - A.a_field + - values: + - B + - B.a_field + runner-options: ['compile-failure'] + - values: + - B + - B.c_field + runner-options: ['compile-failure'] + + + - file-name: "with_wrong_field_size_p" + description: > + Check that verifier reports error when the field resolves to a field with size + that is not corresponding to bytecode in PandaAssembly context. + isa: + verification: + - field_id_size + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + code-template: | + .function i32 main() { + newobj v0, R + movi v2, 0 + stobj.v v2, v0, %s + cases: + - values: + - R.fi64 + - values: + - R.fu64 + - values: + - R.ff64 + - values: + - R.ff32 + - values: + - R.fObj + - values: + - R.fObjArray + - values: + - R.fi32Array + + + - file-name: "with_wrong_field_size_j" + description: Check that verifier reports error when the field resolves to a field with size that is not corresponding to bytecode in Java context. + isa: + verification: + - field_id_size + header-template: ['java_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['use-java', 'verifier-failure', 'verifier-debug-config'] + code-template: | + .function i32 main() { + newobj v0, R + movi v2, 0 + stobj.v v2, v0, %s + cases: + - values: + - R.fi64 + - values: + - R.ff64 + - values: + - R.ff32 + - values: + - R.fObj + - values: + - R.fObjArray + - values: + - R.fi32Array + - values: + - R.fI + - values: + - R.fIArray + + + - file-name: "with_wrong_reg_type_p" + description: Check that verifier reports error when the register contains a value of type not corresponding to the bytecode in PandaAssembly context + isa: + verification: + - v1_type + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['verifier-failure', 'verifier-debug-config'] + code-template: | + .function i32 main() { + newobj v0, R + %s + stobj.v v1, v0, %s + cases: + - values: + - movi.64 v1, 0xF000F000F000F000 + - R.fu1 + ignore: true + bugid: ['4166'] + - values: + - movi.64 v1, 0 + - R.fi8 + ignore: true + bugid: ['4166'] + - values: + - movi.64 v1, 0xCAFECAFECAFECAFE + - R.fu8 + ignore: true + bugid: ['4166'] + - values: + - movi.64 v1, 0 + - R.fi16 + ignore: true + bugid: ['4166'] + - values: + - movi.64 v1, 0x5A5A5A5A5A5A5A5A + - R.fi32 + ignore: true + bugid: ['4166'] + - values: + - movi.64 v1, 1234567890 + - R.fu32 + ignore: true + bugid: ['4166'] + - values: + - fmovi.64 v1, 0x7FFFFFFFFFFFFFFF + - R.fu1 + - values: + - fmovi.64 v1, 0.0 + - R.fu8 + - values: + - fmovi.64 v1, -0.0 + - R.fi8 + - values: + - fmovi.64 v1, 1.0 + - R.fu16 + - values: + - fmovi.64 v1, 3.0 + - R.fi16 + - values: + - fmovi.64 v1, 0.123456 + - R.fu32 + - values: + - fmovi.64 v1, 123456.0 + - R.fi32 + - values: + - mov.null v1 + - R.fu32 + - values: + - newobj v1, panda.Object + - R.fi32 + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[] + - R.fi32 + + + - file-name: "with_wrong_reg_type_j" + description: > + Check that verifier reports error when the register contains + a value of type not corresponding to the bytecode in Java context. + isa: + verification: + - v1_type + header-template: ['java_header'] + check-type: exit-positive + tags: ['verifier'] + runner-options: ['use-java', 'verifier-failure', 'verifier-debug-config'] + code-template: | + .function i32 main() { + newobj v0, R + %s + stobj.v v1, v0, %s + cases: + - values: + - movi.64 v1, 0xF000F000F000F000 + - R.fu1 + ignore: true + bugid: ['4166'] + - values: + - movi.64 v1, 0 + - R.fi8 + ignore: true + bugid: ['4166'] + - values: + - movi.64 v1, 0 + - R.fi16 + ignore: true + bugid: ['4166'] + - values: + - movi.64 v1, 0x5A5A5A5A5A5A5A5A + - R.fi32 + ignore: true + bugid: ['4166'] + - values: + - fmovi.64 v1, 0x7FFFFFFFFFFFFFFF + - R.fu1 + - values: + - fmovi.64 v1, -0.0 + - R.fi8 + - values: + - fmovi.64 v1, 1.0 + - R.fu16 + - values: + - fmovi.64 v1, 3.0 + - R.fi16 + - values: + - fmovi.64 v1, 123456.0 + - R.fi32 + - values: + - mov.null v1 + - R.fi32 + - values: + - newobj v1, Q + - R.fi16 + - values: + - | + # + movi v1, 10 + newarr v1, v1, i32[] + - R.fi32 + - values: + - | + # + movi v1, 10 + newarr v1, v1, java.lang.Object[][] + - R.fi8 + + + - file-name: "op_v1_4_v2_4_id_16" + description: Check that compiler reports error when the register number is out of 4 bit size + isa: + instructions: + - sig: stobj.v v1:in:i32, v2:in:ref, field_id + acc: none + format: [op_v1_4_v2_4_id_16] + header-template: ['pandasm_header'] + runner-options: ['compile-failure'] + check-type: exit-positive + code-template: | + + .function i32 main() { + stobj.v %s, R.fi32 + cases: + - values: ['v15, v15'] + runner-options: ['compile-only'] + - values: ['v16, v15'] + - values: ['v15, v16'] + - values: ['v255, v0'] + - values: ['v15, v256'] + - values: ['v65535, v65535'] + - values: ['v32767, v0'] + + + - file-name: "into_all_unsigned_field_types" + description: Check that register value is stored in field. Unsigned cases. + isa: + description: If field type size is less than 32, register content will be truncated to storage size before storing. + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['tsan'] + code-template: | + + .function i32 main() { + movi v7, 123456789 + newobj v0, R + %s + ldai 123456789 + stobj.v v1, v0, R.%s + jeq v7, cont # check acc_none + ldai 2 + return + cont: + ldobj.v v2, v0, R.%s + lda v2 + movi v1, %s + ucmp v1 + jeqz success + ldai 1 + return + success: + cases: + # u1 + - values: ['movi v1, 0x00000000', 'fu1', 'fu1', 0] + - values: ['movi v1, 0xffffffff', 'fu1', 'fu1', 1] + bugid: ['1848'] + ignore: true + - values: ['movi v1, 0x00000001', 'fu1', 'fu1', 1] + - values: ['movi v1, 0xfffffffe', 'fu1', 'fu1', 0] + bugid: ['1848'] + ignore: true + - values: ['movi v1, 0x11111111', 'fu1', 'fu1', 1] + bugid: ['1848'] + ignore: true + - values: ['movi v1, 0x88888888', 'fu1', 'fu1', 0] + bugid: ['1848'] + ignore: true + # u8 + - values: ['movi v1, 0x00000000', 'fu8', 'fu8', 0] + - values: ['movi v1, 0xffffffff', 'fu8', 'fu8', 255] + - values: ['movi v1, 0x000000ff', 'fu8', 'fu8', 255] + - values: ['movi v1, 0xffffff00', 'fu8', 'fu8', 0] + - values: ['movi v1, 0x11111111', 'fu8', 'fu8', 17] + - values: ['movi v1, 0x88888888', 'fu8', 'fu8', 136] + # u16 + - values: ['movi v1, 0x00000000', 'fu16', 'fu16', 0] + - values: ['movi v1, 0xffffffff', 'fu16', 'fu16', 65535] + - values: ['movi v1, 0x0000ffff', 'fu16', 'fu16', 65535] + - values: ['movi v1, 0xffff0000', 'fu16', 'fu16', 0] + - values: ['movi v1, 0x11111111', 'fu16', 'fu16', 4369] + - values: ['movi v1, 0x88888888', 'fu16', 'fu16', 34952] + # u32 + - values: ['movi v1, 0x00000000', 'fu32', 'fu32', 0] + - values: ['movi v1, 0xffffffff', 'fu32', 'fu32', 4294967295] + - values: ['movi v1, 0x11111111', 'fu32', 'fu32', 286331153] + - values: ['movi v1, 0x88888888', 'fu32', 'fu32', 2290649224] + + - file-name: "into_float_field_type" + description: Check that register value is stored in field. + isa: + instructions: + - sig: stobj v:in:ref, field_id + acc: in:b32 + format: [op_v_8_id_16] + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['tsan'] + code-template: | + .function i32 main() { + movi v7, 5151515 + newobj v0, R + %s + ldai 5151515 + stobj.v v1, v0, R.%s + jeq v7, cont # check acc_none + ldai 2 + return + cont: + ldobj.v v2, v0, R.%s + lda v2 + %s + jeqz success + ldai 1 + return + success: + cases: + # f32 + - values: + - fmovi v1, 0.0 + - ff32 + - ff32 + - | + # + fmovi v1, 0.0 + fcmpg v1 + - values: + - fmovi v1, -6510615.0 + - ff32 + - ff32 + - | + # + fmovi v1, -6510615.0 + fcmpg v1 + - values: + - fmovi v1, 0x7fffffff # NaN + - ff32 + - ff32 + - | + # + fmovi v1, 0.0 + fcmpg v1 + subi 1 + - values: + - fmovi v1, 0x7f800000 # + Inf + - ff32 + - ff32 + - | + # + fmovi v1, 0x7f800000 + fcmpg v1 + - values: + - fmovi v1, 0xff800000 # - Inf + - ff32 + - ff32 + - | + # + fmovi v1, 0xff800000 + fcmpg v1 + + - file-name: "into_all_field_types_int" + description: Check that register value is stored in field. Version for signed types. + isa: + description: If field type size is less than 32, register content will be truncated to storage size before storing. + header-template: ['pandasm_header'] + check-type: exit-positive + tags: ['tsan'] + code-template: | + + .function i32 main() { + movi v7, 123456789 + newobj v0, R + %s + ldai 123456789 + stobj.v v1, v0, R.%s + jeq v7, cont # check acc_none + ldai 2 + return + cont: + ldobj.v v2, v0, R.%s + lda v2 + movi v1, %s + jeq v1, success + ldai 1 + return + success: + cases: + # i8 + - values: ['movi v1, 0x00000000', 'fi8', 'fi8', 0] + - values: ['movi v1, 0xffffffff', 'fi8', 'fi8', -1] + - values: ['movi v1, 0x000000ff', 'fi8', 'fi8', -1] + - values: ['movi v1, 0xffffff00', 'fi8', 'fi8', 0] + - values: ['movi v1, 0x11111111', 'fi8', 'fi8', 17] + - values: ['movi v1, 0x88888888', 'fi8', 'fi8', -120] + # i16 + - values: ['movi v1, 0x00000000', 'fi16', 'fi16', 0] + - values: ['movi v1, 0xffffffff', 'fi16', 'fi16', -1] + - values: ['movi v1, 0x0000ffff', 'fi16', 'fi16', -1] + - values: ['movi v1, 0xffff0000', 'fi16', 'fi16', 0] + - values: ['movi v1, 0x11111111', 'fi16', 'fi16', 4369] + - values: ['movi v1, 0x88888888', 'fi16', 'fi16', -30584] + # i32 + - values: ['movi v1, 0x00000000', 'fi32', 'fi32', 0] + - values: ['movi v1, 0xffffffff', 'fi32', 'fi32', -1] + - values: ['movi v1, 0x11111111', 'fi32', 'fi32', 286331153] + - values: ['movi v1, 0x88888888', 'fi32', 'fi32', -2004318072] diff --git a/tests/cts-generator/cts-template/stobj.yaml b/tests/cts-generator/cts-template/stobj.yaml index 2cc20b411e..d6a9f4da20 100644 --- a/tests/cts-generator/cts-template/stobj.yaml +++ b/tests/cts-generator/cts-template/stobj.yaml @@ -117,7 +117,7 @@ tests: .function i32 main() { call.short get_null sta.obj v0 - ldai 1 + %s try_begin: stobj v0, %s ldai 1 @@ -129,19 +129,30 @@ tests: } cases: - values: + - ldai 1 - R.fu1 - values: + - ldai 1 - R.fu8 - values: + - ldai 1 - R.fi8 - values: + - ldai 1 - R.fu16 - values: + - ldai 1 - R.fi16 - values: + - ldai 1 - R.fu32 - values: + - ldai 1 - R.fi32 + - values: + - fldai 1.1 + - R.ff32 + bugid: ['1882'] - file-name: "with_non_object_ref" description: Check that verifier reports error when the 1st operand is not a ref to an object (other than array) @@ -394,47 +405,59 @@ tests: stobj v0, R.%s lda.null ldobj v0, R.%s - movi v1, %s + %s v1, %s %s v1 + %s jeqz success ldai 1 return success: cases: # u1 - - values: ['ldai 0x00000000', 'fu1', 'fu1', 0, 'ucmp'] - - values: ['ldai 0xffffffff', 'fu1', 'fu1', 1, 'ucmp'] + - values: ['ldai 0x00000000', 'fu1', 'fu1', 'movi', 0, 'ucmp', ''] + - values: ['ldai 0xffffffff', 'fu1', 'fu1', 'movi', 1, 'ucmp', ''] bugid: ['1848'] ignore: true - - values: ['ldai 0x00000001', 'fu1', 'fu1', 1, 'ucmp'] - - values: ['ldai 0xfffffffe', 'fu1', 'fu1', 0, 'ucmp'] + - values: ['ldai 0x00000001', 'fu1', 'fu1', 'movi', 1, 'ucmp', ''] + - values: ['ldai 0xfffffffe', 'fu1', 'fu1', 'movi', 0, 'ucmp', ''] bugid: ['1848'] ignore: true - - values: ['ldai 0x11111111', 'fu1', 'fu1', 1, 'ucmp'] + - values: ['ldai 0x11111111', 'fu1', 'fu1', 'movi', 1, 'ucmp', ''] bugid: ['1848'] ignore: true - - values: ['ldai 0x88888888', 'fu1', 'fu1', 0, 'ucmp'] + - values: ['ldai 0x88888888', 'fu1', 'fu1', 'movi', 0, 'ucmp', ''] bugid: ['1848'] ignore: true # u8 - - values: ['ldai 0x00000000', 'fu8', 'fu8', 0, 'ucmp'] - - values: ['ldai 0xffffffff', 'fu8', 'fu8', 255, 'ucmp'] - - values: ['ldai 0x000000ff', 'fu8', 'fu8', 255, 'ucmp'] - - values: ['ldai 0xffffff00', 'fu8', 'fu8', 0, 'ucmp'] - - values: ['ldai 0x11111111', 'fu8', 'fu8', 17, 'ucmp'] - - values: ['ldai 0x88888888', 'fu8', 'fu8', 136, 'ucmp'] + - values: ['ldai 0x00000000', 'fu8', 'fu8', 'movi', 0, 'ucmp', ''] + - values: ['ldai 0xffffffff', 'fu8', 'fu8', 'movi', 255, 'ucmp', ''] + - values: ['ldai 0x000000ff', 'fu8', 'fu8', 'movi', 255, 'ucmp', ''] + - values: ['ldai 0xffffff00', 'fu8', 'fu8', 'movi', 0, 'ucmp', ''] + - values: ['ldai 0x11111111', 'fu8', 'fu8', 'movi', 17, 'ucmp', ''] + - values: ['ldai 0x88888888', 'fu8', 'fu8', 'movi', 136, 'ucmp', ''] # u16 - - values: ['ldai 0x00000000', 'fu16', 'fu16', 0, 'ucmp'] - - values: ['ldai 0xffffffff', 'fu16', 'fu16', 65535, 'ucmp'] - - values: ['ldai 0x0000ffff', 'fu16', 'fu16', 65535, 'ucmp'] - - values: ['ldai 0xffff0000', 'fu16', 'fu16', 0, 'ucmp'] - - values: ['ldai 0x11111111', 'fu16', 'fu16', 4369, 'ucmp'] - - values: ['ldai 0x88888888', 'fu16', 'fu16', 34952, 'ucmp'] + - values: ['ldai 0x00000000', 'fu16', 'fu16', 'movi', 0, 'ucmp', ''] + - values: ['ldai 0xffffffff', 'fu16', 'fu16', 'movi', 65535, 'ucmp', ''] + - values: ['ldai 0x0000ffff', 'fu16', 'fu16', 'movi', 65535, 'ucmp', ''] + - values: ['ldai 0xffff0000', 'fu16', 'fu16', 'movi', 0, 'ucmp', ''] + - values: ['ldai 0x11111111', 'fu16', 'fu16', 'movi', 4369, 'ucmp', ''] + - values: ['ldai 0x88888888', 'fu16', 'fu16', 'movi', 34952, 'ucmp', ''] # u32 - - values: ['ldai 0x00000000', 'fu32', 'fu32', 0, 'ucmp'] - - values: ['ldai 0xffffffff', 'fu32', 'fu32', 4294967295, 'ucmp'] - - values: ['ldai 0x11111111', 'fu32', 'fu32', 286331153, 'ucmp'] - - values: ['ldai 0x88888888', 'fu32', 'fu32', 2290649224, 'ucmp'] + - values: ['ldai 0x00000000', 'fu32', 'fu32', 'movi', 0, 'ucmp', ''] + - values: ['ldai 0xffffffff', 'fu32', 'fu32', 'movi', 4294967295, 'ucmp', ''] + - values: ['ldai 0x11111111', 'fu32', 'fu32', 'movi', 286331153, 'ucmp', ''] + - values: ['ldai 0x88888888', 'fu32', 'fu32', 'movi', 2290649224, 'ucmp', ''] + # f32 + - values: ['fldai 0.0', 'ff32', 'ff32', 'fmovi', 0.0, 'fcmpg', ''] + bugid: ['3292'] + - values: ['fldai -6510615.0', 'ff32', 'ff32', 'fmovi', -6510615.0, 'fcmpg', ''] + bugid: ['3292'] + - values: ['fldai 0x7fffffff', 'ff32', 'ff32', 'fmovi', 0.0, 'fcmpg', 'subi 1'] + bugid: ['3292'] + - values: ['fldai 0x7f800000', 'ff32', 'ff32', 'fmovi', '0x7f800000', 'fcmpg', ''] + bugid: ['3292'] + - values: ['fldai 0xff800000', 'ff32', 'ff32', 'fmovi', '0xff800000', 'fcmpg', ''] + bugid: ['3292'] - file-name: "into_all_field_types_int" description: Version for integer types diff --git a/tests/cts-generator/cts-template/ststatic.64.yaml b/tests/cts-generator/cts-template/ststatic.64.yaml index 561654db35..e178cad3ff 100644 --- a/tests/cts-generator/cts-template/ststatic.64.yaml +++ b/tests/cts-generator/cts-template/ststatic.64.yaml @@ -215,6 +215,8 @@ tests: - R.fu32 - values: - R.fi32 + - values: + - R.ff32 - values: - R.fObj - values: @@ -305,34 +307,15 @@ tests: newarr v1, v1, i32[] lda.obj v1 - R.ff64 - # f32 - - values: - - ldai 0 - - R.ff32 - - values: - - ldai 0xCAFECAFE - - R.ff32 - - values: - - ldai.64 1 - - R.ff32 - - values: - - lda.null - - R.ff32 - - values: - - initobj Q.ctor - - R.ff32 - - values: - - | - movi v1, 10 - newarr v1, v1, i32[] - lda.obj v1 - - R.ff32 - file-name: "into_all_field_types" description: Check that accumulator value is stored in field isa: - description: If field type is f32, accumulator content will be implicitly converted from f64 to f32 before storing. + instructions: + - sig: ststatic.64 field_id + acc: in:b64 + format: [op_id_16] header-template: ['pandasm_header'] check-type: exit-positive tags: ['tsan'] @@ -393,43 +376,6 @@ tests: - | movi.64 v1, -6510615555426900571 cmp.64 v1 - # f32 - - values: - - fldai.64 0.0 - - ff32 - - ff32 - - | - fmovi.64 v1, 0.0 - fcmpg.64 v1 - - values: - - fldai.64 -6510615.0 - - ff32 - - ff32 - - | - fmovi.64 v1, -6510615.0 - fcmpg.64 v1 - - values: - - fldai.64 0x7FFFFFFFFFFFFFFF # NaN - - ff32 - - ff32 - - | - fmovi.64 v1, 0.0 - fcmpg.64 v1 - subi 1 - - values: - - fldai.64 0x7ff0000000000000 # + Inf - - ff32 - - ff32 - - | - fmovi.64 v1, 0x7ff0000000000000 - fcmpg.64 v1 - - values: - - fldai.64 0xfff0000000000000 # - Inf - - ff32 - - ff32 - - | - fmovi.64 v1, 0xfff0000000000000 - fcmpg.64 v1 # f64 - values: - fldai.64 0.0 diff --git a/tests/cts-generator/cts-template/ststatic.yaml b/tests/cts-generator/cts-template/ststatic.yaml index 8d1dd0c124..02b1a54d78 100644 --- a/tests/cts-generator/cts-template/ststatic.yaml +++ b/tests/cts-generator/cts-template/ststatic.yaml @@ -207,8 +207,6 @@ tests: - R.fu64 - values: - R.ff64 - - values: - - R.ff32 - values: - R.fObj - values: @@ -296,6 +294,28 @@ tests: newarr v1, v1, i32[] lda.obj v1 - R.fi32 + # f32 + - values: + - ldai 0 + - R.ff32 + - values: + - ldai 0xCAFECAFE + - R.ff32 + - values: + - ldai 1 + - R.ff32 + - values: + - lda.null + - R.ff32 + - values: + - initobj Q.ctor + - R.ff32 + - values: + - | + movi v1, 10 + newarr v1, v1, i32[] + lda.obj v1 + - R.ff32 - file-name: "into_all_field_types" @@ -312,47 +332,54 @@ tests: ststatic R.%s lda.null ldstatic R.%s - movi v1, %s + %s v1, %s %s v1 + %s jeqz success ldai 1 return success: cases: # u1 - - values: ['ldai 0x00000000', 'fu1', 'fu1', 0, 'ucmp'] - - values: ['ldai 0xffffffff', 'fu1', 'fu1', 1, 'ucmp'] + - values: ['ldai 0x00000000', 'fu1', 'fu1', 'movi', 0, 'ucmp', ''] + - values: ['ldai 0xffffffff', 'fu1', 'fu1', 'movi', 1, 'ucmp', ''] bugid: ['1848'] ignore: true - - values: ['ldai 0x00000001', 'fu1', 'fu1', 1, 'ucmp'] - - values: ['ldai 0xfffffffe', 'fu1', 'fu1', 0, 'ucmp'] + - values: ['ldai 0x00000001', 'fu1', 'fu1', 'movi', 1, 'ucmp', ''] + - values: ['ldai 0xfffffffe', 'fu1', 'fu1', 'movi', 0, 'ucmp', ''] bugid: ['1848'] ignore: true - - values: ['ldai 0x11111111', 'fu1', 'fu1', 1, 'ucmp'] + - values: ['ldai 0x11111111', 'fu1', 'fu1', 'movi', 1, 'ucmp', ''] bugid: ['1848'] ignore: true - - values: ['ldai 0x88888888', 'fu1', 'fu1', 0, 'ucmp'] + - values: ['ldai 0x88888888', 'fu1', 'fu1', 'movi', 0, 'ucmp', ''] bugid: ['1848'] ignore: true # u8 - - values: ['ldai 0x00000000', 'fu8', 'fu8', 0, 'ucmp'] - - values: ['ldai 0xffffffff', 'fu8', 'fu8', 255, 'ucmp'] - - values: ['ldai 0x000000ff', 'fu8', 'fu8', 255, 'ucmp'] - - values: ['ldai 0xffffff00', 'fu8', 'fu8', 0, 'ucmp'] - - values: ['ldai 0x11111111', 'fu8', 'fu8', 17, 'ucmp'] - - values: ['ldai 0x88888888', 'fu8', 'fu8', 136, 'ucmp'] + - values: ['ldai 0x00000000', 'fu8', 'fu8', 'movi', 0, 'ucmp', ''] + - values: ['ldai 0xffffffff', 'fu8', 'fu8', 'movi', 255, 'ucmp', ''] + - values: ['ldai 0x000000ff', 'fu8', 'fu8', 'movi', 255, 'ucmp', ''] + - values: ['ldai 0xffffff00', 'fu8', 'fu8', 'movi', 0, 'ucmp', ''] + - values: ['ldai 0x11111111', 'fu8', 'fu8', 'movi', 17, 'ucmp', ''] + - values: ['ldai 0x88888888', 'fu8', 'fu8', 'movi', 136, 'ucmp', ''] # u16 - - values: ['ldai 0x00000000', 'fu16', 'fu16', 0, 'ucmp'] - - values: ['ldai 0xffffffff', 'fu16', 'fu16', 65535, 'ucmp'] - - values: ['ldai 0x0000ffff', 'fu16', 'fu16', 65535, 'ucmp'] - - values: ['ldai 0xffff0000', 'fu16', 'fu16', 0, 'ucmp'] - - values: ['ldai 0x11111111', 'fu16', 'fu16', 4369, 'ucmp'] - - values: ['ldai 0x88888888', 'fu16', 'fu16', 34952, 'ucmp'] + - values: ['ldai 0x00000000', 'fu16', 'fu16', 'movi', 0, 'ucmp', ''] + - values: ['ldai 0xffffffff', 'fu16', 'fu16', 'movi', 65535, 'ucmp', ''] + - values: ['ldai 0x0000ffff', 'fu16', 'fu16', 'movi', 65535, 'ucmp', ''] + - values: ['ldai 0xffff0000', 'fu16', 'fu16', 'movi', 0, 'ucmp', ''] + - values: ['ldai 0x11111111', 'fu16', 'fu16', 'movi', 4369, 'ucmp', ''] + - values: ['ldai 0x88888888', 'fu16', 'fu16', 'movi', 34952, 'ucmp', ''] # u32 - - values: ['ldai 0x00000000', 'fu32', 'fu32', 0, 'ucmp'] - - values: ['ldai 0xffffffff', 'fu32', 'fu32', 4294967295, 'ucmp'] - - values: ['ldai 0x11111111', 'fu32', 'fu32', 286331153, 'ucmp'] - - values: ['ldai 0x88888888', 'fu32', 'fu32', 2290649224, 'ucmp'] + - values: ['ldai 0x00000000', 'fu32', 'fu32', 'movi', 0, 'ucmp', ''] + - values: ['ldai 0xffffffff', 'fu32', 'fu32', 'movi', 4294967295, 'ucmp', ''] + - values: ['ldai 0x11111111', 'fu32', 'fu32', 'movi', 286331153, 'ucmp', ''] + - values: ['ldai 0x88888888', 'fu32', 'fu32', 'movi', 2290649224, 'ucmp', ''] + # f32 + - values: ['fldai 0.0', 'ff32', 'ff32', 'fmovi', 0.0, 'fcmpg', ''] + - values: ['fldai -6510615.0', 'ff32', 'ff32', 'fmovi', -6510615.0, 'fcmpg', ''] + - values: ['fldai 0x7fffffff', 'ff32', 'ff32', 'fmovi', 0, 'fcmpg', 'subi 1'] + - values: ['fldai 0x7f800000', 'ff32', 'ff32', 'fmovi', '0x7f800000', 'fcmpg', ''] + - values: ['fldai 0xff800000', 'ff32', 'ff32', 'fmovi', '0xff800000', 'fcmpg', ''] - file-name: "into_all_field_types_int" description: Version for signed integer types diff --git a/tests/cts-generator/test-runner.rb b/tests/cts-generator/test-runner.rb index 2d69c92f65..6a9a459d16 100755 --- a/tests/cts-generator/test-runner.rb +++ b/tests/cts-generator/test-runner.rb @@ -274,7 +274,6 @@ else while file = queue.pop(true) runner = TestRunner::SingleTestRunner.new( file, 1, reporter_factory, $root_dir, $report_dir) - end runner.process_single if ($GLOBAL_TIMEOUT > 0 && (Time.now - start_time >= $GLOBAL_TIMEOUT)) puts "Global timeout reached, finish test execution" diff --git a/tests/verifier-tests/bug_3060.pa b/tests/verifier-tests/bug_3060.pa index a7396ee67f..cc2e7b5b85 100644 --- a/tests/verifier-tests/bug_3060.pa +++ b/tests/verifier-tests/bug_3060.pa @@ -15,7 +15,7 @@ movi v0, 1 newarr v1, v0, f32[] movi v2,0 - fldai.64 0 + fldai 0 fstarr.32 v1, v2 ldai 0 return diff --git a/verification/absint/abs_int_inl.h b/verification/absint/abs_int_inl.h index 375ba2406d..b8a6e11641 100644 --- a/verification/absint/abs_int_inl.h +++ b/verification/absint/abs_int_inl.h @@ -226,6 +226,11 @@ public: return inst_.GetSecondaryOpcode(); } + bool IsPrimaryOpcodeValid() const + { + return inst_.IsPrimaryOpcodeValid(); + } + bool IsRegDefined(int reg); const PandaString &ImageOf(const Type &type); @@ -395,6 +400,16 @@ public: AssignRegToReg(dst, ACC); } + template + bool HandleNop() + { + LOG_INST(); + DBGBRK(); + Sync(); + MoveToNextInst(); + return true; + } + template bool HandleMov() { @@ -487,6 +502,18 @@ public: return true; } + template + bool HandleFmovi() + { + LOG_INST(); + DBGBRK(); + uint16_t vd = inst_.GetVReg(); + Sync(); + SetReg(vd, F32); + MoveToNextInst(); + return true; + } + template bool HandleFmoviWide() { @@ -625,6 +652,17 @@ public: return true; } + template + bool HandleFldai() + { + LOG_INST(); + DBGBRK(); + Sync(); + SetAcc(F32); + MoveToNextInst(); + return true; + } + template bool HandleFldaiWide() { @@ -830,6 +868,15 @@ public: return CheckBinaryOp2(Types().Integral64Type(), Types().Integral64Type(), I32); } + template + bool HandleFcmpl() + { + LOG_INST(); + DBGBRK(); + Sync(); + return CheckBinaryOp2(F32, F32, I32); + } + template bool HandleFcmplWide() { @@ -839,6 +886,15 @@ public: return CheckBinaryOp2(F64, F64, I32); } + template + bool HandleFcmpg() + { + LOG_INST(); + DBGBRK(); + Sync(); + return CheckBinaryOp2(F32, F32, I32); + } + template bool HandleFcmpgWide() { @@ -1089,6 +1145,15 @@ public: return CheckBinaryOp2(Types().Integral64Type(), Types().Integral64Type(), I64); } + template + bool HandleFadd2() + { + LOG_INST(); + DBGBRK(); + Sync(); + return CheckBinaryOp2(F32, F32, F32); + } + template bool HandleFadd2Wide() { @@ -1126,6 +1191,15 @@ public: return CheckBinaryOp2(Types().Integral64Type(), Types().Integral64Type(), I64); } + template + bool HandleFsub2() + { + LOG_INST(); + DBGBRK(); + Sync(); + return CheckBinaryOp2(F32, F32, F32); + } + template bool HandleFsub2Wide() { @@ -1163,6 +1237,15 @@ public: return CheckBinaryOp2(Types().Integral64Type(), Types().Integral64Type(), I64); } + template + bool HandleFmul2() + { + LOG_INST(); + DBGBRK(); + Sync(); + return CheckBinaryOp2(F32, F32, F32); + } + template bool HandleFmul2Wide() { @@ -1172,6 +1255,17 @@ public: return CheckBinaryOp2(F64, F64, F64); } + template + bool HandleFdiv2() + { + LOG_INST(); + DBGBRK(); + Sync(); + // TODO(vdyadov): take into consideration possible exception generation + // context is of good precision here + return CheckBinaryOp2(F32, F32, F32); + } + template bool HandleFdiv2Wide() { @@ -1182,6 +1276,15 @@ public: return CheckBinaryOp2(F64, F64, F64); } + template + bool HandleFmod2() + { + LOG_INST(); + DBGBRK(); + Sync(); + return CheckBinaryOp2(F32, F32, F32); + } + template bool HandleFmod2Wide() { @@ -2162,7 +2265,7 @@ public: uint16_t v1 = inst_.GetVReg(); uint16_t v2 = inst_.GetVReg(); Sync(); - return CheckArrayStoreExact(v1, v2, Types().Float64Type(), {F32}); + return CheckArrayStoreExact(v1, v2, Types().Float32Type(), {F32}); } template @@ -2637,7 +2740,7 @@ public: template bool ProcessStobj(int vd, int vs, bool is_static) { - return ProcessStoreField(vd, vs, Types().Integral32Type(), is_static, CheckStobj); + return ProcessStoreField(vd, vs, Types().Bits32Type(), is_static, CheckStobj); } template @@ -2786,7 +2889,7 @@ public: LOG_INST(); DBGBRK(); Sync(); - return ProcessFieldLoad(INVALID_REG, Types().Integral32Type(), true); + return ProcessFieldLoad(INVALID_REG, Types().Bits32Type(), true); } template @@ -3697,98 +3800,6 @@ public: return inst_; } - // builtins - - template - bool HandleBuiltinI32tof32() - { - LOG_VERIFIER_DEBUG_BUILTIN("i32tof32"); - DBGBRK(); - Sync(); - return HandleConversion(I32, F32); - } - - template - bool HandleBuiltinI64tof32() - { - LOG_VERIFIER_DEBUG_BUILTIN("i64tof32"); - DBGBRK(); - Sync(); - return HandleConversion(I64, F32); - } - - template - bool HandleBuiltinF64tof32() - { - LOG_VERIFIER_DEBUG_BUILTIN("f64tof32"); - DBGBRK(); - Sync(); - return HandleConversion(F64, F32); - } - - template - bool HandleBuiltinFadd2f32() - { - LOG_INST(); - DBGBRK(); - Sync(); - return CheckBinaryOp2(F64, F64, F32); - } - - template - bool HandleBuiltinFsub2f32() - { - LOG_INST(); - DBGBRK(); - Sync(); - return CheckBinaryOp2(F64, F64, F32); - } - - template - bool HandleBuiltinFmul2f32() - { - LOG_INST(); - DBGBRK(); - Sync(); - return CheckBinaryOp2(F64, F64, F32); - } - - template - bool HandleBuiltinFdiv2f32() - { - LOG_INST(); - DBGBRK(); - Sync(); - return CheckBinaryOp2(F64, F64, F32); - } - - template - bool HandleBuiltinFmod2f32() - { - LOG_INST(); - DBGBRK(); - Sync(); - return CheckBinaryOp2(F64, F64, F32); - } - - template - bool HandleBuiltinFcmpl2f32() - { - LOG_INST(); - DBGBRK(); - Sync(); - return CheckBinaryOp2(F64, F64, I32); - } - - template - bool HandleBuiltinFcmpg2f32() - { - LOG_INST(); - DBGBRK(); - Sync(); - return CheckBinaryOp2(F64, F64, I32); - } - template bool HandleBuiltinCall_polymorphic_short() { @@ -3846,180 +3857,6 @@ public: return true; } - template - bool HandleBuiltinTern3() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.tern3"; - return true; - } - - template - bool HandleBuiltinQuatern4() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.quatern4"; - return true; - } - - template - bool HandleBuiltinQuin5() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.quin5"; - return true; - } - - template - bool HandleBuiltinR2i() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.r2i"; - return true; - } - - template - bool HandleBuiltinR3i() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.r3i"; - return true; - } - - template - bool HandleBuiltinR4i() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.r4i"; - return true; - } - - template - bool HandleBuiltinBin3() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.bin3"; - } - - template - bool HandleBuiltinBin5() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.bin5"; - } - - template - bool HandleBuiltinId() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.id"; - return true; - } - - template - bool HandleBuiltinMidr() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.midr"; - return true; - } - - template - bool HandleBuiltinIdr3i() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.idr3i"; - return true; - } - - template - bool HandleBuiltinIdi() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.idi"; - return true; - } - - template - bool HandleBuiltinIdr4i() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.idr4i"; - return true; - } - - template - bool HandleBuiltinI2r3() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.i2r3"; - return true; - } - - template - bool HandleBuiltinI2r2() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.i2r2"; - return true; - } - - template - bool HandleBuiltinImm() - { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.imm"; - return true; - } - - template - bool HandleBuiltinImr2() const - { - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.imr"; - return true; - } - - template - bool HandleBuiltinIdr3() const - { - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.idr3"; - return true; - } - - template - bool HandleBuiltinIdr4() const - { - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.idr4"; - return true; - } - - template - bool HandleBuiltinIdr6() const - { - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "builtin.idr6"; - return true; - } - #include "abs_int_builtin_handlers.h" static PandaString RegisterName(int reg_idx, bool capitalize = false) diff --git a/verification/absint/exec_context.h b/verification/absint/exec_context.h index 4f1e839ecf..f0d78ca10b 100644 --- a/verification/absint/exec_context.h +++ b/verification/absint/exec_context.h @@ -217,7 +217,6 @@ private: PandaUnorderedMap RegContextOnCheckPoint_; RegContext CurrentRegContext_; }; - } // namespace panda::verifier #endif // PANDA_VERIFICATION_ABSINT_EXEC_CONTEXT_H_ diff --git a/verification/cflow/instructions_map.h b/verification/cflow/instructions_map.h index ee88675fee..9b6e6bfbc5 100644 --- a/verification/cflow/instructions_map.h +++ b/verification/cflow/instructions_map.h @@ -21,7 +21,6 @@ #include namespace panda::verifier { - class InstructionsMap { public: bool PutInstruction(const void *pc_curr, const void *pc_next) @@ -36,27 +35,22 @@ public: pc_next = reinterpret_cast(reinterpret_cast(pc_next) - 1); return AddrMap_.Mark(pc_curr, pc_next); } - bool PutInstruction(const void *pc_ptr, size_t sz) { return PutInstruction(pc_ptr, reinterpret_cast(reinterpret_cast(pc_ptr) + sz)); } - bool MarkCodeBlock(const void *pc_start, const void *pc_end) { return AddrMap_.Mark(pc_start, pc_end); } - bool MarkCodeBlock(const void *pc_start, size_t sz) { return AddrMap_.Mark(pc_start, reinterpret_cast(reinterpret_cast(pc_start) + sz - 1)); } - bool ClearCodeBlock(const void *pc_start, const void *pc_end) { return AddrMap_.Clear(pc_start, pc_end); } - bool ClearCodeBlock(const void *pc_start, size_t sz) { return AddrMap_.Clear(pc_start, reinterpret_cast(reinterpret_cast(pc_start) + sz - 1)); @@ -68,7 +62,6 @@ public: : InstructionsMap(ptr_start, reinterpret_cast(reinterpret_cast(ptr_start) + size - 1)) { } - InstructionsMap() = delete; ~InstructionsMap() = default; @@ -93,7 +86,6 @@ private: AddrMap AddrMap_; friend class JumpsMap; }; - } // namespace panda::verifier #endif // PANDA_VERIFICATION_CFLOW_INSTRUCTIONS_MAP_H_ diff --git a/verification/cflow/jumps_map.h b/verification/cflow/jumps_map.h index fe42fa67c2..3d15ed0547 100644 --- a/verification/cflow/jumps_map.h +++ b/verification/cflow/jumps_map.h @@ -27,7 +27,6 @@ #include namespace panda::verifier { - class JumpsMap { public: struct FromTo { @@ -52,12 +51,10 @@ public: } JumpsMap(const void *pc_start_ptr, const void *pc_end_ptr) : AddrMap_(pc_start_ptr, pc_end_ptr) {} - JumpsMap(const void *pc_start_ptr, size_t size) : JumpsMap(pc_start_ptr, reinterpret_cast(reinterpret_cast(pc_start_ptr) + size - 1)) { } - JumpsMap() = delete; ~JumpsMap() = default; @@ -92,12 +89,10 @@ public: } } } - bool IsConflictingWith(const InstructionsMap &inst_map) const { return AddrMap_.HasCommonMarks(inst_map.AddrMap_); } - template bool GetFirstConflictingJump(const InstructionsMap &inst_map, PtrType *pc_jump_ptr, PtrType *pc_target_ptr) const { @@ -118,7 +113,6 @@ private: PandaVector Target_; PandaVector FromTo_; }; - } // namespace panda::verifier #endif // PANDA_VERIFICATION_CFLOW_JUMPS_MAP_H_ diff --git a/verification/debug/README.md b/verification/debug/README.md index 0d193beac9..6d0b59a78e 100644 --- a/verification/debug/README.md +++ b/verification/debug/README.md @@ -47,4 +47,4 @@ debug { ``` -Note newline after last `}`. \ No newline at end of file +Note newline after last `}`. diff --git a/verification/debug/config_load.cpp b/verification/debug/config_load.cpp index cd41c73a60..2871db0dd3 100644 --- a/verification/debug/config_load.cpp +++ b/verification/debug/config_load.cpp @@ -73,7 +73,6 @@ bool LoadConfig(std::string_view filename) if (!file.IsValid()) { break; } - auto size = file.GetFileSize(); if (!size.HasValue()) { file.Close(); diff --git a/verification/gen/templates/abs_int_builtin_handlers.h.erb b/verification/gen/templates/abs_int_builtin_handlers.h.erb index a7749a14a6..8660021bd7 100644 --- a/verification/gen/templates/abs_int_builtin_handlers.h.erb +++ b/verification/gen/templates/abs_int_builtin_handlers.h.erb @@ -14,6 +14,8 @@ */ % builtin_kinds = PandaBuiltins::builtins.map(&:insn).uniq +% builtin_mnemonics = PandaBuiltins::instructions.map { |instruction| instruction.sig.split(' ').at(0) } +% undefined_builtins = builtin_mnemonics.select { |mnemonic| not builtin_kinds.include?(mnemonic) }.uniq % builtin_kinds.each do |kind| % mnemonic = kind.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join % builtins = PandaBuiltins::builtins.select { |builtin| builtin.insn == kind }.sort_by(&:id) @@ -33,3 +35,14 @@ bool Handle<%= mnemonic %>() { } % end +% undefined_builtins.each do |builtin| +% mnemonic = builtin.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join +template +bool Handle<%= mnemonic %>() { + LOG_INST(); + LOG(DEBUG, VERIFIER) << "ABSINT: " + << "<%= builtin %>"; + return true; +} + +%end diff --git a/verification/gen/templates/abs_int_inl_compat_checks.h.erb b/verification/gen/templates/abs_int_inl_compat_checks.h.erb index 865ec56eaa..c84a11fa02 100644 --- a/verification/gen/templates/abs_int_inl_compat_checks.h.erb +++ b/verification/gen/templates/abs_int_inl_compat_checks.h.erb @@ -21,7 +21,6 @@ % checks = Verification.compatibility_checks namespace panda::verifier { - struct CheckResult { VerificationStatus status; const char* msg; @@ -88,4 +87,4 @@ inline const CheckResult& Check<%= check_name.to_s %>(<%= type1 %> x, <%= type2 } // namespace panda::verifier -#endif // PANDA_VERIFICATION_ABS_INT_INL_COMPAT_CHECKS_H_ \ No newline at end of file +#endif // PANDA_VERIFICATION_ABS_INT_INL_COMPAT_CHECKS_H_ diff --git a/verification/gen/templates/abs_int_inl_gen.h.erb b/verification/gen/templates/abs_int_inl_gen.h.erb index c1d36f76eb..a54ab4853c 100644 --- a/verification/gen/templates/abs_int_inl_gen.h.erb +++ b/verification/gen/templates/abs_int_inl_gen.h.erb @@ -33,7 +33,7 @@ VerificationStatus AbstractInterpret([[maybe_unused]] VerificationLevel v_level, AbsIntInstructionHandler handler(v_ctx, pc, code_type); uint8_t secondary_opcode; - if(handler.GetPrimaryOpcode() > <%= Panda::dispatch_table.primary_opcode_bound %>) { + if (!handler.IsPrimaryOpcodeValid()) { LOG(ERROR, VERIFIER) << "Incorrect opcode"; return VerificationStatus::ERROR; } @@ -41,19 +41,28 @@ VerificationStatus AbstractInterpret([[maybe_unused]] VerificationLevel v_level, % Panda::instructions.each do |i| % mnemonic = i.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join -HANDLE_<%= Panda::dispatch_table.instruction_handler_name(i) %>: +HANDLE_<%= i.handler_name %>: +% if i.namespace != 'core' +#ifdef PANDA_WITH_<%= i.namespace.upcase %> +% end if (!handler.template Handle<%= mnemonic %>>()) { return handler.GetStatus(); } - if(handler.GetPrimaryOpcode() > <%= Panda::dispatch_table.primary_opcode_bound %>) { + + if (!handler.IsPrimaryOpcodeValid()) { LOG(ERROR, VERIFIER) << "Incorrect opcode"; return VerificationStatus::ERROR; } +% if i.namespace != 'core' +#endif // PANDA_WITH_<%= i.namespace.upcase %> +% end goto* dispatch_table[handler.GetPrimaryOpcode()]; % end - +HANDLE_INVALID: + LOG(ERROR, VERIFIER) << "Incorrect opcode"; + return VerificationStatus::ERROR; % Panda::prefixes.each do |p| -HANDLE_<%= Panda::dispatch_table.prefix_hanlder_name(p) %>: +HANDLE_<%= p.handler_name %>: secondary_opcode = handler.GetSecondaryOpcode(); LOG(DEBUG, VERIFIER) << "CFLOW: Prefix subdispatch: " << "<%= p.name %>, " << secondary_opcode; diff --git a/verification/gen/templates/cflow_iterate_inl_gen.h.erb b/verification/gen/templates/cflow_iterate_inl_gen.h.erb index bb7457c9c2..68b45762c3 100644 --- a/verification/gen/templates/cflow_iterate_inl_gen.h.erb +++ b/verification/gen/templates/cflow_iterate_inl_gen.h.erb @@ -30,6 +30,10 @@ public: return inst_.GetSecondaryOpcode(); } + bool IsPrimaryOpcodeValid() const + { + return inst_.IsPrimaryOpcodeValid(); + } #include "cflow_iterate_inl_gen_builtin_handlers.h" @@ -120,24 +124,33 @@ CflowStatus IterateOverInstructions(const uint8_t* pc, const uint8_t* from, cons std::optional status; uint8_t secondary_opcode; - ASSERT(handler.GetPrimaryOpcode() <= <%= Panda::dispatch_table.primary_opcode_bound %>); + ASSERT(handler.IsPrimaryOpcodeValid()); goto* dispatch_table[handler.GetPrimaryOpcode()]; % Panda::instructions.each do |i| % mnemonic = i.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join -HANDLE_<%= Panda::dispatch_table.instruction_handler_name(i) %>: +HANDLE_<%= i.handler_name %>: status = handler.template Handle<%= mnemonic %>>(); if (status) { return *status; } - if (handler.GetPrimaryOpcode() > <%= Panda::dispatch_table.primary_opcode_bound %>) { + if (!handler.IsPrimaryOpcodeValid()) { LOG(DEBUG, VERIFIER) << "Opcode value is out of range. " - << "Current value is: " << handler.GetPrimaryOpcode() - << "Maximum allowed value is: " << <%= Panda::dispatch_table.primary_opcode_bound %>; + << "Current value is: " << static_cast(handler.GetPrimaryOpcode()) + << ". Allowed value is in the interval: [0, <%= Panda::dispatch_table.invalid_non_prefixed_interval.min - 1 %>] U " + << "[<%= Panda::dispatch_table.invalid_non_prefixed_interval.max + 1 %>, <%= Panda::dispatch_table.invalid_prefixes_interval.min + 1 %>] U " + << "[<%= Panda::dispatch_table.invalid_prefixes_interval.max + 1 %>, 255]"; return CflowStatus::ERROR; } goto* dispatch_table[handler.GetPrimaryOpcode()]; % end +HANDLE_INVALID: + LOG(DEBUG, VERIFIER) << "Opcode value is out of range. " + << "Current value is: " << static_cast(handler.GetPrimaryOpcode()) + << ". Allowed value is in the interval: [0, <%= Panda::dispatch_table.invalid_non_prefixed_interval.min - 1 %>] U " + << "[<%= Panda::dispatch_table.invalid_non_prefixed_interval.max + 1 %>, <%= Panda::dispatch_table.invalid_prefixes_interval.min + 1 %>] U " + << "[<%= Panda::dispatch_table.invalid_prefixes_interval.max + 1 %>, 255]"; + return CflowStatus::ERROR; % Panda::prefixes.each do |p| -HANDLE_<%= Panda::dispatch_table.prefix_hanlder_name(p) %>: +HANDLE_<%= p.handler_name %>: secondary_opcode = handler.GetSecondaryOpcode(); LOG(DEBUG, VERIFIER) << "CFLOW: Prefix subdispatch: " << "<%= p.name %>, " << secondary_opcode; diff --git a/verification/gen/templates/job_fill_gen.h.erb b/verification/gen/templates/job_fill_gen.h.erb index 353866ce37..8f5996f2fb 100644 --- a/verification/gen/templates/job_fill_gen.h.erb +++ b/verification/gen/templates/job_fill_gen.h.erb @@ -40,7 +40,7 @@ bool ResolveIdentifiersForJob(CacheOfRuntimeThings& cache, Job& job, const uint8 BytecodeInstructionSafe inst{start, start, end}; uint8_t secondary_opcode; - ASSERT(inst.GetPrimaryOpcode() <= <%= Panda::dispatch_table.primary_opcode_bound %>); + ASSERT(inst.IsPrimaryOpcodeValid()); goto* dispatch_table[inst.GetPrimaryOpcode()]; % Panda::instructions.each do |i| @@ -153,10 +153,12 @@ HANDLE_<%= i.opcode.upcase %>: { auto next_inst = inst.GetNext(); - if (inst.GetPrimaryOpcode() > <%= Panda::dispatch_table.primary_opcode_bound %>) { + if (!inst.IsPrimaryOpcodeValid()) { LOG(DEBUG, VERIFIER) << "Opcode value is out of range. " - << "Current value is: " << inst.GetPrimaryOpcode() - << "Maximum allowed value is: " << <%= Panda::dispatch_table.primary_opcode_bound %>; + << "Current value is: " << static_cast(inst.GetPrimaryOpcode()) + << ". Allowed value is in the interval: [0, <%= Panda::dispatch_table.invalid_non_prefixed_interval.min - 1 %>] U " + << "[<%= Panda::dispatch_table.invalid_non_prefixed_interval.max + 1 %>, <%= Panda::dispatch_table.invalid_prefixes_interval.min + 1 %>] U " + << "[<%= Panda::dispatch_table.invalid_prefixes_interval.max + 1 %>, 255]"; return false; } if (!next_inst.IsValid()) { @@ -169,9 +171,11 @@ HANDLE_<%= i.opcode.upcase %>: } goto* dispatch_table[inst.GetPrimaryOpcode()]; % end - +HANDLE_INVALID: + LOG(ERROR, VERIFIER) << "Incorrect opcode"; + return false; % Panda::prefixes.each do |p| -HANDLE_<%= Panda::dispatch_table.prefix_hanlder_name(p) %>: +HANDLE_<%= p.handler_name %>: secondary_opcode = inst.GetSecondaryOpcode(); LOG(DEBUG, VERIFIER) << "Prefix subdispatch: " << "<%= p.name %>, " << secondary_opcode; diff --git a/verification/util/tests/verifier_test.h b/verification/util/tests/verifier_test.h index 28024f526b..c1e1fa79a1 100644 --- a/verification/util/tests/verifier_test.h +++ b/verification/util/tests/verifier_test.h @@ -28,7 +28,7 @@ public: RuntimeOptions options; options.SetShouldLoadBootPandaFiles(false); options.SetShouldInitializeIntrinsics(false); - options.SetObjectPoolSize(64_MB); + options.SetHeapSizeLimit(64_MB); options.SetVerificationEnabled(true); Runtime::Create(options); thread_ = panda::MTManagedThread::GetCurrent(); diff --git a/verification/verification.yaml b/verification/verification.yaml index a13f007f51..4ef2b68e69 100644 --- a/verification/verification.yaml +++ b/verification/verification.yaml @@ -195,6 +195,14 @@ compatibility_checks: - i64 size: - u64 + f32: + _default: wrong_acc + unknown: + - invalid + - void + - reference + ok: f32 + precision: f64 StobjWide: _domains: -- Gitee From 0c032663dbad28ab627729f1a14eea5a3e8ca2d6 Mon Sep 17 00:00:00 2001 From: y00576111 Date: Wed, 8 Sep 2021 10:01:07 +0800 Subject: [PATCH 2/6] update runtime_core code Signed-off-by: y00576111 Change-Id: I9eade652c4a35d0565ef89198f223c63c1cef398 --- docs/images/def-use-structure.png | Bin 65289 -> 0 bytes docs/images/osr_trigger.png | Bin 46737 -> 0 bytes isa/BUILD.gn | 6 +++--- libpandafile/BUILD.gn | 2 +- runtime/BUILD.gn | 1 + 5 files changed, 5 insertions(+), 4 deletions(-) delete mode 100644 docs/images/def-use-structure.png delete mode 100644 docs/images/osr_trigger.png diff --git a/docs/images/def-use-structure.png b/docs/images/def-use-structure.png deleted file mode 100644 index dd9c29ebcd6ee05039a86789013a4ad579c52e58..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65289 zcmaI82Ut@}*EUQ-0-=W@1Zkm35hQ>D(wlT?D$)tk6%bT;%^m*R*^Bmv*y6|jH*x7s5%$hZ8?)zR7W2mo5LwTH%goK1fTT9)T zgan2mA%QF*$iOFjhE{VVBxn+Cb(M?0)=T%`X-pj-UfU!oC!w3ILc^!^8AN;$D=#Q$ z@zX0SjWyR)JrK+vCnh*T`Aw4!-ikI(9xY)izCI}Tq+6vQR_7M{PLwd z7#SHEB^5;y$zOg@nFIkQ47I%M>3EnH?q5I3^!ITpnrH~azke|D5K2@e7te7mD4+7b ze;{FsfB6*3hxLVm_bI8LPWso&h_8o|1^v4f;1j|cOc09-j&?@>#fT&lIQ8z|tV_bp zP#6+0`^W+1zgU0<25kP#G&H1@@jlLWhdUqtH`9Ot3#5PjL!^K*q;*YAomBg8MhIg2 z$^X*FI2g474jMTV6-}1%HzN!Q_v!vVcDcarRyukbzP}j(29E3BqXs_t{~tKyLs*mCE*RcljK;@6VojwmeI@r!*m%XL6^6?dKB9~ISM*MO3nUIx_ zXSFj<-IMOMwfOby4BQkYsp-=5QLcg_C8PxZ7(M!P$&=qI7^FP#Tk z(t_>}fR`Vt5yars)P18BPW(Z;n}?FdOB8?c({Nj8FhACHvfk`AlMq8>RH~K0A0yXC zKl0KgRm7_HA`}Xh|A4r5g7{}S*uDnA`Tf&7>M;!GBB@zhnty%#zYe{I#BVK+Q%N1N z%Xt?^nPV$|bw@VN27wwW{65#6A#rs`FhTOq2H~P8HdiJrbkaqH{Jwwr;h|fcOEmOQ zlOP6*3nQn~d7E?g?2A7};=l7bSO?rgt;E6R9s5V$P#a9Yj%B$jB>gMa_};}mfyYgS z99ik4333nQpZk7VVA$Z#K!H7n{nC?l~h3o{bNc2xl8t@oP0VJ;m_1PPr zqrV;V{i^?t5~Z6ik}U7Hp|$b(O+)zY-hVVI3Fm|e+;}6vfI=-~b(x){2v;SD96Fgp z!Z`mGBoD!#Acak9j!L17nAjsD!u|Pw%>D%)kF{wPzwMQKT}h6f@i;T6)(8KNx;TB} zGj$+#pF5LN#B3CQBu4x(3R;9}*h9Un{NX->yQkk&M`qS|Rlt%?Xz0CDLt~kbB#UrH zkMucQCTc6el#A8>N5iJ=phz*y8yTM!OD>BmlV5rnl<#I>MCoF1X8V0

t8Ok2$o* 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%0AwWry{SZVH*P8GD8At&jhz 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 QOcD6lS~=3LQ<1n7W-1EEJ-O#Nm^7QWE)%2 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 axkmF~XU9&zq&Fz|voJkua^KiJ;(q|X|KZpG diff --git a/isa/BUILD.gn b/isa/BUILD.gn index 64c028b09c..62aa71f001 100644 --- a/isa/BUILD.gn +++ b/isa/BUILD.gn @@ -17,15 +17,15 @@ action("isa_combine") { script = "$ark_root/isa/combine.rb" inputs = [ "$ark_root/isa/isa.yaml", - "$ark_root/../js_runtime/ecmascript/ecma_isa.yaml" + "$ark_root/../js_runtime/ecmascript/ecma_isa.yaml", ] input0 = rebase_path(inputs[0], root_build_dir) input1 = rebase_path(inputs[1], root_build_dir) - outputs = ["$root_gen_dir/isa/isa.yaml"] + outputs = [ "$root_gen_dir/isa/isa.yaml" ] args = [ "-d", "$input0,$input1", "-o", - rebase_path(outputs[0], root_build_dir) + rebase_path(outputs[0], root_build_dir), ] } diff --git a/libpandafile/BUILD.gn b/libpandafile/BUILD.gn index 200373ac2a..8c74d927d2 100644 --- a/libpandafile/BUILD.gn +++ b/libpandafile/BUILD.gn @@ -31,7 +31,6 @@ config("arkfile_public_config") { libarkfile_sources = [ "annotation_data_accessor.cpp", - "file_format_version.cpp", "bytecode_emitter.cpp", "class_data_accessor.cpp", "code_data_accessor.cpp", @@ -39,6 +38,7 @@ libarkfile_sources = [ "debug_info_extractor.cpp", "field_data_accessor.cpp", "file.cpp", + "file_format_version.cpp", "file_item_container.cpp", "file_items.cpp", "file_writer.cpp", diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index e62d543060..1edc9db4c3 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -333,6 +333,7 @@ template("gen_intrinsics_yaml") { action("$target_name") { script = "$ark_root/runtime/templates/gen_intrinsics_data.rb" + # rerun action when data file or template file update inputs = [ template_file ] inputs += invoker.data_files -- Gitee From 9eda24b6357431b67de43a254084b3db27995c61 Mon Sep 17 00:00:00 2001 From: y00576111 Date: Wed, 8 Sep 2021 11:56:04 +0800 Subject: [PATCH 3/6] format gni Signed-off-by: y00576111 Change-Id: Ia2491d01ba796315e2a70dc29504fa0da31b107a --- ark_config.gni | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ark_config.gni b/ark_config.gni index 10ddc2c113..057ccd8058 100644 --- a/ark_config.gni +++ b/ark_config.gni @@ -170,7 +170,7 @@ template("ark_isa_gen") { isa_requires += invoker.requires } - dependencies = ["$ark_root/isa:isa_combine"] + dependencies = [ "$ark_root/isa:isa_combine" ] if (defined(invoker.extra_dependencies)) { dependencies += invoker.extra_dependencies } -- Gitee From deac647c19389d3782abbdd9bb2c9c5ca1e1733d Mon Sep 17 00:00:00 2001 From: yaojian16 Date: Wed, 8 Sep 2021 03:59:47 +0000 Subject: [PATCH 4/6] update README_zh.md. Signed-off-by: y00576111 --- README_zh.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_zh.md b/README_zh.md index 72bcfb6148..2873a55bc5 100644 --- a/README_zh.md +++ b/README_zh.md @@ -133,7 +133,7 @@ ark_dissam [选项] 输入文件 输出文件 ## 相关仓 -[方舟运行时子系统](https://gitee.com/openharmony/ark_js_runtime/blob/master/docs/%E6%96%B9%E8%88%9F%E8%BF%90%E8%A1%8C%E6%97%B6%E5%AD%90%E7%B3%BB%E7%BB%9F.md) +[方舟运行时子系统](https://gitee.com/openharmony/ark_js_runtime/blob/master/docs/ARK-Runtime-Subsystem-zh.md) **[ark/runtime\_core](README_zh.md)** -- Gitee From 9056b76ebee3df8312958f12b58c7ada3d12caf5 Mon Sep 17 00:00:00 2001 From: Bolshov Maxim Date: Tue, 7 Sep 2021 21:25:50 +0300 Subject: [PATCH 5/6] Remove builtins Signed-off-by: Bolshov Maxim --- assembler/BUILD.gn | 31 -- assembler/CMakeLists.txt | 30 -- assembler/asm_isapi.rb | 4 - assembler/templates/builtin_parsing.cpp.erb | 63 --- .../templates/builtin_parsing_tests.cpp.erb | 146 ------- assembler/templates/ins_create_api.h.erb | 2 - .../templates/ins_create_builtins_api.h.erb | 60 --- assembler/templates/opcode_parsing.h.erb | 4 +- disassembler/BUILD.gn | 10 - disassembler/CMakeLists.txt | 9 - disassembler/disassembler.cpp | 85 ++++ .../templates/get_instructions.cpp.erb | 143 ------- disassembler/tests/sources/builtins.pa | 30 -- isa/builtins.yaml | 398 ------------------ isa/builtinsapi.rb | 224 ---------- isa/isapi.rb | 7 - libpandafile/BUILD.gn | 10 - libpandafile/CMakeLists.txt | 8 - libpandafile/bytecode_instruction.h | 4 - .../templates/bytecode_builtin_enum_gen.h.erb | 22 - .../bytecode_instruction-inl_gen.h.erb | 15 - runtime/BUILD.gn | 20 - runtime/CMakeLists.txt | 20 - .../interpreter/templates/builtin_count.h.erb | 21 - .../templates/builtin_dispatch.h.erb | 23 - .../templates/builtin_handlers.h.erb | 57 --- .../templates/builtin_insn_handlers.h.erb | 30 -- .../templates/interpreter-inl_gen.h.erb | 10 +- verification/absint/abs_int_inl.h | 59 --- verification/gen/BUILD.gn | 17 - verification/gen/CMakeLists.txt | 18 +- .../templates/abs_int_builtin_handlers.h.erb | 48 --- .../gen/templates/cflow_iterate_inl_gen.h.erb | 7 +- ...low_iterate_inl_gen_builtin_handlers.h.erb | 51 --- verification/messages.yaml | 6 - 35 files changed, 90 insertions(+), 1602 deletions(-) delete mode 100644 assembler/templates/builtin_parsing.cpp.erb delete mode 100644 assembler/templates/builtin_parsing_tests.cpp.erb delete mode 100644 assembler/templates/ins_create_builtins_api.h.erb delete mode 100644 disassembler/templates/get_instructions.cpp.erb delete mode 100644 disassembler/tests/sources/builtins.pa delete mode 100644 isa/builtins.yaml delete mode 100755 isa/builtinsapi.rb delete mode 100644 libpandafile/templates/bytecode_builtin_enum_gen.h.erb delete mode 100644 runtime/interpreter/templates/builtin_count.h.erb delete mode 100644 runtime/interpreter/templates/builtin_dispatch.h.erb delete mode 100644 runtime/interpreter/templates/builtin_handlers.h.erb delete mode 100644 runtime/interpreter/templates/builtin_insn_handlers.h.erb delete mode 100644 verification/gen/templates/abs_int_builtin_handlers.h.erb delete mode 100644 verification/gen/templates/cflow_iterate_inl_gen_builtin_handlers.h.erb diff --git a/assembler/BUILD.gn b/assembler/BUILD.gn index 0c0297880b..2061bb7614 100644 --- a/assembler/BUILD.gn +++ b/assembler/BUILD.gn @@ -25,7 +25,6 @@ config("arkassembler_public_config") { } libarkassembler_sources = [ - "$target_gen_dir/builtin_parsing.cpp", "$target_gen_dir/ins_to_string.cpp", "annotation.cpp", "assembly-emitter.cpp", @@ -55,9 +54,7 @@ ohos_shared_library("libarkassembler") { deps = [ ":ark_asm_ecmascript_meta_gen_h", - ":ark_asm_ins_create_builtins_api_h", ":ark_asm_meta_gen_h", - ":builtin_parsing_cpp", ":isa_gen_libarkassembler_ins_create_api_h", ":isa_gen_libarkassembler_ins_emit_h", ":isa_gen_libarkassembler_ins_to_string_cpp", @@ -82,9 +79,7 @@ ohos_static_library("libarkassembler_frontend_static") { deps = [ ":ark_asm_ecmascript_meta_gen_h", - ":ark_asm_ins_create_builtins_api_h", ":ark_asm_meta_gen_h", - ":builtin_parsing_cpp", ":isa_gen_libarkassembler_ins_create_api_h", ":isa_gen_libarkassembler_ins_emit_h", ":isa_gen_libarkassembler_ins_to_string_cpp", @@ -140,11 +135,6 @@ ark_isa_gen("isa_gen_libarkassembler") { "asm_isapi.rb", "../libpandafile/pandafile_isapi.rb", ] - extra_dependencies = [ - ":ark_asm_ins_create_builtins_api_h", - ":builtin_parsing_cpp", - ":builtin_parsing_tests_cpp", - ] } ark_gen_file("ark_asm_meta_gen_h") { @@ -154,27 +144,6 @@ ark_gen_file("ark_asm_meta_gen_h") { output_file = "$target_gen_dir/meta_gen.h" } -ark_gen_file("ark_asm_ins_create_builtins_api_h") { - template_file = "templates/ins_create_builtins_api.h.erb" - data_file = "../isa/builtins.yaml" - requires = [ "../isa/builtinsapi.rb" ] - output_file = "$target_gen_dir/ins_create_builtins_api.h" -} - -ark_gen_file("builtin_parsing_cpp") { - template_file = "templates/builtin_parsing.cpp.erb" - data_file = "../isa/builtins.yaml" - requires = [ "../isa/builtinsapi.rb" ] - output_file = "$target_gen_dir/builtin_parsing.cpp" -} - -ark_gen_file("builtin_parsing_tests_cpp") { - template_file = "templates/builtin_parsing_tests.cpp.erb" - data_file = "../isa/builtins.yaml" - requires = [ "../isa/builtinsapi.rb" ] - output_file = "$target_gen_dir/builtin_parsing_tests.cpp" -} - ark_gen_file("ark_asm_ecmascript_meta_gen_h") { template_file = "templates/meta_gen.cpp.erb" data_file = "extensions/ecmascript/metadata.yaml" diff --git a/assembler/CMakeLists.txt b/assembler/CMakeLists.txt index a084ddaf67..ed87b64d7d 100644 --- a/assembler/CMakeLists.txt +++ b/assembler/CMakeLists.txt @@ -16,33 +16,9 @@ project(assembler CXX) panda_add_executable(ark_asm pandasm.cpp) -set(INS_CREATE_BUILTINS_API_H ${CMAKE_CURRENT_BINARY_DIR}/ins_create_builtins_api.h) -panda_gen_file( - DATAFILE ${PANDA_ROOT}/isa/builtins.yaml - TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/templates/ins_create_builtins_api.h.erb - REQUIRES ${PANDA_ROOT}/isa/builtinsapi.rb - OUTPUTFILE ${INS_CREATE_BUILTINS_API_H} -) - -set(BUILTIN_PARSING_CPP ${CMAKE_CURRENT_BINARY_DIR}/builtin_parsing.cpp) -panda_gen_file( - DATAFILE ${PANDA_ROOT}/isa/builtins.yaml - TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/templates/builtin_parsing.cpp.erb - REQUIRES ${PANDA_ROOT}/isa/builtinsapi.rb - OUTPUTFILE ${BUILTIN_PARSING_CPP} -) - set(PANDASM_BIN_TESTS ${CMAKE_CURRENT_BINARY_DIR}/tests) file(MAKE_DIRECTORY "${PANDASM_BIN_TESTS}") -set(BUILTIN_PARSING_TESTS_CPP ${PANDASM_BIN_TESTS}/builtin_parsing_tests.cpp) -panda_gen_file( - DATAFILE ${PANDA_ROOT}/isa/builtins.yaml - TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/templates/builtin_parsing_tests.cpp.erb - REQUIRES ${PANDA_ROOT}/isa/builtinsapi.rb - OUTPUTFILE ${BUILTIN_PARSING_TESTS_CPP} -) - panda_isa_gen( TEMPLATES "isa.h.erb" @@ -54,10 +30,6 @@ panda_isa_gen( REQUIRES "${CMAKE_CURRENT_SOURCE_DIR}/asm_isapi.rb" "${PANDA_ROOT}/libpandafile/pandafile_isapi.rb" - EXTRA_DEPENDENCIES - ${INS_CREATE_BUILTINS_API_H} - ${BUILTIN_PARSING_CPP} - ${BUILTIN_PARSING_TESTS_CPP} ) add_library(arkassembler ${PANDA_DEFAULT_LIB_TYPE} @@ -73,7 +45,6 @@ add_library(arkassembler ${PANDA_DEFAULT_LIB_TYPE} ins_to_string.cpp extensions/extensions.cpp extensions/ecmascript/ecmascript_meta.cpp - builtin_parsing.cpp ) add_dependencies(arkassembler isa_gen_assembler arkfile) @@ -122,7 +93,6 @@ panda_add_gtest( tests/parser_test.cpp tests/emitter_test.cpp tests/mangling_tests.cpp - ${PANDASM_BIN_TESTS}/builtin_parsing_tests.cpp LIBRARIES arkbase arkassembler SANITIZERS diff --git a/assembler/asm_isapi.rb b/assembler/asm_isapi.rb index 7481a51ba5..8b18df34d9 100755 --- a/assembler/asm_isapi.rb +++ b/assembler/asm_isapi.rb @@ -17,10 +17,6 @@ Instruction.class_eval do mnemonic.tr('.', '_').upcase end - def builtin? - stripped_mnemonic == 'builtin' - end - def call? properties.include?('call') || stripped_mnemonic == 'initobj' end diff --git a/assembler/templates/builtin_parsing.cpp.erb b/assembler/templates/builtin_parsing.cpp.erb deleted file mode 100644 index 2bc8fbd9d5..0000000000 --- a/assembler/templates/builtin_parsing.cpp.erb +++ /dev/null @@ -1,63 +0,0 @@ -/* - * 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 "assembly-parser.h" - -// Autogenerated file -- DO NOT EDIT! - -namespace panda::pandasm { - -int64_t Parser::MnemonicToBuiltinId() { - [[maybe_unused]] const auto token = context_.GiveToken(); - - --context_; - [[maybe_unused]] const auto ins = context_.GiveToken(); - ++context_; - -% PandaBuiltins::builtins.each_with_index do |builtin, i| -% - <%= i != 0 ? "else " : "" %>if (token == "<%= builtin.mnemonic%>" && ins == "<%= builtin.insn%>") { - return static_cast(<%= builtin.id%>); - } -% -% end - - return -1; -} - -bool Parser::ParseOperandBuiltinMnemonic() { - if (context_.err.err != Error::ErrorType::ERR_NONE) { - return false; - } - - if (*context_ != Token::Type::ID) { - context_.err = GetError("Expected Mnemonic", Error::ErrorType::ERR_BAD_OPERAND); - return false; - } - - auto builtin_id = MnemonicToBuiltinId(); - if (builtin_id != -1) { - curr_ins_->imms.insert(curr_ins_->imms.begin(), builtin_id); - } else { - context_.err = GetError("The non-public extension of ISA does not contain such a builtin", Error::ErrorType::ERR_BAD_MNEMONIC_NAME); - return false; - } - - ++context_; - - return true; -} - -} // namespace panda::pandasm diff --git a/assembler/templates/builtin_parsing_tests.cpp.erb b/assembler/templates/builtin_parsing_tests.cpp.erb deleted file mode 100644 index bb83689662..0000000000 --- a/assembler/templates/builtin_parsing_tests.cpp.erb +++ /dev/null @@ -1,146 +0,0 @@ -/* - * 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 -#include - -#include -#include "assembly-parser.h" -#include "define.h" -#include "lexer.h" -#include "operand_types_print.h" - -using namespace panda::pandasm; - -% PandaBuiltins::builtins.each do |builtin| -% -TEST(builtinparsingtests, builtins_<%=builtin.insn.tr('.', '_')%>_id<%=builtin.id%>) - { - Parser p; - std::string src = std::string(R"( - .function void g() { - <%=builtin.insn%> <%=builtin.mnemonic%>)" -% PandaBuiltins::instructions.each do |insn| -% -% if (insn.mnemonic == builtin.insn) -% -% insn.sig.split(', ').each_with_index do |op, i| -% if (i != 0) -% if (op.start_with?('v')) - ", v<%=i%>" -% elsif (op.start_with?('imm')) - ", <%=i%>" -% elsif (op == 'type_id') - ", A" -% elsif (op == 'method_id') - ", g" -% elsif (op == 'string_id') - ", \"string_string\"" -% elsif (op == 'field_id') - ", A.B" -% end -% end -% end -% -% end -% end - "\nreturn.void\n}\n"); - - auto res = p.Parse(src); - - Error e = p.ShowError(); - - ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); - } -% -% end - -% PandaBuiltins::instructions.each do |insn| -% -TEST(builtinparsingtests, builtins_<%=insn.mnemonic.tr('.', '_')%>_bad_mnemonic_name) { - { - Parser p; - std::string src = std::string(R"( - .function void g() { - <%=insn.mnemonic%> wrong_mnemonic)" -% insn.sig.split(', ').each_with_index do |op, i| -% if (i != 0) -% if (op.start_with?('v')) - ", v<%=i%>" -% elsif (op == 'imm') - ", <%=i%>" -% elsif (op == 'type_id') - ", A" -% elsif (op == 'method_id') - ", g" -% elsif (op == 'string_id') - ", \"string_string\"" -% elsif (op == 'field_id') - ", A.B" -% end -% end -% end - "\nreturn.void\n}\n"); - - auto res = p.Parse(src); - - Error e = p.ShowError(); - - ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_MNEMONIC_NAME); - } -} -% -% end - -% PandaBuiltins::instructions.each do |insn| -% -TEST(builtinparsingtests, builtins_<%=insn.mnemonic.tr('.', '_')%>_bad_operand) { - { - Parser p; - std::string src = std::string(R"( - .record A { - u1 B - } - .function void g() { - <%=insn.mnemonic%> "")" -% insn.sig.split(', ').each_with_index do |op, i| -% if (i != 0) -% if (op.start_with?('v')) - ", v<%=i%>" -% elsif (op == 'imm') - ", <%=i%>" -% elsif (op == 'type_id') - ", A" -% elsif (op == 'method_id') - ", g" -% elsif (op == 'string_id') - ", \"string_string\"" -% elsif (op == 'field_id') - ", A.B" -% end -% end -% end - "\nreturn.void\n}\n"); - - auto res = p.Parse(src); - - Error e = p.ShowError(); - - ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_OPERAND); - } -} -% -% end - diff --git a/assembler/templates/ins_create_api.h.erb b/assembler/templates/ins_create_api.h.erb index a269ba0645..0b73694c1a 100644 --- a/assembler/templates/ins_create_api.h.erb +++ b/assembler/templates/ins_create_api.h.erb @@ -59,5 +59,3 @@ inline Ins Create_<%= insn.asm_token %>(<%= signature_str %>) } // namespace panda::pandasm - -#include diff --git a/assembler/templates/ins_create_builtins_api.h.erb b/assembler/templates/ins_create_builtins_api.h.erb deleted file mode 100644 index ba4d69b8cd..0000000000 --- a/assembler/templates/ins_create_builtins_api.h.erb +++ /dev/null @@ -1,60 +0,0 @@ -/* - * 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. - */ - -// Autogenerated file -- DO NOT EDIT! - -namespace panda::pandasm { - -% PandaBuiltins::builtins.each do |builtin| -% i_mnemo = builtin.insn.tr('.', '_').upcase -% b_mnemo = builtin.mnemonic.tr('.', '_').upcase -% sig = [] -% args = ['BUILTIN_ID'] -% -% # NB! This logic below is very simplistic. May need proper -% # work with formats in builtinsapi.rb some day. -% format_list = builtin.format.split("_"); -% format_list.each_index do |i| -% next if i == 0 -% if format_list[i] == "v4" then -% sig << "uint16_t v" + i.to_s -% args << "v" + i.to_s -% elsif format_list[i] == "v8" then -% sig << "uint16_t v" + i.to_s -% args << "v" + i.to_s -% elsif format_list[i] == "id16" -% sig << "std::string& id" + i.to_s -% args << "id" + i.to_s -% elsif format_list[i] == "id32" -% sig << "std::string& id" + i.to_s -% args << "id" + i.to_s - -% elsif format_list[i] == "imm8" -% sig << "uint8_t imm" + i.to_s -% args << "imm" + i.to_s -% elsif format_list[i] == "imm16" -% sig << "uint16_t imm" + i.to_s -% args << "imm" + i.to_s -% end -% end -inline Ins Create_BUILTIN_<%= b_mnemo %>(<%= sig.join(', ') %>) -{ - constexpr uint8_t BUILTIN_ID = <%= builtin.id %>; - return panda::pandasm::Create_<%= i_mnemo %>(<%= args.join(', ') %>); -} - -% end - -} // namespace panda::pandasm diff --git a/assembler/templates/opcode_parsing.h.erb b/assembler/templates/opcode_parsing.h.erb index c2c173aec5..33c8071c14 100644 --- a/assembler/templates/opcode_parsing.h.erb +++ b/assembler/templates/opcode_parsing.h.erb @@ -83,9 +83,7 @@ bool Parser::ParseOperands() ParseOperandVreg(); % elsif op.imm? -% if (insn.builtin? && j == 0) - ParseOperandBuiltinMnemonic(); -% elsif properties.include?("jump") +% if properties.include?("jump") ParseOperandLabel(); % else % if properties.include?("float") diff --git a/disassembler/BUILD.gn b/disassembler/BUILD.gn index 5ce73714ec..92c2a99f86 100644 --- a/disassembler/BUILD.gn +++ b/disassembler/BUILD.gn @@ -21,7 +21,6 @@ config("arkdisassembler_public_config") { arkdisassembler_sources = [ "$target_gen_dir/bc_ins_to_pandasm_ins.cpp", "$target_gen_dir/get_ins_info.cpp", - "$target_gen_dir/get_instructions.cpp", "$target_gen_dir/opcode_translator.cpp", "$target_gen_dir/type_to_pandasm_type.cpp", "disassembler.cpp", @@ -44,7 +43,6 @@ ohos_shared_library("arkdisassembler") { configs = arkdisassembler_configs deps = [ - ":get_instructions_cpp", ":isa_gen_ark_disam_bc_ins_to_pandasm_ins_cpp", ":isa_gen_ark_disam_get_ins_info_cpp", ":isa_gen_ark_disam_opcode_translator_cpp", @@ -69,7 +67,6 @@ ohos_static_library("arkdisassembler_frontend_static") { configs = arkdisassembler_configs deps = [ - ":get_instructions_cpp", ":isa_gen_ark_disam_bc_ins_to_pandasm_ins_cpp", ":isa_gen_ark_disam_get_ins_info_cpp", ":isa_gen_ark_disam_opcode_translator_cpp", @@ -123,13 +120,6 @@ ark_isa_gen("isa_gen_ark_disam") { ] } -ark_gen_file("get_instructions_cpp") { - template_file = "$ark_root/disassembler/templates/get_instructions.cpp.erb" - data_file = "$ark_root/isa/builtins.yaml" - requires = [ "$ark_root/isa/builtinsapi.rb" ] - output_file = "$target_gen_dir/get_instructions.cpp" -} - ark_gen_file("type_to_pandasm_type_cpp") { template_file = "$ark_root/disassembler/templates/type_to_pandasm_type.cpp.erb" diff --git a/disassembler/CMakeLists.txt b/disassembler/CMakeLists.txt index abb1a28b5e..27f7d9b3bf 100644 --- a/disassembler/CMakeLists.txt +++ b/disassembler/CMakeLists.txt @@ -28,14 +28,6 @@ panda_isa_gen( ${GET_INSTRUCTIONS_CPP} ) -set(GET_INSTRUCTIONS_CPP ${CMAKE_CURRENT_BINARY_DIR}/get_instructions.cpp) -panda_gen_file( - DATAFILE ${PANDA_ROOT}/isa/builtins.yaml - TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/templates/get_instructions.cpp.erb - REQUIRES ${PANDA_ROOT}/isa/builtinsapi.rb - OUTPUTFILE ${GET_INSTRUCTIONS_CPP} -) - set(GENERATOR ${PANDA_ROOT}/libpandafile/types.rb) set(TEMPLATE ${CMAKE_CURRENT_LIST_DIR}/templates/type_to_pandasm_type.cpp.erb) set(DATAFILE ${PANDA_ROOT}/libpandafile/types.yaml) @@ -53,7 +45,6 @@ add_library(arkdisassembler ${PANDA_DEFAULT_LIB_TYPE} bc_ins_to_pandasm_ins.cpp get_ins_info.cpp type_to_pandasm_type.cpp - get_instructions.cpp ) target_include_directories(arkdisassembler diff --git a/disassembler/disassembler.cpp b/disassembler/disassembler.cpp index 8597921d5c..6e36ee6db1 100644 --- a/disassembler/disassembler.cpp +++ b/disassembler/disassembler.cpp @@ -1348,4 +1348,89 @@ pandasm::extensions::Language Disassembler::GetClassLanguage(panda_file::File::E return PFLangToPandasmLang(cda.GetSourceLang()); } +IdList Disassembler::GetInstructions(pandasm::Function *method, panda_file::File::EntityId method_id, + panda_file::File::EntityId code_id) const +{ + panda_file::CodeDataAccessor code_accessor(*file_, code_id); + + const auto ins_sz = code_accessor.GetCodeSize(); + const auto ins_arr = code_accessor.GetInstructions(); + + method->regs_num = code_accessor.GetNumVregs(); + + auto bc_ins = BytecodeInstruction(ins_arr); + const auto bc_ins_last = bc_ins.JumpTo(ins_sz); + + LabelTable label_table = GetExceptions(method, method_id, code_id); + + IdList unknown_external_methods {}; + + while (bc_ins.GetAddress() != bc_ins_last.GetAddress()) { + if (bc_ins.GetAddress() > bc_ins_last.GetAddress()) { + LOG(ERROR, DISASSEMBLER) << "> error encountered at " << std::dec << code_id.GetOffset() << " (" + << "0x" << std::hex << code_id.GetOffset() + << "). bytecode instructions sequence corrupted for method " << method->name + << "! went out of bounds"; + + break; + } + + auto pa_ins = BytecodeInstructionToPandasmInstruction(bc_ins, method_id, method->language); + // alter instructions operands depending on instruction type + if (pa_ins.IsConditionalJump() || pa_ins.IsJump()) { + const int32_t jmp_offset = std::get(pa_ins.imms.at(0)); + const auto bc_ins_dest = bc_ins.JumpTo(jmp_offset); + if (bc_ins_last.GetAddress() > bc_ins_dest.GetAddress()) { + size_t idx = GetBytecodeInstructionNumber(BytecodeInstruction(ins_arr), bc_ins_dest); + + if (idx != std::numeric_limits::max()) { + if (label_table.find(idx) == label_table.end()) { + std::stringstream ss {}; + ss << "jump_label_" << label_table.size(); + label_table[idx] = ss.str(); + } + + pa_ins.imms.clear(); + pa_ins.ids.push_back(label_table[idx]); + } else { + LOG(ERROR, DISASSEMBLER) + << "> error encountered at " << std::dec << code_id.GetOffset() << " (" + << "0x" << std::hex << code_id.GetOffset() << "). incorrect instruction at offset " + << (bc_ins.GetAddress() - ins_arr) << ": invalid jump offset " << jmp_offset + << " - jumping in the middle of another instruction!"; + } + } else { + LOG(ERROR, DISASSEMBLER) << "> error encountered at " << std::dec << code_id.GetOffset() << " (" + << "0x" << std::hex << code_id.GetOffset() + << "). incorrect instruction at offset: " << (bc_ins.GetAddress() - ins_arr) + << ": invalid jump offset " << jmp_offset << " - jumping out of bounds!"; + } + } + + // check if method id is unknown external method. if so, emplace it in table + if (bc_ins.HasFlag(BytecodeInstruction::Flags::METHOD_ID)) { + const auto arg_method_idx = bc_ins.GetId().AsIndex(); + const auto arg_method_id = file_->ResolveMethodIndex(method_id, arg_method_idx); + + const auto arg_method_name = GetFullMethodName(arg_method_id, method->language); + + const bool is_present = prog_.function_table.find(arg_method_name) != prog_.function_table.cend(); + const bool is_external = file_->IsExternal(arg_method_id); + if (is_external && !is_present) { + unknown_external_methods.push_back(arg_method_id); + } + } + + method->ins.push_back(pa_ins); + bc_ins = bc_ins.GetNext(); + } + + for (const auto &pair : label_table) { + method->ins[pair.first].label = pair.second; + method->ins[pair.first].set_label = true; + } + + return unknown_external_methods; +} + } // namespace panda::disasm diff --git a/disassembler/templates/get_instructions.cpp.erb b/disassembler/templates/get_instructions.cpp.erb deleted file mode 100644 index 48befa49b2..0000000000 --- a/disassembler/templates/get_instructions.cpp.erb +++ /dev/null @@ -1,143 +0,0 @@ -/* - * 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 "disassembler.h" - -namespace panda::disasm { - -IdList Disassembler::GetInstructions(pandasm::Function *method, panda_file::File::EntityId method_id, - panda_file::File::EntityId code_id) const { - panda_file::CodeDataAccessor code_accessor(*file_, code_id); - - const auto ins_sz = code_accessor.GetCodeSize(); - const auto ins_arr = code_accessor.GetInstructions(); - - method->regs_num = code_accessor.GetNumVregs(); - - auto bc_ins = BytecodeInstruction(ins_arr); - const auto bc_ins_last = bc_ins.JumpTo(ins_sz); - - LabelTable label_table = GetExceptions(method, method_id, code_id); - - IdList unknown_external_methods{}; - - while (bc_ins.GetAddress() != bc_ins_last.GetAddress()) { - if (bc_ins.GetAddress() > bc_ins_last.GetAddress()) { - LOG(ERROR, DISASSEMBLER) << "> error encountered at " << std::dec << code_id.GetOffset() << " (" << "0x" << std::hex - << code_id.GetOffset() << "). bytecode instructions sequence corrupted for method " - << method->name << "! went out of bounds"; - - break; - } - - auto pa_ins = BytecodeInstructionToPandasmInstruction(bc_ins, method_id, method->language); - - // alter instructions operands depending on instruction type - if (pa_ins.IsConditionalJump() || pa_ins.IsJump()) { - const int32_t jmp_offset = std::get(pa_ins.imms.at(0)); - const auto bc_ins_dest = bc_ins.JumpTo(jmp_offset); - if (bc_ins_last.GetAddress() > bc_ins_dest.GetAddress()) { - size_t idx = GetBytecodeInstructionNumber(BytecodeInstruction(ins_arr), bc_ins_dest); - - if (idx != std::numeric_limits::max()) { - if (label_table.find(idx) == label_table.end()) { - std::stringstream ss{}; - ss << "jump_label_" << label_table.size(); - label_table[idx] = ss.str(); - } - - pa_ins.imms.clear(); - pa_ins.ids.push_back(label_table[idx]); - } else { - LOG(ERROR, DISASSEMBLER) << "> error encountered at " << std::dec << code_id.GetOffset() << " (" - << "0x" << std::hex << code_id.GetOffset() << "). incorrect instruction at offset " - << (bc_ins.GetAddress() - ins_arr) << ": invalid jump offset " - << jmp_offset << " - jumping in the middle of another instruction!"; - - } - } else { - LOG(ERROR, DISASSEMBLER) << "> error encountered at " << std::dec << code_id.GetOffset() << " (" - << "0x" << std::hex << code_id.GetOffset() - << "). incorrect instruction at offset: " << (bc_ins.GetAddress() - ins_arr) - << ": invalid jump offset " << jmp_offset << " - jumping out of bounds!"; - } - } - - // if builtin - change imm to mnemonic - switch (pa_ins.opcode) { -% PandaBuiltins::instructions.each do |insn| - case pandasm::Opcode::<%=insn.mnemonic.tr('.', '_').upcase%>: - switch(pa_ins.imms[0].index()) { - // contains int64_t - case 0: - switch (std::get(pa_ins.imms[0])) { -% PandaBuiltins::builtins.each do |builtin| -% if (builtin.insn == insn.mnemonic) - case <%= builtin.id%>: - pa_ins.ids.insert(pa_ins.ids.begin(), std::string("<%=builtin.mnemonic%>")); - break; -% end -% end - default: - LOG(ERROR, DISASSEMBLER) << "> error encountered at " << std::dec << code_id.GetOffset() << " (" - << "0x" << std::hex << code_id.GetOffset() - << "). incorrect builtin mnemonic id!"; - break; - } - - break; - // float or nothing - throw error - default: - LOG(ERROR, DISASSEMBLER) << "> error encountered at " << std::dec << code_id.GetOffset() << " (" - << "0x" << std::hex << code_id.GetOffset() - << "). incorrect type of builtin mnemonic id! expected integer, but " - "float (or nothing) received!"; - break; - } - pa_ins.imms.erase(pa_ins.imms.begin()); - - break; -% end - default: - break; - } - - // check if method id is unknown external method. if so, emplace it in table - if (bc_ins.HasFlag(BytecodeInstruction::Flags::METHOD_ID)) { - const auto arg_method_idx = bc_ins.GetId().AsIndex(); - const auto arg_method_id = file_->ResolveMethodIndex(method_id, arg_method_idx); - - const auto arg_method_name = GetFullMethodName(arg_method_id, method->language); - - const bool is_present = prog_.function_table.find(arg_method_name) != prog_.function_table.cend(); - const bool is_external = file_->IsExternal(arg_method_id); - if (is_external && !is_present) { - unknown_external_methods.push_back(arg_method_id); - } - } - - method->ins.push_back(pa_ins); - bc_ins = bc_ins.GetNext(); - } - - for (const auto& pair : label_table) { - method->ins[pair.first].label = pair.second; - method->ins[pair.first].set_label = true; - } - - return unknown_external_methods; -} - -} // namespace panda::disasm diff --git a/disassembler/tests/sources/builtins.pa b/disassembler/tests/sources/builtins.pa deleted file mode 100644 index 86d2077c26..0000000000 --- a/disassembler/tests/sources/builtins.pa +++ /dev/null @@ -1,30 +0,0 @@ -# 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. - -.function void g(f32 a0, f32 a1) { - builtin.acc i32tof32 - builtin.acc i64tof32 - builtin.acc f64tof32 - builtin.acc monitorenter - builtin.acc monitorexit - - builtin.bin2 fadd2f32, a1 - builtin.bin2 fsub2f32, v13 - builtin.bin2 fmul2f32, v13 - builtin.bin2 fdiv2f32, v13 - builtin.bin2 fmod2f32, v13 - builtin.bin2 fcmpl2f32, a0 - builtin.bin2 fcmpg2f32, v13 - - return.void -} diff --git a/isa/builtins.yaml b/isa/builtins.yaml deleted file mode 100644 index d3608b914f..0000000000 --- a/isa/builtins.yaml +++ /dev/null @@ -1,398 +0,0 @@ -# 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. - ---- - -# This is a non-public extension of Panda instruction set architecture. -# Each group from the section below defines a single 'builtin.*' instruction -# without predefined semantics. Each 'builtin.*' instruction can be -# dispatched to maximum 256 handlers, each executing in the interpreter's -# context (like all public instruction handlers do). These extension handlers -# are called builtins. Dispatching 'builtin.*' instructions to actual handlers -# is achieved via first immediate operand of each 'builtin.*' instruction. -# -# Following restrictions apply to the 'groups' section: -# -# * The entire 'groups' section must have exactly the same format as isa.yaml. -# * Each group must define exactly one 'builtin.*' instruction. -# * Each 'builtin.*' instruction must have exactly one encoding format. -# This limitation is introduced to avoid writing complex and untestable -# code generation routines -- currently "one instruction <=> one format" -# is enough. Feel free to remove this constraint on demand. -# * There must be no 'builtin.*' instructions with the same signature -# (consult with the API for signature validation rules). -# -# Following restrtictions apply to the 'builtins' section: -# -# * All builtin names must be unique -# * Signature of each builtin must match exactly one signature of some -# 'builtin.*' instruction (consult with the API for signature matching rules). -# Please note that there is no need to specify correspondence between -# builtins and 'builtin.*' instructions explicitly, this done by the API. -# -# Following runtime restrictions apply to builtins handlers: -# -# * Builtin handler is not expected to run in parallel with GC at STW phase -# * Builtin handler must not trigger runtime operations that start GC -# -# NB! Important note about ordering and dispatch table layout. -# The order of builtin definitions in this file is not important. However, -# API may reorder these definitions to guarantee following layout -# for the dispatch table: -# -# public_opcode_01 -# public_opcode_02 -# ... -# builtin_opcode_01 -# builtin_opcode_02 -# ... -# builtin_01_for_builtin_opcode_01 \ -# builtin_02_for_builtin_opcode_01 | All builtins with signature of builtin_opcode_01 -# builtin_03_for_builtin_opcode_01 / -# builtin_01_for_builtin_opcode_02 \ -# ... | All builtins with signature of builtin_opcode_02 -# builtin_NN_for_builtin_opcode_02 / -# - -groups: - - title: Built-in operations without explicit operands - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm) - acc = builtin(acc) - semantics: | - skip - instructions: - - sig: builtin.acc imm - acc: inout:top - format: [op_imm_8] - - - title: Built-in two address binary operations on accumulator - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm) - acc = builtin(acc, v) - semantics: | - skip - instructions: - - sig: builtin.bin2 imm, v:in:top - acc: inout:top - format: [op_imm_8_v_8] - - - title: Built-in three address operations on accumulator - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm) - acc = builtin(acc, v1, v2) - semantics: | - skip - instructions: - - sig: builtin.tern3 imm, v1:in:top, v2:in:top - acc: inout:top - format: [op_imm_8_v1_8_v2_8] - - - title: Built-in four address operations on accumulator - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm) - acc = builtin(acc, v1, v2, v3) - semantics: | - skip - instructions: - - sig: builtin.quatern4 imm, v1:in:top, v2:in:top, v3:in:top - acc: inout:top - format: [op_imm_8_v1_8_v2_8_v3_8] - - - title: Built-in five address operations on accumulator - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm) - acc = builtin(acc, v1, v2, v3, v4) - semantics: | - skip - instructions: - - sig: builtin.quin5 imm, v1:in:top, v2:in:top, v3:in:top, v4:in:top - acc: inout:top - format: [op_imm_8_v1_8_v2_8_v3_8_v4_8] - - - title: Built-in opcode for imm8_v - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm1) - acc = builtin(imm2, acc, v) - semantics: | - skip - instructions: - - sig: builtin.r2i imm1, imm2, v:in:top - acc: inout:top - format: [op_imm1_8_imm2_16_v_8] - - - title: Built-in opcode for imm8_v1_v2 - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm1) - acc = builtin(imm2, acc, v1, v2) - semantics: | - skip - instructions: - - sig: builtin.r3i imm1, imm2, v1:in:top, v2:in:top - acc: inout:top - format: [op_imm1_8_imm2_16_v1_8_v2_8] - - - title: Built-in opcode for imm8_v1_v2_v3 - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm1) - acc = builtin(imm2, acc, v1, v2, v3) - semantics: | - skip - instructions: - - sig: builtin.r4i imm1, imm2, v1:in:top, v2:in:top, v3:in:top - acc: inout:top - format: [op_imm1_8_imm2_16_v1_8_v2_8_v3_8] - - - title: Built-in opcode for id_32 - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - string_id - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm) - acc = builtin(acc, id) - semantics: | - skip - instructions: - - sig: builtin.id imm, string_id - acc: inout:top - format: [op_imm_8_id_32] - - - title: Built-in opcode for method_id_v_8 - description: Non-public extension of the instruction set. - verification: - - method_id_static - exceptions: - - x_none - properties: - - method_id - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm) - acc = builtin(acc, method_id, v) - semantics: | - skip - instructions: - - sig: builtin.midr imm, method_id, v:in:top - acc: inout:top - format: [op_imm_8_id_16_v_8] - - - title: Built-in opcode for id_32_imm_16 - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - string_id - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm1) - acc = builtin(acc, id, imm2) - semantics: | - skip - instructions: - - sig: builtin.idi imm1, string_id, imm2 - acc: inout:top - format: [op_imm1_8_id_32_imm2_16] - - - title: Built-in opcode for id_32_imm_16_v_8 - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - string_id - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm1) - acc = builtin(acc, id, imm2, v) - semantics: | - skip - instructions: - - sig: builtin.idr3i imm1, string_id, imm2, v:in:top - acc: inout:top - format: [op_imm1_8_id_32_imm2_16_v_8] - - - title: Built-in opcode for id_32_imm_16_v1_8_v2_8 - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - string_id - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm1) - acc = builtin(acc, id, imm2, v1, v2) - semantics: | - skip - instructions: - - sig: builtin.idr4i imm1, string_id, imm2, v1:in:top, v2:in:top - acc: inout:top - format: [op_imm1_8_id_32_imm2_16_v1_8_v2_8] - - - title: Built-in opcode for imm_16_imm_16_v_8 - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm1) - acc = builtin(acc, imm2, imm3, v) - semantics: | - skip - instructions: - - sig: builtin.i2r3 imm1, imm2, imm3, v:in:top - acc: inout:top - format: [op_imm1_8_imm2_16_imm3_16_v_8] - - - title: Built-in opcode for imm_16_imm_16 - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm1) - acc = builtin(acc, imm2, imm3) - semantics: | - skip - instructions: - - sig: builtin.i2r2 imm1, imm2, imm3 - acc: inout:top - format: [op_imm1_8_imm2_16_imm3_16] - - - title: Built-in opcode for imm_16 - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_read - - acc_write - pseudo: | - builtin = resolve_builtin(imm1) - acc = builtin(acc, imm2) - semantics: | - skip - instructions: - - sig: builtin.imm imm1, imm2 - acc: inout:top - format: [op_imm1_8_imm2_16] - - - title: Built-in opcode with method id imm16 and two regs - description: Non-public extension of the instruction set. - verification: - - none - exceptions: - - x_none - properties: - - acc_write - - method_id - pseudo: | - pseudo: | - builtin = resolve_builtin(imm1) - acc = builtin(id, imm2, v1, v2) - semantics: | - skip - instructions: - - sig: builtin.imr2 imm1, method_id, imm2, v1:in:top, v2:in:top - acc: out:top - format: [op_imm1_8_id_16_imm2_16_v1_8_v2_8] - -builtins: [ ] -# diff --git a/isa/builtinsapi.rb b/isa/builtinsapi.rb deleted file mode 100755 index cc881f1303..0000000000 --- a/isa/builtinsapi.rb +++ /dev/null @@ -1,224 +0,0 @@ -# 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. - -require 'delegate' -require 'ostruct' - -class BuiltinInstruction < SimpleDelegator - def mnemonic - sig.split(' ')[0] - end - - def opcode - mnemonic.sub('.', '_') + self[:format] - end - - def format - self[:format].length() == 0 ? 'NONE' : self[:format].sub('_', '') - end -end - -class Builtin < SimpleDelegator - def mnemonic - sig.split(' ')[0] - end - - def opcode - mnemonic.sub('.', '_') + self[:format] - end - - def format - self[:format].length() == 0 ? 'NONE' : self[:format].sub('_', '') - end - - def stripped_mnemonic - mnemonic.split('.')[0] - end - - def throwing? - throwable = ['monitorenter', 'monitorexit'] - throwable.include?(stripped_mnemonic) || self[:exception] == true - end - - def ins - self[:insn].sub('.', '_') - end - - def id - self[:id] - end - - def language_context - self[:space] - end -end - -module PandaBuiltins - module_function - - def instructions - insns = [] - @data["groups"].each do |group| - group.instructions[0][:format].each do |f| - props = group.instructions[0].to_h - props[:format] = f.sub('op', '').gsub(/imm[0-9]+?/, 'imm').gsub(/v[0-9]+?/, 'v').gsub(/_([0-9]+)/, '\1') - - insns << BuiltinInstruction.new(OpenStruct.new(props)) - end - end - insns - end - - def builtins - all_builtins = [] - @data["builtins"].each do |b| - b[:format].each do |f| - props = b.to_h - props[:format] = f.sub('op', '').gsub(/imm[0-9]+?/, 'imm').gsub(/v[0-9]+?/, 'v').gsub(/_([0-9]+)/, '\1') - - all_builtins << Builtin.new(OpenStruct.new(props)) - end - end - - # Assign an ID to each builtin. - # NB! IDs are unique only for builtins corresponding - # to a *single* 'builtin.*' instruction! - id = 0 - for i in 1 .. all_builtins.length() - 1 - all_builtins[i - 1][:id] = id - id += 1 - - id = 0 unless all_builtins[i - 1][:insn] == all_builtins[i][:insn] - end - all_builtins[all_builtins.length() - 1][:id] = id if all_builtins.any? - - all_builtins - end - - # Delegating part of module - # - def wrap_data(data) - @data = data - end - -end - -def prepare_data(data) - insn_ids = [] - mnemos = {} # insn id => mnemonics - formats = {} # insn id => supported encoding formats - counts = {} # insn id => number of corresponding builtins (counting different formats) - ordered = {} # insn id => list of corresponding builtins in order of definition - - raise 'Number of builtin.* instructions is too high' if data["groups"].length() > 20 - - insn_names = {} - data["groups"].each do |group| - - raise 'Expecting exactly one instruction per builtin.* group' unless group["instructions"].length() == 1 - - group["instructions"].each do |insn| - - sig = insn["sig"] - args = sig.split(/,?\s+/) - args_len = args.length() - - raise 'Expecting at least one argument for a builtin' if args_len < 2 - raise "Expecting 'builtin.' prefix for the mnemonic" unless /^builtin\./.match(args[0]) - - raise "Expecting an imm as the builtin's first argument" unless args[1].start_with?('imm') - - raise "Duplicate builtin instruction name '#{args[0]}'" if insn_names.key?(args[0]) - insn_names[args[0]] = 1 - - insn_id = args[2 .. args_len - 1].map{ |arg| arg =~ /^([^:]+):?/; $1 }.join('_') - - raise "Non-unique signature is detected while parsing instruction '#{sig}'" if formats.key?(insn_id) - - # Currently a single format per instruction is enough, so the assert below just guards status quo - raise 'Expecting exactly one encoding format per instruction' unless insn["format"].length() == 1 - - insn_ids << insn_id - mnemos[insn_id] = args[0] - formats[insn_id] = insn["format"] - counts[insn_id] = 0 - ordered[insn_id] = [] - end - end - - builtin_names = {} - data["builtins"].each do |builtin| - raise "'sig' property is missing" unless builtin['sig'] - raise "'acc' property is missing" unless builtin['acc'] - raise "Unexpected 'insn' property" if builtin['insn'] - raise "Unexpected 'format' property" if builtin['format'] - - sig = builtin["sig"] - args = sig.split(/,?\s+/) - args_len = args.length() - - raise "Malformed signature of a builtin" if args_len < 1 - - raise "Duplicate builtin name '#{args[0]}'" if builtin_names.key?(args[0]) - builtin_names[args[0]] = 1 - - insn_id = args[1 .. args_len - 1].map{ |arg| arg =~ /^([^:]+):?/; $1 }.join('_') - - raise "Signature for builtin '#{sig}' does not match any builtin.* instruction" unless formats.key?(insn_id) - - builtin["insn"] = mnemos[insn_id] - builtin["format"] = formats[insn_id].clone - counts[insn_id] += builtin["format"].length() - ordered[insn_id] << builtin - - raise "Number of builtins for '#{insn_id}' exceeds builtin_id" if counts[insn_id] > 256 - end - - # Enforce order of builtins and add "delta" property, defined as follows: - # builtin1.delta = 0 - # builtin2.delta = num_builtins_with_sig_of(builtin1) - # builtin3.delta = num_builtins_with_sig_of(builtin1) + num_builtins_with_sig_of(builtin2) - # ... - # builtinN.delta = num_builtins_with_sig_of(builtin1) + num_builtins_with_sig_of(builtin2) + ... + num_builtins_with_sig_of(builtinN_1) - builtins = [] - for i in 0 .. data["groups"].length() - 1 - curr_insn = data["groups"][i]["instructions"][0] - curr_insn_id = insn_ids[i] - - if i > 0 - prev_insn = data["groups"][i - 1]["instructions"][0] - prev_insn_id = insn_ids[i - 1] - - curr_insn["delta"] = prev_insn["delta"] + counts[prev_insn_id] - else - curr_insn["delta"] = 0 - end - - ordered[curr_insn_id].each do |builtin| - builtins << builtin - end - end - - {"groups" => data["groups"], "builtins" => builtins} -end - -module ExtBuiltins - def self.load_ecma_builtins(data); end -end - -def Gen.on_require(data) - ExtBuiltins.load_ecma_builtins(data) - prepared_data = prepare_data(data) - PandaBuiltins.wrap_data(prepared_data) -end - diff --git a/isa/isapi.rb b/isa/isapi.rb index e16735ed9a..a6e205d2b1 100755 --- a/isa/isapi.rb +++ b/isa/isapi.rb @@ -533,12 +533,5 @@ module Panda end def Gen.on_require(data) - builtins_fname = File.expand_path(File.join(File.dirname(__FILE__), 'builtins.yaml')) - builtins = YAML.load_file(builtins_fname) - builtins = JSON.parse(builtins.to_json, object_class: OpenStruct) - builtins.groups.each do |group| - data.groups << group - end - Panda.wrap_data(data) end diff --git a/libpandafile/BUILD.gn b/libpandafile/BUILD.gn index 8c74d927d2..ee9080e488 100644 --- a/libpandafile/BUILD.gn +++ b/libpandafile/BUILD.gn @@ -66,7 +66,6 @@ ohos_shared_library("libarkfile") { ":isa_gen_libarkfile_bytecode_instruction_enum_gen_h", ":isa_gen_libarkfile_file_format_version_h", ":isa_gen_libarkfile_tests_bytecode_emitter_tests_gen_h", - ":libarkfile_bytecode_builtin_enum_gen_h", ":libarkfile_type_gen_h", "$ark_root/libpandabase:libarkbase", "$ark_root/libziparchive:libarkziparchive", @@ -92,7 +91,6 @@ ohos_static_library("libarkfile_frontend_static") { ":isa_gen_libarkfile_bytecode_instruction_enum_gen_h", ":isa_gen_libarkfile_file_format_version_h", ":isa_gen_libarkfile_tests_bytecode_emitter_tests_gen_h", - ":libarkfile_bytecode_builtin_enum_gen_h", ":libarkfile_type_gen_h", "$ark_root/libpandabase:libarkbase_frontend_static", "$ark_root/libziparchive:libarkziparchive_frontend_static", @@ -107,13 +105,6 @@ ark_gen_file("libarkfile_type_gen_h") { output_file = "$target_gen_dir/type.h" } -ark_gen_file("libarkfile_bytecode_builtin_enum_gen_h") { - template_file = "templates/bytecode_builtin_enum_gen.h.erb" - data_file = "$ark_root/isa/builtins.yaml" - requires = [ "$ark_root/isa/builtinsapi.rb" ] - output_file = "$target_gen_dir/bytecode_builtin_enum_gen.h" -} - ark_isa_gen("isa_gen_libarkfile") { template_files = [ "bytecode_instruction_enum_gen.h.erb", @@ -126,5 +117,4 @@ ark_isa_gen("isa_gen_libarkfile") { sources = "templates" ## ark_root/templates destination = "$target_gen_dir/include" ## target_gen_dir/include requires = [ "pandafile_isapi.rb" ] - extra_dependencies = [ ":libarkfile_bytecode_builtin_enum_gen_h" ] } diff --git a/libpandafile/CMakeLists.txt b/libpandafile/CMakeLists.txt index ebfb611914..011bfad1f5 100644 --- a/libpandafile/CMakeLists.txt +++ b/libpandafile/CMakeLists.txt @@ -28,14 +28,6 @@ set(TEMPLATES tests/bytecode_emitter_tests_gen.h.erb ) -set(output "${CMAKE_CURRENT_BINARY_DIR}/include/bytecode_builtin_enum_gen.h") -panda_gen_file( - DATAFILE "${PANDA_ROOT}/isa/builtins.yaml" - REQUIRES "${PANDA_ROOT}/isa/builtinsapi.rb" - TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/templates/bytecode_builtin_enum_gen.h.erb" - OUTPUTFILE ${output} -) - panda_isa_gen(TEMPLATES ${TEMPLATES} SOURCE ${CMAKE_CURRENT_LIST_DIR}/templates DESTINATION ${GEN_INCLUDE_DIR} diff --git a/libpandafile/bytecode_instruction.h b/libpandafile/bytecode_instruction.h index 36051a1fa5..fad30a073b 100644 --- a/libpandafile/bytecode_instruction.h +++ b/libpandafile/bytecode_instruction.h @@ -209,8 +209,6 @@ class BytecodeInst : public BytecodeInstBase { public: #include -#include - BytecodeInst() = default; ~BytecodeInst() = default; @@ -349,8 +347,6 @@ public: bool CanThrow() const; - bool IsBuiltin() const; - bool IsTerminator() const { return HasFlag(Flags::RETURN) || HasFlag(Flags::JUMP) || (GetOpcode() == Opcode::THROW_V8); diff --git a/libpandafile/templates/bytecode_builtin_enum_gen.h.erb b/libpandafile/templates/bytecode_builtin_enum_gen.h.erb deleted file mode 100644 index 2c7de28f94..0000000000 --- a/libpandafile/templates/bytecode_builtin_enum_gen.h.erb +++ /dev/null @@ -1,22 +0,0 @@ -/* - * 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. - */ - -% PandaBuiltins::instructions.each do |instr| -enum <%= instr.mnemonic.tr('.','_').upcase %> { -% PandaBuiltins::builtins.select{ |b| b.insn == instr.mnemonic }.each do |builtin| - <%= builtin.opcode.tr('.','_').upcase %>, -% end -}; -% end diff --git a/libpandafile/templates/bytecode_instruction-inl_gen.h.erb b/libpandafile/templates/bytecode_instruction-inl_gen.h.erb index f498cdb9fd..8b1ed3b02d 100644 --- a/libpandafile/templates/bytecode_instruction-inl_gen.h.erb +++ b/libpandafile/templates/bytecode_instruction-inl_gen.h.erb @@ -359,21 +359,6 @@ std::ostream& operator<<(std::ostream& os, const typename BytecodeInst::Op return os; } -template -inline bool BytecodeInst::IsBuiltin() const -{ - switch (GetOpcode()) { -% Panda::instructions.each do |inst| -% if inst["sig"].include? "builtin" - case BytecodeInst::Opcode::<%= inst.opcode.upcase %>: -% end -% end - return true; - default: - return false; - } -} - template inline bool BytecodeInst::IsPrimaryOpcodeValid() const { diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn index 1edc9db4c3..e4d9aee1af 100644 --- a/runtime/BUILD.gn +++ b/runtime/BUILD.gn @@ -212,7 +212,6 @@ ohos_static_library("libarkruntime_static") { "$ark_root/verification/gen:isa_gen_verification_gen_abs_int_inl_gen_h", "$ark_root/verification/gen:isa_gen_verification_gen_cflow_iterate_inl_gen_h", "$ark_root/verification/gen:isa_gen_verification_gen_job_fill_gen_h", - "$ark_root/verification/gen:verification_abs_int_builtin_handlers_h", "$ark_root/verification/gen:verification_abs_int_inl_compat_checks_h", "$ark_root/verification/gen:verification_verifier_messages_h", sdk_libc_secshared_dep, @@ -358,24 +357,6 @@ gen_intrinsics_yaml("arkruntime_gen_intrinsics_yaml") { output_file = "$target_gen_dir/intrinsics.yaml" } -builtin_templates = [ - "builtin_count", - "builtin_dispatch", - "builtin_handlers", - "builtin_insn_handlers", -] -builtin_labels = [] -foreach(t, builtin_templates) { - output = "$target_gen_dir/include/${t}.h" - builtin_labels += [ ":${t}" ] - ark_gen_file(t) { - data_file = "$ark_root/isa/builtins.yaml" - requires = [ "$ark_root/isa/builtinsapi.rb" ] - template_file = "interpreter/templates/${t}.h.erb" - output_file = output - } -} - gen_include_dir = "$target_gen_dir/include" ark_isa_gen("isa_gen_libarkruntime") { @@ -386,7 +367,6 @@ ark_isa_gen("isa_gen_libarkruntime") { ] sources = "interpreter/templates" destination = gen_include_dir - extra_dependencies = builtin_labels } isa = "$root_gen_dir/isa/isa.yaml" diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index af45d448b3..c4a96809e9 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -179,25 +179,6 @@ set(INTERPRETER_IMPL_SOURCES add_library(arkruntime_interpreter_impl OBJECT ${INTERPRETER_IMPL_SOURCES}) panda_set_lib_32bit_property(arkruntime_interpreter_impl) -set(builtin_templates - builtin_count - builtin_dispatch - builtin_handlers - builtin_insn_handlers -) - -set(builtin_headers) -foreach(template ${builtin_templates}) - set(output "${CMAKE_CURRENT_BINARY_DIR}/include/${template}.h") - panda_gen_file( - DATAFILE "${PANDA_ROOT}/isa/builtins.yaml" - REQUIRES "${PANDA_ROOT}/isa/builtinsapi.rb" - TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/interpreter/templates/${template}.h.erb" - OUTPUTFILE ${output} - ) - list(APPEND builtin_headers ${output}) -endforeach() - set(ISA_TEMPLATES interpreter-inl_gen.h.erb isa_constants_gen.h.erb @@ -209,7 +190,6 @@ panda_isa_gen( TEMPLATES ${ISA_TEMPLATES} SOURCE ${CMAKE_CURRENT_LIST_DIR}/interpreter/templates DESTINATION ${GEN_INCLUDE_DIR} - EXTRA_DEPENDENCIES ${builtin_headers} ) set(ISA "${CMAKE_BINARY_DIR}/isa/isa.yaml") diff --git a/runtime/interpreter/templates/builtin_count.h.erb b/runtime/interpreter/templates/builtin_count.h.erb deleted file mode 100644 index 1467d2d791..0000000000 --- a/runtime/interpreter/templates/builtin_count.h.erb +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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. - */ - -#ifndef PANDA_RUNTIME_INCLUDE_BUILTIN_COUNT_H_ -#define PANDA_RUNTIME_INCLUDE_BUILTIN_COUNT_H_ - -constexpr size_t NUM_BUILTINS = <%= PandaBuiltins::builtins.length() %>; - -#endif // PANDA_RUNTIME_INCLUDE_BUILTIN_COUNT_H_ diff --git a/runtime/interpreter/templates/builtin_dispatch.h.erb b/runtime/interpreter/templates/builtin_dispatch.h.erb deleted file mode 100644 index 5e0973a4d0..0000000000 --- a/runtime/interpreter/templates/builtin_dispatch.h.erb +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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. - */ - -#ifndef PANDA_RUNTIME_INCLUDE_BUILTIN_DISPATCH_H_ -#define PANDA_RUNTIME_INCLUDE_BUILTIN_DISPATCH_H_ - -% PandaBuiltins::builtins.each do |builtin| - &&HANDLE_BUILTIN_<%= builtin.opcode.tr('.','_').upcase %>, -% end - -#endif // PANDA_RUNTIME_INCLUDE_BUILTIN_DISPATCH_H_ diff --git a/runtime/interpreter/templates/builtin_handlers.h.erb b/runtime/interpreter/templates/builtin_handlers.h.erb deleted file mode 100644 index 08b4872a0b..0000000000 --- a/runtime/interpreter/templates/builtin_handlers.h.erb +++ /dev/null @@ -1,57 +0,0 @@ -/* - * 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. - */ - -#ifndef PANDA_RUNTIME_INCLUDE_BUILTIN_HANDLERS_H_ -#define PANDA_RUNTIME_INCLUDE_BUILTIN_HANDLERS_H_ - -% PandaBuiltins::builtins.each do |builtin| -HANDLE_BUILTIN_<%= builtin.opcode.tr('.','_').upcase %>: { -% if builtin.language_context == 'ecmascript' - ecmascript::InstructionHandler handler(&state); -% elsif builtin.language_context == 'java' - java::InstructionHandler handler(&state); -% else - InstructionHandler handler(&state); -% end -% mnemonic = builtin.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join - handler.DumpVRegs(); - handler.InstrumentInstruction(); - - ASSERT(PandaVM::GetCurrent()->GetLanguageContext().GetLanguage() == panda_file::SourceLang::ECMASCRIPT || - !PandaVM::GetCurrent()->GetGC()->IsGCRunning() || Locks::mutator_lock->HasLock()); - - handler.template HandleBuiltin<%= mnemonic %>>(); - - ASSERT(PandaVM::GetCurrent()->GetLanguageContext().GetLanguage() == panda_file::SourceLang::ECMASCRIPT || - !PandaVM::GetCurrent()->GetGC()->IsGCRunning() || Locks::mutator_lock->HasLock()); - - if (enable_instrumentation) { - frame->GetAcc() = handler.GetAcc(); - } -% if builtin['sig'].include?('Return') || builtin['sig'].include?('suspendGenerator') - return; -% else -% if builtin.throwing? - ASSERT(handler.GetExceptionOpcode() < dispatch_table.size()); - DISPATCH(GetDispatchTable(dispatch_table), handler.GetExceptionOpcode(), label); -% else - ASSERT(handler.GetPrimaryOpcode() < dispatch_table.size()); - DISPATCH(GetDispatchTable(dispatch_table), handler.GetPrimaryOpcode(), label); -% end -% end -} -% end - -#endif // PANDA_RUNTIME_INCLUDE_BUILTIN_HANDLERS_H_ diff --git a/runtime/interpreter/templates/builtin_insn_handlers.h.erb b/runtime/interpreter/templates/builtin_insn_handlers.h.erb deleted file mode 100644 index b709ffca03..0000000000 --- a/runtime/interpreter/templates/builtin_insn_handlers.h.erb +++ /dev/null @@ -1,30 +0,0 @@ -/* - * 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. - */ - -#ifndef PANDA_RUNTIME_INCLUDE_BUILTIN_INSN_HANDLERS_H_ -#define PANDA_RUNTIME_INCLUDE_BUILTIN_INSN_HANDLERS_H_ - -% PandaBuiltins::instructions.each do |insn| -HANDLE_<%= insn.opcode.upcase %>: { - const auto builtin_id = state.GetInst().template GetImm>(); - - LOG(DEBUG, INTERPRETER) << "Subdispatch: " << "<%= insn.mnemonic %>, " << builtin_id - << " (NUM_PREFIXED=" << NUM_PREFIXED - << ", delta=" << <%= insn.delta %> << ")"; - DISPATCH(GetDispatchTable(dispatch_table), 256 + NUM_PREFIXED + 1 + <%= insn.delta %> + builtin_id, label); -} -% end - -#endif // PANDA_RUNTIME_INCLUDE_BUILTIN_INSN_HANDLERS_H_ diff --git a/runtime/interpreter/templates/interpreter-inl_gen.h.erb b/runtime/interpreter/templates/interpreter-inl_gen.h.erb index db8b3de0f0..9570fd4705 100644 --- a/runtime/interpreter/templates/interpreter-inl_gen.h.erb +++ b/runtime/interpreter/templates/interpreter-inl_gen.h.erb @@ -34,7 +34,6 @@ void ExecuteImpl(ManagedThread* thread, const uint8_t *pc, Frame* frame) { #define INSTRUMENT_FRAME() do { if (enable_instrumentation && (handler.GetFrame()->IsForcePop() || handler.GetFrame()->IsRetryInstruction())) { goto INSTRUMENT_FRAME_HANDLER; } } while (0) ASSERT(!thread->IsCurrentFrameCompiled()); -#include EVENT_METHOD_ENTER(frame->GetMethod()->GetFullName(), events::MethodEnterKind::INTERP, thread->RecordMethodEnter()); @@ -45,12 +44,11 @@ void ExecuteImpl(ManagedThread* thread, const uint8_t *pc, Frame* frame) { PandaUniquePtr method_exit(&method_exit_event, method_exit_event); #endif - static std::array dispatch_table{ + static std::array dispatch_table{ % Panda::dispatch_table.handler_names.each do |name| &&HANDLE_<%= name %>, % end &&EXCEPTION_HANDLER, -#include }; SetDispatchTable(dispatch_table); @@ -64,7 +62,7 @@ void ExecuteImpl(ManagedThread* thread, const uint8_t *pc, Frame* frame) { const void *label; DISPATCH(GetDispatchTable(dispatch_table), state.GetPrimaryOpcode(), label); -% Panda::instructions.reject(&:builtin?).each do |i| +% Panda::instructions.each do |i| % mnemonic = i.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join HANDLE_<%= i.handler_name %>: { % namespace = i.namespace == 'core' ? '' : "#{i.namespace}::" @@ -117,10 +115,6 @@ HANDLE_<%= p.handler_name %>: { } % end -#include - -#include - INSTRUMENT_FRAME_HANDLER: { InstructionHandler handler(&state); diff --git a/verification/absint/abs_int_inl.h b/verification/absint/abs_int_inl.h index b8a6e11641..3d133dd966 100644 --- a/verification/absint/abs_int_inl.h +++ b/verification/absint/abs_int_inl.h @@ -3800,65 +3800,6 @@ public: return inst_; } - template - bool HandleBuiltinCall_polymorphic_short() - { - LOG_INST(); - DBGBRK(); - Sync(); - return true; - } - - template - bool HandleBuiltinMonitorenter() - { - LOG_VERIFIER_DEBUG_BUILTIN("monitorenter"); - DBGBRK(); - Sync(); - auto &&acc_type = GetAccType(); - if (acc_type.ForAllTypes([&](Type acc_type1) { return acc_type1 == Types().NullRefType(); })) { - // treat it as always throw NPE - SHOW_MSG(AlwaysNpeAccumulator) - LOG_VERIFIER_ALWAYS_NPE_ACCUMULATOR(); - END_SHOW_MSG(); - SET_STATUS_FOR_MSG(AlwaysNpeAccumulator); - return false; - } - if (!CheckTypes(acc_type, {Types().RefType()})) { - SET_STATUS_FOR_MSG(BadRegisterType); - SET_STATUS_FOR_MSG(UndefinedRegister); - return false; - } - MoveToNextInst(); - return true; - } - - template - bool HandleBuiltinMonitorexit() - { - LOG_VERIFIER_DEBUG_BUILTIN("monitorexit"); - DBGBRK(); - Sync(); - auto &&acc_type = GetAccType(); - if (acc_type.ForAllTypes([&](Type acc_type1) { return acc_type1 == Types().NullRefType(); })) { - // treat it as always throw NPE - SHOW_MSG(AlwaysNpeAccumulator) - LOG_VERIFIER_ALWAYS_NPE_ACCUMULATOR(); - END_SHOW_MSG(); - SET_STATUS_FOR_MSG(AlwaysNpeAccumulator); - return false; - } - if (!CheckTypes(acc_type, {Types().RefType()})) { - SET_STATUS_FOR_MSG(BadRegisterType); - SET_STATUS_FOR_MSG(UndefinedRegister); - return false; - } - MoveToNextInst(); - return true; - } - -#include "abs_int_builtin_handlers.h" - static PandaString RegisterName(int reg_idx, bool capitalize = false) { if (reg_idx == ACC) { diff --git a/verification/gen/BUILD.gn b/verification/gen/BUILD.gn index cff3c18d42..440644e9a4 100644 --- a/verification/gen/BUILD.gn +++ b/verification/gen/BUILD.gn @@ -22,21 +22,6 @@ config("verification_public_config") { ] } -ark_gen_file("verification_abs_int_builtin_handlers_h") { - template_file = "templates/abs_int_builtin_handlers.h.erb" - data_file = "$ark_root/isa/builtins.yaml" - requires = [ "$ark_root/isa/builtinsapi.rb" ] - output_file = "$target_gen_dir/include/abs_int_builtin_handlers.h" -} - -ark_gen_file("verification_cflow_iterate_inl_gen_builtin_handlers_h") { - template_file = "templates/cflow_iterate_inl_gen_builtin_handlers.h.erb" - data_file = "$ark_root/isa/builtins.yaml" - requires = [ "$ark_root/isa/builtinsapi.rb" ] - output_file = - "$target_gen_dir/include/cflow_iterate_inl_gen_builtin_handlers.h" -} - ark_gen_file("verification_abs_int_inl_compat_checks_h") { template_file = "templates/abs_int_inl_compat_checks.h.erb" data_file = "$ark_root/verification/verification.yaml" @@ -53,9 +38,7 @@ ark_isa_gen("isa_gen_verification_gen") { sources = "templates" ## ark_root/templates destination = "$target_gen_dir/include" ## target_gen_dir/include extra_dependencies = [ - ":verification_abs_int_builtin_handlers_h", ":verification_abs_int_inl_compat_checks_h", - ":verification_cflow_iterate_inl_gen_builtin_handlers_h", ] } diff --git a/verification/gen/CMakeLists.txt b/verification/gen/CMakeLists.txt index 42d260a2ee..0e18e8fd91 100644 --- a/verification/gen/CMakeLists.txt +++ b/verification/gen/CMakeLists.txt @@ -15,22 +15,6 @@ cmake_minimum_required(VERSION 3.10) project(pandaverification_gen) -set(abs_int_builtin_templates - abs_int_builtin_handlers - cflow_iterate_inl_gen_builtin_handlers -) -set(abs_int_builtin_headers) -foreach(template ${abs_int_builtin_templates}) - set(output "${CMAKE_CURRENT_BINARY_DIR}/include/${template}.h") - panda_gen_file( - DATAFILE "${PANDA_ROOT}/isa/builtins.yaml" - REQUIRES "${PANDA_ROOT}/isa/builtinsapi.rb" - TEMPLATE "${CMAKE_CURRENT_SOURCE_DIR}/templates/${template}.h.erb" - OUTPUTFILE ${output} - ) - list(APPEND abs_int_builtin_headers ${output}) -endforeach() - set(ABS_INT_EXTRA_HEADERS) set(ABS_INT_TEMPLATES abs_int_inl_compat_checks @@ -57,7 +41,7 @@ panda_isa_gen( TEMPLATES ${ISA_TEMPLATES} SOURCE ${CMAKE_CURRENT_LIST_DIR}/templates DESTINATION ${GEN_INCLUDE_DIR} - EXTRA_DEPENDENCIES ${abs_int_builtin_headers};${ABS_INT_EXTRA_HEADERS} + EXTRA_DEPENDENCIES ${ABS_INT_EXTRA_HEADERS} ) panda_gen_messages( diff --git a/verification/gen/templates/abs_int_builtin_handlers.h.erb b/verification/gen/templates/abs_int_builtin_handlers.h.erb deleted file mode 100644 index 8660021bd7..0000000000 --- a/verification/gen/templates/abs_int_builtin_handlers.h.erb +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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. - */ - -% builtin_kinds = PandaBuiltins::builtins.map(&:insn).uniq -% builtin_mnemonics = PandaBuiltins::instructions.map { |instruction| instruction.sig.split(' ').at(0) } -% undefined_builtins = builtin_mnemonics.select { |mnemonic| not builtin_kinds.include?(mnemonic) }.uniq -% builtin_kinds.each do |kind| -% mnemonic = kind.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join -% builtins = PandaBuiltins::builtins.select { |builtin| builtin.insn == kind }.sort_by(&:id) -template -bool Handle<%= mnemonic %>() { - LOG_INST(); - const auto builtin_id = GetInst().template GetImm(); - switch (builtin_id) { -% builtins.each do |builtin| - case <%= builtin.id %>: return HandleBuiltin<%= builtin.mnemonic.capitalize.tr('.', '_') %>(); -% end - default: - LOG(DEBUG, VERIFIER) << "Incorrect builtin id 0x" << std::hex << builtin_id << " for '<%= kind %>'"; - } - status_ = VerificationStatus::ERROR; - return false; -} - -% end -% undefined_builtins.each do |builtin| -% mnemonic = builtin.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join -template -bool Handle<%= mnemonic %>() { - LOG_INST(); - LOG(DEBUG, VERIFIER) << "ABSINT: " - << "<%= builtin %>"; - return true; -} - -%end diff --git a/verification/gen/templates/cflow_iterate_inl_gen.h.erb b/verification/gen/templates/cflow_iterate_inl_gen.h.erb index 68b45762c3..80805ba525 100644 --- a/verification/gen/templates/cflow_iterate_inl_gen.h.erb +++ b/verification/gen/templates/cflow_iterate_inl_gen.h.erb @@ -35,8 +35,6 @@ public: return inst_.IsPrimaryOpcodeValid(); } -#include "cflow_iterate_inl_gen_builtin_handlers.h" - % Panda::instructions.uniq{|i| i.mnemonic}.each do |i| % mnemonic = i.mnemonic.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join template @@ -47,10 +45,7 @@ public: } const uint8_t* pc = inst_.GetAddress(); const size_t sz = inst_.Size(format); -% if i.mnemonic.split('.').at(0) == 'builtin' - bool const EXC_SRC = IsExceptionSource<%= mnemonic %>(); -% elsif i.properties.include?('call') or i.stripped_mnemonic == 'throw' or !i.exceptions.include?('x_none') - // TOOD: add support of builtins: monitorenter monitorexit +% if !i.exceptions.include?('x_none') bool const EXC_SRC = true; % else bool const EXC_SRC = false; diff --git a/verification/gen/templates/cflow_iterate_inl_gen_builtin_handlers.h.erb b/verification/gen/templates/cflow_iterate_inl_gen_builtin_handlers.h.erb deleted file mode 100644 index 9d26e770a3..0000000000 --- a/verification/gen/templates/cflow_iterate_inl_gen_builtin_handlers.h.erb +++ /dev/null @@ -1,51 +0,0 @@ -/* - * 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. - */ - -% throwing_builtins = [ "monitorenter", "monitorexit" ] -% builtin_kinds = PandaBuiltins::builtins.map(&:insn).uniq -% builtin_mnemonics = PandaBuiltins::instructions.map { |instruction| instruction.sig.split(' ').at(0) } -% undefined_builtins = builtin_mnemonics.select { |mnemonic| not builtin_kinds.include?(mnemonic) }.uniq -% builtin_kinds.each do |kind| -% mnemonic = kind.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join -% builtins = PandaBuiltins::builtins.select { |builtin| builtin.insn == kind }.sort_by(&:id) -% builtins.each do |builtin| -bool IsExceptionSourceBuiltin<%= builtin.mnemonic.capitalize %>() { -% if throwing_builtins.include?(builtin.mnemonic) - return true; -% else - return false; -% end -} -% end - -template -bool IsExceptionSource<%= mnemonic %>() { - const auto builtin_id = inst_.template GetImm(); - switch (builtin_id) { -% builtins.each do |builtin| - case <%= builtin.id %>: return IsExceptionSourceBuiltin<%= builtin.mnemonic.capitalize %>(); -% end - default: - LOG(DEBUG, VERIFIER) << "Incorrect builtin id 0x" << std::hex << builtin_id << " for '<%= kind %>'"; - } - return false; -} -% end -% undefined_builtins.each do |builtin| -template -bool IsExceptionSource<%= builtin.split('.').map { |p| p == '64' ? 'Wide' : p.capitalize }.join %>() { - return false; -} -% end diff --git a/verification/messages.yaml b/verification/messages.yaml index 9db37eb8fe..e97cc70298 100644 --- a/verification/messages.yaml +++ b/verification/messages.yaml @@ -51,12 +51,6 @@ messages: args: method message: ( method is '${method}' ) - DebugBuiltin: - number: 306 - level: debug - args: name - message: "builtin: ${name}" - DebugResult: number: 307 level: debug -- Gitee From eb57e603ee42a656a153d719c8b2ad76c337b19d Mon Sep 17 00:00:00 2001 From: shawn_hu_ls Date: Thu, 9 Sep 2021 21:08:28 +0800 Subject: [PATCH 6/6] Fix README doc Signed-off-by: shawn_hu_ls --- README.md | 15 ++++++++++----- README_zh.md | 21 +++++++++++++-------- 2 files changed, 23 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 09b5f3b20e..ae591472d0 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,6 @@ As a common module of ARK runtime, Runtime consists of some basic language-irrel ├── libziparchive # provides APIs for reading and using zip files implemented by miniz. ├── panda # CLI tool used to execute ARK bytecode files (*.abc). ├── pandastdlib # Standard libraries wrote by the ARK assembler. -├── resources # CI jobs description files. ├── runtime # ARK runtime command module. ├── scripts # CI scripts. ├── templates # Ruby templates and scripts used to process command line options, loggers, error messages, and events. @@ -70,6 +69,11 @@ ark_asm [Option] Input file Output file

Specifies the log file output path after log printing is enabled.

+tr id="row1015112763020">

-optimize

+ +

Runs the bytecode optimization.

+ +

--optimize

Enables compilation optimization.

@@ -92,14 +96,14 @@ Input file: ARK bytecodes in text format Output file: ARK bytecodes in binary format -Disassembler ark\_dissam +Disassembler ark\_disasm -The ark\_dissam disassembler converts a bytecode file in binary format into a text ARK bytecode file. +The ark\_disasm disassembler converts a bytecode file in binary format into a text ARK bytecode file. Command: ``` -ark_dissam [Option] Input file Output file +ark_disasm [Option] Input file Output file ``` @@ -138,6 +142,8 @@ Output file: ARK bytecodes in text format ## Repositories Involved +[ARK Runtime Usage Guide](https://gitee.com/openharmony/ark_js_runtime/blob/master/docs/ARK-Runtime-Usage-Guide.md) + [ARK Runtime Subsystem](https://gitee.com/openharmony/ark_js_runtime/blob/master/docs/ARK-Runtime-Subsystem.md) **[ark/runtime\_core](README_zh.md)** @@ -145,4 +151,3 @@ Output file: ARK bytecodes in text format [ark/js\_runtime](https://gitee.com/openharmony/ark_js_runtime/blob/master/README.md) [ark/ts2abc](https://gitee.com/openharmony/ark_js_runtime/blob/master/README.md) - diff --git a/README_zh.md b/README_zh.md index 2873a55bc5..85fd3fed42 100644 --- a/README_zh.md +++ b/README_zh.md @@ -17,17 +17,16 @@ Runtime组件是方舟运行时的公共组件,主要包括一些语言无关 ├── cmake # cmake脚本,包含工具链文件和用于定义构建和测试目标的常用cmake函数 ├── CMakeLists.txt # cmake主入口文件 ├── disassembler # 反汇编器,将二进制格式的方舟字节码文件(*.abc)转换为文本格式的方舟字节码文件(*.pa) -├── docs # 包含语言前端、方舟文件格式和运行时的设计文档。 +├── docs # 包含语言前端、方舟文件格式和运行时的设计文档 ├── dprof # 用于ARK运行时搜集profile数据 ├── gn # GN模板和配置文件 ├── isa # 字节码ISA描述文件YAML,和ruby脚本和模板 -├── ldscripts # 包含链接器脚本,用于在非PIE可执行文件中放置4GB以上的ELF section。 +├── ldscripts # 包含链接器脚本,用于在非PIE可执行文件中放置4GB以上的ELF section ├── libpandabase # ARK运行时基本库,包含:日志、同步原语、公共数据结构等 ├── libpandafile # 二进制格式的方舟字节码文件(*.abc)源码仓 -├── libziparchive # 提供读取和使用miniz的ZIP压缩文件的API。 -├── panda # CLI工具,用于执行方舟字节码文件(*.abc)文件 +├── libziparchive # 提供读取和使用miniz的ZIP压缩文件的API +├── panda # CLI工具,用于执行方舟字节码文件(*.abc) ├── pandastdlib # 通过方舟汇编编写的标准库 -├── resources # CI jobs描述文件 ├── runtime # ARK运行时公共组件 ├── scripts # CI脚本 ├── templates # ruby模板和脚本,处理包括:命令行选项、记录器组件、错误消息、事件等 @@ -70,6 +69,11 @@ ark_asm [选项] 输入文件 输出文件

使能log打印后,指定log文件输出路径

+

--optimize

+ +

执行字节码优化

+ +

--size-stat

统计并打印出转换后方舟字节码信息

@@ -89,12 +93,12 @@ ark_asm [选项] 输入文件 输出文件 反汇编器工具概述 -工具名称为ark\_dissam,用于将二进制格式的方舟字节码文件转换为可读的文本格式的方舟字节码文件。 +工具名称为ark\_disasm,用于将二进制格式的方舟字节码文件转换为可读的文本格式的方舟字节码文件。 命令行格式: ``` -ark_dissam [选项] 输入文件 输出文件 +ark_disasm [选项] 输入文件 输出文件 ``` @@ -133,6 +137,8 @@ ark_dissam [选项] 输入文件 输出文件 ## 相关仓 +[方舟运行时使用指南](https://gitee.com/openharmony/ark_js_runtime/blob/master/docs/ARK-Runtime-Usage-Guide-zh.md) + [方舟运行时子系统](https://gitee.com/openharmony/ark_js_runtime/blob/master/docs/ARK-Runtime-Subsystem-zh.md) **[ark/runtime\_core](README_zh.md)** @@ -140,4 +146,3 @@ ark_dissam [选项] 输入文件 输出文件 [ark/js\_runtime](https://gitee.com/openharmony/ark_js_runtime/blob/master/README_zh.md) [ark/ts2abc](https://gitee.com/openharmony/ark_ts2abc/blob/master/README_zh.md) - -- Gitee