From 14c9021696ce6806fa6669bde482a7e9ad4f8dff Mon Sep 17 00:00:00 2001 From: wanyanglan Date: Sat, 4 Sep 2021 16:04:43 +0800 Subject: [PATCH 1/3] add ark runtime_core Signed-off-by: wanyanglan Change-Id: I2564094cef9c6c41263e37faf9ffbbec14223dc7 --- .clang-format | 126 + .clang-tidy | 75 + .gitattributes | 6 + .gitignore | 16 + .gn | 19 + AUTHORS | 135 + BUILD.gn | 150 + CMakeLists.txt | 240 + LICENSE | 202 + OAT.xml | 69 + README.en.md | 36 - README.md | 163 +- README_zh.md | 143 + ark_config.gni | 186 + assembler/BUILD.gn | 187 + assembler/CMakeLists.txt | 148 + assembler/annotation.cpp | 246 + assembler/annotation.h | 562 ++ assembler/asm_isapi.rb | 124 + assembler/asm_metadata.rb | 248 + assembler/assembly-context.h | 78 + assembler/assembly-debug.h | 54 + assembler/assembly-emitter.cpp | 1799 +++++++ assembler/assembly-emitter.h | 241 + assembler/assembly-field.h | 44 + assembler/assembly-file-location.h | 43 + assembler/assembly-function.h | 177 + assembler/assembly-ins.cpp | 101 + assembler/assembly-ins.h | 236 + assembler/assembly-label.h | 40 + assembler/assembly-literals.h | 45 + assembler/assembly-methodhandle.h | 31 + assembler/assembly-parser.cpp | 1855 +++++++ assembler/assembly-parser.h | 250 + assembler/assembly-program.cpp | 35 + assembler/assembly-program.h | 48 + assembler/assembly-record.h | 64 + assembler/assembly-type.cpp | 124 + assembler/assembly-type.h | 187 + assembler/context.cpp | 196 + assembler/define.h | 48 + assembler/error.h | 121 + .../extensions/ecmascript/ecmascript_meta.cpp | 22 + .../extensions/ecmascript/ecmascript_meta.h | 231 + assembler/extensions/ecmascript/metadata.yaml | 27 + assembler/extensions/extensions.cpp | 142 + assembler/extensions/extensions.h | 49 + assembler/ide_helpers.h | 86 + assembler/lexer.cpp | 386 ++ assembler/lexer.h | 121 + assembler/mangling.h | 60 + assembler/meta.cpp | 511 ++ assembler/meta.h | 595 +++ assembler/metadata.yaml | 55 + assembler/pandasm.cpp | 246 + assembler/pandasm.h | 51 + assembler/samples/Bubblesort.pa | 83 + assembler/samples/Factorial.pa | 37 + assembler/samples/Fibonacci.pa | 52 + assembler/templates/builtin_parsing.cpp.erb | 63 + .../templates/builtin_parsing_tests.cpp.erb | 146 + assembler/templates/ins_create_api.h.erb | 63 + .../templates/ins_create_builtins_api.h.erb | 60 + assembler/templates/ins_emit.h.erb | 192 + assembler/templates/ins_to_string.cpp.erb | 60 + assembler/templates/isa.h.erb | 57 + assembler/templates/meta_gen.cpp.erb | 46 + assembler/templates/opcode_parsing.h.erb | 135 + assembler/templates/operand_types_print.h.erb | 53 + assembler/tests/emitter_test.cpp | 871 ++++ assembler/tests/lexer_test.cpp | 217 + assembler/tests/mangling_tests.cpp | 47 + assembler/tests/parser_test.cpp | 3706 +++++++++++++ assembler/utils/number-utils.h | 207 + cmake/ClangTidy.cmake | 179 + cmake/CodeStyle.cmake | 108 + cmake/CommonTesting.cmake | 149 + cmake/Definitions.cmake | 214 + cmake/HostTools.cmake | 59 + cmake/PandaAssembly.cmake | 431 ++ cmake/PandaCCache.cmake | 19 + cmake/PandaCmakeFunctions.cmake | 61 + cmake/README.md | 73 + cmake/Sanitizers.cmake | 90 + cmake/TemplateBasedGen.cmake | 230 + cmake/Testing.cmake | 85 + cmake/ark-third-party/miniz/CMakeLists.txt | 36 + cmake/ark-third-party/securec/CMakeLists.txt | 76 + cmake/host-tools-CMakeLists.txt | 75 + cmake/toolchain/aflplusplus.cmake | 28 + cmake/toolchain/common.cmake | 50 + .../cross-clang-8-qemu-aarch64.cmake | 31 + ...cross-clang-8-qemu-arm-linux-gnueabi.cmake | 34 + ...oss-clang-8-qemu-arm-linux-gnueabihf.cmake | 34 + cmake/toolchain/cross-clang-8-x86.cmake | 18 + ...ss-clang-8-x86_64-w64-mingw32-static.cmake | 51 + .../cross-clang-9-qemu-aarch64.cmake | 31 + ...oss-clang-9-qemu-arm-linux-gnueabihf.cmake | 34 + cmake/toolchain/cross-clang-9-x86.cmake | 18 + ...ss-clang-9-x86_64-w64-mingw32-static.cmake | 51 + .../cross-clang-default-qemu-aarch64.cmake | 31 + ...clang-default-qemu-arm-linux-gnueabi.cmake | 34 + ...ang-default-qemu-arm-linux-gnueabihf.cmake | 34 + cmake/toolchain/cross-clang-default-x86.cmake | 18 + .../toolchain/cross-gcc-8-qemu-aarch64.cmake | 24 + .../cross-gcc-8-qemu-arm-linux-gnueabi.cmake | 33 + ...cross-gcc-8-qemu-arm-linux-gnueabihf.cmake | 32 + cmake/toolchain/cross-gcc-8-x86.cmake | 18 + .../cross-gcc-default-qemu-aarch64.cmake | 24 + ...s-gcc-default-qemu-arm-linux-gnueabi.cmake | 31 + ...gcc-default-qemu-arm-linux-gnueabihf.cmake | 31 + cmake/toolchain/cross-gcc-default-x86.cmake | 18 + cmake/toolchain/cross-ohos-aarch64.cmake | 37 + cmake/toolchain/fuzzing-coverage.cmake | 22 + cmake/toolchain/host_clang_12.cmake | 18 + cmake/toolchain/host_clang_8.cmake | 16 + cmake/toolchain/host_clang_9.cmake | 16 + cmake/toolchain/host_clang_default.cmake | 16 + cmake/toolchain/host_gcc_8.cmake | 16 + cmake/toolchain/host_gcc_default.cmake | 16 + cmake/toolchain/libfuzzer.cmake | 21 + disassembler/BUILD.gn | 137 + disassembler/CMakeLists.txt | 251 + disassembler/accumulators.h | 57 + disassembler/disasm.cpp | 105 + disassembler/disassembler.cpp | 1351 +++++ disassembler/disassembler.h | 163 + .../templates/bc_ins_to_pandasm_ins.cpp.erb | 109 + disassembler/templates/get_ins_info.cpp.erb | 77 + .../templates/get_instructions.cpp.erb | 143 + disassembler/templates/intrinsics_gen.h.erb | 108 + .../templates/opcode_translator.cpp.erb | 31 + .../templates/type_to_pandasm_type.cpp.erb | 70 + disassembler/tests/instructions_test.cpp | 357 ++ disassembler/tests/labels_test.cpp | 124 + disassembler/tests/records_test.cpp | 98 + disassembler/tests/sources/builtins.pa | 30 + disassembler/tests/sources/calls.pa | 149 + disassembler/tests/sources/empty_record.pa | 14 + disassembler/tests/sources/exceptions.pa | 42 + disassembler/tests/sources/instructions.pa | 194 + disassembler/tests/sources/labels1.pa | 26 + disassembler/tests/sources/labels2.pa | 42 + disassembler/tests/sources/meta.pa | 30 + disassembler/tests/sources/newarrs.pa | 31 + .../tests/sources/record_in_record.pa | 21 + .../tests/sources/record_with_fields.pa | 26 + disassembler/tests/sources/returns.pa | 26 + docs/assembly_format.md | 508 ++ docs/bc_verification/absint_checks.md | 37 + docs/bc_verification/cflow_checks.md | 309 ++ docs/bc_verification/type_system.md | 61 + docs/bc_verification/types_n_values.md | 104 + docs/cfi_directives.md | 37 + docs/coding-style.md | 82 + docs/debugger-vscode-communication.md | 21 + docs/design-of-interpreter.md | 205 + docs/diagrams/gc-mark.puactivity | 41 + docs/diagrams/gc-thread-activity.puactivity | 42 + .../gc-trigger-sequence-OOM.pusequence | 38 + .../gc-trigger-sequence-threshold.pusequence | 43 + ...al-concurrent-major-gc-activity.puactivity | 29 + .../generational-major-gc-activity.puactivity | 21 + .../generational-minor-gc-activity.puactivity | 24 + docs/diagrams/mm-components.pucomponent | 29 + .../panda-states-concurrent-gc.pustate | 47 + .../panda-states-generational-gc.pustate | 47 + docs/diagrams/reference-processor.puactivity | 41 + docs/diagrams/reference-processor.pusequence | 17 + docs/diagrams/stacktrace.pusequence | 33 + ...tatic-analyzer-gc-func-list-gen.puactivity | 34 + ...atic-analyzer-report-generation.puactivity | 24 + ...ic-analyzer-warnings-generation.puactivity | 39 + docs/file_format.md | 1033 ++++ docs/glossary.md | 81 + docs/images/cfi_hack_bridges.png | Bin 0 -> 20658 bytes docs/images/def-use-structure.png | Bin 0 -> 65289 bytes docs/images/osr_trigger.png | Bin 0 -> 46737 bytes docs/images/panda-mm-overview.png | Bin 0 -> 100463 bytes docs/interpreter-language-extensions.md | 101 + docs/memory-management-SW-requirements.md | 72 + docs/memory-management.md | 597 +++ docs/panda-runtime.md | 31 + docs/rationale-for-bytecode.md | 214 + docs/runtime-class.md | 96 + docs/runtime-compiled_code-interaction.md | 409 ++ docs/runtime-debug-api.md | 29 + docs/tracing.md | 53 + dprof/BUILD.gn | 40 + dprof/CMakeLists.txt | 17 + dprof/converter/CMakeLists.txt | 26 + dprof/converter/features/hotness_counters.h | 135 + dprof/converter/features_manager.h | 82 + dprof/converter/main.cpp | 104 + dprof/converter/options.yaml | 37 + dprof/daemon/CMakeLists.txt | 25 + dprof/daemon/main.cpp | 281 + dprof/daemon/options.yaml | 32 + dprof/libdprof/CMakeLists.txt | 40 + dprof/libdprof/dprof/ipc/ipc_message.cpp | 80 + dprof/libdprof/dprof/ipc/ipc_message.h | 73 + .../libdprof/dprof/ipc/ipc_message_protocol.h | 45 + dprof/libdprof/dprof/ipc/ipc_unix_socket.cpp | 162 + dprof/libdprof/dprof/ipc/ipc_unix_socket.h | 31 + dprof/libdprof/dprof/profiling_data.cpp | 84 + dprof/libdprof/dprof/profiling_data.h | 45 + dprof/libstorage/CMakeLists.txt | 25 + dprof/libstorage/dprof/storage.cpp | 220 + dprof/libstorage/dprof/storage.h | 99 + gn/ark-third-party/miniz/BUILD.gn | 31 + gn/ark-third-party/securec/BUILD.gn | 91 + gn/ark/runtime/ark_config.gni | 186 + gn/build/BUILD.gn | 41 + gn/build/config/BUILDCONFIG.gn | 50 + gn/build/config/compiler/BUILD.gn | 18 + gn/build/config/ohos/rules.gni | 12 + gn/build/ohos.gni | 94 + gn/build/toolchain/BUILD.gn | 120 + isa/CMakeLists.txt | 53 + isa/README.md | 25 + isa/asserts.rb | 181 + isa/builtins.yaml | 535 ++ isa/builtinsapi.rb | 226 + isa/gen.rb | 88 + isa/gen_wrapper.sh | 63 + isa/isa.yaml | 2854 ++++++++++ isa/isapi.rb | 462 ++ isa/schema.json | 149 + isa/templates/instructions.txt.erb | 15 + isa/templates/isa.md.erb | 52 + ldscripts/panda.ld | 121 + ldscripts/panda_test_asan.ld | 361 ++ libpandabase/BUILD.gn | 137 + libpandabase/CMakeLists.txt | 263 + libpandabase/README.md | 154 + libpandabase/clang.h | 96 + libpandabase/cmake/mm_coverage.cmake | 53 + libpandabase/concepts.h | 140 + libpandabase/events/events.h | 21 + libpandabase/events/events.rb | 83 + libpandabase/events/events.yaml | 186 + libpandabase/events/events_gen.h.erb | 287 ++ libpandabase/globals.h | 39 + libpandabase/macros.h | 304 ++ libpandabase/mem/alloc_tracker.cpp | 265 + libpandabase/mem/alloc_tracker.h | 217 + libpandabase/mem/arena.cpp | 149 + libpandabase/mem/arena.h | 226 + libpandabase/mem/arena_allocator.cpp | 181 + libpandabase/mem/arena_allocator.h | 239 + .../mem/arena_allocator_stl_adapter.h | 175 + libpandabase/mem/base_mem_stats.cpp | 111 + libpandabase/mem/base_mem_stats.h | 62 + libpandabase/mem/code_allocator.cpp | 98 + libpandabase/mem/code_allocator.h | 75 + libpandabase/mem/gc_barrier.h | 201 + libpandabase/mem/malloc_mem_pool-inl.h | 124 + libpandabase/mem/malloc_mem_pool.h | 55 + libpandabase/mem/mem.h | 250 + libpandabase/mem/mem_config.cpp | 26 + libpandabase/mem/mem_config.h | 91 + libpandabase/mem/mem_pool.h | 157 + libpandabase/mem/mem_range.h | 78 + libpandabase/mem/mmap_mem_pool-inl.h | 482 ++ libpandabase/mem/mmap_mem_pool.h | 269 + libpandabase/mem/object_pointer.h | 143 + libpandabase/mem/pool_manager.cpp | 88 + libpandabase/mem/pool_manager.h | 50 + libpandabase/mem/pool_map.cpp | 83 + libpandabase/mem/pool_map.h | 171 + libpandabase/mem/space.h | 75 + libpandabase/os/debug_info.cpp | 562 ++ libpandabase/os/debug_info.h | 187 + libpandabase/os/dfx_option.cpp | 59 + libpandabase/os/dfx_option.h | 82 + libpandabase/os/error.h | 45 + libpandabase/os/exec.h | 37 + libpandabase/os/file.h | 61 + libpandabase/os/filesystem.cpp | 41 + libpandabase/os/filesystem.h | 41 + libpandabase/os/library_loader.h | 42 + libpandabase/os/mem.h | 365 ++ libpandabase/os/mutex.h | 123 + libpandabase/os/native_stack.cpp | 57 + libpandabase/os/native_stack.h | 59 + libpandabase/os/property.cpp | 25 + libpandabase/os/property.h | 39 + libpandabase/os/stacktrace.cpp | 324 ++ libpandabase/os/stacktrace.h | 55 + libpandabase/os/stacktrace_stub.cpp | 30 + libpandabase/os/thread.h | 132 + libpandabase/os/time.cpp | 35 + libpandabase/os/time.h | 38 + libpandabase/os/unix/error.cpp | 47 + libpandabase/os/unix/exec.cpp | 52 + libpandabase/os/unix/failure_retry.h | 24 + libpandabase/os/unix/file.cpp | 57 + libpandabase/os/unix/file.h | 219 + libpandabase/os/unix/filesystem.cpp | 32 + libpandabase/os/unix/futex/mutex.cpp | 539 ++ libpandabase/os/unix/futex/mutex.h | 297 ++ libpandabase/os/unix/library_loader.cpp | 42 + libpandabase/os/unix/library_loader.h | 67 + libpandabase/os/unix/mem.cpp | 282 + libpandabase/os/unix/mutex.cpp | 203 + libpandabase/os/unix/mutex.h | 108 + libpandabase/os/unix/native_stack.cpp | 224 + libpandabase/os/unix/native_stack.h | 47 + libpandabase/os/unix/pipe.cpp | 122 + libpandabase/os/unix/pipe.h | 44 + libpandabase/os/unix/property.cpp | 34 + libpandabase/os/unix/property.h | 33 + libpandabase/os/unix/sighooklib/sighook.cpp | 499 ++ libpandabase/os/unix/sighooklib/sighook.h | 55 + libpandabase/os/unix/thread.cpp | 128 + libpandabase/os/unix/time_unix.cpp | 57 + libpandabase/os/unix/time_unix.h | 39 + libpandabase/os/unix/unique_fd.h | 94 + libpandabase/os/unix/unix_mem.h | 35 + libpandabase/os/windows/error.cpp | 41 + libpandabase/os/windows/file.cpp | 86 + libpandabase/os/windows/file.h | 188 + libpandabase/os/windows/mem.cpp | 237 + libpandabase/os/windows/thread.cpp | 27 + libpandabase/os/windows/windows_mem.h | 32 + libpandabase/serializer/for_each_tuple.h | 40 + libpandabase/serializer/serializer.h | 325 ++ libpandabase/serializer/struct_to_tuple.h | 65 + libpandabase/serializer/tuple_to_struct.h | 40 + libpandabase/tests/alloc_tracker_test.cpp | 157 + libpandabase/tests/arena_allocator_test.cpp | 571 ++ libpandabase/tests/arena_test.cpp | 106 + libpandabase/tests/base_mem_stats_test.cpp | 79 + libpandabase/tests/bit_helpers_test.cpp | 72 + libpandabase/tests/bit_memory_region_test.cpp | 164 + libpandabase/tests/bit_table_test.cpp | 463 ++ libpandabase/tests/bit_utils_test.cpp | 67 + libpandabase/tests/bit_vector_test.cpp | 318 ++ libpandabase/tests/code_allocator_test.cpp | 65 + libpandabase/tests/dfx_test.cpp | 141 + libpandabase/tests/expected_test.cpp | 117 + libpandabase/tests/hash_test.cpp | 164 + libpandabase/tests/json_parser_test.cpp | 214 + libpandabase/tests/leb128_test.cpp | 215 + libpandabase/tests/list_test.cpp | 256 + libpandabase/tests/logger_test.cpp | 356 ++ libpandabase/tests/math_helpers_test.cpp | 72 + libpandabase/tests/mem_range_test.cpp | 209 + libpandabase/tests/memory_literals_test.cpp | 33 + libpandabase/tests/mmap_fixed_test.cpp | 66 + libpandabase/tests/mmap_mem_pool_test.cpp | 168 + .../tests/native_bytes_from_mallinfo_test.cpp | 68 + libpandabase/tests/pandargs_test.cpp | 815 +++ libpandabase/tests/pool_map_test.cpp | 188 + libpandabase/tests/serializer_test.cpp | 188 + libpandabase/tests/small_vector_test.cpp | 430 ++ libpandabase/tests/span_test.cpp | 126 + libpandabase/tests/string_helpers_test.cpp | 108 + libpandabase/tests/type_converter_tests.cpp | 94 + libpandabase/tests/unique_fd_test.cpp | 135 + libpandabase/tests/utf_test.cpp | 402 ++ libpandabase/trace/trace.cpp | 31 + libpandabase/trace/trace.h | 125 + libpandabase/trace/unix/trace.cpp | 92 + libpandabase/trace/windows/trace.cpp | 50 + libpandabase/utils/aligned_storage.h | 53 + libpandabase/utils/arch.h | 298 ++ libpandabase/utils/arena_containers.h | 72 + libpandabase/utils/asan_interface.h | 58 + libpandabase/utils/bit_field.h | 135 + libpandabase/utils/bit_helpers.h | 53 + libpandabase/utils/bit_memory_region-inl.h | 67 + libpandabase/utils/bit_memory_region.h | 286 + libpandabase/utils/bit_memory_stream.h | 113 + libpandabase/utils/bit_table.h | 688 +++ libpandabase/utils/bit_utils.h | 320 ++ libpandabase/utils/bit_vector.h | 695 +++ libpandabase/utils/cframe_layout.h | 301 ++ libpandabase/utils/debug.cpp | 38 + libpandabase/utils/debug.h | 31 + libpandabase/utils/dfx.cpp | 196 + libpandabase/utils/dfx.h | 104 + libpandabase/utils/expected.h | 165 + libpandabase/utils/hash.h | 148 + libpandabase/utils/hash_base.h | 77 + libpandabase/utils/json_parser.cpp | 283 + libpandabase/utils/json_parser.h | 200 + libpandabase/utils/leb128.h | 159 + libpandabase/utils/list.h | 630 +++ libpandabase/utils/logger.cpp | 327 ++ libpandabase/utils/logger.h | 449 ++ libpandabase/utils/math_helpers.h | 157 + libpandabase/utils/murmur3_hash.h | 202 + libpandabase/utils/pandargs.h | 898 ++++ libpandabase/utils/small_vector.h | 520 ++ libpandabase/utils/span.h | 275 + libpandabase/utils/string_helpers.h | 112 + libpandabase/utils/terminate.cpp | 56 + libpandabase/utils/terminate.h | 25 + libpandabase/utils/time.cpp | 47 + libpandabase/utils/time.h | 35 + libpandabase/utils/tsan_interface.h | 31 + libpandabase/utils/type_converter.cpp | 136 + libpandabase/utils/type_converter.h | 110 + libpandabase/utils/type_helpers.h | 70 + libpandabase/utils/utf.cpp | 395 ++ libpandabase/utils/utf.h | 143 + libpandabase/utils/utils.h | 45 + libpandabase/utils/value_object.h | 24 + libpandafile/BUILD.gn | 136 + libpandafile/CMakeLists.txt | 125 + libpandafile/annotation_data_accessor.cpp | 52 + libpandafile/annotation_data_accessor.h | 123 + libpandafile/ark_version.cpp | 37 + libpandafile/ark_version.h | 30 + libpandafile/bytecode_emitter.cpp | 477 ++ libpandafile/bytecode_emitter.h | 139 + libpandafile/bytecode_instruction-inl.h | 96 + libpandafile/bytecode_instruction.h | 388 ++ libpandafile/class_data_accessor-inl.h | 170 + libpandafile/class_data_accessor.cpp | 69 + libpandafile/class_data_accessor.h | 150 + libpandafile/code_data_accessor-inl.h | 65 + libpandafile/code_data_accessor.cpp | 53 + libpandafile/code_data_accessor.h | 185 + libpandafile/debug_data_accessor-inl.h | 83 + libpandafile/debug_data_accessor.cpp | 31 + libpandafile/debug_data_accessor.h | 91 + libpandafile/debug_info_extractor.cpp | 347 ++ libpandafile/debug_info_extractor.h | 84 + libpandafile/external/BUILD.gn | 73 + libpandafile/external/CMakeLists.txt | 48 + libpandafile/external/file_ext.cpp | 175 + libpandafile/external/file_ext.h | 50 + libpandafile/external/panda_file_external.h | 121 + libpandafile/external/panda_file_support.cpp | 66 + libpandafile/field_data_accessor-inl.h | 151 + libpandafile/field_data_accessor.cpp | 91 + libpandafile/field_data_accessor.h | 170 + libpandafile/file-inl.h | 38 + libpandafile/file.cpp | 649 +++ libpandafile/file.h | 383 ++ libpandafile/file_item_container.cpp | 983 ++++ libpandafile/file_item_container.h | 462 ++ libpandafile/file_items.cpp | 1548 ++++++ libpandafile/file_items.h | 1612 ++++++ libpandafile/file_writer.cpp | 69 + libpandafile/file_writer.h | 226 + libpandafile/helpers.h | 124 + libpandafile/line_program_state.h | 113 + libpandafile/literal_data_accessor-inl.h | 101 + libpandafile/literal_data_accessor.cpp | 28 + libpandafile/literal_data_accessor.h | 96 + libpandafile/method_data_accessor-inl.h | 236 + libpandafile/method_data_accessor.cpp | 45 + libpandafile/method_data_accessor.h | 190 + libpandafile/method_handle_data_accessor.cpp | 32 + libpandafile/method_handle_data_accessor.h | 68 + libpandafile/modifiers.h | 70 + libpandafile/panda_cache.h | 192 + libpandafile/pandafile_isapi.rb | 80 + .../param_annotations_data_accessor.h | 141 + libpandafile/proto_data_accessor-inl.h | 116 + libpandafile/proto_data_accessor.h | 82 + libpandafile/shorty_iterator.h | 95 + .../templates/bytecode_builtin_enum_gen.h.erb | 22 + .../templates/bytecode_emitter_def_gen.h.erb | 23 + .../templates/bytecode_emitter_gen.h.erb | 193 + .../bytecode_instruction-inl_gen.h.erb | 375 ++ .../bytecode_instruction_enum_gen.h.erb | 33 + libpandafile/templates/isa_checksum.h.erb | 23 + .../tests/bytecode_emitter_tests_gen.h.erb | 156 + libpandafile/templates/type.h.erb | 237 + libpandafile/tests/ark_version_test.cpp | 47 + libpandafile/tests/bytecode_emitter_tests.cpp | 749 +++ .../tests/bytecode_instruction_tests.cpp | 725 +++ .../tests/debug_info_extractor_test.cpp | 374 ++ .../tests/file_item_container_test.cpp | 801 +++ libpandafile/tests/file_items_test.cpp | 54 + libpandafile/tests/file_test.cpp | 199 + libpandafile/tests/panda_cache_test.cpp | 316 ++ libpandafile/type_helper.h | 43 + libpandafile/types.rb | 35 + libpandafile/types.yaml | 122 + libpandafile/value.h | 124 + libziparchive/BUILD.gn | 87 + libziparchive/CMakeLists.txt | 44 + libziparchive/tests/libziparchive_tests.cpp | 1115 ++++ libziparchive/zip_archive.cpp | 233 + libziparchive/zip_archive.h | 170 + ohos.build | 18 + panda/BUILD.gn | 42 + panda/CMakeLists.txt | 50 + panda/panda.cpp | 291 ++ pandastdlib/CMakeLists.txt | 28 + pandastdlib/pandastdlib.pa | 750 +++ runtime/BUILD.gn | 456 ++ runtime/CMakeLists.txt | 624 +++ runtime/arch/aarch64/helpers_aarch64.S | 156 + runtime/arch/aarch64/interpreter_support.S | 58 + runtime/arch/aarch64/memory.h | 28 + runtime/arch/aarch64/shorty.S | 42 + runtime/arch/amd64/helpers_amd64.S | 56 + runtime/arch/amd64/interpreter_support.S | 54 + runtime/arch/amd64/memory.h | 29 + runtime/arch/amd64/shorty.S | 44 + runtime/arch/arm/asm_constants.h | 101 + runtime/arch/arm/interpreter_support.S | 56 + runtime/arch/arm/memory.h | 32 + runtime/arch/arm/shorty.S | 42 + runtime/arch/asm_support.cpp | 69 + runtime/arch/asm_support.h | 94 + runtime/arch/helpers.h | 357 ++ runtime/arch/memory_helpers.h | 44 + runtime/arch/x86/interpreter_support.S | 29 + runtime/arch/x86/memory.h | 29 + runtime/arch/x86/shorty.S | 44 + runtime/asm_defines/BUILD.gn | 54 + runtime/asm_defines/CMakeLists.txt | 56 + runtime/asm_defines/asm_defines.def | 91 + runtime/asm_defines/defines.cpp | 33 + runtime/asm_defines/defines_generator.rb | 49 + runtime/assert_gc_scope.cpp | 27 + runtime/assert_gc_scope.h | 76 + ...piled_code_to_interpreter_bridge_aarch64.S | 264 + ...d_code_to_interpreter_bridge_dyn_aarch64.S | 225 + .../compiled_code_to_runtime_bridge_aarch64.S | 137 + .../aarch64/handle_call_imm16_v16_aarch64.S | 58 + .../handle_call_imm4_v4_v4_v4_aarch64.S | 72 + .../handle_call_imm8_imm16_v8_aarch64.S | 67 + .../aarch64/handle_call_imm8_v8_aarch64.S | 35 + .../aarch64/handle_call_imm8_v8_v8_aarch64.S | 40 + .../handle_call_imm8_v8_v8_v8_aarch64.S | 45 + .../handle_call_imm8_v8_v8_v8_v8_aarch64.S | 50 + .../handle_call_v4_imm4_id16_aarch64.S | 64 + .../aarch64/handle_call_v4_v4_id16_aarch64.S | 42 + .../handle_call_v4_v4_v4_imm4_id16_aarch64.S | 54 + .../aarch64/handle_call_v8_id16_aarch64.S | 33 + .../handle_initobj_v4_v4_id16_aarch64.S | 50 + .../aarch64/handle_initobj_v8_id16_aarch64.S | 40 + ...erpreter_to_compiled_code_bridge_aarch64.S | 479 ++ ...eter_to_compiled_code_bridge_dyn_aarch64.S | 174 + ...ompiled_code_to_interpreter_bridge_amd64.S | 257 + ...led_code_to_interpreter_bridge_dyn_amd64.S | 243 + .../compiled_code_to_runtime_bridge_amd64.S | 109 + .../arch/amd64/handle_call_imm16_v16_amd64.S | 64 + .../amd64/handle_call_imm4_v4_v4_v4_amd64.S | 83 + .../amd64/handle_call_imm8_imm16_v8_amd64.S | 79 + .../arch/amd64/handle_call_imm8_v8_amd64.S | 43 + .../arch/amd64/handle_call_imm8_v8_v8_amd64.S | 53 + .../amd64/handle_call_imm8_v8_v8_v8_amd64.S | 62 + .../handle_call_imm8_v8_v8_v8_v8_amd64.S | 71 + .../amd64/handle_call_v4_imm4_id16_amd64.S | 66 + .../arch/amd64/handle_call_v4_v4_id16_amd64.S | 46 + .../handle_call_v4_v4_v4_imm4_id16_amd64.S | 62 + .../arch/amd64/handle_call_v8_id16_amd64.S | 37 + .../amd64/handle_initobj_v4_v4_id16_amd64.S | 56 + .../arch/amd64/handle_initobj_v8_id16_amd64.S | 46 + ...nterpreter_to_compiled_code_bridge_amd64.S | 646 +++ ...preter_to_compiled_code_bridge_dyn_amd64.S | 236 + .../compiled_code_to_interpreter_bridge_arm.S | 246 + ...ompiled_code_to_interpreter_bridge_armhf.S | 281 + ...piled_code_to_interpreter_bridge_dyn_arm.S | 33 + .../arm/compiled_code_to_runtime_bridge_arm.S | 93 + .../arch/arm/handle_call_imm16_v16_arm.S | 50 + .../arch/arm/handle_call_imm4_v4_v4_v4_arm.S | 80 + .../arch/arm/handle_call_imm8_imm16_v8_arm.S | 14 + .../bridge/arch/arm/handle_call_imm8_v8_arm.S | 14 + .../arch/arm/handle_call_imm8_v8_v8_arm.S | 14 + .../arch/arm/handle_call_imm8_v8_v8_v8_arm.S | 14 + .../arm/handle_call_imm8_v8_v8_v8_v8_arm.S | 14 + .../arch/arm/handle_call_v4_imm4_id16_arm.S | 61 + .../arch/arm/handle_call_v4_imm4_id16_armhf.S | 63 + .../arch/arm/handle_call_v4_v4_id16_arm.S | 38 + .../arch/arm/handle_call_v4_v4_id16_armhf.S | 39 + .../arm/handle_call_v4_v4_v4_imm4_id16_arm.S | 55 + .../handle_call_v4_v4_v4_imm4_id16_armhf.S | 64 + .../bridge/arch/arm/handle_call_v8_id16_arm.S | 32 + .../arch/arm/handle_call_v8_id16_armhf.S | 33 + .../arch/arm/handle_initobj_v4_v4_id16_arm.S | 46 + .../arm/handle_initobj_v4_v4_id16_armhf.S | 47 + .../arch/arm/handle_initobj_v8_id16_arm.S | 39 + .../arch/arm/handle_initobj_v8_id16_armhf.S | 40 + .../interpreter_to_compiled_code_bridge_arm.S | 430 ++ ...nterpreter_to_compiled_code_bridge_armhf.S | 592 +++ ...erpreter_to_compiled_code_bridge_dyn_arm.S | 103 + .../compiled_code_to_interpreter_bridge_x86.S | 230 + .../arch/x86/handle_call_v4_imm4_id16_x86.S | 19 + .../arch/x86/handle_call_v4_v4_id16_x86.S | 56 + .../x86/handle_call_v4_v4_v4_imm4_id16_x86.S | 18 + .../bridge/arch/x86/handle_call_v8_id16_x86.S | 42 + .../interpreter_to_compiled_code_bridge_x86.S | 488 ++ runtime/bridge/bridge.cpp | 105 + runtime/bridge/bridge.h | 57 + runtime/cframe.cpp | 161 + runtime/class.cpp | 166 + runtime/class_helper.cpp | 179 + runtime/class_initializer.cpp | 346 ++ runtime/class_initializer.h | 39 + runtime/class_linker.cpp | 1377 +++++ runtime/class_linker_context.h | 205 + runtime/class_linker_extension.cpp | 322 ++ runtime/core/Core.cmake | 18 + runtime/core/core_class_linker_extension.cpp | 340 ++ runtime/core/core_class_linker_extension.h | 83 + runtime/core/core_itable_builder.h | 48 + runtime/core/core_language_context.cpp | 111 + runtime/core/core_language_context.h | 280 + runtime/core/core_vm.cpp | 263 + runtime/core/core_vm.h | 174 + runtime/core/core_vtable_builder.h | 41 + runtime/coretypes/array.cpp | 127 + runtime/coretypes/string.cpp | 819 +++ runtime/dprofiler/dprofiler.cpp | 107 + runtime/dprofiler/dprofiler.h | 67 + runtime/dyn_class_linker_extension.cpp | 189 + runtime/dyn_class_linker_extension.h | 91 + runtime/entrypoints/entrypoints.cpp | 169 + runtime/entrypoints/entrypoints.h | 34 + runtime/entrypoints/entrypoints.rb | 85 + runtime/entrypoints/entrypoints.yaml | 309 ++ .../entrypoints/entrypoints_compiler.inl.erb | 63 + runtime/entrypoints/entrypoints_gen.S.erb | 22 + runtime/entrypoints/entrypoints_gen.h.erb | 76 + runtime/exceptions.cpp | 331 ++ runtime/field.cpp | 74 + runtime/file_manager.cpp | 56 + runtime/gc_task.cpp | 67 + runtime/global_handle_storage-inl.h | 149 + runtime/global_handle_storage.h | 121 + runtime/handle_base-inl.h | 32 + runtime/handle_base.h | 92 + runtime/handle_scope-inl.h | 65 + runtime/handle_scope.cpp | 37 + runtime/handle_scope.h | 92 + runtime/handle_storage-inl.h | 175 + runtime/handle_storage.h | 85 + runtime/imtable_builder.cpp | 129 + runtime/include/cframe.h | 259 + runtime/include/cframe_iterators.h | 486 ++ runtime/include/class-inl.h | 574 +++ runtime/include/class.h | 901 ++++ runtime/include/class_helper.h | 145 + runtime/include/class_linker-inl.h | 55 + runtime/include/class_linker.h | 393 ++ runtime/include/class_linker_extension.h | 301 ++ runtime/include/class_root.h | 57 + runtime/include/compiler_interface.h | 50 + runtime/include/coretypes/array-inl.h | 272 + runtime/include/coretypes/array.h | 211 + runtime/include/coretypes/class.h | 108 + runtime/include/coretypes/dyn_objects.h | 83 + runtime/include/coretypes/native_pointer.h | 59 + runtime/include/coretypes/string-inl.h | 47 + runtime/include/coretypes/string.h | 334 ++ runtime/include/coretypes/tagged_value.h | 333 ++ runtime/include/exceptions.h | 97 + runtime/include/field.h | 157 + runtime/include/file_manager.h | 35 + runtime/include/gc_task.h | 85 + runtime/include/hclass.h | 125 + runtime/include/histogram-inl.h | 97 + runtime/include/histogram.h | 162 + runtime/include/imtable_builder.h | 64 + runtime/include/itable.h | 109 + runtime/include/itable_builder.h | 50 + runtime/include/language_config.h | 37 + runtime/include/language_context.h | 496 ++ runtime/include/locks.h | 68 + runtime/include/mem/allocator-inl.h | 60 + runtime/include/mem/allocator.h | 807 +++ runtime/include/mem/panda_containers.h | 118 + runtime/include/mem/panda_smart_pointers.h | 90 + runtime/include/mem/panda_string.h | 84 + runtime/include/method-inl.h | 317 ++ runtime/include/method.h | 721 +++ runtime/include/object_accessor-inl.h | 438 ++ runtime/include/object_accessor.h | 183 + runtime/include/object_header-inl.h | 207 + runtime/include/object_header.h | 300 ++ runtime/include/panda_vm.h | 107 + runtime/include/runtime.h | 442 ++ runtime/include/runtime_notification.h | 561 ++ runtime/include/runtime_options.h | 388 ++ runtime/include/stack_walker-inl.h | 74 + runtime/include/stack_walker.h | 350 ++ runtime/include/thread-inl.h | 92 + runtime/include/thread.h | 1346 +++++ runtime/include/thread_scopes.h | 88 + runtime/include/thread_status.h | 39 + runtime/include/time_utils.h | 53 + runtime/include/tooling/debug_inf.h | 58 + runtime/include/tooling/debug_interface.h | 505 ++ runtime/include/tooling/pt_class.h | 46 + runtime/include/tooling/pt_lang_extension.h | 80 + runtime/include/tooling/pt_location.h | 68 + runtime/include/tooling/pt_method.h | 44 + runtime/include/tooling/pt_object.h | 42 + runtime/include/tooling/pt_property.h | 42 + runtime/include/tooling/pt_reference.h | 37 + runtime/include/tooling/pt_thread.h | 50 + runtime/include/tooling/pt_value.h | 82 + runtime/include/value-inl.h | 51 + runtime/include/value.h | 94 + runtime/include/vtable_builder-inl.h | 171 + runtime/include/vtable_builder.h | 325 ++ runtime/interpreter/acc_vregister.h | 77 + .../interpreter/arch/aarch64/global_regs.h | 101 + runtime/interpreter/arch/aarch64/macros.h | 36 + runtime/interpreter/arch/global_regs.h | 25 + runtime/interpreter/arch/macros.h | 37 + runtime/interpreter/cache.h | 72 + runtime/interpreter/dispatch_table.h | 61 + runtime/interpreter/frame.h | 363 ++ .../interpreter/instruction_handler_base.h | 230 + .../interpreter/instruction_handler_state.h | 142 + runtime/interpreter/interpreter-inl.h | 3518 +++++++++++++ runtime/interpreter/interpreter.cpp | 42 + runtime/interpreter/interpreter.h | 30 + runtime/interpreter/interpreter_impl.cpp | 85 + runtime/interpreter/interpreter_impl.h | 30 + runtime/interpreter/math_helpers.h | 224 + runtime/interpreter/runtime_interface.cpp | 42 + runtime/interpreter/runtime_interface.h | 293 ++ runtime/interpreter/state.h | 241 + .../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 | 31 + .../templates/interpreter-inl_gen.h.erb | 181 + .../templates/isa_constants_gen.h.erb | 28 + .../unimplemented_handlers-inl.h.erb | 32 + runtime/interpreter/vregister-inl.h | 124 + runtime/interpreter/vregister.h | 269 + runtime/interpreter/vregister_iterator.h | 84 + runtime/intrinsics.cpp | 354 ++ runtime/itable_builder.cpp | 36 + runtime/jit/jit.h | 21 + runtime/jit/profiling_data.h | 150 + runtime/language_context.cpp | 83 + runtime/locks.cpp | 100 + runtime/mark_word.cpp | 97 + runtime/mark_word.h | 389 ++ runtime/mem/alloc_config.h | 352 ++ runtime/mem/allocator.cpp | 629 +++ runtime/mem/allocator_adapter.h | 172 + runtime/mem/bump-allocator-inl.h | 325 ++ runtime/mem/bump-allocator.h | 206 + runtime/mem/frame_allocator-inl.h | 210 + runtime/mem/frame_allocator.h | 124 + runtime/mem/freelist.h | 424 ++ runtime/mem/freelist_allocator-inl.h | 777 +++ runtime/mem/freelist_allocator.h | 340 ++ runtime/mem/gc/bitmap.cpp | 83 + runtime/mem/gc/bitmap.h | 644 +++ runtime/mem/gc/card_table-inl.h | 130 + runtime/mem/gc/card_table.cpp | 164 + runtime/mem/gc/card_table.h | 211 + runtime/mem/gc/crossing_map.cpp | 327 ++ runtime/mem/gc/crossing_map.h | 308 ++ runtime/mem/gc/crossing_map_singleton.cpp | 106 + runtime/mem/gc/crossing_map_singleton.h | 65 + runtime/mem/gc/dynamic/gc_dynamic_data.h | 55 + runtime/mem/gc/dynamic/gc_dynamic_impl.cpp | 132 + runtime/mem/gc/epsilon/epsilon.cpp | 77 + runtime/mem/gc/epsilon/epsilon.h | 49 + runtime/mem/gc/epsilon/epsilon_barrier.cpp | 27 + runtime/mem/gc/epsilon/epsilon_barrier.h | 32 + runtime/mem/gc/g1/g1-allocator.cpp | 280 + runtime/mem/gc/g1/g1-allocator.h | 138 + runtime/mem/gc/g1/g1-gc.cpp | 160 + runtime/mem/gc/g1/g1-gc.h | 167 + runtime/mem/gc/gc.cpp | 737 +++ runtime/mem/gc/gc.h | 861 ++++ runtime/mem/gc/gc_barrier_set.cpp | 133 + runtime/mem/gc/gc_barrier_set.h | 263 + runtime/mem/gc/gc_extension_data.h | 54 + runtime/mem/gc/gc_phase.h | 55 + runtime/mem/gc/gc_queue.cpp | 87 + runtime/mem/gc/gc_queue.h | 97 + runtime/mem/gc/gc_reason.h | 27 + runtime/mem/gc/gc_root-inl.h | 33 + runtime/mem/gc/gc_root.cpp | 280 + runtime/mem/gc/gc_root.h | 166 + runtime/mem/gc/gc_scoped_phase.cpp | 59 + runtime/mem/gc/gc_scoped_phase.h | 114 + runtime/mem/gc/gc_stats.cpp | 330 ++ runtime/mem/gc/gc_stats.h | 233 + runtime/mem/gc/gc_trigger.cpp | 182 + runtime/mem/gc/gc_trigger.h | 177 + runtime/mem/gc/gc_types.h | 130 + runtime/mem/gc/gen-gc/gen-gc.cpp | 708 +++ runtime/mem/gc/gen-gc/gen-gc.h | 146 + runtime/mem/gc/generational-gc-base.cpp | 71 + runtime/mem/gc/generational-gc-base.h | 128 + .../gc/hybrid-gc/hybrid_object_allocator.cpp | 129 + .../gc/hybrid-gc/hybrid_object_allocator.h | 144 + runtime/mem/gc/lang/gc_lang.cpp | 115 + runtime/mem/gc/lang/gc_lang.h | 103 + .../empty_reference_processor.h | 63 + .../reference_processor.cpp | 22 + .../reference-processor/reference_processor.h | 87 + runtime/mem/gc/static/gc_static_impl.cpp | 113 + runtime/mem/gc/stw-gc/stw-gc.cpp | 253 + runtime/mem/gc/stw-gc/stw-gc.h | 63 + runtime/mem/heap_manager.cpp | 407 ++ runtime/mem/heap_manager.h | 244 + runtime/mem/heap_verifier.cpp | 101 + runtime/mem/heap_verifier.h | 108 + runtime/mem/humongous_obj_allocator-inl.h | 511 ++ runtime/mem/humongous_obj_allocator.h | 323 ++ runtime/mem/internal_allocator-inl.h | 118 + runtime/mem/internal_allocator.cpp | 350 ++ runtime/mem/internal_allocator.h | 174 + runtime/mem/lock_config_helper.h | 40 + runtime/mem/malloc-proxy-allocator-inl.h | 92 + runtime/mem/malloc-proxy-allocator.h | 70 + runtime/mem/mem_hooks.cpp | 117 + runtime/mem/mem_hooks.h | 54 + runtime/mem/mem_stats.cpp | 196 + runtime/mem/mem_stats.h | 136 + runtime/mem/mem_stats_additional_info.cpp | 110 + runtime/mem/mem_stats_additional_info.h | 69 + runtime/mem/mem_stats_default.cpp | 50 + runtime/mem/mem_stats_default.h | 59 + runtime/mem/memory_manager.cpp | 140 + runtime/mem/memory_manager.h | 159 + runtime/mem/object_helpers-inl.h | 235 + runtime/mem/object_helpers.cpp | 416 ++ runtime/mem/object_helpers.h | 121 + runtime/mem/panda_string.cpp | 99 + runtime/mem/pygote_space_allocator-inl.h | 303 ++ runtime/mem/pygote_space_allocator.h | 108 + .../mem/refstorage/global_object_storage.cpp | 152 + .../mem/refstorage/global_object_storage.h | 449 ++ runtime/mem/refstorage/ref_block.cpp | 152 + runtime/mem/refstorage/ref_block.h | 179 + runtime/mem/refstorage/reference.h | 136 + runtime/mem/refstorage/reference_storage.cpp | 457 ++ runtime/mem/refstorage/reference_storage.h | 215 + runtime/mem/region_allocator-inl.h | 405 ++ runtime/mem/region_allocator.h | 378 ++ runtime/mem/region_space-inl.h | 115 + runtime/mem/region_space.cpp | 219 + runtime/mem/region_space.h | 510 ++ runtime/mem/rem_set-inl.h | 130 + runtime/mem/rem_set.h | 94 + runtime/mem/rendezvous.cpp | 72 + runtime/mem/rendezvous.h | 88 + runtime/mem/runslots.cpp | 197 + runtime/mem/runslots.h | 313 ++ runtime/mem/runslots_allocator-inl.h | 891 ++++ runtime/mem/runslots_allocator.h | 450 ++ runtime/mem/runslots_allocator_stl_adapter.h | 180 + runtime/mem/tlab.cpp | 123 + runtime/mem/tlab.h | 300 ++ runtime/mem/vm_handle.h | 70 + runtime/method.cpp | 693 +++ runtime/monitor.cpp | 930 ++++ runtime/monitor.h | 226 + runtime/monitor_object_lock.cpp | 62 + runtime/monitor_object_lock.h | 49 + runtime/monitor_pool.cpp | 80 + runtime/monitor_pool.h | 97 + runtime/object_accessor-impl.cpp | 73 + runtime/object_accessor.cpp | 18 + runtime/object_header.cpp | 215 + runtime/object_header_config.h | 77 + runtime/options.yaml | 549 ++ runtime/panda_vm.cpp | 60 + runtime/profilesaver/profile_dump_info.cpp | 575 +++ runtime/profilesaver/profile_dump_info.h | 289 ++ runtime/profilesaver/profile_saver.cpp | 333 ++ runtime/profilesaver/profile_saver.h | 170 + runtime/runtime.cpp | 1210 +++++ runtime/runtime.yaml | 524 ++ runtime/runtime_helpers.cpp | 50 + runtime/signal_handler.cpp | 289 ++ runtime/signal_handler.h | 100 + runtime/stack_walker.cpp | 489 ++ runtime/string_table.cpp | 344 ++ runtime/string_table.h | 162 + runtime/templates/bridge_dispatch.S.erb | 46 + runtime/templates/bridge_helpers_aarch64.rb | 24 + runtime/templates/bridge_helpers_amd64.rb | 25 + runtime/templates/bridge_helpers_arm.rb | 25 + runtime/templates/bridge_helpers_armhf.rb | 25 + runtime/templates/bridge_helpers_dynamic.rb | 34 + runtime/templates/bridge_helpers_static.rb | 30 + runtime/templates/bridge_helpers_x86.rb | 25 + runtime/templates/gen_intrinsics_data.rb | 75 + runtime/templates/intrinsics.h.erb | 68 + runtime/templates/intrinsics.rb | 129 + runtime/templates/intrinsics.yaml.erb | 38 + runtime/templates/intrinsics_gen.h.erb | 126 + runtime/templates/runtime.rb | 155 + runtime/templates/shorty_values.h.erb | 51 + .../unimplemented_intrinsics-inl.cpp.erb | 34 + runtime/tests/allocator_test_base.h | 1405 +++++ .../tests/arch/aarch64/invokation_helper.S | 72 + runtime/tests/arch/amd64/invokation_helper.S | 95 + runtime/tests/arch/arm/invokation_helper.S | 22 + runtime/tests/arch/arm/invokation_helper_hf.S | 22 + runtime/tests/array_test.cpp | 82 + runtime/tests/bitmap_clear_range_test.cpp | 61 + .../bitmap_order_object_alignment_test.cpp | 31 + runtime/tests/bitmap_page_alignment_test.cpp | 72 + runtime/tests/bitmap_test_base.h | 164 + .../bitmap_visitor_object_alignment_test.cpp | 31 + runtime/tests/bump_allocator_test.cpp | 249 + runtime/tests/c2i_bridge_test.cpp | 438 ++ runtime/tests/card_table_test.cpp | 259 + runtime/tests/class_linker_test.cpp | 810 +++ runtime/tests/class_linker_test_extension.cpp | 45 + runtime/tests/class_linker_test_extension.h | 123 + runtime/tests/class_size_test.cpp | 141 + runtime/tests/crossing_map_test.cpp | 332 ++ runtime/tests/debugger_test.cpp | 176 + runtime/tests/frame_allocator_test.cpp | 232 + runtime/tests/frame_test.cpp | 101 + runtime/tests/freelist_allocator_test.cpp | 399 ++ runtime/tests/gc_task_test.cpp | 32 + runtime/tests/histogram_test.cpp | 164 + .../tests/humongous_obj_allocator_test.cpp | 268 + .../tests/hybrid_object_allocator_test.cpp | 108 + runtime/tests/i2c_bridge_test.cpp | 1642 ++++++ runtime/tests/internal_allocator_test.cpp | 132 + .../tests/interpreter/test_interpreter.cpp | 29 + runtime/tests/interpreter/test_interpreter.h | 29 + .../interpreter/test_interpreter_impl.cpp | 28 + .../tests/interpreter/test_interpreter_impl.h | 29 + .../interpreter/test_runtime_interface.cpp | 63 + .../interpreter/test_runtime_interface.h | 467 ++ runtime/tests/interpreter_test.cpp | 3905 ++++++++++++++ runtime/tests/invokation_helper.cpp | 27 + runtime/tests/invokation_helper.h | 144 + runtime/tests/malloc-proxy-allocator-test.cpp | 82 + runtime/tests/mark_word_test.cpp | 528 ++ runtime/tests/math_helpers_test.cpp | 281 + runtime/tests/mem_leak_test.cpp | 80 + .../tests/mem_stats_additional_info_test.cpp | 143 + runtime/tests/mem_stats_gc_test.cpp | 162 + runtime/tests/mem_stats_test.cpp | 466 ++ runtime/tests/method_test.cpp | 509 ++ runtime/tests/mock_queue_thread_pool.cpp | 357 ++ runtime/tests/monitor_test.cpp | 276 + ...multithreaded_intern_string_table_test.cpp | 172 + runtime/tests/offsets_test.cpp | 70 + runtime/tests/options_test.cpp | 118 + runtime/tests/panda_smart_pointers_test.cpp | 82 + .../tests/pygote_space_allocator_gen_test.cpp | 75 + .../tests/pygote_space_allocator_stw_test.cpp | 75 + .../tests/pygote_space_allocator_test_base.h | 276 + runtime/tests/region_allocator_test.cpp | 645 +++ runtime/tests/rem_set_test.cpp | 196 + runtime/tests/runslots_allocator_test.cpp | 368 ++ runtime/tests/string_table_test.cpp | 159 + runtime/tests/string_test.cpp | 766 +++ runtime/tests/thread_test.cpp | 171 + runtime/tests/time_utils_test.cpp | 90 + runtime/tests/tlab_test.cpp | 115 + runtime/thread.cpp | 677 +++ runtime/thread_manager.cpp | 336 ++ runtime/thread_manager.h | 314 ++ runtime/thread_pool.h | 297 ++ runtime/thread_pool_queue.h | 72 + runtime/time_utils.cpp | 75 + runtime/timing.cpp | 100 + runtime/timing.h | 139 + runtime/tooling/debug_inf.cpp | 170 + runtime/tooling/debugger.cpp | 817 +++ runtime/tooling/debugger.h | 493 ++ runtime/tooling/pt_class.cpp | 46 + runtime/tooling/pt_class_private.h | 27 + runtime/tooling/pt_hook_type_info.h | 75 + runtime/tooling/pt_hooks_wrapper.h | 498 ++ runtime/tooling/pt_lang_ext_private.h | 44 + runtime/tooling/pt_lang_extension.cpp | 25 + runtime/tooling/pt_method.cpp | 26 + runtime/tooling/pt_method_private.h | 38 + runtime/tooling/pt_object_private.h | 54 + runtime/tooling/pt_reference.cpp | 132 + runtime/tooling/pt_reference_private.h | 39 + runtime/tooling/pt_scoped_managed_code.h | 46 + runtime/tooling/pt_thread.cpp | 23 + runtime/tooling/pt_thread_info.h | 116 + runtime/tooling/pt_value_private.h | 56 + runtime/vreg_info.h | 220 + runtime/vtable_builder.cpp | 72 + scripts/dep-lists/ubuntu-18-04-arm-dev | 20 + scripts/dep-lists/ubuntu-18-04-build | 5 + scripts/dep-lists/ubuntu-18-04-ci | 23 + scripts/dep-lists/ubuntu-18-04-cross-arm-all | 15 + scripts/dep-lists/ubuntu-18-04-cross-windows | 2 + scripts/dep-lists/ubuntu-18-04-cross-x86 | 4 + scripts/dep-lists/ubuntu-18-04-dev | 24 + scripts/dep-lists/ubuntu-18-04-fuzzing | 8 + scripts/dep-lists/ubuntu-20-04-build | 5 + scripts/dep-lists/ubuntu-20-04-ci | 18 + scripts/dep-lists/ubuntu-20-04-cross-arm-all | 14 + scripts/dep-lists/ubuntu-20-04-cross-windows | 2 + scripts/dep-lists/ubuntu-20-04-cross-x86 | 3 + scripts/dep-lists/ubuntu-20-04-dev | 24 + scripts/dep-lists/ubuntu-20-04-fuzzing | 8 + scripts/dep-lists/ubuntu-build | 5 + scripts/dep-lists/ubuntu-cross-arm-all | 13 + scripts/dep-lists/ubuntu-cross-windows | 2 + scripts/dep-lists/ubuntu-cross-x86 | 3 + scripts/dep-lists/ubuntu-dev | 22 + scripts/dep-lists/ubuntu-fuzzing | 8 + scripts/extra/build.sh | 37 + scripts/install-deps-ubuntu | 274 + scripts/install-third-party | 61 + scripts/memdump.py | 240 + scripts/memusage.py | 237 + scripts/run-check-concurrency-format.sh | 43 + scripts/run-clang-format | 42 + scripts/trace_enable.sh | 113 + templates/common.rb | 144 + templates/events/events.h.erb | 61 + .../logger_components.inc.erb | 28 + templates/messages.rb | 98 + templates/messages/messages.h.erb | 92 + templates/options/options.h.erb | 118 + tests/CMakeLists.txt | 804 +++ tests/benchmarks/3d-morph.pa | 153 + tests/benchmarks/CMakeLists.txt | 167 + tests/benchmarks/access-binary-trees.pa | 171 + tests/benchmarks/access-fannkuch.pa | 173 + tests/benchmarks/access-nbody.pa | 507 ++ tests/benchmarks/access-nsieve.pa | 105 + tests/benchmarks/bitops-3bit-bits-in-byte.pa | 80 + tests/benchmarks/bitops-bits-in-byte.pa | 71 + tests/benchmarks/bitops-bitwise-and.pa | 30 + tests/benchmarks/bitops-nsieve-bits.pa | 127 + tests/benchmarks/controlflow-recursive.pa | 136 + tests/benchmarks/math-cordic.pa | 190 + tests/benchmarks/math-partial-sums.pa | 186 + tests/benchmarks/math-spectral-norm.pa | 211 + tests/cts-assembly/arrays-01.pa | 48 + tests/cts-assembly/arrays-02.pa | 69 + tests/cts-assembly/arrays-03.pa | 94 + tests/cts-assembly/arrays-04.pa | 94 + tests/cts-assembly/arrays-05.pa | 37 + tests/cts-assembly/arrays-06.pa | 204 + tests/cts-assembly/arrays-07.pa | 71 + tests/cts-assembly/arrays-08.pa | 71 + tests/cts-assembly/arrays-09.pa | 43 + tests/cts-assembly/arrays-10.pa | 44 + tests/cts-assembly/arrays-11.pa | 42 + tests/cts-assembly/arrays-12.pa | 47 + tests/cts-assembly/arrays-13.pa | 48 + tests/cts-assembly/arrays-14.pa | 45 + tests/cts-assembly/big_ark_option_value.pa | 39 + .../cts-assembly/compiler_effective_types.pa | 36 + tests/cts-assembly/env-01.pa | 47 + tests/cts-assembly/exceptions-02.pa | 41 + tests/cts-assembly/exceptions-03.pa | 42 + tests/cts-assembly/exceptions-04.pa | 39 + tests/cts-assembly/far-jump-01.pa | 4031 +++++++++++++++ tests/cts-assembly/far-jump-02.pa | 4031 +++++++++++++++ tests/cts-assembly/far-jump-03.pa | 4031 +++++++++++++++ tests/cts-assembly/far-jump-04.pa | 4031 +++++++++++++++ tests/cts-assembly/far-jump-05.pa | 4031 +++++++++++++++ tests/cts-assembly/far-jump-06.pa | 4031 +++++++++++++++ tests/cts-assembly/far-jump-07.pa | 4038 +++++++++++++++ tests/cts-assembly/far-jump-08.pa | 4038 +++++++++++++++ tests/cts-assembly/far-jump-09.pa | 4039 +++++++++++++++ tests/cts-assembly/far-jump-10.pa | 4039 +++++++++++++++ tests/cts-assembly/far-jump-11.pa | 4039 +++++++++++++++ tests/cts-assembly/far-jump-12.pa | 4039 +++++++++++++++ tests/cts-assembly/far-jump-13.pa | 4039 +++++++++++++++ tests/cts-assembly/far-jump-14.pa | 4049 +++++++++++++++ tests/cts-assembly/far-jump-15.pa | 4049 +++++++++++++++ tests/cts-assembly/far-jump-16.pa | 4049 +++++++++++++++ tests/cts-assembly/far-jump-17.pa | 4049 +++++++++++++++ tests/cts-assembly/far-jump-18.pa | 4049 +++++++++++++++ tests/cts-assembly/far-jump-19.pa | 4049 +++++++++++++++ tests/cts-assembly/initobj-01.pa | 46 + tests/cts-assembly/initobj-02.pa | 64 + tests/cts-assembly/initobj-03.pa | 73 + tests/cts-assembly/initobj-04.pa | 45 + tests/cts-assembly/initobj-05.pa | 49 + tests/cts-assembly/initobj-06.pa | 50 + tests/cts-assembly/initobj-bad-02.pa | 38 + tests/cts-assembly/intrinsics-01.pa | 30 + tests/cts-assembly/intrinsics-02.pa | 30 + tests/cts-assembly/intrinsics-03.pa | 51 + tests/cts-assembly/intrinsics-04.pa | 51 + tests/cts-assembly/intrinsics-05.pa | 34 + tests/cts-assembly/intrinsics-06.pa | 34 + tests/cts-assembly/intrinsics-07.pa | 34 + tests/cts-assembly/intrinsics-08.pa | 34 + tests/cts-assembly/intrinsics-09.pa | 35 + tests/cts-assembly/intrinsics-10.pa | 35 + tests/cts-assembly/intrinsics-11.pa | 34 + tests/cts-assembly/intrinsics-12.pa | 34 + tests/cts-assembly/intrinsics-13.pa | 22 + tests/cts-assembly/intrinsics-14.pa | 22 + tests/cts-assembly/intrinsics-15.pa | 22 + tests/cts-assembly/intrinsics-16.pa | 22 + tests/cts-assembly/intrinsics-17.pa | 22 + tests/cts-assembly/intrinsics-18.pa | 22 + tests/cts-assembly/intrinsics-19.pa | 24 + tests/cts-assembly/intrinsics-20.pa | 22 + tests/cts-assembly/intrinsics-21.pa | 25 + tests/cts-assembly/intrinsics-22.pa | 37 + tests/cts-assembly/intrinsics-23.pa | 67 + tests/cts-assembly/intrinsics-24.pa | 57 + tests/cts-assembly/intrinsics-25.pa | 57 + tests/cts-assembly/intrinsics-26.pa | 49 + tests/cts-assembly/intrinsics-28.pa | 41 + tests/cts-assembly/intrinsics-29.pa | 22 + tests/cts-assembly/intrinsics-f32-01.pa | 29 + tests/cts-assembly/math-01.pa | 25 + tests/cts-assembly/math-02.pa | 25 + tests/cts-assembly/math-03.pa | 25 + tests/cts-assembly/math-04.pa | 25 + tests/cts-assembly/math-05.pa | 25 + tests/cts-assembly/math-06.pa | 25 + tests/cts-assembly/math-07.pa | 25 + tests/cts-assembly/math-08.pa | 25 + tests/cts-assembly/math-09.pa | 25 + tests/cts-assembly/math-10.pa | 28 + tests/cts-assembly/math-11.pa | 26 + tests/cts-assembly/math-12.pa | 26 + tests/cts-assembly/math-13.pa | 26 + tests/cts-assembly/math-14.pa | 26 + tests/cts-assembly/math-15.pa | 26 + tests/cts-assembly/math-16.pa | 26 + tests/cts-assembly/math-17.pa | 26 + tests/cts-assembly/math-18.pa | 26 + tests/cts-assembly/math-21.pa | 27 + tests/cts-assembly/math-22.pa | 43 + tests/cts-assembly/math-23.pa | 43 + tests/cts-assembly/math-24.pa | 27 + tests/cts-assembly/math-25.pa | 43 + tests/cts-assembly/math-26.pa | 27 + tests/cts-assembly/math-27.pa | 27 + tests/cts-assembly/math-28.pa | 27 + tests/cts-assembly/math-29.pa | 27 + tests/cts-assembly/math-30.pa | 27 + tests/cts-assembly/math-31.pa | 27 + tests/cts-assembly/math-32.pa | 27 + tests/cts-assembly/math-33.pa | 35 + tests/cts-assembly/math-34.pa | 35 + tests/cts-assembly/math-35.pa | 26 + tests/cts-assembly/math-36.pa | 26 + tests/cts-assembly/math-40.pa | 26 + tests/cts-assembly/math-41.pa | 25 + tests/cts-assembly/math-42.pa | 28 + tests/cts-assembly/math-43.pa | 27 + tests/cts-assembly/math-44.pa | 27 + tests/cts-assembly/math-45.pa | 27 + tests/cts-assembly/math-46.pa | 27 + tests/cts-assembly/math-47.pa | 46 + tests/cts-assembly/math-48.pa | 46 + tests/cts-assembly/math-49.pa | 28 + tests/cts-assembly/math-50.pa | 23 + tests/cts-assembly/math-51.pa | 28 + tests/cts-assembly/math-52.pa | 23 + tests/cts-assembly/math-53.pa | 56 + tests/cts-assembly/math-54.pa | 133 + tests/cts-assembly/math-55.pa | 120 + tests/cts-assembly/math-56.pa | 119 + tests/cts-assembly/math-57.pa | 110 + tests/cts-assembly/math-58.pa | 264 + tests/cts-assembly/math-59.pa | 264 + tests/cts-assembly/math-60.pa | 264 + tests/cts-assembly/math-61.pa | 265 + tests/cts-assembly/math-62.pa | 265 + tests/cts-assembly/math-63.pa | 288 ++ tests/cts-assembly/math-64.pa | 276 + tests/cts-assembly/math-65.pa | 276 + tests/cts-assembly/math-66.pa | 110 + tests/cts-assembly/math-67.pa | 35 + tests/cts-assembly/obj-01.pa | 36 + tests/cts-assembly/obj-02.pa | 51 + tests/cts-assembly/obj-03.pa | 24 + tests/cts-assembly/obj-04.pa | 29 + tests/cts-assembly/obj-05.pa | 42 + tests/cts-assembly/obj-06.pa | 67 + tests/cts-assembly/obj-07.pa | 32 + tests/cts-assembly/obj-08.pa | 40 + tests/cts-assembly/obj-09.pa | 25 + tests/cts-assembly/obj-10.pa | 33 + tests/cts-assembly/obj-11.pa | 36 + tests/cts-assembly/obj-12.pa | 48 + tests/cts-assembly/obj-13.pa | 109 + tests/cts-assembly/obj-14.pa | 123 + tests/cts-assembly/obj-15.pa | 26 + tests/cts-assembly/obj-16.pa | 31 + tests/cts-assembly/obj-17.pa | 30 + tests/cts-assembly/obj-18.pa | 31 + tests/cts-assembly/obj-23.pa | 28 + tests/cts-assembly/obj-24.pa | 29 + tests/cts-assembly/obj-25.pa | 39 + tests/cts-assembly/obj-26.pa | 47 + tests/cts-assembly/obj-27.pa | 48 + tests/cts-assembly/obj-28.pa | 50 + tests/cts-assembly/obj-29.pa | 49 + tests/cts-assembly/obj-30.pa | 50 + tests/cts-assembly/obj-31.pa | 37 + tests/cts-assembly/obj-32.pa | 41 + tests/cts-assembly/obj-33.pa | 44 + tests/cts-assembly/obj-34.pa | 38 + tests/cts-assembly/obj-35.pa | 43 + tests/cts-assembly/obj-36.pa | 49 + tests/cts-assembly/op-01.pa | 26 + tests/cts-assembly/op-02.pa | 26 + tests/cts-assembly/op-03.pa | 25 + tests/cts-assembly/op-04.pa | 22 + tests/cts-assembly/op-05.pa | 22 + tests/cts-assembly/op-06.pa | 23 + tests/cts-assembly/op-07.pa | 23 + tests/cts-assembly/op-08.pa | 23 + tests/cts-assembly/op-09.pa | 27 + tests/cts-assembly/op-10.pa | 27 + tests/cts-assembly/op-11.pa | 27 + tests/cts-assembly/op-12.pa | 27 + tests/cts-assembly/op-13.pa | 27 + tests/cts-assembly/op-14.pa | 24 + tests/cts-assembly/op-15.pa | 29 + tests/cts-assembly/op-16.pa | 29 + tests/cts-assembly/op-17.pa | 33 + tests/cts-assembly/op-18.pa | 43 + tests/cts-assembly/op-19.pa | 33 + tests/cts-assembly/op-20.pa | 22 + tests/cts-assembly/op-21.pa | 32 + tests/cts-assembly/op-22.pa | 32 + tests/cts-assembly/op-25.pa | 27 + tests/cts-assembly/op-26.pa | 26 + tests/cts-assembly/op-jeq-obj.pa | 29 + tests/cts-assembly/op-jeqz-obj.pa | 28 + tests/cts-assembly/op-jne-obj.pa | 29 + tests/cts-assembly/op-jnez-obj.pa | 28 + tests/cts-assembly/verify-01.pa | 23 + tests/cts-coverage-tool/CMakeLists.txt | 49 + tests/cts-coverage-tool/README.md | 46 + tests/cts-coverage-tool/non_testable.yaml | 137 + tests/cts-coverage-tool/spec.rb | 296 ++ tests/cts-coverage-tool/spectrac.rb | 89 + tests/cts-coverage-tool/templates/full_md.erb | 70 + tests/cts-coverage-tool/templates/full_md.rb | 75 + .../templates/orphaned_md.erb | 25 + .../templates/orphaned_md.rb | 46 + tests/cts-coverage-tool/templates/report.erb | 30 + .../cts-coverage-tool/templates/report_md.rb | 38 + .../templates/uncovered_md.erb | 54 + .../templates/uncovered_md.rb | 52 + tests/cts-generator/CMakeLists.txt | 192 + tests/cts-generator/README.md | 162 + tests/cts-generator/cts-template/add.yaml | 590 +++ tests/cts-generator/cts-template/add2.64.yaml | 474 ++ tests/cts-generator/cts-template/add2.yaml | 574 +++ tests/cts-generator/cts-template/addi.yaml | 384 ++ tests/cts-generator/cts-template/and.yaml | 534 ++ tests/cts-generator/cts-template/and2.64.yaml | 456 ++ tests/cts-generator/cts-template/and2.yaml | 513 ++ tests/cts-generator/cts-template/andi.yaml | 345 ++ tests/cts-generator/cts-template/ashr.yaml | 457 ++ .../cts-generator/cts-template/ashr2.64.yaml | 395 ++ tests/cts-generator/cts-template/ashr2.yaml | 457 ++ tests/cts-generator/cts-template/ashri.yaml | 315 ++ .../cts-template/call.range.yaml | 1218 +++++ .../cts-template/call.short.yaml | 1160 +++++ .../cts-template/call.virt.negative.yaml | 1106 ++++ .../call.virt.range.negative.yaml | 1100 ++++ .../cts-template/call.virt.range.yaml | 815 +++ .../cts-template/call.virt.range_base.yaml | 957 ++++ .../call.virt.short.negative.yaml | 774 +++ .../cts-template/call.virt.short.yaml | 894 ++++ .../cts-generator/cts-template/call.virt.yaml | 1057 ++++ tests/cts-generator/cts-template/call.yaml | 1313 +++++ .../cts-generator/cts-template/checkcast.yaml | 474 ++ tests/cts-generator/cts-template/cmp.64.yaml | 328 ++ tests/cts-generator/cts-template/cmp.obj.yaml | 633 +++ tests/cts-generator/cts-template/cmp.yaml | 370 ++ tests/cts-generator/cts-template/div.yaml | 421 ++ tests/cts-generator/cts-template/div2.64.yaml | 395 ++ tests/cts-generator/cts-template/div2.yaml | 484 ++ tests/cts-generator/cts-template/divi.yaml | 351 ++ .../cts-generator/cts-template/divu2.64.yaml | 402 ++ tests/cts-generator/cts-template/divu2.yaml | 461 ++ .../cts-generator/cts-template/f64toi32.yaml | 316 ++ .../cts-generator/cts-template/f64toi64.yaml | 290 ++ .../cts-generator/cts-template/f64tou32.yaml | 272 + .../cts-generator/cts-template/f64tou64.yaml | 280 + tests/cts-generator/cts-template/fadd2.yaml | 1008 ++++ tests/cts-generator/cts-template/fcmpg.yaml | 445 ++ tests/cts-generator/cts-template/fcmpl.yaml | 445 ++ tests/cts-generator/cts-template/fdiv2.yaml | 1043 ++++ tests/cts-generator/cts-template/fldai.yaml | 226 + .../cts-generator/cts-template/fldarr.32.yaml | 652 +++ .../cts-generator/cts-template/fldarr.64.yaml | 651 +++ tests/cts-generator/cts-template/fmod2.yaml | 943 ++++ .../cts-generator/cts-template/fmovi.64.yaml | 260 + tests/cts-generator/cts-template/fmul2.yaml | 983 ++++ tests/cts-generator/cts-template/fneg.yaml | 204 + tests/cts-generator/cts-template/fp.yaml | 584 +++ .../cts-generator/cts-template/fstarr.32.yaml | 702 +++ .../cts-generator/cts-template/fstarr.64.yaml | 700 +++ tests/cts-generator/cts-template/fsub2.yaml | 1005 ++++ .../cts-generator/cts-template/i32tof64.yaml | 136 + .../cts-generator/cts-template/i32toi16.yaml | 123 + .../cts-generator/cts-template/i32toi64.yaml | 118 + tests/cts-generator/cts-template/i32toi8.yaml | 123 + tests/cts-generator/cts-template/i32tou1.yaml | 119 + .../cts-generator/cts-template/i32tou16.yaml | 118 + tests/cts-generator/cts-template/i32tou8.yaml | 118 + .../cts-generator/cts-template/i64tof64.yaml | 151 + .../cts-generator/cts-template/i64toi32.yaml | 126 + tests/cts-generator/cts-template/i64tou1.yaml | 127 + tests/cts-generator/cts-template/inci.yaml | 360 ++ .../cts-template/initobj.range.yaml | 2146 ++++++++ .../cts-template/initobj.short.yaml | 1890 +++++++ tests/cts-generator/cts-template/initobj.yaml | 1977 +++++++ .../cts-template/isinstance.yaml | 430 ++ tests/cts-generator/cts-template/jeq.obj.yaml | 981 ++++ tests/cts-generator/cts-template/jeq.yaml | 945 ++++ .../cts-generator/cts-template/jeqz.obj.yaml | 496 ++ tests/cts-generator/cts-template/jeqz.yaml | 415 ++ tests/cts-generator/cts-template/jge.yaml | 941 ++++ tests/cts-generator/cts-template/jgez.yaml | 485 ++ tests/cts-generator/cts-template/jgt.yaml | 941 ++++ tests/cts-generator/cts-template/jgtz.yaml | 425 ++ tests/cts-generator/cts-template/jle.yaml | 941 ++++ tests/cts-generator/cts-template/jlez.yaml | 490 ++ tests/cts-generator/cts-template/jlt.yaml | 941 ++++ tests/cts-generator/cts-template/jltz.yaml | 427 ++ tests/cts-generator/cts-template/jmp.yaml | 249 + tests/cts-generator/cts-template/jne.obj.yaml | 984 ++++ tests/cts-generator/cts-template/jne.yaml | 941 ++++ .../cts-generator/cts-template/jnez.obj.yaml | 494 ++ tests/cts-generator/cts-template/jnez.yaml | 416 ++ tests/cts-generator/cts-template/lda.64.yaml | 333 ++ .../cts-generator/cts-template/lda.null.yaml | 42 + tests/cts-generator/cts-template/lda.obj.yaml | 369 ++ tests/cts-generator/cts-template/lda.str.yaml | 318 ++ .../cts-generator/cts-template/lda.type.yaml | 486 ++ tests/cts-generator/cts-template/lda.yaml | 336 ++ tests/cts-generator/cts-template/ldai.64.yaml | 112 + tests/cts-generator/cts-template/ldai.yaml | 222 + .../cts-generator/cts-template/ldarr.16.yaml | 649 +++ .../cts-generator/cts-template/ldarr.64.yaml | 667 +++ tests/cts-generator/cts-template/ldarr.8.yaml | 665 +++ .../cts-generator/cts-template/ldarr.obj.yaml | 704 +++ tests/cts-generator/cts-template/ldarr.yaml | 657 +++ .../cts-generator/cts-template/ldarru.16.yaml | 648 +++ .../cts-generator/cts-template/ldarru.8.yaml | 663 +++ .../cts-generator/cts-template/ldobj.64.yaml | 381 ++ .../cts-generator/cts-template/ldobj.obj.yaml | 418 ++ tests/cts-generator/cts-template/ldobj.yaml | 413 ++ .../cts-template/ldstatic.64.yaml | 351 ++ .../cts-template/ldstatic.obj.yaml | 371 ++ .../cts-generator/cts-template/ldstatic.yaml | 358 ++ tests/cts-generator/cts-template/lenarr.yaml | 295 ++ tests/cts-generator/cts-template/mod.yaml | 422 ++ tests/cts-generator/cts-template/mod2.64.yaml | 394 ++ tests/cts-generator/cts-template/mod2.yaml | 481 ++ tests/cts-generator/cts-template/modi.yaml | 350 ++ .../cts-generator/cts-template/modu2.64.yaml | 401 ++ tests/cts-generator/cts-template/modu2.yaml | 461 ++ tests/cts-generator/cts-template/mov.64.yaml | 480 ++ .../cts-generator/cts-template/mov.null.yaml | 82 + tests/cts-generator/cts-template/mov.obj.yaml | 447 ++ tests/cts-generator/cts-template/mov.yaml | 403 ++ tests/cts-generator/cts-template/movi.64.yaml | 173 + tests/cts-generator/cts-template/movi.yaml | 223 + tests/cts-generator/cts-template/mul.yaml | 451 ++ tests/cts-generator/cts-template/mul2.64.yaml | 358 ++ tests/cts-generator/cts-template/mul2.yaml | 440 ++ tests/cts-generator/cts-template/muli.yaml | 315 ++ tests/cts-generator/cts-template/neg.64.yaml | 163 + tests/cts-generator/cts-template/neg.yaml | 179 + tests/cts-generator/cts-template/newarr.yaml | 650 +++ tests/cts-generator/cts-template/newobj.yaml | 666 +++ tests/cts-generator/cts-template/not.64.yaml | 166 + tests/cts-generator/cts-template/not.yaml | 181 + tests/cts-generator/cts-template/or.yaml | 407 ++ tests/cts-generator/cts-template/or2.64.yaml | 334 ++ tests/cts-generator/cts-template/or2.yaml | 396 ++ tests/cts-generator/cts-template/ori.yaml | 275 + .../cts-generator/cts-template/return.64.yaml | 505 ++ .../cts-template/return.obj.yaml | 583 +++ .../cts-template/return.void.yaml | 258 + tests/cts-generator/cts-template/return.yaml | 307 ++ tests/cts-generator/cts-template/shl.yaml | 465 ++ tests/cts-generator/cts-template/shl2.64.yaml | 404 ++ tests/cts-generator/cts-template/shl2.yaml | 466 ++ tests/cts-generator/cts-template/shli.yaml | 315 ++ tests/cts-generator/cts-template/shr.yaml | 477 ++ tests/cts-generator/cts-template/shr2.64.yaml | 404 ++ tests/cts-generator/cts-template/shr2.yaml | 466 ++ tests/cts-generator/cts-template/shri.yaml | 315 ++ tests/cts-generator/cts-template/sta.64.yaml | 363 ++ tests/cts-generator/cts-template/sta.obj.yaml | 346 ++ tests/cts-generator/cts-template/sta.yaml | 320 ++ .../cts-generator/cts-template/starr.16.yaml | 722 +++ .../cts-generator/cts-template/starr.64.yaml | 710 +++ tests/cts-generator/cts-template/starr.8.yaml | 744 +++ .../cts-generator/cts-template/starr.obj.yaml | 933 ++++ tests/cts-generator/cts-template/starr.yaml | 700 +++ .../cts-generator/cts-template/stobj.64.yaml | 558 ++ .../cts-generator/cts-template/stobj.obj.yaml | 463 ++ tests/cts-generator/cts-template/stobj.yaml | 480 ++ .../cts-template/ststatic.64.yaml | 537 ++ .../cts-template/ststatic.obj.yaml | 438 ++ .../cts-generator/cts-template/ststatic.yaml | 463 ++ tests/cts-generator/cts-template/sub.yaml | 487 ++ tests/cts-generator/cts-template/sub2.64.yaml | 372 ++ tests/cts-generator/cts-template/sub2.yaml | 476 ++ tests/cts-generator/cts-template/subi.yaml | 316 ++ .../cts-generator/cts-template/template.yaml | 323 ++ .../cts-template/test-schema.json | 316 ++ tests/cts-generator/cts-template/throw.yaml | 473 ++ .../cts-generator/cts-template/u32tof64.yaml | 136 + .../cts-generator/cts-template/u32toi16.yaml | 123 + .../cts-generator/cts-template/u32toi64.yaml | 118 + tests/cts-generator/cts-template/u32toi8.yaml | 123 + tests/cts-generator/cts-template/u32tou1.yaml | 119 + .../cts-generator/cts-template/u32tou16.yaml | 118 + tests/cts-generator/cts-template/u32tou8.yaml | 118 + .../cts-generator/cts-template/u64tof64.yaml | 157 + .../cts-generator/cts-template/u64toi32.yaml | 123 + tests/cts-generator/cts-template/u64tou1.yaml | 119 + .../cts-generator/cts-template/u64tou32.yaml | 118 + tests/cts-generator/cts-template/ucmp.64.yaml | 303 ++ tests/cts-generator/cts-template/ucmp.yaml | 297 ++ tests/cts-generator/cts-template/xor.yaml | 416 ++ tests/cts-generator/cts-template/xor2.64.yaml | 343 ++ tests/cts-generator/cts-template/xor2.yaml | 405 ++ tests/cts-generator/cts-template/xori.yaml | 283 + .../cts-template/yaml-schema.json | 44 + tests/cts-generator/generate-cts.rb | 79 + tests/cts-generator/generator/command.rb | 118 + tests/cts-generator/generator/definitions.rb | 45 + tests/cts-generator/generator/generator.rb | 80 + tests/cts-generator/generator/parser.rb | 108 + tests/cts-generator/generator/single_test.rb | 63 + tests/cts-generator/generator/test.rb | 65 + tests/cts-generator/generator/test_base.rb | 109 + tests/cts-generator/generator/test_case.rb | 150 + .../runner/reporters/base_test_reporter.rb | 104 + .../runner/reporters/jtr_reporter.rb | 161 + .../runner/reporters/string_logger.rb | 56 + .../runner/reporters/test_reporter.rb | 142 + tests/cts-generator/runner/result.rb | 135 + tests/cts-generator/runner/runner.rb | 112 + .../runner/single_test_runner.rb | 294 ++ tests/cts-generator/test-runner.rb | 309 ++ tests/cts-generator/verifier.debug.config | 38 + tests/verifier-tests/bug_1697.pa | 22 + tests/verifier-tests/bug_1702.pa | 23 + tests/verifier-tests/bug_1745.pa | 23 + tests/verifier-tests/bug_1813.pa | 21 + tests/verifier-tests/bug_1826.pa | 29 + tests/verifier-tests/bug_1827.pa | 31 + tests/verifier-tests/bug_1828.pa | 28 + tests/verifier-tests/bug_1833.pa | 32 + tests/verifier-tests/bug_1834.pa | 38 + tests/verifier-tests/bug_1863.pa | 33 + tests/verifier-tests/bug_1926.pa | 37 + tests/verifier-tests/bug_1940.pa | 25 + tests/verifier-tests/bug_2072.pa | 29 + tests/verifier-tests/bug_2075.pa | 22 + tests/verifier-tests/bug_2084.pa | 72 + tests/verifier-tests/bug_2085.pa | 78 + tests/verifier-tests/bug_2086_1.pa | 57 + tests/verifier-tests/bug_2086_2.pa | 57 + tests/verifier-tests/bug_2088.pa | 76 + tests/verifier-tests/bug_2089.pa | 26 + tests/verifier-tests/bug_2090.pa | 21 + tests/verifier-tests/bug_2107_1.pa | 49 + tests/verifier-tests/bug_2107_2.pa | 51 + tests/verifier-tests/bug_2136.pa | 21 + tests/verifier-tests/bug_2256.pa | 38 + tests/verifier-tests/bug_2260.pa | 21 + tests/verifier-tests/bug_2374.pa | 30 + tests/verifier-tests/bug_2702_1.pa | 21 + tests/verifier-tests/bug_2702_2.pa | 21 + tests/verifier-tests/bug_2702_3.pa | 21 + tests/verifier-tests/bug_2702_4.pa | 21 + tests/verifier-tests/bug_2740.pa | 21 + tests/verifier-tests/bug_2787.pa | 19 + tests/verifier-tests/bug_2816.pa | 25 + tests/verifier-tests/bug_2817.pa | 22 + tests/verifier-tests/bug_2818_1.pa | 20 + tests/verifier-tests/bug_2818_2.pa | 19 + tests/verifier-tests/bug_2921.pa | 22 + tests/verifier-tests/bug_3060.pa | 22 + tests/verifier-tests/bug_3133.pa | 19 + tests/verifier-tests/bug_3197.pa | 47 + tests/verifier-tests/bug_3219.pa | 27 + tests/verifier-tests/bug_3228.pa | 34 + .../cflow_err_beyond_end_of_function.pa | 27 + .../cflow_execution_may_go_beyond_the_end.pa | 31 + ...through_from_exc_handler_to_exc_handler.pa | 55 + ...ow_fallthrough_to_exc_handler_from_body.pa | 41 + ...ow_jump_from_exc_handler_to_exc_handler.pa | 55 + .../cflow_jump_on_exc_handler_from_body.pa | 42 + .../verifier-tests/cflow_jump_out_of_body.pa | 30 + tests/verifier-tests/issue_1163.pa | 39 + tests/verifier-tests/issue_1981.pa | 42 + tests/verifier-tests/issue_964.pa | 18 + tests/verifier-tests/jumps_1.pa | 26 + tests/verifier-tests/jumps_2.pa | 27 + tests/verifier-tests/jumps_3.pa | 27 + tests/verifier-tests/mr_3176.pa | 18 + verification/CMakeLists.txt | 14 + verification/Verification.cmake | 116 + verification/absint/AbsInt.cmake | 29 + verification/absint/abs_int_inl.cpp | 233 + verification/absint/abs_int_inl.h | 4588 +++++++++++++++++ verification/absint/absint.cpp | 278 + verification/absint/absint.h | 38 + verification/absint/exec_context.h | 223 + verification/absint/panda_types.cpp | 328 ++ verification/absint/panda_types.h | 490 ++ verification/absint/reg_context.h | 226 + .../absint/tests/exec_context_test.cpp | 143 + .../absint/tests/reg_context_test.cpp | 77 + verification/absint/verification_context.h | 128 + verification/absint/verification_status.h | 25 + verification/cache/Cache.cmake | 16 + verification/cache/file_entity_cache.h | 66 + verification/cache/results_cache.cpp | 153 + verification/cache/results_cache.h | 40 + verification/cflow/Cflow.cmake | 23 + verification/cflow/cflow_check.cpp | 265 + verification/cflow/cflow_check.h | 30 + verification/cflow/cflow_check_options.h | 38 + verification/cflow/cflow_common.cpp | 31 + verification/cflow/cflow_common.h | 27 + verification/cflow/cflow_info.cpp | 265 + verification/cflow/cflow_info.h | 92 + verification/cflow/cflow_iterate_inl.h | 49 + verification/cflow/cflow_status.h | 23 + verification/cflow/exception_source_map.h | 76 + verification/cflow/instructions_map.h | 99 + verification/cflow/jumps_map.h | 124 + .../cflow/tests/instructions_map_test.cpp | 49 + verification/cflow/tests/jumps_map_test.cpp | 95 + verification/debug/Debug.cmake | 36 + verification/debug/README.md | 50 + verification/debug/allowlist/allowlist.cpp | 58 + verification/debug/allowlist/allowlist.h | 35 + .../debug/allowlist/allowlist_private.h | 27 + verification/debug/breakpoint/breakpoint.cpp | 65 + verification/debug/breakpoint/breakpoint.h | 41 + .../debug/breakpoint/breakpoint_private.h | 33 + verification/debug/config/config.h | 59 + verification/debug/config/config_parse.cpp | 113 + verification/debug/config/config_parse.h | 25 + verification/debug/config/config_process.cpp | 58 + verification/debug/config/config_process.h | 32 + verification/debug/config_load.cpp | 117 + verification/debug/config_load.h | 27 + verification/debug/context/context.cpp | 49 + verification/debug/context/context.h | 60 + verification/debug/default_config.cpp | 64 + verification/debug/default_config.h | 25 + .../handlers/config_handler_allowlist.cpp | 107 + .../handlers/config_handler_breakpoints.cpp | 130 + .../handlers/config_handler_method_groups.cpp | 96 + .../config_handler_method_options.cpp | 269 + .../debug/handlers/config_handler_options.cpp | 130 + verification/debug/handlers/config_handlers.h | 28 + verification/debug/handlers/literal_parser.h | 79 + .../debug/options/method_group_parser.h | 52 + verification/debug/options/method_options.h | 339 ++ .../debug/options/method_options_config.h | 64 + verification/debug/options/method_selector.h | 50 + verification/debug/options/msg_set_parser.h | 147 + verification/debug/parser/charset.h | 90 + verification/debug/parser/parser.h | 367 ++ verification/gen/BUILD.gn | 67 + verification/gen/CMakeLists.txt | 66 + .../templates/abs_int_builtin_handlers.h.erb | 35 + .../templates/abs_int_inl_compat_checks.h.erb | 91 + .../gen/templates/abs_int_inl_gen.h.erb | 72 + .../gen/templates/cflow_iterate_inl_gen.h.erb | 156 + ...low_iterate_inl_gen_builtin_handlers.h.erb | 51 + verification/gen/templates/job_fill_gen.h.erb | 190 + verification/job_queue/JobQueue.cmake | 22 + verification/job_queue/cache.cpp | 1282 +++++ verification/job_queue/cache.h | 531 ++ verification/job_queue/index_table_cache.h | 73 + verification/job_queue/job.h | 164 + verification/job_queue/job_fill.cpp | 60 + verification/job_queue/job_fill.h | 25 + verification/job_queue/job_queue.cpp | 288 ++ verification/job_queue/job_queue.h | 101 + verification/messages.yaml | 687 +++ verification/models/README.md | 28 + .../check_set_intersection_as_lub.als | 114 + .../models/contexts_merge/java_typing.als | 46 + .../typesystem/ark_subtyping_closure.als | 278 + .../models/typesystem/ark_typesystem.als | 173 + verification/tests/CMakeLists.txt | 17 + verification/tests/gtest/CMakeLists.txt | 38 + .../tests/rapidcheck_catch2/CMakeLists.txt | 41 + .../tests/rapidcheck_gtest/CMakeLists.txt | 40 + verification/thread/VerifierThread.cmake | 16 + verification/thread/verifier_thread.cpp | 128 + verification/thread/verifier_thread.h | 25 + verification/type/Type.cmake | 26 + verification/type/subtyping_closure.h | 77 + verification/type/tests/type_system_test.cpp | 230 + verification/type/type_image.h | 101 + verification/type/type_index.h | 61 + verification/type/type_info.h | 85 + verification/type/type_param.cpp | 43 + verification/type/type_param.h | 52 + verification/type/type_parametric.cpp | 64 + verification/type/type_parametric.h | 53 + verification/type/type_parametric_inl.h | 35 + verification/type/type_params.cpp | 46 + verification/type/type_params.h | 56 + verification/type/type_params_inl.h | 32 + verification/type/type_set.cpp | 50 + verification/type/type_set.h | 138 + verification/type/type_sort.h | 61 + verification/type/type_system.h | 363 ++ verification/type/type_system_kind.h | 43 + verification/type/type_systems.cpp | 148 + verification/type/type_systems.h | 48 + verification/type/type_type.cpp | 158 + verification/type/type_type.h | 139 + verification/type/type_type_inl.h | 62 + verification/util/Util.cmake | 33 + verification/util/abstract_index.h | 97 + verification/util/access.h | 46 + verification/util/addr_map.h | 215 + verification/util/bit_vector.h | 734 +++ verification/util/callable.h | 115 + verification/util/descriptor_string.h | 134 + verification/util/enum_array.h | 121 + verification/util/equiv_classes.h | 410 ++ verification/util/flags.h | 135 + verification/util/function_traits.h | 134 + verification/util/index.h | 116 + verification/util/int_set.h | 848 +++ verification/util/invalid_ref.h | 58 + verification/util/lazy.h | 378 ++ verification/util/misc.h | 48 + verification/util/obj_pool.h | 193 + verification/util/panda_or_std.h | 56 + verification/util/range.h | 194 + verification/util/ref_wrapper.h | 68 + verification/util/relation.h | 153 + verification/util/saturated_enum.h | 165 + verification/util/set_operations.h | 118 + verification/util/shifted_vector.h | 79 + verification/util/str.h | 70 + verification/util/struct_field.h | 31 + verification/util/synchronized.h | 157 + verification/util/tagged_index.h | 213 + verification/util/tests/addr_map_test.cpp | 59 + verification/util/tests/bit_vector_test.cpp | 510 ++ verification/util/tests/environment.cpp | 119 + verification/util/tests/environment.h | 54 + .../util/tests/equiv_classes_test.cpp | 100 + verification/util/tests/flags.cpp | 48 + verification/util/tests/int_set_test.cpp | 158 + verification/util/tests/lazy_test.cpp | 71 + verification/util/tests/obj_pool_test.cpp | 105 + verification/util/tests/relation_test.cpp | 148 + .../util/tests/set_operations_test.cpp | 170 + verification/util/tests/tagged_index.cpp | 67 + verification/util/tests/verifier_test.h | 49 + verification/value/Value.cmake | 21 + verification/value/abstract_type.h | 203 + verification/value/abstract_typed_value.h | 122 + verification/value/abstract_value.h | 77 + verification/value/origin.h | 59 + .../value/tests/abstract_typed_value_test.cpp | 71 + verification/value/tests/variables_test.cpp | 56 + verification/value/var_binding.h | 49 + verification/value/variables.h | 110 + verification/verification.gni | 75 + verification/verification.rb | 37 + verification/verification.yaml | 355 ++ verification/verification_options.cpp | 85 + verification/verification_options.h | 90 + verification/verifier/BUILD.gn | 45 + verification/verifier/CMakeLists.txt | 52 + verification/verifier/verifier.config | 25 + verification/verifier/verifier.cpp | 195 + 1689 files changed, 393113 insertions(+), 63 deletions(-) create mode 100644 .clang-format create mode 100644 .clang-tidy create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .gn create mode 100644 AUTHORS create mode 100644 BUILD.gn create mode 100644 CMakeLists.txt create mode 100644 LICENSE create mode 100644 OAT.xml delete mode 100644 README.en.md create mode 100644 README_zh.md create mode 100644 ark_config.gni create mode 100644 assembler/BUILD.gn create mode 100644 assembler/CMakeLists.txt create mode 100644 assembler/annotation.cpp create mode 100644 assembler/annotation.h create mode 100755 assembler/asm_isapi.rb create mode 100755 assembler/asm_metadata.rb create mode 100644 assembler/assembly-context.h create mode 100644 assembler/assembly-debug.h create mode 100644 assembler/assembly-emitter.cpp create mode 100644 assembler/assembly-emitter.h create mode 100644 assembler/assembly-field.h create mode 100644 assembler/assembly-file-location.h create mode 100644 assembler/assembly-function.h create mode 100644 assembler/assembly-ins.cpp create mode 100644 assembler/assembly-ins.h create mode 100644 assembler/assembly-label.h create mode 100644 assembler/assembly-literals.h create mode 100644 assembler/assembly-methodhandle.h create mode 100644 assembler/assembly-parser.cpp create mode 100644 assembler/assembly-parser.h create mode 100644 assembler/assembly-program.cpp create mode 100644 assembler/assembly-program.h create mode 100644 assembler/assembly-record.h create mode 100644 assembler/assembly-type.cpp create mode 100644 assembler/assembly-type.h create mode 100644 assembler/context.cpp create mode 100644 assembler/define.h create mode 100644 assembler/error.h create mode 100644 assembler/extensions/ecmascript/ecmascript_meta.cpp create mode 100644 assembler/extensions/ecmascript/ecmascript_meta.h create mode 100644 assembler/extensions/ecmascript/metadata.yaml create mode 100644 assembler/extensions/extensions.cpp create mode 100644 assembler/extensions/extensions.h create mode 100644 assembler/ide_helpers.h create mode 100644 assembler/lexer.cpp create mode 100644 assembler/lexer.h create mode 100644 assembler/mangling.h create mode 100644 assembler/meta.cpp create mode 100644 assembler/meta.h create mode 100644 assembler/metadata.yaml create mode 100644 assembler/pandasm.cpp create mode 100644 assembler/pandasm.h create mode 100644 assembler/samples/Bubblesort.pa create mode 100644 assembler/samples/Factorial.pa create mode 100644 assembler/samples/Fibonacci.pa create mode 100644 assembler/templates/builtin_parsing.cpp.erb create mode 100644 assembler/templates/builtin_parsing_tests.cpp.erb create mode 100644 assembler/templates/ins_create_api.h.erb create mode 100644 assembler/templates/ins_create_builtins_api.h.erb create mode 100644 assembler/templates/ins_emit.h.erb create mode 100644 assembler/templates/ins_to_string.cpp.erb create mode 100644 assembler/templates/isa.h.erb create mode 100644 assembler/templates/meta_gen.cpp.erb create mode 100644 assembler/templates/opcode_parsing.h.erb create mode 100644 assembler/templates/operand_types_print.h.erb create mode 100644 assembler/tests/emitter_test.cpp create mode 100644 assembler/tests/lexer_test.cpp create mode 100644 assembler/tests/mangling_tests.cpp create mode 100644 assembler/tests/parser_test.cpp create mode 100644 assembler/utils/number-utils.h create mode 100644 cmake/ClangTidy.cmake create mode 100644 cmake/CodeStyle.cmake create mode 100644 cmake/CommonTesting.cmake create mode 100644 cmake/Definitions.cmake create mode 100644 cmake/HostTools.cmake create mode 100644 cmake/PandaAssembly.cmake create mode 100644 cmake/PandaCCache.cmake create mode 100644 cmake/PandaCmakeFunctions.cmake create mode 100644 cmake/README.md create mode 100644 cmake/Sanitizers.cmake create mode 100644 cmake/TemplateBasedGen.cmake create mode 100644 cmake/Testing.cmake create mode 100644 cmake/ark-third-party/miniz/CMakeLists.txt create mode 100644 cmake/ark-third-party/securec/CMakeLists.txt create mode 100644 cmake/host-tools-CMakeLists.txt create mode 100644 cmake/toolchain/aflplusplus.cmake create mode 100644 cmake/toolchain/common.cmake create mode 100644 cmake/toolchain/cross-clang-8-qemu-aarch64.cmake create mode 100644 cmake/toolchain/cross-clang-8-qemu-arm-linux-gnueabi.cmake create mode 100644 cmake/toolchain/cross-clang-8-qemu-arm-linux-gnueabihf.cmake create mode 100644 cmake/toolchain/cross-clang-8-x86.cmake create mode 100644 cmake/toolchain/cross-clang-8-x86_64-w64-mingw32-static.cmake create mode 100644 cmake/toolchain/cross-clang-9-qemu-aarch64.cmake create mode 100644 cmake/toolchain/cross-clang-9-qemu-arm-linux-gnueabihf.cmake create mode 100644 cmake/toolchain/cross-clang-9-x86.cmake create mode 100644 cmake/toolchain/cross-clang-9-x86_64-w64-mingw32-static.cmake create mode 100644 cmake/toolchain/cross-clang-default-qemu-aarch64.cmake create mode 100644 cmake/toolchain/cross-clang-default-qemu-arm-linux-gnueabi.cmake create mode 100644 cmake/toolchain/cross-clang-default-qemu-arm-linux-gnueabihf.cmake create mode 100644 cmake/toolchain/cross-clang-default-x86.cmake create mode 100644 cmake/toolchain/cross-gcc-8-qemu-aarch64.cmake create mode 100644 cmake/toolchain/cross-gcc-8-qemu-arm-linux-gnueabi.cmake create mode 100644 cmake/toolchain/cross-gcc-8-qemu-arm-linux-gnueabihf.cmake create mode 100644 cmake/toolchain/cross-gcc-8-x86.cmake create mode 100644 cmake/toolchain/cross-gcc-default-qemu-aarch64.cmake create mode 100644 cmake/toolchain/cross-gcc-default-qemu-arm-linux-gnueabi.cmake create mode 100644 cmake/toolchain/cross-gcc-default-qemu-arm-linux-gnueabihf.cmake create mode 100644 cmake/toolchain/cross-gcc-default-x86.cmake create mode 100644 cmake/toolchain/cross-ohos-aarch64.cmake create mode 100644 cmake/toolchain/fuzzing-coverage.cmake create mode 100644 cmake/toolchain/host_clang_12.cmake create mode 100644 cmake/toolchain/host_clang_8.cmake create mode 100644 cmake/toolchain/host_clang_9.cmake create mode 100644 cmake/toolchain/host_clang_default.cmake create mode 100644 cmake/toolchain/host_gcc_8.cmake create mode 100644 cmake/toolchain/host_gcc_default.cmake create mode 100644 cmake/toolchain/libfuzzer.cmake create mode 100644 disassembler/BUILD.gn create mode 100644 disassembler/CMakeLists.txt create mode 100644 disassembler/accumulators.h create mode 100644 disassembler/disasm.cpp create mode 100644 disassembler/disassembler.cpp create mode 100644 disassembler/disassembler.h create mode 100644 disassembler/templates/bc_ins_to_pandasm_ins.cpp.erb create mode 100644 disassembler/templates/get_ins_info.cpp.erb create mode 100644 disassembler/templates/get_instructions.cpp.erb create mode 100644 disassembler/templates/intrinsics_gen.h.erb create mode 100644 disassembler/templates/opcode_translator.cpp.erb create mode 100644 disassembler/templates/type_to_pandasm_type.cpp.erb create mode 100644 disassembler/tests/instructions_test.cpp create mode 100644 disassembler/tests/labels_test.cpp create mode 100644 disassembler/tests/records_test.cpp create mode 100644 disassembler/tests/sources/builtins.pa create mode 100644 disassembler/tests/sources/calls.pa create mode 100644 disassembler/tests/sources/empty_record.pa create mode 100644 disassembler/tests/sources/exceptions.pa create mode 100644 disassembler/tests/sources/instructions.pa create mode 100644 disassembler/tests/sources/labels1.pa create mode 100644 disassembler/tests/sources/labels2.pa create mode 100644 disassembler/tests/sources/meta.pa create mode 100644 disassembler/tests/sources/newarrs.pa create mode 100644 disassembler/tests/sources/record_in_record.pa create mode 100644 disassembler/tests/sources/record_with_fields.pa create mode 100644 disassembler/tests/sources/returns.pa create mode 100644 docs/assembly_format.md create mode 100644 docs/bc_verification/absint_checks.md create mode 100644 docs/bc_verification/cflow_checks.md create mode 100644 docs/bc_verification/type_system.md create mode 100644 docs/bc_verification/types_n_values.md create mode 100644 docs/cfi_directives.md create mode 100644 docs/coding-style.md create mode 100644 docs/debugger-vscode-communication.md create mode 100644 docs/design-of-interpreter.md create mode 100644 docs/diagrams/gc-mark.puactivity create mode 100644 docs/diagrams/gc-thread-activity.puactivity create mode 100644 docs/diagrams/gc-trigger-sequence-OOM.pusequence create mode 100644 docs/diagrams/gc-trigger-sequence-threshold.pusequence create mode 100644 docs/diagrams/generational-concurrent-major-gc-activity.puactivity create mode 100644 docs/diagrams/generational-major-gc-activity.puactivity create mode 100644 docs/diagrams/generational-minor-gc-activity.puactivity create mode 100644 docs/diagrams/mm-components.pucomponent create mode 100644 docs/diagrams/panda-states-concurrent-gc.pustate create mode 100644 docs/diagrams/panda-states-generational-gc.pustate create mode 100644 docs/diagrams/reference-processor.puactivity create mode 100644 docs/diagrams/reference-processor.pusequence create mode 100644 docs/diagrams/stacktrace.pusequence create mode 100644 docs/diagrams/static-analyzer-gc-func-list-gen.puactivity create mode 100644 docs/diagrams/static-analyzer-report-generation.puactivity create mode 100644 docs/diagrams/static-analyzer-warnings-generation.puactivity create mode 100644 docs/file_format.md create mode 100644 docs/glossary.md create mode 100644 docs/images/cfi_hack_bridges.png create mode 100644 docs/images/def-use-structure.png create mode 100644 docs/images/osr_trigger.png create mode 100644 docs/images/panda-mm-overview.png create mode 100644 docs/interpreter-language-extensions.md create mode 100644 docs/memory-management-SW-requirements.md create mode 100644 docs/memory-management.md create mode 100644 docs/panda-runtime.md create mode 100644 docs/rationale-for-bytecode.md create mode 100644 docs/runtime-class.md create mode 100644 docs/runtime-compiled_code-interaction.md create mode 100644 docs/runtime-debug-api.md create mode 100644 docs/tracing.md create mode 100644 dprof/BUILD.gn create mode 100644 dprof/CMakeLists.txt create mode 100644 dprof/converter/CMakeLists.txt create mode 100644 dprof/converter/features/hotness_counters.h create mode 100644 dprof/converter/features_manager.h create mode 100644 dprof/converter/main.cpp create mode 100644 dprof/converter/options.yaml create mode 100644 dprof/daemon/CMakeLists.txt create mode 100644 dprof/daemon/main.cpp create mode 100644 dprof/daemon/options.yaml create mode 100644 dprof/libdprof/CMakeLists.txt create mode 100644 dprof/libdprof/dprof/ipc/ipc_message.cpp create mode 100644 dprof/libdprof/dprof/ipc/ipc_message.h create mode 100644 dprof/libdprof/dprof/ipc/ipc_message_protocol.h create mode 100644 dprof/libdprof/dprof/ipc/ipc_unix_socket.cpp create mode 100644 dprof/libdprof/dprof/ipc/ipc_unix_socket.h create mode 100644 dprof/libdprof/dprof/profiling_data.cpp create mode 100644 dprof/libdprof/dprof/profiling_data.h create mode 100644 dprof/libstorage/CMakeLists.txt create mode 100644 dprof/libstorage/dprof/storage.cpp create mode 100644 dprof/libstorage/dprof/storage.h create mode 100644 gn/ark-third-party/miniz/BUILD.gn create mode 100644 gn/ark-third-party/securec/BUILD.gn create mode 100644 gn/ark/runtime/ark_config.gni create mode 100644 gn/build/BUILD.gn create mode 100644 gn/build/config/BUILDCONFIG.gn create mode 100644 gn/build/config/compiler/BUILD.gn create mode 100644 gn/build/config/ohos/rules.gni create mode 100644 gn/build/ohos.gni create mode 100644 gn/build/toolchain/BUILD.gn create mode 100644 isa/CMakeLists.txt create mode 100644 isa/README.md create mode 100755 isa/asserts.rb create mode 100644 isa/builtins.yaml create mode 100755 isa/builtinsapi.rb create mode 100755 isa/gen.rb create mode 100644 isa/gen_wrapper.sh create mode 100644 isa/isa.yaml create mode 100755 isa/isapi.rb create mode 100644 isa/schema.json create mode 100644 isa/templates/instructions.txt.erb create mode 100644 isa/templates/isa.md.erb create mode 100644 ldscripts/panda.ld create mode 100644 ldscripts/panda_test_asan.ld create mode 100644 libpandabase/BUILD.gn create mode 100644 libpandabase/CMakeLists.txt create mode 100644 libpandabase/README.md create mode 100644 libpandabase/clang.h create mode 100644 libpandabase/cmake/mm_coverage.cmake create mode 100644 libpandabase/concepts.h create mode 100644 libpandabase/events/events.h create mode 100755 libpandabase/events/events.rb create mode 100644 libpandabase/events/events.yaml create mode 100755 libpandabase/events/events_gen.h.erb create mode 100644 libpandabase/globals.h create mode 100644 libpandabase/macros.h create mode 100644 libpandabase/mem/alloc_tracker.cpp create mode 100644 libpandabase/mem/alloc_tracker.h create mode 100644 libpandabase/mem/arena.cpp create mode 100644 libpandabase/mem/arena.h create mode 100644 libpandabase/mem/arena_allocator.cpp create mode 100644 libpandabase/mem/arena_allocator.h create mode 100644 libpandabase/mem/arena_allocator_stl_adapter.h create mode 100644 libpandabase/mem/base_mem_stats.cpp create mode 100644 libpandabase/mem/base_mem_stats.h create mode 100644 libpandabase/mem/code_allocator.cpp create mode 100644 libpandabase/mem/code_allocator.h create mode 100644 libpandabase/mem/gc_barrier.h create mode 100644 libpandabase/mem/malloc_mem_pool-inl.h create mode 100644 libpandabase/mem/malloc_mem_pool.h create mode 100644 libpandabase/mem/mem.h create mode 100644 libpandabase/mem/mem_config.cpp create mode 100644 libpandabase/mem/mem_config.h create mode 100644 libpandabase/mem/mem_pool.h create mode 100644 libpandabase/mem/mem_range.h create mode 100644 libpandabase/mem/mmap_mem_pool-inl.h create mode 100644 libpandabase/mem/mmap_mem_pool.h create mode 100644 libpandabase/mem/object_pointer.h create mode 100644 libpandabase/mem/pool_manager.cpp create mode 100644 libpandabase/mem/pool_manager.h create mode 100644 libpandabase/mem/pool_map.cpp create mode 100644 libpandabase/mem/pool_map.h create mode 100644 libpandabase/mem/space.h create mode 100644 libpandabase/os/debug_info.cpp create mode 100644 libpandabase/os/debug_info.h create mode 100644 libpandabase/os/dfx_option.cpp create mode 100644 libpandabase/os/dfx_option.h create mode 100644 libpandabase/os/error.h create mode 100644 libpandabase/os/exec.h create mode 100644 libpandabase/os/file.h create mode 100644 libpandabase/os/filesystem.cpp create mode 100644 libpandabase/os/filesystem.h create mode 100644 libpandabase/os/library_loader.h create mode 100644 libpandabase/os/mem.h create mode 100644 libpandabase/os/mutex.h create mode 100644 libpandabase/os/native_stack.cpp create mode 100644 libpandabase/os/native_stack.h create mode 100644 libpandabase/os/property.cpp create mode 100644 libpandabase/os/property.h create mode 100644 libpandabase/os/stacktrace.cpp create mode 100644 libpandabase/os/stacktrace.h create mode 100644 libpandabase/os/stacktrace_stub.cpp create mode 100644 libpandabase/os/thread.h create mode 100644 libpandabase/os/time.cpp create mode 100644 libpandabase/os/time.h create mode 100644 libpandabase/os/unix/error.cpp create mode 100644 libpandabase/os/unix/exec.cpp create mode 100644 libpandabase/os/unix/failure_retry.h create mode 100644 libpandabase/os/unix/file.cpp create mode 100644 libpandabase/os/unix/file.h create mode 100644 libpandabase/os/unix/filesystem.cpp create mode 100644 libpandabase/os/unix/futex/mutex.cpp create mode 100644 libpandabase/os/unix/futex/mutex.h create mode 100644 libpandabase/os/unix/library_loader.cpp create mode 100644 libpandabase/os/unix/library_loader.h create mode 100644 libpandabase/os/unix/mem.cpp create mode 100644 libpandabase/os/unix/mutex.cpp create mode 100644 libpandabase/os/unix/mutex.h create mode 100644 libpandabase/os/unix/native_stack.cpp create mode 100644 libpandabase/os/unix/native_stack.h create mode 100644 libpandabase/os/unix/pipe.cpp create mode 100644 libpandabase/os/unix/pipe.h create mode 100644 libpandabase/os/unix/property.cpp create mode 100644 libpandabase/os/unix/property.h create mode 100644 libpandabase/os/unix/sighooklib/sighook.cpp create mode 100644 libpandabase/os/unix/sighooklib/sighook.h create mode 100644 libpandabase/os/unix/thread.cpp create mode 100644 libpandabase/os/unix/time_unix.cpp create mode 100644 libpandabase/os/unix/time_unix.h create mode 100644 libpandabase/os/unix/unique_fd.h create mode 100644 libpandabase/os/unix/unix_mem.h create mode 100644 libpandabase/os/windows/error.cpp create mode 100644 libpandabase/os/windows/file.cpp create mode 100644 libpandabase/os/windows/file.h create mode 100644 libpandabase/os/windows/mem.cpp create mode 100644 libpandabase/os/windows/thread.cpp create mode 100644 libpandabase/os/windows/windows_mem.h create mode 100644 libpandabase/serializer/for_each_tuple.h create mode 100644 libpandabase/serializer/serializer.h create mode 100644 libpandabase/serializer/struct_to_tuple.h create mode 100644 libpandabase/serializer/tuple_to_struct.h create mode 100644 libpandabase/tests/alloc_tracker_test.cpp create mode 100644 libpandabase/tests/arena_allocator_test.cpp create mode 100644 libpandabase/tests/arena_test.cpp create mode 100644 libpandabase/tests/base_mem_stats_test.cpp create mode 100644 libpandabase/tests/bit_helpers_test.cpp create mode 100644 libpandabase/tests/bit_memory_region_test.cpp create mode 100644 libpandabase/tests/bit_table_test.cpp create mode 100644 libpandabase/tests/bit_utils_test.cpp create mode 100644 libpandabase/tests/bit_vector_test.cpp create mode 100644 libpandabase/tests/code_allocator_test.cpp create mode 100644 libpandabase/tests/dfx_test.cpp create mode 100644 libpandabase/tests/expected_test.cpp create mode 100644 libpandabase/tests/hash_test.cpp create mode 100644 libpandabase/tests/json_parser_test.cpp create mode 100644 libpandabase/tests/leb128_test.cpp create mode 100644 libpandabase/tests/list_test.cpp create mode 100644 libpandabase/tests/logger_test.cpp create mode 100644 libpandabase/tests/math_helpers_test.cpp create mode 100644 libpandabase/tests/mem_range_test.cpp create mode 100644 libpandabase/tests/memory_literals_test.cpp create mode 100644 libpandabase/tests/mmap_fixed_test.cpp create mode 100644 libpandabase/tests/mmap_mem_pool_test.cpp create mode 100644 libpandabase/tests/native_bytes_from_mallinfo_test.cpp create mode 100644 libpandabase/tests/pandargs_test.cpp create mode 100644 libpandabase/tests/pool_map_test.cpp create mode 100644 libpandabase/tests/serializer_test.cpp create mode 100644 libpandabase/tests/small_vector_test.cpp create mode 100644 libpandabase/tests/span_test.cpp create mode 100644 libpandabase/tests/string_helpers_test.cpp create mode 100644 libpandabase/tests/type_converter_tests.cpp create mode 100644 libpandabase/tests/unique_fd_test.cpp create mode 100644 libpandabase/tests/utf_test.cpp create mode 100644 libpandabase/trace/trace.cpp create mode 100644 libpandabase/trace/trace.h create mode 100644 libpandabase/trace/unix/trace.cpp create mode 100644 libpandabase/trace/windows/trace.cpp create mode 100644 libpandabase/utils/aligned_storage.h create mode 100644 libpandabase/utils/arch.h create mode 100644 libpandabase/utils/arena_containers.h create mode 100644 libpandabase/utils/asan_interface.h create mode 100644 libpandabase/utils/bit_field.h create mode 100644 libpandabase/utils/bit_helpers.h create mode 100644 libpandabase/utils/bit_memory_region-inl.h create mode 100644 libpandabase/utils/bit_memory_region.h create mode 100644 libpandabase/utils/bit_memory_stream.h create mode 100644 libpandabase/utils/bit_table.h create mode 100644 libpandabase/utils/bit_utils.h create mode 100644 libpandabase/utils/bit_vector.h create mode 100644 libpandabase/utils/cframe_layout.h create mode 100644 libpandabase/utils/debug.cpp create mode 100644 libpandabase/utils/debug.h create mode 100644 libpandabase/utils/dfx.cpp create mode 100644 libpandabase/utils/dfx.h create mode 100644 libpandabase/utils/expected.h create mode 100644 libpandabase/utils/hash.h create mode 100644 libpandabase/utils/hash_base.h create mode 100644 libpandabase/utils/json_parser.cpp create mode 100644 libpandabase/utils/json_parser.h create mode 100644 libpandabase/utils/leb128.h create mode 100644 libpandabase/utils/list.h create mode 100644 libpandabase/utils/logger.cpp create mode 100644 libpandabase/utils/logger.h create mode 100644 libpandabase/utils/math_helpers.h create mode 100644 libpandabase/utils/murmur3_hash.h create mode 100644 libpandabase/utils/pandargs.h create mode 100644 libpandabase/utils/small_vector.h create mode 100644 libpandabase/utils/span.h create mode 100644 libpandabase/utils/string_helpers.h create mode 100644 libpandabase/utils/terminate.cpp create mode 100644 libpandabase/utils/terminate.h create mode 100644 libpandabase/utils/time.cpp create mode 100644 libpandabase/utils/time.h create mode 100644 libpandabase/utils/tsan_interface.h create mode 100644 libpandabase/utils/type_converter.cpp create mode 100644 libpandabase/utils/type_converter.h create mode 100644 libpandabase/utils/type_helpers.h create mode 100644 libpandabase/utils/utf.cpp create mode 100644 libpandabase/utils/utf.h create mode 100644 libpandabase/utils/utils.h create mode 100644 libpandabase/utils/value_object.h create mode 100644 libpandafile/BUILD.gn create mode 100644 libpandafile/CMakeLists.txt create mode 100644 libpandafile/annotation_data_accessor.cpp create mode 100644 libpandafile/annotation_data_accessor.h create mode 100644 libpandafile/ark_version.cpp create mode 100644 libpandafile/ark_version.h create mode 100644 libpandafile/bytecode_emitter.cpp create mode 100644 libpandafile/bytecode_emitter.h create mode 100644 libpandafile/bytecode_instruction-inl.h create mode 100644 libpandafile/bytecode_instruction.h create mode 100644 libpandafile/class_data_accessor-inl.h create mode 100644 libpandafile/class_data_accessor.cpp create mode 100644 libpandafile/class_data_accessor.h create mode 100644 libpandafile/code_data_accessor-inl.h create mode 100644 libpandafile/code_data_accessor.cpp create mode 100644 libpandafile/code_data_accessor.h create mode 100644 libpandafile/debug_data_accessor-inl.h create mode 100644 libpandafile/debug_data_accessor.cpp create mode 100644 libpandafile/debug_data_accessor.h create mode 100644 libpandafile/debug_info_extractor.cpp create mode 100644 libpandafile/debug_info_extractor.h create mode 100644 libpandafile/external/BUILD.gn create mode 100644 libpandafile/external/CMakeLists.txt create mode 100644 libpandafile/external/file_ext.cpp create mode 100644 libpandafile/external/file_ext.h create mode 100644 libpandafile/external/panda_file_external.h create mode 100644 libpandafile/external/panda_file_support.cpp create mode 100644 libpandafile/field_data_accessor-inl.h create mode 100644 libpandafile/field_data_accessor.cpp create mode 100644 libpandafile/field_data_accessor.h create mode 100644 libpandafile/file-inl.h create mode 100644 libpandafile/file.cpp create mode 100644 libpandafile/file.h create mode 100644 libpandafile/file_item_container.cpp create mode 100644 libpandafile/file_item_container.h create mode 100644 libpandafile/file_items.cpp create mode 100644 libpandafile/file_items.h create mode 100644 libpandafile/file_writer.cpp create mode 100644 libpandafile/file_writer.h create mode 100644 libpandafile/helpers.h create mode 100644 libpandafile/line_program_state.h create mode 100644 libpandafile/literal_data_accessor-inl.h create mode 100644 libpandafile/literal_data_accessor.cpp create mode 100644 libpandafile/literal_data_accessor.h create mode 100644 libpandafile/method_data_accessor-inl.h create mode 100644 libpandafile/method_data_accessor.cpp create mode 100644 libpandafile/method_data_accessor.h create mode 100644 libpandafile/method_handle_data_accessor.cpp create mode 100644 libpandafile/method_handle_data_accessor.h create mode 100644 libpandafile/modifiers.h create mode 100644 libpandafile/panda_cache.h create mode 100755 libpandafile/pandafile_isapi.rb create mode 100644 libpandafile/param_annotations_data_accessor.h create mode 100644 libpandafile/proto_data_accessor-inl.h create mode 100644 libpandafile/proto_data_accessor.h create mode 100644 libpandafile/shorty_iterator.h create mode 100644 libpandafile/templates/bytecode_builtin_enum_gen.h.erb create mode 100644 libpandafile/templates/bytecode_emitter_def_gen.h.erb create mode 100644 libpandafile/templates/bytecode_emitter_gen.h.erb create mode 100644 libpandafile/templates/bytecode_instruction-inl_gen.h.erb create mode 100644 libpandafile/templates/bytecode_instruction_enum_gen.h.erb create mode 100644 libpandafile/templates/isa_checksum.h.erb create mode 100644 libpandafile/templates/tests/bytecode_emitter_tests_gen.h.erb create mode 100644 libpandafile/templates/type.h.erb create mode 100644 libpandafile/tests/ark_version_test.cpp create mode 100644 libpandafile/tests/bytecode_emitter_tests.cpp create mode 100644 libpandafile/tests/bytecode_instruction_tests.cpp create mode 100644 libpandafile/tests/debug_info_extractor_test.cpp create mode 100644 libpandafile/tests/file_item_container_test.cpp create mode 100644 libpandafile/tests/file_items_test.cpp create mode 100644 libpandafile/tests/file_test.cpp create mode 100644 libpandafile/tests/panda_cache_test.cpp create mode 100644 libpandafile/type_helper.h create mode 100755 libpandafile/types.rb create mode 100644 libpandafile/types.yaml create mode 100644 libpandafile/value.h create mode 100644 libziparchive/BUILD.gn create mode 100644 libziparchive/CMakeLists.txt create mode 100644 libziparchive/tests/libziparchive_tests.cpp create mode 100644 libziparchive/zip_archive.cpp create mode 100644 libziparchive/zip_archive.h create mode 100644 ohos.build create mode 100644 panda/BUILD.gn create mode 100644 panda/CMakeLists.txt create mode 100644 panda/panda.cpp create mode 100644 pandastdlib/CMakeLists.txt create mode 100644 pandastdlib/pandastdlib.pa create mode 100644 runtime/BUILD.gn create mode 100644 runtime/CMakeLists.txt create mode 100644 runtime/arch/aarch64/helpers_aarch64.S create mode 100644 runtime/arch/aarch64/interpreter_support.S create mode 100644 runtime/arch/aarch64/memory.h create mode 100644 runtime/arch/aarch64/shorty.S create mode 100644 runtime/arch/amd64/helpers_amd64.S create mode 100644 runtime/arch/amd64/interpreter_support.S create mode 100644 runtime/arch/amd64/memory.h create mode 100644 runtime/arch/amd64/shorty.S create mode 100644 runtime/arch/arm/asm_constants.h create mode 100644 runtime/arch/arm/interpreter_support.S create mode 100644 runtime/arch/arm/memory.h create mode 100644 runtime/arch/arm/shorty.S create mode 100644 runtime/arch/asm_support.cpp create mode 100644 runtime/arch/asm_support.h create mode 100644 runtime/arch/helpers.h create mode 100644 runtime/arch/memory_helpers.h create mode 100644 runtime/arch/x86/interpreter_support.S create mode 100644 runtime/arch/x86/memory.h create mode 100644 runtime/arch/x86/shorty.S create mode 100644 runtime/asm_defines/BUILD.gn create mode 100644 runtime/asm_defines/CMakeLists.txt create mode 100644 runtime/asm_defines/asm_defines.def create mode 100644 runtime/asm_defines/defines.cpp create mode 100755 runtime/asm_defines/defines_generator.rb create mode 100644 runtime/assert_gc_scope.cpp create mode 100644 runtime/assert_gc_scope.h create mode 100644 runtime/bridge/arch/aarch64/compiled_code_to_interpreter_bridge_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/compiled_code_to_interpreter_bridge_dyn_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/compiled_code_to_runtime_bridge_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_imm16_v16_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_imm4_v4_v4_v4_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_imm8_imm16_v8_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_imm8_v8_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_imm8_v8_v8_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_imm8_v8_v8_v8_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_imm8_v8_v8_v8_v8_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_v4_imm4_id16_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_v4_v4_id16_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_v4_v4_v4_imm4_id16_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_call_v8_id16_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_initobj_v4_v4_id16_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/handle_initobj_v8_id16_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/interpreter_to_compiled_code_bridge_aarch64.S create mode 100644 runtime/bridge/arch/aarch64/interpreter_to_compiled_code_bridge_dyn_aarch64.S create mode 100644 runtime/bridge/arch/amd64/compiled_code_to_interpreter_bridge_amd64.S create mode 100644 runtime/bridge/arch/amd64/compiled_code_to_interpreter_bridge_dyn_amd64.S create mode 100644 runtime/bridge/arch/amd64/compiled_code_to_runtime_bridge_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_imm16_v16_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_imm4_v4_v4_v4_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_imm8_imm16_v8_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_imm8_v8_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_imm8_v8_v8_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_imm8_v8_v8_v8_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_imm8_v8_v8_v8_v8_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_v4_imm4_id16_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_v4_v4_id16_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_v4_v4_v4_imm4_id16_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_v8_id16_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_initobj_v4_v4_id16_amd64.S create mode 100644 runtime/bridge/arch/amd64/handle_initobj_v8_id16_amd64.S create mode 100644 runtime/bridge/arch/amd64/interpreter_to_compiled_code_bridge_amd64.S create mode 100644 runtime/bridge/arch/amd64/interpreter_to_compiled_code_bridge_dyn_amd64.S create mode 100644 runtime/bridge/arch/arm/compiled_code_to_interpreter_bridge_arm.S create mode 100644 runtime/bridge/arch/arm/compiled_code_to_interpreter_bridge_armhf.S create mode 100644 runtime/bridge/arch/arm/compiled_code_to_interpreter_bridge_dyn_arm.S create mode 100644 runtime/bridge/arch/arm/compiled_code_to_runtime_bridge_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_imm16_v16_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_imm4_v4_v4_v4_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_imm8_imm16_v8_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_imm8_v8_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_imm8_v8_v8_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_imm8_v8_v8_v8_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_imm8_v8_v8_v8_v8_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_v4_imm4_id16_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_v4_imm4_id16_armhf.S create mode 100644 runtime/bridge/arch/arm/handle_call_v4_v4_id16_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_v4_v4_id16_armhf.S create mode 100644 runtime/bridge/arch/arm/handle_call_v4_v4_v4_imm4_id16_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_v4_v4_v4_imm4_id16_armhf.S create mode 100644 runtime/bridge/arch/arm/handle_call_v8_id16_arm.S create mode 100644 runtime/bridge/arch/arm/handle_call_v8_id16_armhf.S create mode 100644 runtime/bridge/arch/arm/handle_initobj_v4_v4_id16_arm.S create mode 100644 runtime/bridge/arch/arm/handle_initobj_v4_v4_id16_armhf.S create mode 100644 runtime/bridge/arch/arm/handle_initobj_v8_id16_arm.S create mode 100644 runtime/bridge/arch/arm/handle_initobj_v8_id16_armhf.S create mode 100644 runtime/bridge/arch/arm/interpreter_to_compiled_code_bridge_arm.S create mode 100644 runtime/bridge/arch/arm/interpreter_to_compiled_code_bridge_armhf.S create mode 100644 runtime/bridge/arch/arm/interpreter_to_compiled_code_bridge_dyn_arm.S create mode 100644 runtime/bridge/arch/x86/compiled_code_to_interpreter_bridge_x86.S create mode 100644 runtime/bridge/arch/x86/handle_call_v4_imm4_id16_x86.S create mode 100644 runtime/bridge/arch/x86/handle_call_v4_v4_id16_x86.S create mode 100644 runtime/bridge/arch/x86/handle_call_v4_v4_v4_imm4_id16_x86.S create mode 100644 runtime/bridge/arch/x86/handle_call_v8_id16_x86.S create mode 100644 runtime/bridge/arch/x86/interpreter_to_compiled_code_bridge_x86.S create mode 100644 runtime/bridge/bridge.cpp create mode 100644 runtime/bridge/bridge.h create mode 100644 runtime/cframe.cpp create mode 100644 runtime/class.cpp create mode 100644 runtime/class_helper.cpp create mode 100644 runtime/class_initializer.cpp create mode 100644 runtime/class_initializer.h create mode 100644 runtime/class_linker.cpp create mode 100644 runtime/class_linker_context.h create mode 100644 runtime/class_linker_extension.cpp create mode 100644 runtime/core/Core.cmake create mode 100644 runtime/core/core_class_linker_extension.cpp create mode 100644 runtime/core/core_class_linker_extension.h create mode 100644 runtime/core/core_itable_builder.h create mode 100644 runtime/core/core_language_context.cpp create mode 100644 runtime/core/core_language_context.h create mode 100644 runtime/core/core_vm.cpp create mode 100644 runtime/core/core_vm.h create mode 100644 runtime/core/core_vtable_builder.h create mode 100644 runtime/coretypes/array.cpp create mode 100644 runtime/coretypes/string.cpp create mode 100644 runtime/dprofiler/dprofiler.cpp create mode 100644 runtime/dprofiler/dprofiler.h create mode 100644 runtime/dyn_class_linker_extension.cpp create mode 100644 runtime/dyn_class_linker_extension.h create mode 100644 runtime/entrypoints/entrypoints.cpp create mode 100644 runtime/entrypoints/entrypoints.h create mode 100755 runtime/entrypoints/entrypoints.rb create mode 100644 runtime/entrypoints/entrypoints.yaml create mode 100644 runtime/entrypoints/entrypoints_compiler.inl.erb create mode 100644 runtime/entrypoints/entrypoints_gen.S.erb create mode 100644 runtime/entrypoints/entrypoints_gen.h.erb create mode 100644 runtime/exceptions.cpp create mode 100644 runtime/field.cpp create mode 100644 runtime/file_manager.cpp create mode 100644 runtime/gc_task.cpp create mode 100644 runtime/global_handle_storage-inl.h create mode 100644 runtime/global_handle_storage.h create mode 100644 runtime/handle_base-inl.h create mode 100644 runtime/handle_base.h create mode 100644 runtime/handle_scope-inl.h create mode 100644 runtime/handle_scope.cpp create mode 100644 runtime/handle_scope.h create mode 100644 runtime/handle_storage-inl.h create mode 100644 runtime/handle_storage.h create mode 100644 runtime/imtable_builder.cpp create mode 100644 runtime/include/cframe.h create mode 100644 runtime/include/cframe_iterators.h create mode 100644 runtime/include/class-inl.h create mode 100644 runtime/include/class.h create mode 100644 runtime/include/class_helper.h create mode 100644 runtime/include/class_linker-inl.h create mode 100644 runtime/include/class_linker.h create mode 100644 runtime/include/class_linker_extension.h create mode 100644 runtime/include/class_root.h create mode 100644 runtime/include/compiler_interface.h create mode 100644 runtime/include/coretypes/array-inl.h create mode 100644 runtime/include/coretypes/array.h create mode 100644 runtime/include/coretypes/class.h create mode 100644 runtime/include/coretypes/dyn_objects.h create mode 100644 runtime/include/coretypes/native_pointer.h create mode 100644 runtime/include/coretypes/string-inl.h create mode 100644 runtime/include/coretypes/string.h create mode 100644 runtime/include/coretypes/tagged_value.h create mode 100644 runtime/include/exceptions.h create mode 100644 runtime/include/field.h create mode 100644 runtime/include/file_manager.h create mode 100644 runtime/include/gc_task.h create mode 100644 runtime/include/hclass.h create mode 100644 runtime/include/histogram-inl.h create mode 100644 runtime/include/histogram.h create mode 100644 runtime/include/imtable_builder.h create mode 100644 runtime/include/itable.h create mode 100644 runtime/include/itable_builder.h create mode 100644 runtime/include/language_config.h create mode 100644 runtime/include/language_context.h create mode 100644 runtime/include/locks.h create mode 100644 runtime/include/mem/allocator-inl.h create mode 100644 runtime/include/mem/allocator.h create mode 100644 runtime/include/mem/panda_containers.h create mode 100644 runtime/include/mem/panda_smart_pointers.h create mode 100644 runtime/include/mem/panda_string.h create mode 100644 runtime/include/method-inl.h create mode 100644 runtime/include/method.h create mode 100644 runtime/include/object_accessor-inl.h create mode 100644 runtime/include/object_accessor.h create mode 100644 runtime/include/object_header-inl.h create mode 100644 runtime/include/object_header.h create mode 100644 runtime/include/panda_vm.h create mode 100644 runtime/include/runtime.h create mode 100644 runtime/include/runtime_notification.h create mode 100644 runtime/include/runtime_options.h create mode 100644 runtime/include/stack_walker-inl.h create mode 100644 runtime/include/stack_walker.h create mode 100644 runtime/include/thread-inl.h create mode 100644 runtime/include/thread.h create mode 100644 runtime/include/thread_scopes.h create mode 100644 runtime/include/thread_status.h create mode 100644 runtime/include/time_utils.h create mode 100644 runtime/include/tooling/debug_inf.h create mode 100644 runtime/include/tooling/debug_interface.h create mode 100644 runtime/include/tooling/pt_class.h create mode 100644 runtime/include/tooling/pt_lang_extension.h create mode 100644 runtime/include/tooling/pt_location.h create mode 100644 runtime/include/tooling/pt_method.h create mode 100644 runtime/include/tooling/pt_object.h create mode 100644 runtime/include/tooling/pt_property.h create mode 100644 runtime/include/tooling/pt_reference.h create mode 100644 runtime/include/tooling/pt_thread.h create mode 100644 runtime/include/tooling/pt_value.h create mode 100644 runtime/include/value-inl.h create mode 100644 runtime/include/value.h create mode 100644 runtime/include/vtable_builder-inl.h create mode 100644 runtime/include/vtable_builder.h create mode 100644 runtime/interpreter/acc_vregister.h create mode 100644 runtime/interpreter/arch/aarch64/global_regs.h create mode 100644 runtime/interpreter/arch/aarch64/macros.h create mode 100644 runtime/interpreter/arch/global_regs.h create mode 100644 runtime/interpreter/arch/macros.h create mode 100644 runtime/interpreter/cache.h create mode 100644 runtime/interpreter/dispatch_table.h create mode 100644 runtime/interpreter/frame.h create mode 100644 runtime/interpreter/instruction_handler_base.h create mode 100644 runtime/interpreter/instruction_handler_state.h create mode 100644 runtime/interpreter/interpreter-inl.h create mode 100644 runtime/interpreter/interpreter.cpp create mode 100644 runtime/interpreter/interpreter.h create mode 100644 runtime/interpreter/interpreter_impl.cpp create mode 100644 runtime/interpreter/interpreter_impl.h create mode 100644 runtime/interpreter/math_helpers.h create mode 100644 runtime/interpreter/runtime_interface.cpp create mode 100644 runtime/interpreter/runtime_interface.h create mode 100644 runtime/interpreter/state.h create mode 100644 runtime/interpreter/templates/builtin_count.h.erb create mode 100644 runtime/interpreter/templates/builtin_dispatch.h.erb create mode 100644 runtime/interpreter/templates/builtin_handlers.h.erb create mode 100644 runtime/interpreter/templates/builtin_insn_handlers.h.erb create mode 100644 runtime/interpreter/templates/interpreter-inl_gen.h.erb create mode 100644 runtime/interpreter/templates/isa_constants_gen.h.erb create mode 100644 runtime/interpreter/templates/unimplemented_handlers-inl.h.erb create mode 100644 runtime/interpreter/vregister-inl.h create mode 100644 runtime/interpreter/vregister.h create mode 100644 runtime/interpreter/vregister_iterator.h create mode 100644 runtime/intrinsics.cpp create mode 100644 runtime/itable_builder.cpp create mode 100644 runtime/jit/jit.h create mode 100644 runtime/jit/profiling_data.h create mode 100644 runtime/language_context.cpp create mode 100644 runtime/locks.cpp create mode 100644 runtime/mark_word.cpp create mode 100644 runtime/mark_word.h create mode 100644 runtime/mem/alloc_config.h create mode 100644 runtime/mem/allocator.cpp create mode 100644 runtime/mem/allocator_adapter.h create mode 100644 runtime/mem/bump-allocator-inl.h create mode 100644 runtime/mem/bump-allocator.h create mode 100644 runtime/mem/frame_allocator-inl.h create mode 100644 runtime/mem/frame_allocator.h create mode 100644 runtime/mem/freelist.h create mode 100644 runtime/mem/freelist_allocator-inl.h create mode 100644 runtime/mem/freelist_allocator.h create mode 100644 runtime/mem/gc/bitmap.cpp create mode 100644 runtime/mem/gc/bitmap.h create mode 100644 runtime/mem/gc/card_table-inl.h create mode 100644 runtime/mem/gc/card_table.cpp create mode 100644 runtime/mem/gc/card_table.h create mode 100644 runtime/mem/gc/crossing_map.cpp create mode 100644 runtime/mem/gc/crossing_map.h create mode 100644 runtime/mem/gc/crossing_map_singleton.cpp create mode 100644 runtime/mem/gc/crossing_map_singleton.h create mode 100644 runtime/mem/gc/dynamic/gc_dynamic_data.h create mode 100644 runtime/mem/gc/dynamic/gc_dynamic_impl.cpp create mode 100644 runtime/mem/gc/epsilon/epsilon.cpp create mode 100644 runtime/mem/gc/epsilon/epsilon.h create mode 100644 runtime/mem/gc/epsilon/epsilon_barrier.cpp create mode 100644 runtime/mem/gc/epsilon/epsilon_barrier.h create mode 100644 runtime/mem/gc/g1/g1-allocator.cpp create mode 100644 runtime/mem/gc/g1/g1-allocator.h create mode 100644 runtime/mem/gc/g1/g1-gc.cpp create mode 100644 runtime/mem/gc/g1/g1-gc.h create mode 100644 runtime/mem/gc/gc.cpp create mode 100644 runtime/mem/gc/gc.h create mode 100644 runtime/mem/gc/gc_barrier_set.cpp create mode 100644 runtime/mem/gc/gc_barrier_set.h create mode 100644 runtime/mem/gc/gc_extension_data.h create mode 100644 runtime/mem/gc/gc_phase.h create mode 100644 runtime/mem/gc/gc_queue.cpp create mode 100644 runtime/mem/gc/gc_queue.h create mode 100644 runtime/mem/gc/gc_reason.h create mode 100644 runtime/mem/gc/gc_root-inl.h create mode 100644 runtime/mem/gc/gc_root.cpp create mode 100644 runtime/mem/gc/gc_root.h create mode 100644 runtime/mem/gc/gc_scoped_phase.cpp create mode 100644 runtime/mem/gc/gc_scoped_phase.h create mode 100644 runtime/mem/gc/gc_stats.cpp create mode 100644 runtime/mem/gc/gc_stats.h create mode 100644 runtime/mem/gc/gc_trigger.cpp create mode 100644 runtime/mem/gc/gc_trigger.h create mode 100644 runtime/mem/gc/gc_types.h create mode 100644 runtime/mem/gc/gen-gc/gen-gc.cpp create mode 100644 runtime/mem/gc/gen-gc/gen-gc.h create mode 100644 runtime/mem/gc/generational-gc-base.cpp create mode 100644 runtime/mem/gc/generational-gc-base.h create mode 100644 runtime/mem/gc/hybrid-gc/hybrid_object_allocator.cpp create mode 100644 runtime/mem/gc/hybrid-gc/hybrid_object_allocator.h create mode 100644 runtime/mem/gc/lang/gc_lang.cpp create mode 100644 runtime/mem/gc/lang/gc_lang.h create mode 100644 runtime/mem/gc/reference-processor/empty_reference_processor.h create mode 100644 runtime/mem/gc/reference-processor/reference_processor.cpp create mode 100644 runtime/mem/gc/reference-processor/reference_processor.h create mode 100644 runtime/mem/gc/static/gc_static_impl.cpp create mode 100644 runtime/mem/gc/stw-gc/stw-gc.cpp create mode 100644 runtime/mem/gc/stw-gc/stw-gc.h create mode 100644 runtime/mem/heap_manager.cpp create mode 100644 runtime/mem/heap_manager.h create mode 100644 runtime/mem/heap_verifier.cpp create mode 100644 runtime/mem/heap_verifier.h create mode 100644 runtime/mem/humongous_obj_allocator-inl.h create mode 100644 runtime/mem/humongous_obj_allocator.h create mode 100644 runtime/mem/internal_allocator-inl.h create mode 100644 runtime/mem/internal_allocator.cpp create mode 100644 runtime/mem/internal_allocator.h create mode 100644 runtime/mem/lock_config_helper.h create mode 100644 runtime/mem/malloc-proxy-allocator-inl.h create mode 100644 runtime/mem/malloc-proxy-allocator.h create mode 100644 runtime/mem/mem_hooks.cpp create mode 100644 runtime/mem/mem_hooks.h create mode 100644 runtime/mem/mem_stats.cpp create mode 100644 runtime/mem/mem_stats.h create mode 100644 runtime/mem/mem_stats_additional_info.cpp create mode 100644 runtime/mem/mem_stats_additional_info.h create mode 100644 runtime/mem/mem_stats_default.cpp create mode 100644 runtime/mem/mem_stats_default.h create mode 100644 runtime/mem/memory_manager.cpp create mode 100644 runtime/mem/memory_manager.h create mode 100644 runtime/mem/object_helpers-inl.h create mode 100644 runtime/mem/object_helpers.cpp create mode 100644 runtime/mem/object_helpers.h create mode 100644 runtime/mem/panda_string.cpp create mode 100644 runtime/mem/pygote_space_allocator-inl.h create mode 100644 runtime/mem/pygote_space_allocator.h create mode 100644 runtime/mem/refstorage/global_object_storage.cpp create mode 100644 runtime/mem/refstorage/global_object_storage.h create mode 100644 runtime/mem/refstorage/ref_block.cpp create mode 100644 runtime/mem/refstorage/ref_block.h create mode 100644 runtime/mem/refstorage/reference.h create mode 100644 runtime/mem/refstorage/reference_storage.cpp create mode 100644 runtime/mem/refstorage/reference_storage.h create mode 100644 runtime/mem/region_allocator-inl.h create mode 100644 runtime/mem/region_allocator.h create mode 100644 runtime/mem/region_space-inl.h create mode 100644 runtime/mem/region_space.cpp create mode 100644 runtime/mem/region_space.h create mode 100644 runtime/mem/rem_set-inl.h create mode 100644 runtime/mem/rem_set.h create mode 100644 runtime/mem/rendezvous.cpp create mode 100644 runtime/mem/rendezvous.h create mode 100644 runtime/mem/runslots.cpp create mode 100644 runtime/mem/runslots.h create mode 100644 runtime/mem/runslots_allocator-inl.h create mode 100644 runtime/mem/runslots_allocator.h create mode 100644 runtime/mem/runslots_allocator_stl_adapter.h create mode 100644 runtime/mem/tlab.cpp create mode 100644 runtime/mem/tlab.h create mode 100644 runtime/mem/vm_handle.h create mode 100644 runtime/method.cpp create mode 100644 runtime/monitor.cpp create mode 100644 runtime/monitor.h create mode 100644 runtime/monitor_object_lock.cpp create mode 100644 runtime/monitor_object_lock.h create mode 100644 runtime/monitor_pool.cpp create mode 100644 runtime/monitor_pool.h create mode 100644 runtime/object_accessor-impl.cpp create mode 100644 runtime/object_accessor.cpp create mode 100644 runtime/object_header.cpp create mode 100644 runtime/object_header_config.h create mode 100644 runtime/options.yaml create mode 100644 runtime/panda_vm.cpp create mode 100644 runtime/profilesaver/profile_dump_info.cpp create mode 100644 runtime/profilesaver/profile_dump_info.h create mode 100644 runtime/profilesaver/profile_saver.cpp create mode 100644 runtime/profilesaver/profile_saver.h create mode 100644 runtime/runtime.cpp create mode 100644 runtime/runtime.yaml create mode 100644 runtime/runtime_helpers.cpp create mode 100644 runtime/signal_handler.cpp create mode 100644 runtime/signal_handler.h create mode 100644 runtime/stack_walker.cpp create mode 100644 runtime/string_table.cpp create mode 100644 runtime/string_table.h create mode 100644 runtime/templates/bridge_dispatch.S.erb create mode 100755 runtime/templates/bridge_helpers_aarch64.rb create mode 100755 runtime/templates/bridge_helpers_amd64.rb create mode 100755 runtime/templates/bridge_helpers_arm.rb create mode 100755 runtime/templates/bridge_helpers_armhf.rb create mode 100755 runtime/templates/bridge_helpers_dynamic.rb create mode 100755 runtime/templates/bridge_helpers_static.rb create mode 100755 runtime/templates/bridge_helpers_x86.rb create mode 100755 runtime/templates/gen_intrinsics_data.rb create mode 100644 runtime/templates/intrinsics.h.erb create mode 100755 runtime/templates/intrinsics.rb create mode 100644 runtime/templates/intrinsics.yaml.erb create mode 100644 runtime/templates/intrinsics_gen.h.erb create mode 100755 runtime/templates/runtime.rb create mode 100644 runtime/templates/shorty_values.h.erb create mode 100644 runtime/templates/unimplemented_intrinsics-inl.cpp.erb create mode 100644 runtime/tests/allocator_test_base.h create mode 100644 runtime/tests/arch/aarch64/invokation_helper.S create mode 100644 runtime/tests/arch/amd64/invokation_helper.S create mode 100644 runtime/tests/arch/arm/invokation_helper.S create mode 100644 runtime/tests/arch/arm/invokation_helper_hf.S create mode 100644 runtime/tests/array_test.cpp create mode 100644 runtime/tests/bitmap_clear_range_test.cpp create mode 100644 runtime/tests/bitmap_order_object_alignment_test.cpp create mode 100644 runtime/tests/bitmap_page_alignment_test.cpp create mode 100644 runtime/tests/bitmap_test_base.h create mode 100644 runtime/tests/bitmap_visitor_object_alignment_test.cpp create mode 100644 runtime/tests/bump_allocator_test.cpp create mode 100644 runtime/tests/c2i_bridge_test.cpp create mode 100644 runtime/tests/card_table_test.cpp create mode 100644 runtime/tests/class_linker_test.cpp create mode 100644 runtime/tests/class_linker_test_extension.cpp create mode 100644 runtime/tests/class_linker_test_extension.h create mode 100644 runtime/tests/class_size_test.cpp create mode 100644 runtime/tests/crossing_map_test.cpp create mode 100644 runtime/tests/debugger_test.cpp create mode 100644 runtime/tests/frame_allocator_test.cpp create mode 100644 runtime/tests/frame_test.cpp create mode 100644 runtime/tests/freelist_allocator_test.cpp create mode 100644 runtime/tests/gc_task_test.cpp create mode 100644 runtime/tests/histogram_test.cpp create mode 100644 runtime/tests/humongous_obj_allocator_test.cpp create mode 100644 runtime/tests/hybrid_object_allocator_test.cpp create mode 100644 runtime/tests/i2c_bridge_test.cpp create mode 100644 runtime/tests/internal_allocator_test.cpp create mode 100644 runtime/tests/interpreter/test_interpreter.cpp create mode 100644 runtime/tests/interpreter/test_interpreter.h create mode 100644 runtime/tests/interpreter/test_interpreter_impl.cpp create mode 100644 runtime/tests/interpreter/test_interpreter_impl.h create mode 100644 runtime/tests/interpreter/test_runtime_interface.cpp create mode 100644 runtime/tests/interpreter/test_runtime_interface.h create mode 100644 runtime/tests/interpreter_test.cpp create mode 100644 runtime/tests/invokation_helper.cpp create mode 100644 runtime/tests/invokation_helper.h create mode 100644 runtime/tests/malloc-proxy-allocator-test.cpp create mode 100644 runtime/tests/mark_word_test.cpp create mode 100644 runtime/tests/math_helpers_test.cpp create mode 100644 runtime/tests/mem_leak_test.cpp create mode 100644 runtime/tests/mem_stats_additional_info_test.cpp create mode 100644 runtime/tests/mem_stats_gc_test.cpp create mode 100644 runtime/tests/mem_stats_test.cpp create mode 100644 runtime/tests/method_test.cpp create mode 100644 runtime/tests/mock_queue_thread_pool.cpp create mode 100644 runtime/tests/monitor_test.cpp create mode 100644 runtime/tests/multithreaded_intern_string_table_test.cpp create mode 100644 runtime/tests/offsets_test.cpp create mode 100644 runtime/tests/options_test.cpp create mode 100644 runtime/tests/panda_smart_pointers_test.cpp create mode 100644 runtime/tests/pygote_space_allocator_gen_test.cpp create mode 100644 runtime/tests/pygote_space_allocator_stw_test.cpp create mode 100644 runtime/tests/pygote_space_allocator_test_base.h create mode 100644 runtime/tests/region_allocator_test.cpp create mode 100644 runtime/tests/rem_set_test.cpp create mode 100644 runtime/tests/runslots_allocator_test.cpp create mode 100644 runtime/tests/string_table_test.cpp create mode 100644 runtime/tests/string_test.cpp create mode 100644 runtime/tests/thread_test.cpp create mode 100644 runtime/tests/time_utils_test.cpp create mode 100644 runtime/tests/tlab_test.cpp create mode 100644 runtime/thread.cpp create mode 100644 runtime/thread_manager.cpp create mode 100644 runtime/thread_manager.h create mode 100644 runtime/thread_pool.h create mode 100644 runtime/thread_pool_queue.h create mode 100644 runtime/time_utils.cpp create mode 100644 runtime/timing.cpp create mode 100644 runtime/timing.h create mode 100644 runtime/tooling/debug_inf.cpp create mode 100644 runtime/tooling/debugger.cpp create mode 100644 runtime/tooling/debugger.h create mode 100644 runtime/tooling/pt_class.cpp create mode 100644 runtime/tooling/pt_class_private.h create mode 100644 runtime/tooling/pt_hook_type_info.h create mode 100644 runtime/tooling/pt_hooks_wrapper.h create mode 100644 runtime/tooling/pt_lang_ext_private.h create mode 100644 runtime/tooling/pt_lang_extension.cpp create mode 100644 runtime/tooling/pt_method.cpp create mode 100644 runtime/tooling/pt_method_private.h create mode 100644 runtime/tooling/pt_object_private.h create mode 100644 runtime/tooling/pt_reference.cpp create mode 100644 runtime/tooling/pt_reference_private.h create mode 100644 runtime/tooling/pt_scoped_managed_code.h create mode 100644 runtime/tooling/pt_thread.cpp create mode 100644 runtime/tooling/pt_thread_info.h create mode 100644 runtime/tooling/pt_value_private.h create mode 100644 runtime/vreg_info.h create mode 100644 runtime/vtable_builder.cpp create mode 100644 scripts/dep-lists/ubuntu-18-04-arm-dev create mode 100644 scripts/dep-lists/ubuntu-18-04-build create mode 100644 scripts/dep-lists/ubuntu-18-04-ci create mode 100644 scripts/dep-lists/ubuntu-18-04-cross-arm-all create mode 100644 scripts/dep-lists/ubuntu-18-04-cross-windows create mode 100644 scripts/dep-lists/ubuntu-18-04-cross-x86 create mode 100644 scripts/dep-lists/ubuntu-18-04-dev create mode 100644 scripts/dep-lists/ubuntu-18-04-fuzzing create mode 100644 scripts/dep-lists/ubuntu-20-04-build create mode 100644 scripts/dep-lists/ubuntu-20-04-ci create mode 100644 scripts/dep-lists/ubuntu-20-04-cross-arm-all create mode 100644 scripts/dep-lists/ubuntu-20-04-cross-windows create mode 100644 scripts/dep-lists/ubuntu-20-04-cross-x86 create mode 100644 scripts/dep-lists/ubuntu-20-04-dev create mode 100644 scripts/dep-lists/ubuntu-20-04-fuzzing create mode 100644 scripts/dep-lists/ubuntu-build create mode 100644 scripts/dep-lists/ubuntu-cross-arm-all create mode 100644 scripts/dep-lists/ubuntu-cross-windows create mode 100644 scripts/dep-lists/ubuntu-cross-x86 create mode 100644 scripts/dep-lists/ubuntu-dev create mode 100644 scripts/dep-lists/ubuntu-fuzzing create mode 100755 scripts/extra/build.sh create mode 100755 scripts/install-deps-ubuntu create mode 100755 scripts/install-third-party create mode 100755 scripts/memdump.py create mode 100755 scripts/memusage.py create mode 100755 scripts/run-check-concurrency-format.sh create mode 100755 scripts/run-clang-format create mode 100755 scripts/trace_enable.sh create mode 100755 templates/common.rb create mode 100644 templates/events/events.h.erb create mode 100644 templates/logger_components/logger_components.inc.erb create mode 100755 templates/messages.rb create mode 100644 templates/messages/messages.h.erb create mode 100644 templates/options/options.h.erb create mode 100644 tests/CMakeLists.txt create mode 100644 tests/benchmarks/3d-morph.pa create mode 100644 tests/benchmarks/CMakeLists.txt create mode 100644 tests/benchmarks/access-binary-trees.pa create mode 100644 tests/benchmarks/access-fannkuch.pa create mode 100644 tests/benchmarks/access-nbody.pa create mode 100644 tests/benchmarks/access-nsieve.pa create mode 100644 tests/benchmarks/bitops-3bit-bits-in-byte.pa create mode 100644 tests/benchmarks/bitops-bits-in-byte.pa create mode 100644 tests/benchmarks/bitops-bitwise-and.pa create mode 100644 tests/benchmarks/bitops-nsieve-bits.pa create mode 100644 tests/benchmarks/controlflow-recursive.pa create mode 100644 tests/benchmarks/math-cordic.pa create mode 100644 tests/benchmarks/math-partial-sums.pa create mode 100644 tests/benchmarks/math-spectral-norm.pa create mode 100644 tests/cts-assembly/arrays-01.pa create mode 100644 tests/cts-assembly/arrays-02.pa create mode 100644 tests/cts-assembly/arrays-03.pa create mode 100644 tests/cts-assembly/arrays-04.pa create mode 100644 tests/cts-assembly/arrays-05.pa create mode 100644 tests/cts-assembly/arrays-06.pa create mode 100644 tests/cts-assembly/arrays-07.pa create mode 100644 tests/cts-assembly/arrays-08.pa create mode 100644 tests/cts-assembly/arrays-09.pa create mode 100644 tests/cts-assembly/arrays-10.pa create mode 100644 tests/cts-assembly/arrays-11.pa create mode 100644 tests/cts-assembly/arrays-12.pa create mode 100644 tests/cts-assembly/arrays-13.pa create mode 100644 tests/cts-assembly/arrays-14.pa create mode 100644 tests/cts-assembly/big_ark_option_value.pa create mode 100644 tests/cts-assembly/compiler_effective_types.pa create mode 100644 tests/cts-assembly/env-01.pa create mode 100644 tests/cts-assembly/exceptions-02.pa create mode 100644 tests/cts-assembly/exceptions-03.pa create mode 100644 tests/cts-assembly/exceptions-04.pa create mode 100644 tests/cts-assembly/far-jump-01.pa create mode 100644 tests/cts-assembly/far-jump-02.pa create mode 100644 tests/cts-assembly/far-jump-03.pa create mode 100644 tests/cts-assembly/far-jump-04.pa create mode 100644 tests/cts-assembly/far-jump-05.pa create mode 100644 tests/cts-assembly/far-jump-06.pa create mode 100644 tests/cts-assembly/far-jump-07.pa create mode 100644 tests/cts-assembly/far-jump-08.pa create mode 100644 tests/cts-assembly/far-jump-09.pa create mode 100644 tests/cts-assembly/far-jump-10.pa create mode 100644 tests/cts-assembly/far-jump-11.pa create mode 100644 tests/cts-assembly/far-jump-12.pa create mode 100644 tests/cts-assembly/far-jump-13.pa create mode 100644 tests/cts-assembly/far-jump-14.pa create mode 100644 tests/cts-assembly/far-jump-15.pa create mode 100644 tests/cts-assembly/far-jump-16.pa create mode 100644 tests/cts-assembly/far-jump-17.pa create mode 100644 tests/cts-assembly/far-jump-18.pa create mode 100644 tests/cts-assembly/far-jump-19.pa create mode 100644 tests/cts-assembly/initobj-01.pa create mode 100644 tests/cts-assembly/initobj-02.pa create mode 100644 tests/cts-assembly/initobj-03.pa create mode 100644 tests/cts-assembly/initobj-04.pa create mode 100644 tests/cts-assembly/initobj-05.pa create mode 100644 tests/cts-assembly/initobj-06.pa create mode 100644 tests/cts-assembly/initobj-bad-02.pa create mode 100644 tests/cts-assembly/intrinsics-01.pa create mode 100644 tests/cts-assembly/intrinsics-02.pa create mode 100644 tests/cts-assembly/intrinsics-03.pa create mode 100644 tests/cts-assembly/intrinsics-04.pa create mode 100644 tests/cts-assembly/intrinsics-05.pa create mode 100644 tests/cts-assembly/intrinsics-06.pa create mode 100644 tests/cts-assembly/intrinsics-07.pa create mode 100644 tests/cts-assembly/intrinsics-08.pa create mode 100644 tests/cts-assembly/intrinsics-09.pa create mode 100644 tests/cts-assembly/intrinsics-10.pa create mode 100644 tests/cts-assembly/intrinsics-11.pa create mode 100644 tests/cts-assembly/intrinsics-12.pa create mode 100644 tests/cts-assembly/intrinsics-13.pa create mode 100644 tests/cts-assembly/intrinsics-14.pa create mode 100644 tests/cts-assembly/intrinsics-15.pa create mode 100644 tests/cts-assembly/intrinsics-16.pa create mode 100644 tests/cts-assembly/intrinsics-17.pa create mode 100644 tests/cts-assembly/intrinsics-18.pa create mode 100644 tests/cts-assembly/intrinsics-19.pa create mode 100644 tests/cts-assembly/intrinsics-20.pa create mode 100644 tests/cts-assembly/intrinsics-21.pa create mode 100644 tests/cts-assembly/intrinsics-22.pa create mode 100644 tests/cts-assembly/intrinsics-23.pa create mode 100644 tests/cts-assembly/intrinsics-24.pa create mode 100644 tests/cts-assembly/intrinsics-25.pa create mode 100644 tests/cts-assembly/intrinsics-26.pa create mode 100644 tests/cts-assembly/intrinsics-28.pa create mode 100644 tests/cts-assembly/intrinsics-29.pa create mode 100644 tests/cts-assembly/intrinsics-f32-01.pa create mode 100644 tests/cts-assembly/math-01.pa create mode 100644 tests/cts-assembly/math-02.pa create mode 100644 tests/cts-assembly/math-03.pa create mode 100644 tests/cts-assembly/math-04.pa create mode 100644 tests/cts-assembly/math-05.pa create mode 100644 tests/cts-assembly/math-06.pa create mode 100644 tests/cts-assembly/math-07.pa create mode 100644 tests/cts-assembly/math-08.pa create mode 100644 tests/cts-assembly/math-09.pa create mode 100644 tests/cts-assembly/math-10.pa create mode 100644 tests/cts-assembly/math-11.pa create mode 100644 tests/cts-assembly/math-12.pa create mode 100644 tests/cts-assembly/math-13.pa create mode 100644 tests/cts-assembly/math-14.pa create mode 100644 tests/cts-assembly/math-15.pa create mode 100644 tests/cts-assembly/math-16.pa create mode 100644 tests/cts-assembly/math-17.pa create mode 100644 tests/cts-assembly/math-18.pa create mode 100644 tests/cts-assembly/math-21.pa create mode 100644 tests/cts-assembly/math-22.pa create mode 100644 tests/cts-assembly/math-23.pa create mode 100644 tests/cts-assembly/math-24.pa create mode 100644 tests/cts-assembly/math-25.pa create mode 100644 tests/cts-assembly/math-26.pa create mode 100644 tests/cts-assembly/math-27.pa create mode 100644 tests/cts-assembly/math-28.pa create mode 100644 tests/cts-assembly/math-29.pa create mode 100644 tests/cts-assembly/math-30.pa create mode 100644 tests/cts-assembly/math-31.pa create mode 100644 tests/cts-assembly/math-32.pa create mode 100644 tests/cts-assembly/math-33.pa create mode 100644 tests/cts-assembly/math-34.pa create mode 100644 tests/cts-assembly/math-35.pa create mode 100644 tests/cts-assembly/math-36.pa create mode 100644 tests/cts-assembly/math-40.pa create mode 100644 tests/cts-assembly/math-41.pa create mode 100644 tests/cts-assembly/math-42.pa create mode 100644 tests/cts-assembly/math-43.pa create mode 100644 tests/cts-assembly/math-44.pa create mode 100644 tests/cts-assembly/math-45.pa create mode 100644 tests/cts-assembly/math-46.pa create mode 100644 tests/cts-assembly/math-47.pa create mode 100644 tests/cts-assembly/math-48.pa create mode 100644 tests/cts-assembly/math-49.pa create mode 100644 tests/cts-assembly/math-50.pa create mode 100644 tests/cts-assembly/math-51.pa create mode 100644 tests/cts-assembly/math-52.pa create mode 100644 tests/cts-assembly/math-53.pa create mode 100644 tests/cts-assembly/math-54.pa create mode 100644 tests/cts-assembly/math-55.pa create mode 100644 tests/cts-assembly/math-56.pa create mode 100644 tests/cts-assembly/math-57.pa create mode 100644 tests/cts-assembly/math-58.pa create mode 100644 tests/cts-assembly/math-59.pa create mode 100644 tests/cts-assembly/math-60.pa create mode 100644 tests/cts-assembly/math-61.pa create mode 100644 tests/cts-assembly/math-62.pa create mode 100644 tests/cts-assembly/math-63.pa create mode 100644 tests/cts-assembly/math-64.pa create mode 100644 tests/cts-assembly/math-65.pa create mode 100644 tests/cts-assembly/math-66.pa create mode 100644 tests/cts-assembly/math-67.pa create mode 100644 tests/cts-assembly/obj-01.pa create mode 100644 tests/cts-assembly/obj-02.pa create mode 100644 tests/cts-assembly/obj-03.pa create mode 100644 tests/cts-assembly/obj-04.pa create mode 100644 tests/cts-assembly/obj-05.pa create mode 100644 tests/cts-assembly/obj-06.pa create mode 100644 tests/cts-assembly/obj-07.pa create mode 100644 tests/cts-assembly/obj-08.pa create mode 100644 tests/cts-assembly/obj-09.pa create mode 100644 tests/cts-assembly/obj-10.pa create mode 100644 tests/cts-assembly/obj-11.pa create mode 100644 tests/cts-assembly/obj-12.pa create mode 100644 tests/cts-assembly/obj-13.pa create mode 100644 tests/cts-assembly/obj-14.pa create mode 100644 tests/cts-assembly/obj-15.pa create mode 100644 tests/cts-assembly/obj-16.pa create mode 100644 tests/cts-assembly/obj-17.pa create mode 100644 tests/cts-assembly/obj-18.pa create mode 100644 tests/cts-assembly/obj-23.pa create mode 100644 tests/cts-assembly/obj-24.pa create mode 100644 tests/cts-assembly/obj-25.pa create mode 100644 tests/cts-assembly/obj-26.pa create mode 100644 tests/cts-assembly/obj-27.pa create mode 100644 tests/cts-assembly/obj-28.pa create mode 100644 tests/cts-assembly/obj-29.pa create mode 100644 tests/cts-assembly/obj-30.pa create mode 100644 tests/cts-assembly/obj-31.pa create mode 100644 tests/cts-assembly/obj-32.pa create mode 100644 tests/cts-assembly/obj-33.pa create mode 100644 tests/cts-assembly/obj-34.pa create mode 100644 tests/cts-assembly/obj-35.pa create mode 100644 tests/cts-assembly/obj-36.pa create mode 100644 tests/cts-assembly/op-01.pa create mode 100644 tests/cts-assembly/op-02.pa create mode 100644 tests/cts-assembly/op-03.pa create mode 100644 tests/cts-assembly/op-04.pa create mode 100644 tests/cts-assembly/op-05.pa create mode 100644 tests/cts-assembly/op-06.pa create mode 100644 tests/cts-assembly/op-07.pa create mode 100644 tests/cts-assembly/op-08.pa create mode 100644 tests/cts-assembly/op-09.pa create mode 100644 tests/cts-assembly/op-10.pa create mode 100644 tests/cts-assembly/op-11.pa create mode 100644 tests/cts-assembly/op-12.pa create mode 100644 tests/cts-assembly/op-13.pa create mode 100644 tests/cts-assembly/op-14.pa create mode 100644 tests/cts-assembly/op-15.pa create mode 100644 tests/cts-assembly/op-16.pa create mode 100644 tests/cts-assembly/op-17.pa create mode 100644 tests/cts-assembly/op-18.pa create mode 100644 tests/cts-assembly/op-19.pa create mode 100644 tests/cts-assembly/op-20.pa create mode 100644 tests/cts-assembly/op-21.pa create mode 100644 tests/cts-assembly/op-22.pa create mode 100644 tests/cts-assembly/op-25.pa create mode 100644 tests/cts-assembly/op-26.pa create mode 100644 tests/cts-assembly/op-jeq-obj.pa create mode 100644 tests/cts-assembly/op-jeqz-obj.pa create mode 100644 tests/cts-assembly/op-jne-obj.pa create mode 100644 tests/cts-assembly/op-jnez-obj.pa create mode 100644 tests/cts-assembly/verify-01.pa create mode 100644 tests/cts-coverage-tool/CMakeLists.txt create mode 100644 tests/cts-coverage-tool/README.md create mode 100644 tests/cts-coverage-tool/non_testable.yaml create mode 100755 tests/cts-coverage-tool/spec.rb create mode 100755 tests/cts-coverage-tool/spectrac.rb create mode 100644 tests/cts-coverage-tool/templates/full_md.erb create mode 100755 tests/cts-coverage-tool/templates/full_md.rb create mode 100644 tests/cts-coverage-tool/templates/orphaned_md.erb create mode 100755 tests/cts-coverage-tool/templates/orphaned_md.rb create mode 100644 tests/cts-coverage-tool/templates/report.erb create mode 100755 tests/cts-coverage-tool/templates/report_md.rb create mode 100644 tests/cts-coverage-tool/templates/uncovered_md.erb create mode 100755 tests/cts-coverage-tool/templates/uncovered_md.rb create mode 100644 tests/cts-generator/CMakeLists.txt create mode 100644 tests/cts-generator/README.md create mode 100644 tests/cts-generator/cts-template/add.yaml create mode 100644 tests/cts-generator/cts-template/add2.64.yaml create mode 100644 tests/cts-generator/cts-template/add2.yaml create mode 100644 tests/cts-generator/cts-template/addi.yaml create mode 100644 tests/cts-generator/cts-template/and.yaml create mode 100644 tests/cts-generator/cts-template/and2.64.yaml create mode 100644 tests/cts-generator/cts-template/and2.yaml create mode 100644 tests/cts-generator/cts-template/andi.yaml create mode 100644 tests/cts-generator/cts-template/ashr.yaml create mode 100644 tests/cts-generator/cts-template/ashr2.64.yaml create mode 100644 tests/cts-generator/cts-template/ashr2.yaml create mode 100644 tests/cts-generator/cts-template/ashri.yaml create mode 100644 tests/cts-generator/cts-template/call.range.yaml create mode 100644 tests/cts-generator/cts-template/call.short.yaml create mode 100644 tests/cts-generator/cts-template/call.virt.negative.yaml create mode 100644 tests/cts-generator/cts-template/call.virt.range.negative.yaml create mode 100644 tests/cts-generator/cts-template/call.virt.range.yaml create mode 100644 tests/cts-generator/cts-template/call.virt.range_base.yaml create mode 100644 tests/cts-generator/cts-template/call.virt.short.negative.yaml create mode 100644 tests/cts-generator/cts-template/call.virt.short.yaml create mode 100644 tests/cts-generator/cts-template/call.virt.yaml create mode 100644 tests/cts-generator/cts-template/call.yaml create mode 100644 tests/cts-generator/cts-template/checkcast.yaml create mode 100644 tests/cts-generator/cts-template/cmp.64.yaml create mode 100644 tests/cts-generator/cts-template/cmp.obj.yaml create mode 100644 tests/cts-generator/cts-template/cmp.yaml create mode 100644 tests/cts-generator/cts-template/div.yaml create mode 100644 tests/cts-generator/cts-template/div2.64.yaml create mode 100644 tests/cts-generator/cts-template/div2.yaml create mode 100644 tests/cts-generator/cts-template/divi.yaml create mode 100644 tests/cts-generator/cts-template/divu2.64.yaml create mode 100644 tests/cts-generator/cts-template/divu2.yaml create mode 100644 tests/cts-generator/cts-template/f64toi32.yaml create mode 100644 tests/cts-generator/cts-template/f64toi64.yaml create mode 100644 tests/cts-generator/cts-template/f64tou32.yaml create mode 100644 tests/cts-generator/cts-template/f64tou64.yaml create mode 100644 tests/cts-generator/cts-template/fadd2.yaml create mode 100644 tests/cts-generator/cts-template/fcmpg.yaml create mode 100644 tests/cts-generator/cts-template/fcmpl.yaml create mode 100644 tests/cts-generator/cts-template/fdiv2.yaml create mode 100644 tests/cts-generator/cts-template/fldai.yaml create mode 100644 tests/cts-generator/cts-template/fldarr.32.yaml create mode 100644 tests/cts-generator/cts-template/fldarr.64.yaml create mode 100644 tests/cts-generator/cts-template/fmod2.yaml create mode 100644 tests/cts-generator/cts-template/fmovi.64.yaml create mode 100644 tests/cts-generator/cts-template/fmul2.yaml create mode 100644 tests/cts-generator/cts-template/fneg.yaml create mode 100644 tests/cts-generator/cts-template/fp.yaml create mode 100644 tests/cts-generator/cts-template/fstarr.32.yaml create mode 100644 tests/cts-generator/cts-template/fstarr.64.yaml create mode 100644 tests/cts-generator/cts-template/fsub2.yaml create mode 100644 tests/cts-generator/cts-template/i32tof64.yaml create mode 100644 tests/cts-generator/cts-template/i32toi16.yaml create mode 100644 tests/cts-generator/cts-template/i32toi64.yaml create mode 100644 tests/cts-generator/cts-template/i32toi8.yaml create mode 100644 tests/cts-generator/cts-template/i32tou1.yaml create mode 100644 tests/cts-generator/cts-template/i32tou16.yaml create mode 100644 tests/cts-generator/cts-template/i32tou8.yaml create mode 100644 tests/cts-generator/cts-template/i64tof64.yaml create mode 100644 tests/cts-generator/cts-template/i64toi32.yaml create mode 100644 tests/cts-generator/cts-template/i64tou1.yaml create mode 100644 tests/cts-generator/cts-template/inci.yaml create mode 100644 tests/cts-generator/cts-template/initobj.range.yaml create mode 100644 tests/cts-generator/cts-template/initobj.short.yaml create mode 100644 tests/cts-generator/cts-template/initobj.yaml create mode 100644 tests/cts-generator/cts-template/isinstance.yaml create mode 100644 tests/cts-generator/cts-template/jeq.obj.yaml create mode 100644 tests/cts-generator/cts-template/jeq.yaml create mode 100644 tests/cts-generator/cts-template/jeqz.obj.yaml create mode 100644 tests/cts-generator/cts-template/jeqz.yaml create mode 100644 tests/cts-generator/cts-template/jge.yaml create mode 100644 tests/cts-generator/cts-template/jgez.yaml create mode 100644 tests/cts-generator/cts-template/jgt.yaml create mode 100644 tests/cts-generator/cts-template/jgtz.yaml create mode 100644 tests/cts-generator/cts-template/jle.yaml create mode 100644 tests/cts-generator/cts-template/jlez.yaml create mode 100644 tests/cts-generator/cts-template/jlt.yaml create mode 100644 tests/cts-generator/cts-template/jltz.yaml create mode 100644 tests/cts-generator/cts-template/jmp.yaml create mode 100644 tests/cts-generator/cts-template/jne.obj.yaml create mode 100644 tests/cts-generator/cts-template/jne.yaml create mode 100644 tests/cts-generator/cts-template/jnez.obj.yaml create mode 100644 tests/cts-generator/cts-template/jnez.yaml create mode 100644 tests/cts-generator/cts-template/lda.64.yaml create mode 100644 tests/cts-generator/cts-template/lda.null.yaml create mode 100644 tests/cts-generator/cts-template/lda.obj.yaml create mode 100644 tests/cts-generator/cts-template/lda.str.yaml create mode 100644 tests/cts-generator/cts-template/lda.type.yaml create mode 100644 tests/cts-generator/cts-template/lda.yaml create mode 100644 tests/cts-generator/cts-template/ldai.64.yaml create mode 100644 tests/cts-generator/cts-template/ldai.yaml create mode 100644 tests/cts-generator/cts-template/ldarr.16.yaml create mode 100644 tests/cts-generator/cts-template/ldarr.64.yaml create mode 100644 tests/cts-generator/cts-template/ldarr.8.yaml create mode 100644 tests/cts-generator/cts-template/ldarr.obj.yaml create mode 100644 tests/cts-generator/cts-template/ldarr.yaml create mode 100644 tests/cts-generator/cts-template/ldarru.16.yaml create mode 100644 tests/cts-generator/cts-template/ldarru.8.yaml create mode 100644 tests/cts-generator/cts-template/ldobj.64.yaml create mode 100644 tests/cts-generator/cts-template/ldobj.obj.yaml create mode 100644 tests/cts-generator/cts-template/ldobj.yaml create mode 100644 tests/cts-generator/cts-template/ldstatic.64.yaml create mode 100644 tests/cts-generator/cts-template/ldstatic.obj.yaml create mode 100644 tests/cts-generator/cts-template/ldstatic.yaml create mode 100644 tests/cts-generator/cts-template/lenarr.yaml create mode 100644 tests/cts-generator/cts-template/mod.yaml create mode 100644 tests/cts-generator/cts-template/mod2.64.yaml create mode 100644 tests/cts-generator/cts-template/mod2.yaml create mode 100644 tests/cts-generator/cts-template/modi.yaml create mode 100644 tests/cts-generator/cts-template/modu2.64.yaml create mode 100644 tests/cts-generator/cts-template/modu2.yaml create mode 100644 tests/cts-generator/cts-template/mov.64.yaml create mode 100644 tests/cts-generator/cts-template/mov.null.yaml create mode 100644 tests/cts-generator/cts-template/mov.obj.yaml create mode 100644 tests/cts-generator/cts-template/mov.yaml create mode 100644 tests/cts-generator/cts-template/movi.64.yaml create mode 100644 tests/cts-generator/cts-template/movi.yaml create mode 100644 tests/cts-generator/cts-template/mul.yaml create mode 100644 tests/cts-generator/cts-template/mul2.64.yaml create mode 100644 tests/cts-generator/cts-template/mul2.yaml create mode 100644 tests/cts-generator/cts-template/muli.yaml create mode 100644 tests/cts-generator/cts-template/neg.64.yaml create mode 100644 tests/cts-generator/cts-template/neg.yaml create mode 100644 tests/cts-generator/cts-template/newarr.yaml create mode 100644 tests/cts-generator/cts-template/newobj.yaml create mode 100644 tests/cts-generator/cts-template/not.64.yaml create mode 100644 tests/cts-generator/cts-template/not.yaml create mode 100644 tests/cts-generator/cts-template/or.yaml create mode 100644 tests/cts-generator/cts-template/or2.64.yaml create mode 100644 tests/cts-generator/cts-template/or2.yaml create mode 100644 tests/cts-generator/cts-template/ori.yaml create mode 100644 tests/cts-generator/cts-template/return.64.yaml create mode 100644 tests/cts-generator/cts-template/return.obj.yaml create mode 100644 tests/cts-generator/cts-template/return.void.yaml create mode 100644 tests/cts-generator/cts-template/return.yaml create mode 100644 tests/cts-generator/cts-template/shl.yaml create mode 100644 tests/cts-generator/cts-template/shl2.64.yaml create mode 100644 tests/cts-generator/cts-template/shl2.yaml create mode 100644 tests/cts-generator/cts-template/shli.yaml create mode 100644 tests/cts-generator/cts-template/shr.yaml create mode 100644 tests/cts-generator/cts-template/shr2.64.yaml create mode 100644 tests/cts-generator/cts-template/shr2.yaml create mode 100644 tests/cts-generator/cts-template/shri.yaml create mode 100644 tests/cts-generator/cts-template/sta.64.yaml create mode 100644 tests/cts-generator/cts-template/sta.obj.yaml create mode 100644 tests/cts-generator/cts-template/sta.yaml create mode 100644 tests/cts-generator/cts-template/starr.16.yaml create mode 100644 tests/cts-generator/cts-template/starr.64.yaml create mode 100644 tests/cts-generator/cts-template/starr.8.yaml create mode 100644 tests/cts-generator/cts-template/starr.obj.yaml create mode 100644 tests/cts-generator/cts-template/starr.yaml create mode 100644 tests/cts-generator/cts-template/stobj.64.yaml create mode 100644 tests/cts-generator/cts-template/stobj.obj.yaml create mode 100644 tests/cts-generator/cts-template/stobj.yaml create mode 100644 tests/cts-generator/cts-template/ststatic.64.yaml create mode 100644 tests/cts-generator/cts-template/ststatic.obj.yaml create mode 100644 tests/cts-generator/cts-template/ststatic.yaml create mode 100644 tests/cts-generator/cts-template/sub.yaml create mode 100644 tests/cts-generator/cts-template/sub2.64.yaml create mode 100644 tests/cts-generator/cts-template/sub2.yaml create mode 100644 tests/cts-generator/cts-template/subi.yaml create mode 100644 tests/cts-generator/cts-template/template.yaml create mode 100644 tests/cts-generator/cts-template/test-schema.json create mode 100644 tests/cts-generator/cts-template/throw.yaml create mode 100644 tests/cts-generator/cts-template/u32tof64.yaml create mode 100644 tests/cts-generator/cts-template/u32toi16.yaml create mode 100644 tests/cts-generator/cts-template/u32toi64.yaml create mode 100644 tests/cts-generator/cts-template/u32toi8.yaml create mode 100644 tests/cts-generator/cts-template/u32tou1.yaml create mode 100644 tests/cts-generator/cts-template/u32tou16.yaml create mode 100644 tests/cts-generator/cts-template/u32tou8.yaml create mode 100644 tests/cts-generator/cts-template/u64tof64.yaml create mode 100644 tests/cts-generator/cts-template/u64toi32.yaml create mode 100644 tests/cts-generator/cts-template/u64tou1.yaml create mode 100644 tests/cts-generator/cts-template/u64tou32.yaml create mode 100644 tests/cts-generator/cts-template/ucmp.64.yaml create mode 100644 tests/cts-generator/cts-template/ucmp.yaml create mode 100644 tests/cts-generator/cts-template/xor.yaml create mode 100644 tests/cts-generator/cts-template/xor2.64.yaml create mode 100644 tests/cts-generator/cts-template/xor2.yaml create mode 100644 tests/cts-generator/cts-template/xori.yaml create mode 100644 tests/cts-generator/cts-template/yaml-schema.json create mode 100755 tests/cts-generator/generate-cts.rb create mode 100755 tests/cts-generator/generator/command.rb create mode 100755 tests/cts-generator/generator/definitions.rb create mode 100755 tests/cts-generator/generator/generator.rb create mode 100755 tests/cts-generator/generator/parser.rb create mode 100755 tests/cts-generator/generator/single_test.rb create mode 100755 tests/cts-generator/generator/test.rb create mode 100755 tests/cts-generator/generator/test_base.rb create mode 100755 tests/cts-generator/generator/test_case.rb create mode 100755 tests/cts-generator/runner/reporters/base_test_reporter.rb create mode 100755 tests/cts-generator/runner/reporters/jtr_reporter.rb create mode 100755 tests/cts-generator/runner/reporters/string_logger.rb create mode 100755 tests/cts-generator/runner/reporters/test_reporter.rb create mode 100755 tests/cts-generator/runner/result.rb create mode 100755 tests/cts-generator/runner/runner.rb create mode 100755 tests/cts-generator/runner/single_test_runner.rb create mode 100755 tests/cts-generator/test-runner.rb create mode 100644 tests/cts-generator/verifier.debug.config create mode 100644 tests/verifier-tests/bug_1697.pa create mode 100644 tests/verifier-tests/bug_1702.pa create mode 100644 tests/verifier-tests/bug_1745.pa create mode 100644 tests/verifier-tests/bug_1813.pa create mode 100644 tests/verifier-tests/bug_1826.pa create mode 100644 tests/verifier-tests/bug_1827.pa create mode 100644 tests/verifier-tests/bug_1828.pa create mode 100644 tests/verifier-tests/bug_1833.pa create mode 100644 tests/verifier-tests/bug_1834.pa create mode 100644 tests/verifier-tests/bug_1863.pa create mode 100644 tests/verifier-tests/bug_1926.pa create mode 100644 tests/verifier-tests/bug_1940.pa create mode 100644 tests/verifier-tests/bug_2072.pa create mode 100644 tests/verifier-tests/bug_2075.pa create mode 100644 tests/verifier-tests/bug_2084.pa create mode 100644 tests/verifier-tests/bug_2085.pa create mode 100644 tests/verifier-tests/bug_2086_1.pa create mode 100644 tests/verifier-tests/bug_2086_2.pa create mode 100644 tests/verifier-tests/bug_2088.pa create mode 100644 tests/verifier-tests/bug_2089.pa create mode 100644 tests/verifier-tests/bug_2090.pa create mode 100644 tests/verifier-tests/bug_2107_1.pa create mode 100644 tests/verifier-tests/bug_2107_2.pa create mode 100644 tests/verifier-tests/bug_2136.pa create mode 100644 tests/verifier-tests/bug_2256.pa create mode 100644 tests/verifier-tests/bug_2260.pa create mode 100644 tests/verifier-tests/bug_2374.pa create mode 100644 tests/verifier-tests/bug_2702_1.pa create mode 100644 tests/verifier-tests/bug_2702_2.pa create mode 100644 tests/verifier-tests/bug_2702_3.pa create mode 100644 tests/verifier-tests/bug_2702_4.pa create mode 100644 tests/verifier-tests/bug_2740.pa create mode 100644 tests/verifier-tests/bug_2787.pa create mode 100644 tests/verifier-tests/bug_2816.pa create mode 100644 tests/verifier-tests/bug_2817.pa create mode 100644 tests/verifier-tests/bug_2818_1.pa create mode 100644 tests/verifier-tests/bug_2818_2.pa create mode 100644 tests/verifier-tests/bug_2921.pa create mode 100644 tests/verifier-tests/bug_3060.pa create mode 100644 tests/verifier-tests/bug_3133.pa create mode 100644 tests/verifier-tests/bug_3197.pa create mode 100644 tests/verifier-tests/bug_3219.pa create mode 100644 tests/verifier-tests/bug_3228.pa create mode 100644 tests/verifier-tests/cflow_err_beyond_end_of_function.pa create mode 100644 tests/verifier-tests/cflow_execution_may_go_beyond_the_end.pa create mode 100644 tests/verifier-tests/cflow_fallthrough_from_exc_handler_to_exc_handler.pa create mode 100644 tests/verifier-tests/cflow_fallthrough_to_exc_handler_from_body.pa create mode 100644 tests/verifier-tests/cflow_jump_from_exc_handler_to_exc_handler.pa create mode 100644 tests/verifier-tests/cflow_jump_on_exc_handler_from_body.pa create mode 100644 tests/verifier-tests/cflow_jump_out_of_body.pa create mode 100644 tests/verifier-tests/issue_1163.pa create mode 100644 tests/verifier-tests/issue_1981.pa create mode 100644 tests/verifier-tests/issue_964.pa create mode 100644 tests/verifier-tests/jumps_1.pa create mode 100644 tests/verifier-tests/jumps_2.pa create mode 100644 tests/verifier-tests/jumps_3.pa create mode 100644 tests/verifier-tests/mr_3176.pa create mode 100644 verification/CMakeLists.txt create mode 100644 verification/Verification.cmake create mode 100644 verification/absint/AbsInt.cmake create mode 100644 verification/absint/abs_int_inl.cpp create mode 100644 verification/absint/abs_int_inl.h create mode 100644 verification/absint/absint.cpp create mode 100644 verification/absint/absint.h create mode 100644 verification/absint/exec_context.h create mode 100644 verification/absint/panda_types.cpp create mode 100644 verification/absint/panda_types.h create mode 100644 verification/absint/reg_context.h create mode 100644 verification/absint/tests/exec_context_test.cpp create mode 100644 verification/absint/tests/reg_context_test.cpp create mode 100644 verification/absint/verification_context.h create mode 100644 verification/absint/verification_status.h create mode 100644 verification/cache/Cache.cmake create mode 100644 verification/cache/file_entity_cache.h create mode 100644 verification/cache/results_cache.cpp create mode 100644 verification/cache/results_cache.h create mode 100644 verification/cflow/Cflow.cmake create mode 100644 verification/cflow/cflow_check.cpp create mode 100644 verification/cflow/cflow_check.h create mode 100644 verification/cflow/cflow_check_options.h create mode 100644 verification/cflow/cflow_common.cpp create mode 100644 verification/cflow/cflow_common.h create mode 100644 verification/cflow/cflow_info.cpp create mode 100644 verification/cflow/cflow_info.h create mode 100644 verification/cflow/cflow_iterate_inl.h create mode 100644 verification/cflow/cflow_status.h create mode 100644 verification/cflow/exception_source_map.h create mode 100644 verification/cflow/instructions_map.h create mode 100644 verification/cflow/jumps_map.h create mode 100644 verification/cflow/tests/instructions_map_test.cpp create mode 100644 verification/cflow/tests/jumps_map_test.cpp create mode 100644 verification/debug/Debug.cmake create mode 100644 verification/debug/README.md create mode 100644 verification/debug/allowlist/allowlist.cpp create mode 100644 verification/debug/allowlist/allowlist.h create mode 100644 verification/debug/allowlist/allowlist_private.h create mode 100644 verification/debug/breakpoint/breakpoint.cpp create mode 100644 verification/debug/breakpoint/breakpoint.h create mode 100644 verification/debug/breakpoint/breakpoint_private.h create mode 100644 verification/debug/config/config.h create mode 100644 verification/debug/config/config_parse.cpp create mode 100644 verification/debug/config/config_parse.h create mode 100644 verification/debug/config/config_process.cpp create mode 100644 verification/debug/config/config_process.h create mode 100644 verification/debug/config_load.cpp create mode 100644 verification/debug/config_load.h create mode 100644 verification/debug/context/context.cpp create mode 100644 verification/debug/context/context.h create mode 100644 verification/debug/default_config.cpp create mode 100644 verification/debug/default_config.h create mode 100644 verification/debug/handlers/config_handler_allowlist.cpp create mode 100644 verification/debug/handlers/config_handler_breakpoints.cpp create mode 100644 verification/debug/handlers/config_handler_method_groups.cpp create mode 100644 verification/debug/handlers/config_handler_method_options.cpp create mode 100644 verification/debug/handlers/config_handler_options.cpp create mode 100644 verification/debug/handlers/config_handlers.h create mode 100644 verification/debug/handlers/literal_parser.h create mode 100644 verification/debug/options/method_group_parser.h create mode 100644 verification/debug/options/method_options.h create mode 100644 verification/debug/options/method_options_config.h create mode 100644 verification/debug/options/method_selector.h create mode 100644 verification/debug/options/msg_set_parser.h create mode 100644 verification/debug/parser/charset.h create mode 100644 verification/debug/parser/parser.h create mode 100644 verification/gen/BUILD.gn create mode 100644 verification/gen/CMakeLists.txt create mode 100644 verification/gen/templates/abs_int_builtin_handlers.h.erb create mode 100644 verification/gen/templates/abs_int_inl_compat_checks.h.erb create mode 100644 verification/gen/templates/abs_int_inl_gen.h.erb create mode 100644 verification/gen/templates/cflow_iterate_inl_gen.h.erb create mode 100644 verification/gen/templates/cflow_iterate_inl_gen_builtin_handlers.h.erb create mode 100644 verification/gen/templates/job_fill_gen.h.erb create mode 100644 verification/job_queue/JobQueue.cmake create mode 100644 verification/job_queue/cache.cpp create mode 100644 verification/job_queue/cache.h create mode 100644 verification/job_queue/index_table_cache.h create mode 100644 verification/job_queue/job.h create mode 100644 verification/job_queue/job_fill.cpp create mode 100644 verification/job_queue/job_fill.h create mode 100644 verification/job_queue/job_queue.cpp create mode 100644 verification/job_queue/job_queue.h create mode 100644 verification/messages.yaml create mode 100644 verification/models/README.md create mode 100644 verification/models/contexts_merge/check_set_intersection_as_lub.als create mode 100644 verification/models/contexts_merge/java_typing.als create mode 100644 verification/models/typesystem/ark_subtyping_closure.als create mode 100644 verification/models/typesystem/ark_typesystem.als create mode 100644 verification/tests/CMakeLists.txt create mode 100644 verification/tests/gtest/CMakeLists.txt create mode 100644 verification/tests/rapidcheck_catch2/CMakeLists.txt create mode 100644 verification/tests/rapidcheck_gtest/CMakeLists.txt create mode 100644 verification/thread/VerifierThread.cmake create mode 100644 verification/thread/verifier_thread.cpp create mode 100644 verification/thread/verifier_thread.h create mode 100644 verification/type/Type.cmake create mode 100644 verification/type/subtyping_closure.h create mode 100644 verification/type/tests/type_system_test.cpp create mode 100644 verification/type/type_image.h create mode 100644 verification/type/type_index.h create mode 100644 verification/type/type_info.h create mode 100644 verification/type/type_param.cpp create mode 100644 verification/type/type_param.h create mode 100644 verification/type/type_parametric.cpp create mode 100644 verification/type/type_parametric.h create mode 100644 verification/type/type_parametric_inl.h create mode 100644 verification/type/type_params.cpp create mode 100644 verification/type/type_params.h create mode 100644 verification/type/type_params_inl.h create mode 100644 verification/type/type_set.cpp create mode 100644 verification/type/type_set.h create mode 100644 verification/type/type_sort.h create mode 100644 verification/type/type_system.h create mode 100644 verification/type/type_system_kind.h create mode 100644 verification/type/type_systems.cpp create mode 100644 verification/type/type_systems.h create mode 100644 verification/type/type_type.cpp create mode 100644 verification/type/type_type.h create mode 100644 verification/type/type_type_inl.h create mode 100644 verification/util/Util.cmake create mode 100644 verification/util/abstract_index.h create mode 100644 verification/util/access.h create mode 100644 verification/util/addr_map.h create mode 100644 verification/util/bit_vector.h create mode 100644 verification/util/callable.h create mode 100644 verification/util/descriptor_string.h create mode 100644 verification/util/enum_array.h create mode 100644 verification/util/equiv_classes.h create mode 100644 verification/util/flags.h create mode 100644 verification/util/function_traits.h create mode 100644 verification/util/index.h create mode 100644 verification/util/int_set.h create mode 100644 verification/util/invalid_ref.h create mode 100644 verification/util/lazy.h create mode 100644 verification/util/misc.h create mode 100644 verification/util/obj_pool.h create mode 100644 verification/util/panda_or_std.h create mode 100644 verification/util/range.h create mode 100644 verification/util/ref_wrapper.h create mode 100644 verification/util/relation.h create mode 100644 verification/util/saturated_enum.h create mode 100644 verification/util/set_operations.h create mode 100644 verification/util/shifted_vector.h create mode 100644 verification/util/str.h create mode 100644 verification/util/struct_field.h create mode 100644 verification/util/synchronized.h create mode 100644 verification/util/tagged_index.h create mode 100644 verification/util/tests/addr_map_test.cpp create mode 100644 verification/util/tests/bit_vector_test.cpp create mode 100644 verification/util/tests/environment.cpp create mode 100644 verification/util/tests/environment.h create mode 100644 verification/util/tests/equiv_classes_test.cpp create mode 100644 verification/util/tests/flags.cpp create mode 100644 verification/util/tests/int_set_test.cpp create mode 100644 verification/util/tests/lazy_test.cpp create mode 100644 verification/util/tests/obj_pool_test.cpp create mode 100644 verification/util/tests/relation_test.cpp create mode 100644 verification/util/tests/set_operations_test.cpp create mode 100644 verification/util/tests/tagged_index.cpp create mode 100644 verification/util/tests/verifier_test.h create mode 100644 verification/value/Value.cmake create mode 100644 verification/value/abstract_type.h create mode 100644 verification/value/abstract_typed_value.h create mode 100644 verification/value/abstract_value.h create mode 100644 verification/value/origin.h create mode 100644 verification/value/tests/abstract_typed_value_test.cpp create mode 100644 verification/value/tests/variables_test.cpp create mode 100644 verification/value/var_binding.h create mode 100644 verification/value/variables.h create mode 100644 verification/verification.gni create mode 100755 verification/verification.rb create mode 100644 verification/verification.yaml create mode 100644 verification/verification_options.cpp create mode 100644 verification/verification_options.h create mode 100644 verification/verifier/BUILD.gn create mode 100644 verification/verifier/CMakeLists.txt create mode 100644 verification/verifier/verifier.config create mode 100644 verification/verifier/verifier.cpp diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..ee064af491 --- /dev/null +++ b/.clang-format @@ -0,0 +1,126 @@ +# 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. +--- +Language: Cpp +BasedOnStyle: Google +AccessModifierOffset: -4 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: true +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: true + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 4 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBlockIndentWidth: 4 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Right +ReflowComments: true +SortIncludes: false +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: true +SpaceBeforeParens: ControlStatements +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: false +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... + diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000000..aae4fa9226 --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,75 @@ +# 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. +--- +# Note well! The list of global exceptions is maintained in cmake/ClangTidy.cmake +WarningsAsErrors: '*' +HeaderFilterRegex: '.*/(assembler|compiler|debugger|libpandabase|libpandafile|runtime|class2panda)/.*' +AnalyzeTemporaryDtors: false +User: user +CheckOptions: + - key: google-readability-braces-around-statements.ShortStatementLines + value: '1' + - key: google-readability-function-size.StatementThreshold + value: '800' + - key: google-readability-namespace-comments.ShortNamespaceLines + value: '10' + - key: google-readability-namespace-comments.SpacesBeforeComments + value: '2' + - key: modernize-loop-convert.MaxCopySize + value: '16' + - key: modernize-loop-convert.MinConfidence + value: reasonable + - key: modernize-loop-convert.NamingStyle + value: CamelCase + - key: modernize-pass-by-value.IncludeStyle + value: llvm + - key: modernize-replace-auto-ptr.IncludeStyle + value: llvm + - key: modernize-use-nullptr.NullMacros + value: 'NULL' + - key: readability-identifier-naming.ClassMethodCase + value: CamelCase + - key: readability-identifier-naming.MethodCase + value: CamelCase + - key: readability-identifier-naming.EnumConstantCase + value: UPPER_CASE + - key: readability-identifier-naming.ConstantCase + value: UPPER_CASE + - key: readability-identifier-naming.ConstantMemberCase + value: UPPER_CASE + - key: readability-function-size.LineThreshold + value: 200 + - key: readability-identifier-naming.NamespaceCase + value: lower_case + - key: readability-identifier-naming.ClassCase + value: CamelCase + - key: readability-identifier-naming.PrivateMemberSuffix + value: _ + - key: readability-identifier-naming.StructCase + value: CamelCase + - key: readability-identifier-naming.FunctionCase + value: CamelCase + - key: readability-identifier-naming.VariableCase + value: lower_case + - key: readability-identifier-naming.GlobalConstantCase + value: UPPER_CASE + - key: readability-identifier-naming.GlobalConstantPrefix + value: g_ + - key: readability-identifier-naming.LocalVariableCase + value: CamelCase + - key: readability-identifier-naming.ParameterCase + value: lower_case + - key: readability-magic-numbers.IgnoredIntegerValues + value: '1;2;3;4;5;6;7;8' +... + diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..b2efbcfc83 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +#Set defaul end of lines for all files +* text eol=lf +# Denote all image files as binary +*.png binary +*.jpg binary +*.gif binary diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..bdc9d7f71d --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +/ark-third-party +**/compile_commands.json +/build** +build_* +/out/ +.vscode +.idea +*cmake-build-* +cts-generated +.dir-locals.el +artifacts/ +cscope* +tags +.byebug_history +.cache +*.swp diff --git a/.gn b/.gn new file mode 100644 index 0000000000..793b5f7016 --- /dev/null +++ b/.gn @@ -0,0 +1,19 @@ +# 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. + +buildconfig = "//build/config/BUILDCONFIG.gn" + +secondary_source = "//gn" +script_executable = "/usr/bin/env" + +exec_script("//scripts/install-third-party") diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000000..c372d2ec1a --- /dev/null +++ b/AUTHORS @@ -0,0 +1,135 @@ +Aleksandr Emelenko +Aleksandr Lovkov +Aleksandr Popov +Aleksei Grebenkin +Aleksei Sidorov +Alexander Semenov +Alexey Biryukov +Alexey Romanov +Alina Kropacheva +Anna Antipina +Anton Makarenko +Anton Romanov +Anton Soldatov +Anton Youdkevitch +Artem Udovichenko +Boris Molodenkov +Boris Ulasevich +Chen Mudan +Chen Qiuyao +Chen Tingwei +Csaba Osztrogonac +Cui Guihua +Dai Huina +Daniil Kochergin +Daniil Kofanov +Denis Kononenko +Denis Krylov +Denis Slynko +Denis Tomashev +Denis Zakharov +Ding Ding +Ding Wen +Dmitrii Trubenkov +Dmitry Alexeev +Dmitry Bubnov +Dmitry Buzmakov +Dmitry Chuyko +Dmitry Kovalenko +Dmitry Pochepko +Dong Kaixing +Evgenii Kudriashov +Evgeny Gavrin +Filipp Zhinkin +Gan Lan +Ge Tingke +Gong Junsong +Guo Bingbing +Hao Tuo +Hu Feng +Hu Xiaowei +Huang Feijie +Huang Haitao +Huang Huijin +Huang Yu +Igor Gorban +Igor Petrov +Ilya Trubachev +Ivan Burimskii +Ivan Trubachev +Ji Andong +Jiang Han +Kirill Galitskiy +Konstantin Baladurin +Konstantin Nazarov +Leonid Dyachkov +Li Chenshuai +Li Wentao +Li Yiming +Li Yongbiao +Lin Xiang +Liu Xin +Lu Kai +Luo Chuhao +Maria Filippova +Mark Gonopolskiy +Martin Negyorku +Maxim Bolshov +Maxim Morozov +Maxim Zimnyukov +Mikhail Aksenov +Mikhail Chernov +Mikhail Kaskov +Mikhail Redkin +Mikhail Sherstennikov +Mikita Strizhak +Nikita Kharitonov +Nikita Sizov +Pan Zhengyu +Pang Desong +Pavel Andrianov +Pavel Ishin +Pei Jiajun +Peng Biao +Qiu Yu +Robert Fancsik +Roland Takacs +Roman Zhuykov +Sergei Shadrin +Sergey Chernykh +Sergey Goldenberg +Sergey Nikitin +Stepan Dyatkovskiy +Su Chongwei +Sun Zhe +Vadim Mutilin +Vadim Sofin +Vasil Dyadov +Vasily Isaenko +Vasily Kopyl +Viktor Kutuzov +Vitalii Mordan +Vladimir Kuznetsov +Vladimir Popov +Vsevolod Pukhov +Vyacheslav Cherkashin +Wan Yanglan +Wang Gang +Wang Yaofeng +Wang Zhaoyong +Weng Changcheng +Wu Pengyong +Wu Zhefeng +Xian Yuqiang +Xiong Luo +Xu Cheng +Xu Jie +Yan Churkin +Ye Xiangrun +Ying Guofeng +Yu Jianchao +Zhang Quan +Zhang Rengao +Zhang Yukun +Zhao Gaoyi +Zheng Jiahuan diff --git a/BUILD.gn b/BUILD.gn new file mode 100644 index 0000000000..54814a0a04 --- /dev/null +++ b/BUILD.gn @@ -0,0 +1,150 @@ +# 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") +import("//build/ohos.gni") + +group("ark_packages") { + if (host_os != "mac") { + deps = [ + "$ark_root/libpandabase:libarkbase", + "$ark_root/libpandafile:libarkfile", + "$ark_root/libziparchive:libarkziparchive", + ] + } +} + +group("ark_host_linux_tools_packages") { + if (host_os != "mac") { + deps = [ + "$ark_root/assembler:ark_asm(${host_toolchain})", + "$ark_root/disassembler:ark_disasm(${host_toolchain})", + "$ark_root/libpandabase:libarkbase(${host_toolchain})", + "$ark_root/libpandafile:libarkfile(${host_toolchain})", + "$ark_root/libziparchive:libarkziparchive(${host_toolchain})", + ] + } +} + +group("ark_host_windows_tools_packages") { + if (host_os != "mac" && !ark_standalone_build) { + deps = [ + "$ark_root/assembler:ark_asm(//build/toolchain/mingw:mingw_x86_64)", + "$ark_root/disassembler:ark_disasm(//build/toolchain/mingw:mingw_x86_64)", + ] + } +} + +group("ark_host_mac_tools_packages") { + if (host_os == "mac") { + deps = [ + "$ark_root/assembler:ark_asm(//build/toolchain/mac:clang_x64)", + "$ark_root/disassembler:ark_disasm(//build/toolchain/mac:clang_x64)", + ] + } +} + +# Common config for ark source +config("ark_config") { + if (!ark_standalone_build) { + visibility = [ ":*" ] + } + + include_dirs = [ "$ark_root" ] + defines = [ "PANDA_ENABLE_LTO" ] + + if (is_linux) { + defines += [ + "PANDA_TARGET_UNIX", + "PANDA_TARGET_LINUX", + "PANDA_USE_FUTEX", + ] + } else if (is_mingw) { + defines += [ + "PANDA_TARGET_WINDOWS", + "_CRTBLD", + "__LIBMSVCRT__", + ] + } else if (is_mac) { + defines += [ + "PANDA_TARGET_UNIX", + "PANDA_TARGET_MACOS", + "PANDA_USE_FUTEX", + ] + } else { + defines += [ "PANDA_TARGET_UNIX", "PANDA_USE_FUTEX", ] + if (!is_standard_system && (current_cpu != "arm" || is_wearable_product)) { + defines += [ + "PANDA_TARGET_MOBILE", + ] + } + } + + if (!is_debug) { + defines += [ "NDEBUG" ] + } + + cflags_cc = [ + "-std=c++17", + "-pedantic", + "-Wall", + "-Wextra", + "-Werror", + "-Wshadow", + "-fno-rtti", + "-fno-exceptions", + "-Wno-invalid-offsetof", + + "-Wno-gnu-statement-expression", + "-Wno-unused-parameter", + "-Wno-unused-result", + ] + + if (!is_mac && use_pbqp) { + cflags_cc += [ + # PBQP regalloc + "-mllvm", + "-regalloc=pbqp", + ] + } + + if (is_debug) { + cflags_cc += [ + "-Og", + "-ggdb3", + ] + } + + if (current_cpu == "arm") { + defines += [ + "PANDA_TARGET_ARM32_ABI_SOFT=1", + "PANDA_TARGET_ARM32", + ] + } else if (current_cpu == "arm64") { + defines += [ + "PANDA_TARGET_ARM64", + "PANDA_TARGET_64", + "PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES", + "PANDA_USE_32_BIT_POINTER", + ] + } else if (current_cpu == "x86") { + defines += [ "PANDA_TARGET_X86" ] + } else if (current_cpu == "amd64" || current_cpu == "x64" || + current_cpu == "x86_64") { + defines += [ + "PANDA_TARGET_64", + "PANDA_TARGET_AMD64", + "PANDA_USE_32_BIT_POINTER", + ] + } +} diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..7eb72f34ba --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,240 @@ +# 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. + +cmake_minimum_required(VERSION 3.10 FATAL_ERROR) +project(PANDA NONE) + +# Add our custom configuration types to +# multi-configuration generators (i.e. Visual Studio): +if(CMAKE_CONFIGURATION_TYPES) + list(APPEND CMAKE_CONFIGURATION_TYPES "FastVerify" "DebugDetailed") + list(REMOVE_DUPLICATES CMAKE_CONFIGURATION_TYPES) + set(CMAKE_CONFIGURATION_TYPES ${CMAKE_CONFIGURATION_TYPES} + CACHE STRING "CMake configuration types" FORCE) +endif() + +enable_language(CXX ASM) + +# NB! For God's sake do not touch the command below. +# See https://gitlab.kitware.com/cmake/cmake/issues/16588. +# and https://clang.llvm.org/docs/JSONCompilationDatabase.html +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# ----- Default flags ---------------------------------------------------------- + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +# ----- Global variables ------------------------------------------------------- +# Please don't use CMAKE_SOURCE_DIR and CMAKE_BINARY_DIR to allow building +# Panda as a cmake subdirectory. You can use the following variables if you +# need to refer the Panda root directories +set(PANDA_ROOT ${CMAKE_CURRENT_SOURCE_DIR}) +set(PANDA_BINARY_ROOT ${CMAKE_CURRENT_BINARY_DIR}) +set(PANDA_THIRD_PARTY_SOURCES_DIR ${PANDA_ROOT}/ark-third-party) +set(PANDA_THIRD_PARTY_CONFIG_DIR ${PANDA_ROOT}/cmake/ark-third-party) + +# ----- Platform definitions --------------------------------------------------- +include(cmake/Definitions.cmake) + +if (NOT "${CMAKE_BUILD_TYPE}" MATCHES "Release" AND NOT PANDA_TARGET_WINDOWS) + # Needed for stacktrace printing + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -rdynamic") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic") +endif() + +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pedantic -Wall -Wextra -Werror -Wshadow") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti -fno-exceptions") +if(PANDA_TARGET_MACOS) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mmacosx-version-min=10.13") +endif() + +set(PANDA_PGO_PROFGEN_PATH "/data/local/tmp") + +if (PANDA_TARGET_MOBILE AND (PANDA_TARGET_ARM64 OR PANDA_TARGET_ARM32)) + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fuse-ld=lld") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fuse-ld=lld") +endif() + +if (PANDA_PGO_INSTRUMENT) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-generate=${PANDA_PGO_PROFGEN_PATH}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-generate=${PANDA_PGO_PROFGEN_PATH}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-generate=${PANDA_PGO_PROFGEN_PATH}") +endif() + +if (PANDA_PGO_OPTIMIZE) + if (NOT PANDA_PGO_PROFILE_DATA) + message(FATAL_ERROR "PANDA_PGO_PROFILE_DATA is not set") + endif() + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-use=${PANDA_PGO_PROFILE_DATA}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fprofile-use=${PANDA_PGO_PROFILE_DATA}") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fprofile-use=${PANDA_PGO_PROFILE_DATA}") +endif() + +if (PANDA_ENABLE_LTO) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -flto=thin") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -flto=thin") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto=thin") +endif() + +if (PANDA_LLVM_REGALLOC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -regalloc=${PANDA_LLVM_REGALLOC}") +endif() + +if ("${CMAKE_BUILD_TYPE}" STREQUAL "RelWithDebInfo") + add_compile_options(-O2 -ggdb3 -fno-omit-frame-pointer) +elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "FastVerify") + add_compile_options(-O2 -ggdb3) +elseif ("${CMAKE_BUILD_TYPE}" STREQUAL "DebugDetailed") + add_compile_options(-Og -ggdb3) +endif() + +if (PANDA_THREAD_SAFETY) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wthread-safety") +endif() + +if (PANDA_ARK_JS_VM) + add_definitions(-DPANDA_ARK_JS_VM) +endif() + +# ----- Deliverable executables and libraries ---------------------------------- +# Please override with per-target properties if your artifact should reside +# elsewhere, like this: +# set_target_properties(... PROPERTIES RUNTIME_OUTPUT_DIRECTORY ...) +# Applicable for tests and all "internal" artifacts. +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PANDA_BINARY_ROOT}/lib) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PANDA_BINARY_ROOT}/lib) +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PANDA_BINARY_ROOT}/bin) + +# ----- Panda CMake functions -------------------------------------------------- +include(cmake/PandaCmakeFunctions.cmake) + +# ----- Bootstrapping (for parts of platform written in managed code ) --------- +include(cmake/HostTools.cmake) + +# ----- Enable CCache ---------------------------------------------------------- +include(cmake/PandaCCache.cmake) + +# ----- Code analysis and style ------------------------------------------------ +include(cmake/ClangTidy.cmake) +include(cmake/CodeStyle.cmake) + +# ----- Sanitizers testing ----------------------------------------------------- +include(cmake/Sanitizers.cmake) + +# ----- Enable testing --------------------------------------------------------- + +# Umbrella target for testing: +add_custom_target(tests COMMENT "Running all test suites") + +include(cmake/Testing.cmake) + +# ----- Template Based Generator ----------------------------------------------- +include(cmake/TemplateBasedGen.cmake) + +# ----- Enable panda assemblies building --------------------------------------- +include(cmake/PandaAssembly.cmake) + +# Some compilers use x87 fp instructions by default in 32-bit mode. +# We need to use SSE one to correspond x86_64 build. +if (PANDA_TARGET_X86) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse -msse3") +endif() + +# ----- Targets ---------------------------------------------------------------- + +execute_process(COMMAND ${PANDA_ROOT}/scripts/install-third-party + WORKING_DIRECTORY ${PANDA_ROOT} + RESULT_VARIABLE THIRD_PARTY_OK) +if (NOT THIRD_PARTY_OK EQUAL 0) + message(FATAL_ERROR "Unable to install required third-party dependencies") +endif() + +if(PANDA_WITH_TOOLCHAIN) + add_subdirectory(isa) + + set(SECUREC_ROOT ${PANDA_THIRD_PARTY_SOURCES_DIR}/securec) + add_subdirectory(${PANDA_THIRD_PARTY_CONFIG_DIR}/securec) + add_subdirectory(libpandabase) + + set(MINIZ_ROOT ${PANDA_THIRD_PARTY_SOURCES_DIR}/miniz/amalgamation) + add_subdirectory(${PANDA_THIRD_PARTY_CONFIG_DIR}/miniz) + add_subdirectory(libziparchive) + + add_subdirectory(libpandafile) + if(NOT PANDA_TARGET_WINDOWS) + add_subdirectory(libpandafile/external) + endif() + + add_subdirectory(assembler) + add_subdirectory(disassembler) + + if(PANDA_WITH_RUNTIME) + if (PANDA_TARGET_X86 OR PANDA_TARGET_AMD64) + add_subdirectory(verification/tests) + endif() + add_subdirectory(verification/gen) + add_subdirectory(verification) + endif() +endif() + +if(PANDA_WITH_RUNTIME) + add_subdirectory(pandastdlib) + + if(NOT PANDA_TARGET_WINDOWS) + add_subdirectory(dprof) + endif() + + add_subdirectory(runtime) + + add_subdirectory(panda) + + add_subdirectory(verification/verifier) + +endif() + +# ----- Testing ---------------------------------------------------------------- + +if(PANDA_WITH_TESTS) + add_subdirectory(${PANDA_THIRD_PARTY_SOURCES_DIR}/googletest) + target_compile_options(gtest PUBLIC "-Wno-shadow" "-Wno-pedantic") + + add_subdirectory(tests) + + add_custom_target(tests_full COMMENT "Running all test suites and code checks") + add_dependencies(tests_full + check_concurrency_format + tests + ) + if(NOT PANDA_TARGET_MACOS) + add_dependencies(tests_full clang_format) + endif() +endif() + +# ----- Benchmarking ----------------------------------------------------------- + +if(PANDA_WITH_BENCHMARKS) + # NB! Please do not merge benchmarks and tests unless you want to mess with + # slow builds, etc. If you want some coupling, you might want to make benchmarks + # depend on tests some day. + + add_custom_target(benchmarks COMMENT "Running all benchmark suites") + add_subdirectory(tests/benchmarks) +endif() + +# ----- Aliases ---------------------------------------------------------------- + +add_custom_target(panda_bins COMMENT "Build all common Panda binaries") +add_dependencies(panda_bins panda pandasm) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/OAT.xml b/OAT.xml new file mode 100644 index 0000000000..0f3b756297 --- /dev/null +++ b/OAT.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + diff --git a/README.en.md b/README.en.md deleted file mode 100644 index 86b1f6e9b9..0000000000 --- a/README.en.md +++ /dev/null @@ -1,36 +0,0 @@ -# ark_runtime_core - -#### Description -{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**} - -#### Software Architecture -Software architecture description - -#### Installation - -1. xxxx -2. xxxx -3. xxxx - -#### Instructions - -1. xxxx -2. xxxx -3. xxxx - -#### Contribution - -1. Fork the repository -2. Create Feat_xxx branch -3. Commit your code -4. Create Pull Request - - -#### Gitee Feature - -1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md -2. Gitee blog [blog.gitee.com](https://blog.gitee.com) -3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore) -4. The most valuable open source project [GVP](https://gitee.com/gvp) -5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help) -6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README.md b/README.md index f58bce0022..ac6f335496 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,148 @@ -# ark_runtime_core +# Runtime -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +- [Introduction](#section11660541593) +- [Directory Structure](#section161941989596) +- [Usage Guidelines](#section1312121216216) +- [Repositories Involved](#section1371113476307) -#### 软件架构 -软件架构说明 +## Introduction +As a common module of ARK runtime, Runtime consists of some basic language-irrelevant runtime libraries, including ARK File, Tooling, and ARK Base. ARK File provides bytecodes and information required for executing bytecodes. Tooling supports Debugger. ARK Base is responsible for implementing system calls. -#### 安装教程 +## Directory Structure -1. xxxx -2. xxxx -3. xxxx +``` +/ark/runtime_core +├── assembler # Assembler that converts an ARK bytecode file (*.pa) in text format into a bytecode file (*.abc) in binary format. For details about the format, see docs/assembly_format.md and docs/file_format.md. +├── cmake # cmake script that contains the toolchain files and common cmake functions used to define the build and test targets. +├── CMakeLists.txt # cmake main entry file. +├── disassembler # Disassembler that converts an ARK bytecode file (*.abc) in binary format into an ARK bytecode file (*.pa) in text format. +├── docs # Language frontend, ARK file format, and runtime design documents. +├── dprof # Data used to collect the profiling data for ARK runtime. +├── gn # GN templates and configuration files. +├── isa # Bytecode ISA description file YAML, and Ruby scripts and templates. +├── ldscripts # Linker scripts used to place ELF sections larger than 4 GB in a non-PIE executable file. +├── libpandabase # Basic ARK runtime library, including logs, synchronization primitives, and common data structure. +├── libpandafile # Source code repository of ARK bytecode files (*.abc) in binary format. +├── 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. +├── tests # UT test cases. +└── verification # Bytecode verifier. See docs/bc_verification. -#### 使用说明 +``` -1. xxxx -2. xxxx -3. xxxx +## Usage Guidelines -#### 参与贡献 +Assembler ark\_asm -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +The ark\_asm assembler converts a text ARK bytecode file into a bytecode file in binary format. +Command: -#### 特技 +``` +ark_asm [Option] Input file Output file +``` + + + + + + + + + + + + + + + + + + + + + + + + + +

Option

+

Description

+

--dump-scopes

+

Saves the result to a JSON file to support the debug mode in Visual Studio Code.

+

--help

+

Displays help information.

+

--log-file

+

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

+

--optimize

+

Enables compilation optimization.

+

--size-stat

+

Collects statistics on and prints ARK bytecode information after conversion.

+

--verbose

+

Enables log printing.

+
+ +Input file: ARK bytecodes in text format + +Output file: ARK bytecodes in binary format + +Disassembler ark\_dissam + +The ark\_dissam disassembler converts a bytecode file in binary format into a text ARK bytecode file. + +Command: + +``` +ark_dissam [Option] Input file Output file +``` + + + + + + + + + + + + + + + + + + + +

Option

+

Description

+

--debug

+

Enables the function for printing debug information.

+

--debug-file

+

Specifies the path of the debug information output file. The default value is std::cout.

+

--help

+

Displays help information.

+

--verbose

+

Outputs the comments of the output file.

+
+ +Input file: ARK bytecodes in binary format + +Output file: ARK bytecodes in text format + +## Repositories Involved + +[ARK Runtime Subsystem](https://gitee.com/wanyanglan/ark_js_runtime/blob/master/docs/ARK-Runtime-Subsystem.md) + +**[ark/runtime\_core](README_zh.md)** + +[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) -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) diff --git a/README_zh.md b/README_zh.md new file mode 100644 index 0000000000..72626b4ebb --- /dev/null +++ b/README_zh.md @@ -0,0 +1,143 @@ +# 方舟公共组件 + +- [简介](#section11660541593) +- [目录](#section161941989596) +- [使用说明](#section1312121216216) +- [相关仓](#section1371113476307) + +## 简介 + +Runtime组件是方舟运行时的公共组件,主要包括一些语言无关的基础运行库,包含承载字节码以及执行字节码所需要相关信息的ARK File、支持Debugger的Tooling、负责对应系统调用的ARK Base等。 + +## 目录 + +``` +/ark/runtime_core +├── assembler # 汇编器,将文本格式的方舟字节码文件(*.pa)转换为二进制格式的字节码文件(*.abc),具体格式见:docs/assembly_format.md和docs/file_format.md +├── cmake # cmake脚本,包含工具链文件和用于定义构建和测试目标的常用cmake函数 +├── CMakeLists.txt # cmake主入口文件 +├── disassembler # 反汇编器,将二进制格式的方舟字节码文件(*.abc)转换为文本格式的方舟字节码文件(*.pa) +├── docs # 包含语言前端、方舟文件格式和运行时的设计文档。 +├── dprof # 用于ARK运行时搜集profile数据 +├── gn # GN模板和配置文件 +├── isa # 字节码ISA描述文件YAML,和ruby脚本和模板 +├── ldscripts # 包含链接器脚本,用于在非PIE可执行文件中放置4GB以上的ELF section。 +├── libpandabase # ARK运行时基本库,包含:日志、同步原语、公共数据结构等 +├── libpandafile # 二进制格式的方舟字节码文件(*.abc)源码仓 +├── libziparchive # 提供读取和使用miniz的ZIP压缩文件的API。 +├── panda # CLI工具,用于执行方舟字节码文件(*.abc)文件 +├── pandastdlib # 通过方舟汇编编写的标准库 +├── resources # CI jobs描述文件 +├── runtime # ARK运行时公共组件 +├── scripts # CI脚本 +├── templates # ruby模板和脚本,处理包括:命令行选项、记录器组件、错误消息、事件等 +├── tests # UT用例 +└── verification # 字节码验证器,具体可以参考 docs/bc_verification + +``` + +## 使用说明 + +汇编器工具概述 + +工具名称为ark\_asm,用于将文本格式的方舟字节码文件转换为二进制格式的方舟字节码文件。 + +命令行格式: + +``` +ark_asm [选项] 输入文件 输出文件 +``` + + + + + + + + + + + + + + + + + + + + + + +

选项

+

描述

+

--dump-scopes

+

将结果保存到json文件中,以支持在VS Code中的debug模式

+

--help

+

帮助提示

+

--log-file

+

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

+

--size-stat

+

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

+

--verbose

+

使能log打印

+
+ +输入文件:文本格式的方舟字节码 + +输出文件:二进制格式的方舟字节码 + +反汇编器工具概述 + +工具名称为ark\_dissam,用于将二进制格式的方舟字节码文件转换为可读的文本格式的方舟字节码文件。 + +命令行格式: + +``` +ark_dissam [选项] 输入文件 输出文件 +``` + + + + + + + + + + + + + + + + + + + +

选项

+

描述

+

--debug

+

使能调试信息

+

--debug-file

+

调试信息输出文件路径,默认为std::cout

+

--help

+

帮助提示

+

--verbose

+

增加输出汇编文件的注释信息

+
+ +输入文件:二进制格式的方舟字节码 + +输出文件:文本格式的方舟字节码 + +## 相关仓 + +[方舟运行时子系统](https://gitee.com/wanyanglan/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) + +**[ark/runtime\_core](README_zh.md)** + +[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) + diff --git a/ark_config.gni b/ark_config.gni new file mode 100644 index 0000000000..ac59f56275 --- /dev/null +++ b/ark_config.gni @@ -0,0 +1,186 @@ +# 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. + +if (!defined(ark_standalone_build)) { + ark_standalone_build = false +} + +if (ark_standalone_build) { + ark_root = "//" + ark_third_party_root = "//ark-third-party" + with_ecmascript = true + use_pbqp = true +} else { + ark_root = "//ark/runtime_core" + ark_third_party_root = "//third_party" + with_ecmascript = false + use_pbqp = false +} + +ark_enable_global_register_variables = true +enable_bytecode_optimizer = false + +if (ark_standalone_build) { + sdk_libc_secshared_dep = "$ark_third_party_root/securec:libc_secshared" + sdk_libc_secshared_config = + "$ark_third_party_root/securec:libsec_public_config" + + if (is_mingw || is_mac || is_linux) { + sdk_libc_secshared_dep = "$ark_third_party_root/securec:libc_secstatic" + } +} else { + sdk_libc_secshared_dep = "//utils/native/base:utilsecurec_shared" + sdk_libc_secshared_config = "//utils/native/base:utils_config" + + if (is_mingw || is_mac || is_linux) { + sdk_libc_secshared_dep = "//utils/native/base:utilsecurec" + } +} + +# Generate file for a template and YAML data provided. +# +# Mandatory arguments: +# data_file -- YAML data full name +# template_file -- template full name +# output_file -- output file full name +# requires -- a list of scripts that provide data-querying API for templates +# extra_dependencies -- a list of files that should be considered as dependencies, must be lable +template("ark_gen_file") { + assert(defined(invoker.data_file), "data_file is required!") + assert(defined(invoker.template_file), "template_file is required!") + assert(defined(invoker.output_file), "output_file is required!") + + requires = "" + if (defined(invoker.requires)) { + requires = string_join(",", rebase_path(invoker.requires, root_build_dir)) + } + + extra_dependencies = [] + if (defined(invoker.extra_dependencies)) { + extra_dependencies += invoker.extra_dependencies + } + + action("$target_name") { + script = "$ark_root/isa/gen.rb" + + # rerun action when data file or template file update + inputs = [ + invoker.template_file, + invoker.data_file, + ] + outputs = [ invoker.output_file ] + args = [ + "--template", + rebase_path(invoker.template_file, root_build_dir), + "--data", + rebase_path(invoker.data_file, root_build_dir), + "--require", + requires, + "--output", + rebase_path(outputs[0]), + ] + + deps = extra_dependencies + } +} + +# Generate files based on templates and YAML data provided. +# Adds targets for every template. Also adds a target for the whole function invocation +# with name ${data_name}_gen_${PROJECT_NAME} for ease of declaring dependencies on generated files. +# +# Mandatory arguments: +# * data -- data source, YAML file +# * template_files -- a list of templates to generate files +# * requires -- a list of Ruby scripts that provide data-querying API for templates +# +# Optional arguments: +# * sources -- a directory with templates, default is ${PROJECT_SOURCE_DIR}/templates +# * destination -- a directory for output files, default is ${PANDA_BINARY_ROOT} +# * extra_dependencies -- a list of files that should be considered as dependencies +template("ark_gen") { + assert(defined(invoker.data), "data were not passed to ark_gen") + assert(defined(invoker.template_files), + "template_files were not passed to ark_gen") + + dir = "" + if (defined(invoker.sources)) { + dir = invoker.sources + } else { + dir = "templates" + } + + destination = "" + if (defined(invoker.destination)) { + destination = invoker.destination + } else { + destination = target_out_dir + } + + input_requires = "" + if (defined(invoker.requires)) { + input_requires = invoker.requires + } + + foreach(t, invoker.template_files) { + name = string_replace(t, ".erb", "") + output = "${destination}/${name}" + name = string_replace(name, ".", "_") + name = string_replace(name, "/", "_") + target = "${target_name}_${name}" + + ark_gen_file(target) { + data_file = invoker.data + template_file = "${dir}/${t}" + output_file = output + requires = input_requires + extra_dependencies = [] + if (defined(invoker.extra_dependencies)) { + extra_dependencies += invoker.extra_dependencies + } + } + } +} + +# Calls `ark_gen` for ISA YAML. +# Adds targets for every template. Also adds a target for the whole function invocation +# with name isa_gen_${PROJECT_NAME} for ease of declaring dependencies on generated files. +# +# Mandatory arguments: +# * template_files -- a list of templates to generate files +# +# Optional arguments: +# * sources -- a directory with templates, default is ${PROJECT_SOURCE_DIR}/templates +# * destination -- a directory for output files, default is ${target_out_dir} +# * 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_requires = [ "$ark_root/isa/isapi.rb" ] + if (defined(invoker.requires)) { + isa_requires += invoker.requires + } + + dependencies = [] + if (defined(invoker.extra_dependencies)) { + dependencies += invoker.extra_dependencies + } + + ark_gen("$target_name") { + data = isa_data + template_files = invoker.template_files + sources = invoker.sources + destination = invoker.destination + requires = isa_requires + extra_dependencies = dependencies + } +} diff --git a/assembler/BUILD.gn b/assembler/BUILD.gn new file mode 100644 index 0000000000..ce39fb400b --- /dev/null +++ b/assembler/BUILD.gn @@ -0,0 +1,187 @@ +# 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") +import("//build/ohos.gni") + +config("arkassembler_public_config") { + include_dirs = [ + "$ark_root/assembler", + "$target_gen_dir", + "$target_gen_dir/include", + ] +} + +libarkassembler_sources = [ + "$target_gen_dir/builtin_parsing.cpp", + "$target_gen_dir/ins_to_string.cpp", + "annotation.cpp", + "assembly-emitter.cpp", + "assembly-parser.cpp", + "assembly-program.cpp", + "assembly-type.cpp", + "assembly-ins.cpp", + "context.cpp", + "extensions/ecmascript/ecmascript_meta.cpp", + "extensions/extensions.cpp", + "lexer.cpp", + "meta.cpp", +] + +libarkassembler_configs = [ + sdk_libc_secshared_config, + "$ark_root:ark_config", + ":arkassembler_public_config", + "$ark_root/libpandabase:arkbase_public_config", + "$ark_root/libpandafile:arkfile_public_config", +] + +ohos_shared_library("libarkassembler") { + sources = libarkassembler_sources + + configs = libarkassembler_configs + + 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", + ":isa_gen_libarkassembler_isa_h", + ":isa_gen_libarkassembler_opcode_parsing_h", + ":isa_gen_libarkassembler_operand_types_print_h", + "$ark_root/libpandabase:libarkbase", + "$ark_root/libpandafile:libarkfile", + sdk_libc_secshared_dep, + ] + if (!is_standard_system) { + relative_install_dir = "ark" + } + output_extension = "so" + subsystem_name = "ark" +} + +ohos_static_library("libarkassembler_frontend_static") { + sources = libarkassembler_sources + + configs = libarkassembler_configs + + 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", + ":isa_gen_libarkassembler_isa_h", + ":isa_gen_libarkassembler_opcode_parsing_h", + ":isa_gen_libarkassembler_operand_types_print_h", + "$ark_root/libpandabase:libarkbase_frontend_static", + "$ark_root/libpandafile:libarkfile_frontend_static", + sdk_libc_secshared_dep, + ] +} + +ohos_executable("ark_asm") { + sources = [ "pandasm.cpp" ] + + include_dirs = [ "$target_gen_dir" ] + + configs = [ + sdk_libc_secshared_config, + ":arkassembler_public_config", + "$ark_root:ark_config", + "$ark_root/libpandabase:arkbase_public_config", + "$ark_root/libpandafile:arkfile_public_config", + "$ark_root/runtime:arkruntime_public_config", + ] + + deps = [ + ":libarkassembler_frontend_static", + "$ark_root/libpandabase:libarkbase_frontend_static", + "$ark_root/libpandafile:libarkfile_frontend_static", + ] + + if (!is_mingw && !ark_standalone_build) { + ldflags = [ "-static-libstdc++" ] + } + + install_enable = true + subsystem_name = "ark" +} + +ark_isa_gen("isa_gen_libarkassembler") { + template_files = [ + "isa.h.erb", + "ins_emit.h.erb", + "ins_to_string.cpp.erb", + "ins_create_api.h.erb", + "opcode_parsing.h.erb", + "operand_types_print.h.erb", + ] + sources = "templates" + destination = "$target_gen_dir" + requires = [ + "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") { + template_file = "templates/meta_gen.cpp.erb" + data_file = "metadata.yaml" + requires = [ "asm_metadata.rb" ] + 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", + "//ark/js_runtime/ecmascript/ecma_builtins.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" + ] + 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" + requires = [ "asm_metadata.rb" ] + output_file = "$target_gen_dir/ecmascript_meta_gen.h" +} diff --git a/assembler/CMakeLists.txt b/assembler/CMakeLists.txt new file mode 100644 index 0000000000..a084ddaf67 --- /dev/null +++ b/assembler/CMakeLists.txt @@ -0,0 +1,148 @@ +# 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. + +cmake_minimum_required(VERSION 3.3.2 FATAL_ERROR) +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" + "ins_emit.h.erb" + "ins_to_string.cpp.erb" + "ins_create_api.h.erb" + "opcode_parsing.h.erb" + "operand_types_print.h.erb" + 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} + lexer.cpp + annotation.cpp + assembly-emitter.cpp + assembly-parser.cpp + assembly-program.cpp + assembly-type.cpp + assembly-ins.cpp + context.cpp + meta.cpp + ins_to_string.cpp + extensions/extensions.cpp + extensions/ecmascript/ecmascript_meta.cpp + builtin_parsing.cpp +) + +add_dependencies(arkassembler isa_gen_assembler arkfile) + +set(META_GEN_H ${CMAKE_CURRENT_BINARY_DIR}/meta_gen.h) +panda_gen_file( + DATAFILE ${CMAKE_CURRENT_SOURCE_DIR}/metadata.yaml + TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/templates/meta_gen.cpp.erb + OUTPUTFILE ${META_GEN_H} + REQUIRES ${CMAKE_CURRENT_SOURCE_DIR}/asm_metadata.rb +) + +set(ECMASCRIPT_META_GEN_H ${CMAKE_CURRENT_BINARY_DIR}/ecmascript_meta_gen.h) +panda_gen_file( + DATAFILE ${CMAKE_CURRENT_SOURCE_DIR}/extensions/ecmascript/metadata.yaml + TEMPLATE ${CMAKE_CURRENT_SOURCE_DIR}/templates/meta_gen.cpp.erb + OUTPUTFILE ${ECMASCRIPT_META_GEN_H} + REQUIRES ${CMAKE_CURRENT_SOURCE_DIR}/asm_metadata.rb +) + +add_custom_target(meta_gen_assembler DEPENDS ${META_GEN_H} ${ECMASCRIPT_META_GEN_H}) + +add_dependencies(arkassembler meta_gen_assembler) + +target_include_directories(arkassembler + PUBLIC ${CMAKE_CURRENT_BINARY_DIR} + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} +) + +panda_add_to_clang_tidy(TARGET ark_asm CHECKS + "-cert-dcl21-cpp" + "-cppcoreguidelines-macro-usage" + "-google-runtime-references" + "-misc-non-private-member-variables-in-classes" +) + +target_link_libraries(arkassembler arkfile) +target_link_libraries(ark_asm arkassembler arkbase) + +include_directories(${PANDA_ROOT}/libpandabase/) + +panda_add_gtest( + NAME assembler_tests + SOURCES + tests/lexer_test.cpp + tests/parser_test.cpp + tests/emitter_test.cpp + tests/mangling_tests.cpp + ${PANDASM_BIN_TESTS}/builtin_parsing_tests.cpp + LIBRARIES + arkbase arkassembler + SANITIZERS + ${PANDA_SANITIZERS_LIST} +) +if(TARGET assembler_tests) + target_compile_options(assembler_tests PUBLIC "-Wno-ignored-attributes") +endif() + +panda_add_sanitizers(TARGET arkassembler SANITIZERS ${PANDA_SANITIZERS_LIST}) +panda_add_sanitizers(TARGET ark_asm SANITIZERS ${PANDA_SANITIZERS_LIST}) + +add_custom_target(pandasm ALL + COMMAND cd $ && ${CMAKE_COMMAND} -E create_symlink $ pandasm) + +add_dependencies(pandasm ark_asm) + +if (PANDA_ENABLE_AFL) + include("${PANDA_ROOT}/fuzzing/Fuzzing.cmake") + panda_substitute_libs(TARGET arkassembler LIBS arkbase c_secshared arkfile) +endif() + +add_check_style(".") diff --git a/assembler/annotation.cpp b/assembler/annotation.cpp new file mode 100644 index 0000000000..42cc2426a4 --- /dev/null +++ b/assembler/annotation.cpp @@ -0,0 +1,246 @@ +/* + * 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 "annotation.h" + +namespace panda::pandasm { + +// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE) +std::unique_ptr InitScalarValue(const ScalarValue &sc_val) +{ + std::unique_ptr copy_val; + switch (sc_val.GetType()) { + case Value::Type::U1: { + copy_val = std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::U8: { + copy_val = std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::U16: { + copy_val = + std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::U32: { + copy_val = + std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::U64: { + copy_val = + std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::I8: { + copy_val = std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::I16: { + copy_val = std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::I32: { + copy_val = std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::I64: { + copy_val = std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::F32: { + copy_val = std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::F64: { + copy_val = std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::STRING: { + copy_val = + std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::STRING_NULLPTR: { + copy_val = std::make_unique( + ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::RECORD: { + copy_val = std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::METHOD: { + copy_val = + std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::ENUM: { + copy_val = + std::make_unique(ScalarValue::Create(sc_val.GetValue())); + break; + } + case Value::Type::ANNOTATION: { + copy_val = std::make_unique( + ScalarValue::Create(sc_val.GetValue())); + break; + } + default: { + UNREACHABLE(); + copy_val = nullptr; + break; + } + } + return copy_val; +} + +std::unique_ptr making_value(const AnnotationElement &ann_elem) +{ + std::unique_ptr copy_val; + switch (ann_elem.GetValue()->GetType()) { + case Value::Type::U1: + case Value::Type::U8: + case Value::Type::U16: + case Value::Type::U32: + case Value::Type::U64: + case Value::Type::I8: + case Value::Type::I16: + case Value::Type::I32: + case Value::Type::I64: + case Value::Type::F32: + case Value::Type::F64: + case Value::Type::STRING: + case Value::Type::STRING_NULLPTR: + case Value::Type::RECORD: + case Value::Type::METHOD: + case Value::Type::ENUM: + case Value::Type::ANNOTATION: { + copy_val = InitScalarValue(*static_cast(ann_elem.GetValue())); + break; + } + case Value::Type::ARRAY: { + Value::Type c_type; + auto *elem_arr = static_cast(ann_elem.GetValue()); + if (elem_arr->GetValues().size() == 0) { + c_type = Value::Type::VOID; + } else { + c_type = elem_arr->GetValues().front().GetType(); + } + std::vector sc_vals; + for (const auto &sc_val : elem_arr->GetValues()) { + sc_vals.push_back(*InitScalarValue(sc_val)); + } + copy_val = std::make_unique(c_type, std::move(sc_vals)); + break; + } + default: { + UNREACHABLE(); + copy_val = nullptr; + break; + } + } + return copy_val; +} + +AnnotationElement::AnnotationElement(const AnnotationElement &ann_elem) +{ + this->value_ = making_value(ann_elem); + this->name_ = ann_elem.GetName(); +} + +AnnotationElement &AnnotationElement::operator=(const AnnotationElement &ann_elem) +{ + if (this == &ann_elem) { + return *this; + } + + this->value_ = making_value(ann_elem); + this->name_ = ann_elem.GetName(); + return *this; +} + +ScalarValue *Value::GetAsScalar() +{ + ASSERT(!IsArray()); + return static_cast(this); +} + +const ScalarValue *Value::GetAsScalar() const +{ + ASSERT(!IsArray()); + return static_cast(this); +} + +ArrayValue *Value::GetAsArray() +{ + ASSERT(IsArray()); + return static_cast(this); +} + +const ArrayValue *Value::GetAsArray() const +{ + ASSERT(IsArray()); + return static_cast(this); +} + +/* static */ +std::string AnnotationElement::TypeToString(Value::Type type) +{ + switch (type) { + case Value::Type::U1: + return "u1"; + case Value::Type::I8: + return "i8"; + case Value::Type::U8: + return "u8"; + case Value::Type::I16: + return "i16"; + case Value::Type::U16: + return "u16"; + case Value::Type::I32: + return "i32"; + case Value::Type::U32: + return "u32"; + case Value::Type::I64: + return "i64"; + case Value::Type::U64: + return "u64"; + case Value::Type::F32: + return "f32"; + case Value::Type::F64: + return "f64"; + case Value::Type::STRING: + return "string"; + case Value::Type::RECORD: + return "class"; + case Value::Type::METHOD: + return "method"; + case Value::Type::ENUM: + return "enum"; + case Value::Type::ANNOTATION: + return "annotation"; + case Value::Type::ARRAY: + return "array"; + case Value::Type::VOID: + return "void"; + default: { + UNREACHABLE(); + return "unknown"; + } + } +} + +} // namespace panda::pandasm diff --git a/assembler/annotation.h b/assembler/annotation.h new file mode 100644 index 0000000000..d4c23a7392 --- /dev/null +++ b/assembler/annotation.h @@ -0,0 +1,562 @@ +/* + * 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_ASSEMBLER_ANNOTATION_H_ +#define PANDA_ASSEMBLER_ANNOTATION_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "assembly-type.h" +#include "macros.h" + +namespace panda::pandasm { + +class AnnotationElement; + +class AnnotationData { +public: + AnnotationData(std::string_view record_name, std::vector elements) + : record_name_(record_name), elements_(std::move(elements)) + { + } + + explicit AnnotationData(std::string_view record_name) : record_name_(record_name) {} + + DEFAULT_MOVE_SEMANTIC(AnnotationData); + DEFAULT_COPY_SEMANTIC(AnnotationData); + + ~AnnotationData() = default; + + std::string GetName() const + { + return record_name_; + } + + const std::vector &GetElements() const + { + return elements_; + } + + void AddElement(AnnotationElement &&element) + { + elements_.push_back(std::forward(element)); + } + +private: + std::string record_name_; + std::vector elements_; +}; + +class ScalarValue; +class ArrayValue; + +class Value { +public: + enum class Type { + U1, + I8, + U8, + I16, + U16, + I32, + U32, + I64, + U64, + F32, + F64, + STRING, + STRING_NULLPTR, + RECORD, + METHOD, + ENUM, + ANNOTATION, + ARRAY, + VOID, + METHOD_HANDLE, + UNKNOWN + }; + + // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE) + static constexpr char GetTypeAsChar(Type t) + { + char type = '0'; + switch (t) { + case Type::U1: + type = '1'; + break; + case Type::I8: + type = '2'; + break; + case Type::U8: + type = '3'; + break; + case Type::I16: + type = '4'; + break; + case Type::U16: + type = '5'; + break; + case Type::I32: + type = '6'; + break; + case Type::U32: + type = '7'; + break; + case Type::I64: + type = '8'; + break; + case Type::U64: + type = '9'; + break; + case Type::F32: + type = 'A'; + break; + case Type::F64: + type = 'B'; + break; + case Type::STRING: + type = 'C'; + break; + case Type::RECORD: + type = 'D'; + break; + case Type::METHOD: + type = 'E'; + break; + case Type::ENUM: + type = 'F'; + break; + case Type::ANNOTATION: + type = 'G'; + break; + case Type::ARRAY: + type = 'H'; + break; + case Type::VOID: + type = 'I'; + break; + case Type::METHOD_HANDLE: + type = 'J'; + break; + case Type::STRING_NULLPTR: + type = '*'; + break; + case Type::UNKNOWN: + default: + type = '0'; + break; + } + return type; + } + + // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE) + static constexpr char GetArrayTypeAsChar(Type t) + { + char type = '0'; + switch (t) { + case Type::U1: + type = 'K'; + break; + case Type::I8: + type = 'L'; + break; + case Type::U8: + type = 'M'; + break; + case Type::I16: + type = 'N'; + break; + case Type::U16: + type = 'O'; + break; + case Type::I32: + type = 'P'; + break; + case Type::U32: + type = 'Q'; + break; + case Type::I64: + type = 'R'; + break; + case Type::U64: + type = 'S'; + break; + case Type::F32: + type = 'T'; + break; + case Type::F64: + type = 'U'; + break; + case Type::STRING: + type = 'V'; + break; + case Type::RECORD: + type = 'W'; + break; + case Type::METHOD: + type = 'X'; + break; + case Type::ENUM: + type = 'Y'; + break; + case Type::ANNOTATION: + type = 'Z'; + break; + case Type::METHOD_HANDLE: + type = '@'; + break; + case Type::UNKNOWN: + default: + type = '0'; + break; + } + return type; + } + + // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE) + static constexpr Type GetCharAsType(char c) + { + Type type = Type::UNKNOWN; + switch (c) { + case '1': + type = Type::U1; + break; + case '2': + type = Type::I8; + break; + case '3': + type = Type::U8; + break; + case '4': + type = Type::I16; + break; + case '5': + type = Type::U16; + break; + case '6': + type = Type::I32; + break; + case '7': + type = Type::U32; + break; + case '8': + type = Type::I64; + break; + case '9': + type = Type::U64; + break; + case 'A': + type = Type::F32; + break; + case 'B': + type = Type::F64; + break; + case 'C': + type = Type::STRING; + break; + case 'D': + type = Type::RECORD; + break; + case 'E': + type = Type::METHOD; + break; + case 'F': + type = Type::ENUM; + break; + case 'G': + type = Type::ANNOTATION; + break; + case 'H': + type = Type::ARRAY; + break; + case 'I': + type = Type::VOID; + break; + case 'J': + type = Type::METHOD_HANDLE; + break; + case '*': + type = Type::STRING_NULLPTR; + break; + case '0': + default: + type = Type::UNKNOWN; + break; + } + return type; + } + + // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE) + static constexpr Type GetCharAsArrayType(char c) + { + Type type = Type::UNKNOWN; + switch (c) { + case 'K': + type = Type::U1; + break; + case 'L': + type = Type::I8; + break; + case 'M': + type = Type::U8; + break; + case 'N': + type = Type::I16; + break; + case 'O': + type = Type::U16; + break; + case 'P': + type = Type::I32; + break; + case 'Q': + type = Type::U32; + break; + case 'R': + type = Type::I64; + break; + case 'S': + type = Type::U64; + break; + case 'T': + type = Type::F32; + break; + case 'U': + type = Type::F64; + break; + case 'V': + type = Type::STRING; + break; + case 'W': + type = Type::RECORD; + break; + case 'X': + type = Type::METHOD; + break; + case 'Y': + type = Type::ENUM; + break; + case 'Z': + type = Type::ANNOTATION; + break; + case '@': + type = Type::METHOD_HANDLE; + break; + case '0': + default: + type = Type::UNKNOWN; + break; + } + return type; + } + + Type GetType() const + { + return type_; + } + + bool IsArray() const + { + return type_ == Type::ARRAY; + } + + ScalarValue *GetAsScalar(); + + const ScalarValue *GetAsScalar() const; + + ArrayValue *GetAsArray(); + + const ArrayValue *GetAsArray() const; + + virtual ~Value() = default; + + DEFAULT_COPY_SEMANTIC(Value); + DEFAULT_MOVE_SEMANTIC(Value); + +protected: + explicit Value(Type type) : type_(type) {} + +private: + Type type_; +}; + +// clang-format off + +template +struct ValueTypeHelper { + // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=40640 + // NOLINTNEXTLINE(readability-magic-numbers) + using type = std::conditional_t>>>>>>>>>>>>>>>>; +}; + +// clang-format on + +template +using ValueTypeHelperT = typename ValueTypeHelper::type; + +class ScalarValue : public Value { +public: + template + // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=40640 + // NOLINTNEXTLINE(readability-magic-numbers) + static ScalarValue Create(ValueTypeHelperT value) + { + // NOLINTNEXTLINE(readability-magic-numbers) + using T = ValueTypeHelperT; + // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203 + // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements) + if constexpr (std::is_integral_v) { // NOLINT(bugprone-suspicious-semicolon) + // NOLINTNEXTLINE(readability-magic-numbers) + return ScalarValue(type, static_cast(value)); + } + + // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements) + if constexpr (!std::is_integral_v) { // NOLINT(bugprone-suspicious-semicolon) + // NOLINTNEXTLINE(readability-magic-numbers) + return ScalarValue(type, value); + } + } + + template + T GetValue() const + { + // Disable checks due to clang-tidy bug https://bugs.llvm.org/show_bug.cgi?id=32203 + // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements) + if constexpr (std::is_integral_v) { // NOLINT(bugprone-suspicious-semicolon) + return static_cast(std::get(value_)); + } + + // NOLINTNEXTLINE(readability-braces-around-statements, hicpp-braces-around-statements) + if constexpr (!std::is_integral_v) { // NOLINT(bugprone-suspicious-semicolon) + return std::get(value_); + } + } + + DEFAULT_MOVE_SEMANTIC(ScalarValue); + DEFAULT_COPY_SEMANTIC(ScalarValue); + + ~ScalarValue() override = default; + +private: + ScalarValue(Type type, uint64_t value) : Value(type), value_(value) {} + + ScalarValue(Type type, float value) : Value(type), value_(value) {} + + ScalarValue(Type type, double value) : Value(type), value_(value) {} + + ScalarValue(Type type, std::string_view value) : Value(type), value_(std::string(value)) {} + + ScalarValue(Type type, pandasm::Type value) : Value(type), value_(std::move(value)) {} + + ScalarValue(Type type, const AnnotationData &value) : Value(type), value_(value) {} + + std::variant value_; +}; + +class ArrayValue : public Value { +public: + ArrayValue(Type component_type, std::vector values) + : Value(Type::ARRAY), component_type_(component_type), values_(std::move(values)) + { + } + + NO_MOVE_SEMANTIC(ArrayValue); + NO_COPY_SEMANTIC(ArrayValue); + + ~ArrayValue() override = default; + + const std::vector &GetValues() const + { + return values_; + } + + Type GetComponentType() const + { + return component_type_; + } + +private: + Type component_type_; + std::vector values_; +}; + +class AnnotationElement { +public: + AnnotationElement(std::string_view name, std::unique_ptr value) : name_(name), value_(std::move(value)) {} + + AnnotationElement(const AnnotationElement &ann_elem); + AnnotationElement &operator=(const AnnotationElement &ann_elem); + DEFAULT_MOVE_SEMANTIC(AnnotationElement); + ~AnnotationElement() = default; + + std::string GetName() const + { + return name_; + } + + Value *GetValue() const + { + return value_.get(); + } + + static std::string TypeToString(Value::Type type); + +private: + std::string name_; + std::unique_ptr value_; +}; + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ANNOTATION_H_ diff --git a/assembler/asm_isapi.rb b/assembler/asm_isapi.rb new file mode 100755 index 0000000000..afd0087319 --- /dev/null +++ b/assembler/asm_isapi.rb @@ -0,0 +1,124 @@ +# 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. + +# Assembler-specific extension of ISAPI +Instruction.class_eval do + def asm_token + mnemonic.tr('.', '_').upcase + 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' + 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' + end + + def calli_range? + calli? && mnemonic.split('.')[-1] == 'range' + end + + def simple_call? + (call? || calli?) && !call_range? + end + + def return? + stripped_mnemonic == 'return' + end + + def return_obj? + mnemonic == 'return.obj' + end + + def return64? + mnemonic == 'return.64' + end + + def return32? + mnemonic == 'return' + end + + def return_void? + mnemonic == 'return.void' + end +end + +def bit_cast(what, to_type, from_type) + "bit_cast<#{to_type}, #{from_type}>(static_cast<#{from_type}>(std::get(#{what})))" +end + +def index_of_max(a) + a.each_with_index.max[1] # returns index of `last` max value +end + +def max_number_of_src_regs + Panda::instructions.map do |insn| + insn.operands.select(&:reg?).select(&:src?).size + end.max +end + +IR = Struct.new(:opcode, :flags, :dst_idx, :use_idxs) + +module Panda + def self.pseudo_instructions + insns = [] + insns << IR.new('MOVX', ['InstFlags::PSEUDO'], 0, [1]) + insns << IR.new('LDAX', ['InstFlags::PSEUDO', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', [0]) + insns << IR.new('STAX', ['InstFlags::PSEUDO', 'InstFlags::ACC_READ'], 0, []) + insns << IR.new('NEWX', ['InstFlags::PSEUDO'], 0, []) + insns << IR.new('INITOBJX', ['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', []) + insns << IR.new('CALLX', ['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', []) + insns << IR.new('CALLX_VIRT', ['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_WRITE'], 'INVALID_REG_IDX', []) + insns << IR.new('B_P_CALLIX', ['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_READ'], 'INVALID_REG_IDX', []) + insns << IR.new('B_P_CALLIEX',['InstFlags::PSEUDO', 'InstFlags::CALL', 'InstFlags::ACC_READ'], 'INVALID_REG_IDX', []) + insns + end +end + +# returns array of OpenStruct with fields +# name - name of variable in emitter code +# type - type of variable in emitter code +def assembler_signature(group, is_jump) + insn = group.first + sig = format_ops(insn.format) + sig.each_with_index do |o, i| + 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] + else + o.type, o.name = is_jump ? ['const std::string &', 'label'] : ["int64_t", o.name] + end + elsif o.name.start_with?('id') + o.type, o.name = ['const std::string &', 'id'] + else + o.type = "uint16_t" + end + end +end diff --git a/assembler/asm_metadata.rb b/assembler/asm_metadata.rb new file mode 100755 index 0000000000..a6376004d5 --- /dev/null +++ b/assembler/asm_metadata.rb @@ -0,0 +1,248 @@ +# 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' + +class Attritute < SimpleDelegator + def getter_name + r = name.capitalize + type == 'bool' ? 'Is' + r : 'Get' + r + end + + def setter_name + 'Set' + name.capitalize + end + + def bool? + type == 'bool' + end + + def enum? + type == 'enum' + end + + def size? + type == 'size' + end + + def multiple? + !bool? && multiple + end + + def applicable_to?(item_type) + applicable_to.include?(item_type) + end + + def set_flags? + (defined? flags) && flags.any? || enum? && values.any? { |v| v.flags && v.flags.any? } + end +end + +module Metadata + module_function + + def attributes + @data.attributes.map do |op| + Attritute.new(op) + end + end + + def language + @data.language || '' + end + + def extends_default? + !language.empty? + end + + def item_types + ['record', 'field', 'function', 'param'] + end + + def wrap_data(data) + @data = data + end +end + +def Gen.on_require(data) + Metadata.wrap_data(data) +end + +module MetadataGen + module_function + + def attribute_name(attribute) + return attribute.name if Metadata.language.empty? + "#{Metadata.language.downcase}.#{attribute.name}" + end + + def class_name(item_type) + item_type.capitalize + 'Metadata' + end + + def validate_body(item_type, is_bool) + attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool } + body = [] + indent = ' ' * 4 + + attributes.each do |a| + body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {" + + unless a.multiple? + body << "#{indent * 2}if (HasAttribute(attribute)) {" + body << "#{indent * 3}return Error(\"Attribute '#{attribute_name(a)}' already defined\"," + body << "#{indent * 3} Error::Type::MULTIPLE_ATTRIBUTE);" + body << "#{indent * 2}}" + end + + if a.enum? + a.values.each do |v| + body << "#{indent * 2}if (value == \"#{v.value}\") {" + body << "#{indent * 3}return {};" + body << "#{indent * 2}}" + body << "" + end + + body << "#{indent * 2}return Error(std::string(\"Attribute '#{attribute_name(a)}' has incorrect value '\").append(value) +" + body << "#{indent * 2} R\"('. Should be one of #{a.values.map(&:value)})\", Error::Type::INVALID_VALUE);" + elsif a.size? + body << "#{indent * 2}return ValidateSize(value);" + else + body << "#{indent * 2}return {};" + end + + body << "#{indent}}" + body << "" + end + + Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? != is_bool }.each do |a| + body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {" + body << "#{indent * 2}return Error(\"Attribute '#{attribute_name(a)}' #{is_bool ? "must" : "must not"} have a value\"," + body << "#{indent * 2} #{is_bool ? "Error::Type::MISSING_VALUE" : "Error::Type::UNEXPECTED_VALUE"});" + body << "#{indent}}" + body << "" + end + + if Metadata::extends_default? + args = ['attribute'] + args << 'value' unless is_bool + body << "#{indent}return pandasm::#{class_name(item_type)}::Validate(#{args.join(', ')});" + else + body << "#{indent}return Error(std::string(\"Unknown attribute '\").append(attribute) + \"'\"," + body << "#{indent} Error::Type::UNKNOWN_ATTRIBUTE);" + end + + body + end + + def set_flags_body(item_type, is_bool) + attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool && a.set_flags? } + body = [] + indent = ' ' * 4 + + attributes.each do |a| + body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {" + + if defined? a.flags + body << "#{indent * 2}SetAccessFlags(GetAccessFlags() | #{a.flags.join(' | ')});" + end + + if a.enum? + a.values.select { |v| v.flags && v.flags.any? }.each do |v| + body << "#{indent * 2}if (value == \"#{v.value}\") {" + body << "#{indent * 3}SetAccessFlags(GetAccessFlags() | #{v.flags.join(' | ')});" + body << "#{indent * 2}}" + body << "" + end + end + + body << "#{indent}}" + end + + if Metadata::extends_default? + args = ['attribute'] + args << 'value' unless is_bool + body << "#{indent}pandasm::#{class_name(item_type)}::SetFlags(#{args.join(', ')});" + end + + body + end + + def remove_flags_body(item_type, is_bool) + attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool && a.set_flags? } + body = [] + indent = ' ' * 4 + + attributes.each do |a| + body << "#{indent}if (attribute == \"#{attribute_name(a)}\") {" + + if defined? a.flags + body << "#{indent * 2}if ((GetAccessFlags() & #{a.flags.join(' | ')}) != 0) {" + body << "#{indent * 3}SetAccessFlags(GetAccessFlags() ^ (#{a.flags.join(' | ')}));" + body << "#{indent * 2}}" + end + + if a.enum? + a.values.select { |v| v.flags && v.flags.any? }.each do |v| + body << "#{indent * 2}if (value == \"#{v.value}\") {" + body << "#{indent * 3}if ((GetAccessFlags() & (#{v.flags.join(' | ')})) != 0) {" + body << "#{indent * 4}SetAccessFlags(GetAccessFlags() ^ (#{v.flags.join(' | ')}));" + body << "#{indent * 3}}" + body << "#{indent * 2}}" + end + end + + body << "#{indent}}" + end + + if Metadata::extends_default? + args = ['attribute'] + args << 'value' unless is_bool + body << "#{indent}pandasm::#{class_name(item_type)}::RemoveFlags(#{args.join(', ')});" + end + + body + end + + def arg_list(is_bool) + args = ['std::string_view attribute'] + args << 'std::string_view value' if !is_bool + args + end + + def add_unused_attribute(arg) + "[[maybe_unused]] #{arg}" + end + + def validate_arg_list(item_type, is_bool) + args = arg_list(is_bool) + return args if Metadata::extends_default? + + attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool } + args[0] = add_unused_attribute(args[0]) if attributes.none? + args[1] = add_unused_attribute(args[1]) if args[1] && attributes.none? { |a| a.enum? } + args + end + + def flags_arg_list(item_type, is_bool) + args = arg_list(is_bool) + return args if Metadata::extends_default? + + attributes = Metadata::attributes.select { |a| a.applicable_to?(item_type) && a.bool? == is_bool && a.set_flags? } + use_value = attributes.any? { |a| a.enum? && a.values.any? { |v| v.flags && v.flags.any? } } + args[0] = add_unused_attribute(args[0]) if attributes.none? + args[1] = add_unused_attribute(args[1]) if args[1] && !use_value + args + end + +end diff --git a/assembler/assembly-context.h b/assembler/assembly-context.h new file mode 100644 index 0000000000..1ad39b468c --- /dev/null +++ b/assembler/assembly-context.h @@ -0,0 +1,78 @@ +/* + * 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_ASSEMBLER_ASSEMBLY_CONTEXT_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_CONTEXT_H_ + +#include +#include +#include +#include + +#include "assembly-ins.h" +#include "assembly-type.h" +#include "error.h" +#include "lexer.h" + +namespace panda::pandasm { + +/* + * Used to move around tokens. + * *context : + * returns current value of a token + * ++context : + * sets the next token value + * returns current value of a token + * context++ : + * sets the next token value + * returns the next value of a token + * similarly --context and context-- + */ +struct Context { + std::string_view token; /* current token */ + std::vector tokens; /* token list */ + size_t number = 0; /* line number */ + bool end = false; /* end of line flag */ + Token::Type id = Token::Type::ID_BAD; /* current token type */ + Token::Type signop = Token::Type::ID_BAD; /* current token operand type (if it is an operation) */ + panda::pandasm::Error err; /* current error */ + int64_t *max_value_of_reg = nullptr; + size_t ins_number = 0; + Type curr_func_return_type; + std::vector> *function_arguments_list = nullptr; + std::unordered_map>> function_arguments_lists; + + void Make(const std::vector &t); + void UpSignOperation(); + bool ValidateRegisterName(char c, size_t n = 0) const; + bool ValidateParameterName(size_t number_of_params_already_is) const; + bool ValidateLabel(); + bool Mask(); + bool NextMask(); + size_t Len() const; + std::string_view GiveToken(); + Token::Type WaitFor(); + Token::Type Next(); + + Token::Type operator++(int); + Token::Type operator--(int); + Token::Type operator++(); + Token::Type operator--(); + Token::Type operator*(); +}; + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ASSEMBLY_CONTEXT_H_ diff --git a/assembler/assembly-debug.h b/assembler/assembly-debug.h new file mode 100644 index 0000000000..cf1f325b31 --- /dev/null +++ b/assembler/assembly-debug.h @@ -0,0 +1,54 @@ +/* + * 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_ASSEMBLER_ASSEMBLY_DEBUG_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_DEBUG_H_ + +#include +#include +#include + +namespace panda::pandasm::debuginfo { + +struct Ins { + size_t line_number = 0; + std::string whole_line = ""; + size_t bound_left = 0; + size_t bound_right = 0; + + void SetLineNumber(size_t ln) + { + line_number = ln; + } + + Ins() = default; + Ins(size_t l_n, std::string &f_c, size_t b_l, size_t b_r) + : line_number(l_n), whole_line(std::move(f_c)), bound_left(b_l), bound_right(b_r) + { + } +}; + +struct LocalVariable { + std::string name; + std::string signature; + std::string signature_type; + int32_t reg = 0; + uint32_t start = 0; + uint32_t length = 0; +}; + +} // namespace panda::pandasm::debuginfo + +#endif // PANDA_ASSEMBLER_ASSEMBLY_DEBUG_H_ diff --git a/assembler/assembly-emitter.cpp b/assembler/assembly-emitter.cpp new file mode 100644 index 0000000000..561b606e50 --- /dev/null +++ b/assembler/assembly-emitter.cpp @@ -0,0 +1,1799 @@ +/* + * 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-emitter.h" + +#include +#include +#include +#include +#include + +#include "bytecode_instruction-inl.h" +#include "file_items.h" +#include "file_writer.h" +#include "mangling.h" +#include "os/file.h" + +namespace { + +using panda::os::file::Mode; +using panda::os::file::Open; +using panda::panda_file::AnnotationItem; +using panda::panda_file::ArrayValueItem; +using panda::panda_file::BaseClassItem; +using panda::panda_file::BaseFieldItem; +using panda::panda_file::BaseMethodItem; +using panda::panda_file::ClassItem; +using panda::panda_file::CodeItem; +using panda::panda_file::DebugInfoItem; +using panda::panda_file::FieldItem; +using panda::panda_file::FileWriter; +using panda::panda_file::ForeignClassItem; +using panda::panda_file::ForeignFieldItem; +using panda::panda_file::ForeignMethodItem; +using panda::panda_file::ItemContainer; +using panda::panda_file::LineNumberProgramItem; +using panda::panda_file::MemoryBufferWriter; +using panda::panda_file::MethodHandleItem; +using panda::panda_file::MethodItem; +using panda::panda_file::MethodParamItem; +using panda::panda_file::ParamAnnotationsItem; +using panda::panda_file::PrimitiveTypeItem; +using panda::panda_file::ProtoItem; +using panda::panda_file::ScalarValueItem; +using panda::panda_file::StringItem; +using panda::panda_file::Type; +using panda::panda_file::TypeItem; +using panda::panda_file::ValueItem; +using panda::panda_file::Writer; + +std::unordered_map CreatePrimitiveTypes(ItemContainer *container) +{ + auto res = std::unordered_map {}; + res.insert({Type::TypeId::VOID, container->CreateItem(Type::TypeId::VOID)}); + res.insert({Type::TypeId::U1, container->CreateItem(Type::TypeId::U1)}); + res.insert({Type::TypeId::I8, container->CreateItem(Type::TypeId::I8)}); + res.insert({Type::TypeId::U8, container->CreateItem(Type::TypeId::U8)}); + res.insert({Type::TypeId::I16, container->CreateItem(Type::TypeId::I16)}); + res.insert({Type::TypeId::U16, container->CreateItem(Type::TypeId::U16)}); + res.insert({Type::TypeId::I32, container->CreateItem(Type::TypeId::I32)}); + res.insert({Type::TypeId::U32, container->CreateItem(Type::TypeId::U32)}); + res.insert({Type::TypeId::I64, container->CreateItem(Type::TypeId::I64)}); + res.insert({Type::TypeId::U64, container->CreateItem(Type::TypeId::U64)}); + res.insert({Type::TypeId::F32, container->CreateItem(Type::TypeId::F32)}); + res.insert({Type::TypeId::F64, container->CreateItem(Type::TypeId::F64)}); + res.insert({Type::TypeId::TAGGED, container->CreateItem(Type::TypeId::TAGGED)}); + return res; +} + +template +typename T::mapped_type Find(const T &map, typename T::key_type key) +{ + auto res = map.find(key); + ASSERT(res != map.end()); + return res->second; +} + +} // anonymous namespace + +namespace panda::pandasm { + +/* static */ +std::string AsmEmitter::last_error(""); + +static panda_file::Type::TypeId GetTypeId(Value::Type type) +{ + switch (type) { + case Value::Type::U1: + return panda_file::Type::TypeId::U1; + case Value::Type::I8: + return panda_file::Type::TypeId::I8; + case Value::Type::U8: + return panda_file::Type::TypeId::U8; + case Value::Type::I16: + return panda_file::Type::TypeId::I16; + case Value::Type::U16: + return panda_file::Type::TypeId::U16; + case Value::Type::I32: + return panda_file::Type::TypeId::I32; + case Value::Type::U32: + return panda_file::Type::TypeId::U32; + case Value::Type::I64: + return panda_file::Type::TypeId::I64; + case Value::Type::U64: + return panda_file::Type::TypeId::U64; + case Value::Type::F32: + return panda_file::Type::TypeId::F32; + case Value::Type::F64: + return panda_file::Type::TypeId::F64; + case Value::Type::VOID: + return panda_file::Type::TypeId::VOID; + default: + return panda_file::Type::TypeId::REFERENCE; + } +} + +/* static */ +bool AsmEmitter::CheckValueType(Value::Type value_type, Type type, const Program &program) +{ + auto value_type_id = GetTypeId(value_type); + if (value_type_id != type.GetId()) { + SetLastError("Inconsistent element (" + AnnotationElement::TypeToString(value_type) + + ") and function's return type (" + type.GetName() + ")"); + return false; + } + + switch (value_type) { + case Value::Type::STRING: + case Value::Type::RECORD: + case Value::Type::ANNOTATION: + case Value::Type::ENUM: { + auto it = program.record_table.find(type.GetName()); + if (it == program.record_table.cend()) { + SetLastError("Record " + type.GetName() + " not found"); + return false; + } + + auto &record = it->second; + if (value_type == Value::Type::ANNOTATION && !record.metadata->IsAnnotation() && + !record.metadata->IsRuntimeAnnotation() && !record.metadata->IsRuntimeTypeAnnotation() && + !record.metadata->IsTypeAnnotation()) { + SetLastError("Record " + type.GetName() + " isn't annotation"); + return false; + } + + if (value_type == Value::Type::ENUM && (record.metadata->GetAccessFlags() & ACC_ENUM) == 0) { + SetLastError("Record " + type.GetName() + " isn't enum"); + return false; + } + + break; + } + case Value::Type::ARRAY: { + if (!type.IsArray()) { + SetLastError("Inconsistent element (" + AnnotationElement::TypeToString(value_type) + + ") and function's return type (" + type.GetName() + ")"); + return false; + } + + break; + } + default: { + break; + } + } + + return true; +} + +/* static */ +// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE) +panda_file::LiteralItem *AsmEmitter::CreateLiteralItem( + ItemContainer *container, const Value *value, std::vector *out, + const std::unordered_map &methods) +{ + auto value_type = value->GetType(); + + switch (value_type) { + case Value::Type::U1: + case Value::Type::I8: + case Value::Type::U8: { + auto v = value->GetAsScalar()->GetValue(); + out->emplace_back(v); + return &out->back(); + } + case Value::Type::I16: + case Value::Type::U16: { + auto v = value->GetAsScalar()->GetValue(); + out->emplace_back(v); + return &out->back(); + } + case Value::Type::I32: + case Value::Type::U32: + case Value::Type::STRING_NULLPTR: { + auto v = value->GetAsScalar()->GetValue(); + out->emplace_back(v); + return &out->back(); + } + case Value::Type::I64: + case Value::Type::U64: { + auto v = value->GetAsScalar()->GetValue(); + out->emplace_back(v); + return &out->back(); + } + case Value::Type::F32: { + auto v = bit_cast(value->GetAsScalar()->GetValue()); + out->emplace_back(v); + return &out->back(); + } + case Value::Type::F64: { + auto v = bit_cast(value->GetAsScalar()->GetValue()); + out->emplace_back(v); + return &out->back(); + } + case Value::Type::STRING: { + auto *string_item = container->GetOrCreateStringItem(value->GetAsScalar()->GetValue()); + out->emplace_back(string_item); + return &out->back(); + } + case Value::Type::METHOD: { + auto name = value->GetAsScalar()->GetValue(); + auto method_item = static_cast(Find(methods, name)); + out->emplace_back(method_item); + return &out->back(); + } + default: + return nullptr; + } +} + +/* static */ +bool AsmEmitter::CheckValueRecordCase(const Value *value, const Program &program) +{ + auto t = value->GetAsScalar()->GetValue(); + if (!t.IsObject()) { + return true; + } + + auto record_name = t.GetName(); + bool is_found = true; + if (t.IsArray()) { + auto it = program.array_types.find(t); + is_found = it != program.array_types.cend(); + } else { + auto it = program.record_table.find(record_name); + is_found = it != program.record_table.cend(); + } + + if (!is_found) { + SetLastError("Incorrect value: record " + record_name + " not found"); + return false; + } + + return true; +} + +/* static */ +bool AsmEmitter::CheckValueMethodCase(const Value *value, const Program &program) +{ + auto function_name = value->GetAsScalar()->GetValue(); + auto it = program.function_table.find(function_name); + if (it == program.function_table.cend()) { + SetLastError("Incorrect value: function " + function_name + " not found"); + return false; + } + + return true; +} + +/* static */ +bool AsmEmitter::CheckValueEnumCase(const Value *value, Type type, const Program &program) +{ + auto enum_value = value->GetAsScalar()->GetValue(); + auto record_name = GetOwnerName(enum_value); + auto field_name = GetItemName(enum_value); + + if (record_name != type.GetName()) { + SetLastError("Incorrect value: Expected " + type.GetName() + " enum record"); + return false; + } + + const auto &record = program.record_table.find(record_name)->second; + auto it = std::find_if(record.field_list.cbegin(), record.field_list.cend(), + [&field_name](const Field &field) { return field.name == field_name; }); + if (it == record.field_list.cend()) { + SetLastError("Incorrect value: Enum field " + enum_value + " not found"); + return false; + } + + const auto &field = *it; + if ((field.metadata->GetAccessFlags() & ACC_ENUM) == 0) { + SetLastError("Incorrect value: Field " + enum_value + " isn't enum"); + return false; + } + + return true; +} + +/* static */ +bool AsmEmitter::CheckValueArrayCase(const Value *value, Type type, const Program &program) +{ + auto component_type = type.GetComponentType(); + auto value_component_type = value->GetAsArray()->GetComponentType(); + + if (value_component_type == Value::Type::VOID && value->GetAsArray()->GetValues().empty()) { + return true; + } + + if (!CheckValueType(value_component_type, component_type, program)) { + SetLastError("Incorrect array's component type: " + GetLastError()); + return false; + } + + for (auto &elem_value : value->GetAsArray()->GetValues()) { + if (!CheckValue(&elem_value, component_type, program)) { + SetLastError("Incorrect array's element: " + GetLastError()); + return false; + } + } + + return true; +} + +/* static */ +bool AsmEmitter::CheckValue(const Value *value, Type type, const Program &program) +{ + auto value_type = value->GetType(); + + if (!CheckValueType(value_type, type, program)) { + SetLastError("Incorrect type: " + GetLastError()); + return false; + } + + switch (value_type) { + case Value::Type::RECORD: { + if (!CheckValueRecordCase(value, program)) { + return false; + } + + break; + } + case Value::Type::METHOD: { + if (!CheckValueMethodCase(value, program)) { + return false; + } + + break; + } + case Value::Type::ENUM: { + if (!CheckValueEnumCase(value, type, program)) { + return false; + } + + break; + } + case Value::Type::ARRAY: { + if (!CheckValueArrayCase(value, type, program)) { + return false; + } + + break; + } + default: { + break; + } + } + + return true; +} + +/* static */ +ScalarValueItem *AsmEmitter::CreateScalarStringValueItem(ItemContainer *container, const Value *value, + std::vector *out) +{ + auto *string_item = container->GetOrCreateStringItem(value->GetAsScalar()->GetValue()); + if (out != nullptr) { + out->emplace_back(string_item); + return &out->back(); + } + + return container->CreateItem(string_item); +} + +/* static */ +ScalarValueItem *AsmEmitter::CreateScalarRecordValueItem( + ItemContainer *container, const Value *value, std::vector *out, + const std::unordered_map &classes) +{ + auto type = value->GetAsScalar()->GetValue(); + BaseClassItem *class_item; + if (type.IsObject()) { + auto name = type.GetName(); + auto it = classes.find(name); + if (it == classes.cend()) { + return nullptr; + } + + class_item = it->second; + } else { + class_item = container->GetOrCreateForeignClassItem(type.GetDescriptor()); + } + + if (out != nullptr) { + out->emplace_back(class_item); + return &out->back(); + } + + return container->CreateItem(class_item); +} + +/* static */ +ScalarValueItem *AsmEmitter::CreateScalarMethodValueItem( + ItemContainer *container, const Value *value, std::vector *out, + const std::unordered_map &methods) +{ + auto name = value->GetAsScalar()->GetValue(); + auto it = methods.find(name); + if (it == methods.cend()) { + return nullptr; + } + + auto *method_item = it->second; + if (out != nullptr) { + out->emplace_back(method_item); + return &out->back(); + } + + return container->CreateItem(method_item); +} + +/* static */ +ScalarValueItem *AsmEmitter::CreateScalarEnumValueItem(ItemContainer *container, const Value *value, + std::vector *out, + const std::unordered_map &fields) +{ + auto name = value->GetAsScalar()->GetValue(); + auto it = fields.find(name); + if (it == fields.cend()) { + return nullptr; + } + + auto *field_item = it->second; + if (out != nullptr) { + out->emplace_back(field_item); + return &out->back(); + } + + return container->CreateItem(field_item); +} + +/* static */ +ScalarValueItem *AsmEmitter::CreateScalarAnnotationValueItem( + ItemContainer *container, const Value *value, std::vector *out, const Program &program, + const std::unordered_map &classes, + const std::unordered_map &fields, + const std::unordered_map &methods) +{ + auto annotation = value->GetAsScalar()->GetValue(); + auto *annotation_item = CreateAnnotationItem(container, annotation, program, classes, fields, methods); + if (annotation_item == nullptr) { + return nullptr; + } + + if (out != nullptr) { + out->emplace_back(annotation_item); + return &out->back(); + } + + return container->CreateItem(annotation_item); +} + +/* static */ +ScalarValueItem *AsmEmitter::CreateScalarValueItem(ItemContainer *container, const Value *value, + std::vector *out, const Program &program, + const std::unordered_map &classes, + const std::unordered_map &fields, + const std::unordered_map &methods) +{ + auto value_type = value->GetType(); + switch (value_type) { + case Value::Type::U1: + case Value::Type::I8: + case Value::Type::U8: + case Value::Type::I16: + case Value::Type::U16: + case Value::Type::I32: + case Value::Type::U32: + case Value::Type::STRING_NULLPTR: { + return CreateScalarPrimValueItem(container, value, out); + } + case Value::Type::I64: + case Value::Type::U64: { + return CreateScalarPrimValueItem(container, value, out); + } + case Value::Type::F32: { + return CreateScalarPrimValueItem(container, value, out); + } + case Value::Type::F64: { + return CreateScalarPrimValueItem(container, value, out); + } + case Value::Type::STRING: { + return CreateScalarStringValueItem(container, value, out); + } + case Value::Type::RECORD: { + return CreateScalarRecordValueItem(container, value, out, classes); + } + case Value::Type::METHOD: { + return CreateScalarMethodValueItem(container, value, out, methods); + } + case Value::Type::ENUM: { + return CreateScalarEnumValueItem(container, value, out, fields); + } + case Value::Type::ANNOTATION: { + return CreateScalarAnnotationValueItem(container, value, out, program, classes, fields, methods); + } + default: { + UNREACHABLE(); + return nullptr; + } + } +} + +/* static */ +ValueItem *AsmEmitter::CreateValueItem(ItemContainer *container, const Value *value, const Program &program, + const std::unordered_map &classes, + const std::unordered_map &fields, + const std::unordered_map &methods) +{ + switch (value->GetType()) { + case Value::Type::ARRAY: { + std::vector elements; + for (const auto &elem_value : value->GetAsArray()->GetValues()) { + auto *item = + CreateScalarValueItem(container, &elem_value, &elements, program, classes, fields, methods); + if (item == nullptr) { + return nullptr; + } + } + + auto component_type = value->GetAsArray()->GetComponentType(); + return container->CreateItem(panda_file::Type(GetTypeId(component_type)), + std::move(elements)); + } + default: { + return CreateScalarValueItem(container, value, nullptr, program, classes, fields, methods); + } + } +} + +/* static */ +AnnotationItem *AsmEmitter::CreateAnnotationItem(ItemContainer *container, const AnnotationData &annotation, + const Program &program, + const std::unordered_map &classes, + const std::unordered_map &fields, + const std::unordered_map &methods) +{ + auto record_name = annotation.GetName(); + auto it = program.record_table.find(record_name); + if (it == program.record_table.cend()) { + SetLastError("Record " + record_name + " not found"); + return nullptr; + } + + auto &record = it->second; + if (!record.metadata->IsAnnotation()) { + SetLastError("Record " + record_name + " isn't annotation"); + return nullptr; + } + + std::vector item_elements; + std::vector tag_elements; + + for (const auto &element : annotation.GetElements()) { + auto name = element.GetName(); + auto *value = element.GetValue(); + + auto value_type = value->GetType(); + + uint8_t tag_type; + + if (value_type == Value::Type::ARRAY && !value->GetAsArray()->GetValues().empty()) { + auto array_element_type = value->GetAsArray()->GetComponentType(); + tag_type = Value::GetArrayTypeAsChar(array_element_type); + } else { + tag_type = Value::GetTypeAsChar(value_type); + } + + ASSERT(tag_type != '0'); + + auto function_name = record.name + "." + name; + + if (record.HasImplementation()) { + auto func_it = program.function_table.find(function_name); + if (func_it == program.function_table.cend()) { + // Definitions of the system annotations in the libcore haven't values. + // So print message and continue if corresponding function isn't found. + LOG(INFO, ASSEMBLER) << "Function " << function_name << " not found"; + } else { + auto &function = func_it->second; + if (!CheckValue(value, function.return_type, program)) { + SetLastError("Incorrect annotation element " + function_name + ": " + GetLastError()); + return nullptr; + } + } + } + + auto *item = CreateValueItem(container, value, program, classes, fields, methods); + if (item == nullptr) { + SetLastError("Cannot create value item for annotation element " + function_name + ": " + GetLastError()); + return nullptr; + } + + item_elements.emplace_back(container->GetOrCreateStringItem(name), item); + tag_elements.emplace_back(tag_type); + } + + auto *cls = classes.find(record_name)->second; + return container->CreateItem(cls, std::move(item_elements), std::move(tag_elements)); +} + +MethodHandleItem *AsmEmitter::CreateMethodHandleItem(ItemContainer *container, const MethodHandle &mh, + const std::unordered_map &fields, + const std::unordered_map &methods) +{ + MethodHandleItem *item = nullptr; + switch (mh.type) { + case panda_file::MethodHandleType::PUT_STATIC: + case panda_file::MethodHandleType::GET_STATIC: + case panda_file::MethodHandleType::PUT_INSTANCE: + case panda_file::MethodHandleType::GET_INSTANCE: { + item = container->CreateItem(mh.type, fields.at(mh.item_name)); + break; + } + case panda_file::MethodHandleType::INVOKE_STATIC: + case panda_file::MethodHandleType::INVOKE_INSTANCE: + case panda_file::MethodHandleType::INVOKE_CONSTRUCTOR: + case panda_file::MethodHandleType::INVOKE_DIRECT: + case panda_file::MethodHandleType::INVOKE_INTERFACE: { + item = container->CreateItem(mh.type, methods.at(mh.item_name)); + break; + } + default: + UNREACHABLE(); + break; + } + return item; +} + +/* static */ +template +bool AsmEmitter::AddAnnotations(T *item, ItemContainer *container, const AnnotationMetadata &metadata, + const Program &program, const std::unordered_map &classes, + const std::unordered_map &fields, + const std::unordered_map &methods) +{ + for (const auto &annotation : metadata.GetAnnotations()) { + auto *annotation_item = CreateAnnotationItem(container, annotation, program, classes, fields, methods); + if (annotation_item == nullptr) { + return false; + } + + auto &record = program.record_table.find(annotation.GetName())->second; + if (record.metadata->IsRuntimeAnnotation()) { + item->AddRuntimeAnnotation(annotation_item); + } else if (record.metadata->IsAnnotation()) { + item->AddAnnotation(annotation_item); + } else if (record.metadata->IsRuntimeTypeAnnotation()) { + item->AddRuntimeTypeAnnotation(annotation_item); + } else if (record.metadata->IsTypeAnnotation()) { + item->AddTypeAnnotation(annotation_item); + } + } + + return true; +} + +template +void SetSourceLang(T *item, extensions::Language lang) +{ + switch (lang) { + case extensions::Language::ECMASCRIPT: { + item->SetSourceLang(panda_file::SourceLang::ECMASCRIPT); + break; + } + case extensions::Language::PANDA_ASSEMBLY: { + item->SetSourceLang(panda_file::SourceLang::PANDA_ASSEMBLY); + break; + } + default: { + UNREACHABLE(); + break; + } + } +} + +template +static void AddBytecodeIndexDependencies(MethodItem *method, const Ins &insn, + const std::unordered_map &items) +{ + ASSERT(!insn.ids.empty()); + + for (const auto &id : insn.ids) { + auto it = items.find(id); + ASSERT(it != items.cend()); + + auto *item = it->second; + ASSERT(item->GetIndexType() != panda_file::IndexType::NONE); + method->AddIndexDependency(item); + } +} + +static void AddBytecodeIndexDependencies(MethodItem *method, const Function &func, + const AsmEmitter::AsmEntityCollections &entities) +{ + for (const auto &insn : func.ins) { + if (insn.opcode == Opcode::INVALID) { + continue; + } + + if (insn.HasFlag(InstFlags::METHOD_ID)) { + AddBytecodeIndexDependencies(method, insn, entities.method_items); + continue; + } + + if (insn.HasFlag(InstFlags::FIELD_ID)) { + AddBytecodeIndexDependencies(method, insn, entities.field_items); + continue; + } + + if (insn.HasFlag(InstFlags::TYPE_ID)) { + AddBytecodeIndexDependencies(method, insn, entities.class_items); + continue; + } + } + + for (const auto &catch_block : func.catch_blocks) { + if (catch_block.exception_record.empty()) { + continue; + } + + auto it = entities.class_items.find(catch_block.exception_record); + ASSERT(it != entities.class_items.cend()); + auto *item = it->second; + ASSERT(item->GetIndexType() != panda_file::IndexType::NONE); + method->AddIndexDependency(item); + } +} + +/* static */ +void AsmEmitter::MakeStringItems(ItemContainer *items, const Program &program, + AsmEmitter::AsmEntityCollections &entities) +{ + for (const auto &s : program.strings) { + auto *item = items->GetOrCreateStringItem(s); + entities.string_items.insert({s, item}); + } +} + +static std::unique_ptr CreateValue(const panda::pandasm::LiteralArray::Literal &literal) +{ + switch (literal.tag_) { + case panda_file::LiteralTag::TAGVALUE: + return std::make_unique( + ScalarValue::Create(std::get(literal.value_))); + case panda_file::LiteralTag::BOOL: + return std::make_unique( + ScalarValue::Create(static_cast(std::get(literal.value_)))); + case panda_file::LiteralTag::ARRAY_I8: + 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_))); + case panda_file::LiteralTag::INTEGER: + [[fallthrough]]; + case panda_file::LiteralTag::ARRAY_I32: + return std::make_unique( + ScalarValue::Create(std::get(literal.value_))); + case panda_file::LiteralTag::ARRAY_I64: + return std::make_unique( + ScalarValue::Create(std::get(literal.value_))); + case panda_file::LiteralTag::FLOAT: + [[fallthrough]]; + case panda_file::LiteralTag::ARRAY_F32: + return std::make_unique( + ScalarValue::Create(std::get(literal.value_))); + case panda_file::LiteralTag::DOUBLE: + [[fallthrough]]; + case panda_file::LiteralTag::ARRAY_F64: + return std::make_unique( + ScalarValue::Create(std::get(literal.value_))); + case panda_file::LiteralTag::STRING: + [[fallthrough]]; + case panda_file::LiteralTag::ARRAY_STRING: + 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_)))); + 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; + } + + return nullptr; +} + +/* static */ +void AsmEmitter::MakeLiteralItems(ItemContainer *items, const Program &program, + AsmEmitter::AsmEntityCollections &entities) +{ + for (const auto &[id, l] : program.literalarray_table) { + auto literal_array_item = items->GetOrCreateLiteralArrayItem(id); + std::vector literal_array; + + for (auto &literal : l.literals_) { + auto value = CreateValue(literal); + // the return pointer of vector element should not be rewrited + CreateLiteralItem(items, value.get(), &literal_array, entities.method_items); + } + + literal_array_item->AddItems(literal_array); + entities.literalarray_items.insert({id, literal_array_item}); + } +} + +/* static */ +void AsmEmitter::MakeArrayTypeItems(ItemContainer *items, const Program &program, + AsmEmitter::AsmEntityCollections &entities) +{ + for (const auto &t : program.array_types) { + auto *foreign_record = items->GetOrCreateForeignClassItem(t.GetDescriptor()); + entities.class_items.insert({t.GetName(), foreign_record}); + } +} + +/* static */ +bool AsmEmitter::HandleRecordAsForeign( + ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities, + const std::unordered_map &primitive_types, const std::string &name, + const Record &rec) +{ + Type record_type = Type::FromName(name); + auto *foreign_record = items->GetOrCreateForeignClassItem(record_type.GetDescriptor(rec.conflict)); + entities.class_items.insert({name, foreign_record}); + for (const auto &f : rec.field_list) { + ASSERT(f.metadata->IsForeign()); + auto *field_name = items->GetOrCreateStringItem(pandasm::DeMangleName(f.name)); + std::string full_field_name = name + "." + f.name; + if (!f.metadata->IsForeign()) { + SetLastError("External record " + name + " has a non-external field " + f.name); + return false; + } + auto *type_item = GetTypeItem(items, primitive_types, f.type, program); + if (type_item == nullptr) { + SetLastError("Field " + full_field_name + " has undefined type"); + return false; + } + auto *field = items->CreateItem(foreign_record, field_name, type_item); + entities.field_items.insert({full_field_name, field}); + } + return true; +} + +/* static */ +bool AsmEmitter::HandleBaseRecord(ItemContainer *items, const Program &program, const std::string &name, + const Record &base_rec, ClassItem *record) +{ + auto base_name = base_rec.metadata->GetBase(); + if (!base_name.empty()) { + auto it = program.record_table.find(base_name); + if (it == program.record_table.cend()) { + SetLastError("Base record " + base_name + " is not defined for record " + name); + return false; + } + auto &rec = it->second; + Type base_type(base_name, 0); + if (rec.metadata->IsForeign()) { + record->SetSuperClass(items->GetOrCreateForeignClassItem(base_type.GetDescriptor(rec.conflict))); + } else { + record->SetSuperClass(items->GetOrCreateClassItem(base_type.GetDescriptor(rec.conflict))); + } + } + return true; +} + +/* static */ +bool AsmEmitter::HandleInterfaces(ItemContainer *items, const Program &program, const std::string &name, + const Record &rec, ClassItem *record) +{ + auto ifaces = rec.metadata->GetInterfaces(); + for (const auto &item : ifaces) { + auto it = program.record_table.find(item); + if (it == program.record_table.cend()) { + SetLastError("Interface record " + item + " is not defined for record " + name); + return false; + } + auto &iface = it->second; + Type iface_type(item, 0); + if (iface.metadata->IsForeign()) { + record->AddInterface(items->GetOrCreateForeignClassItem(iface_type.GetDescriptor(iface.conflict))); + } else { + record->AddInterface(items->GetOrCreateClassItem(iface_type.GetDescriptor(iface.conflict))); + } + } + return true; +} + +/* static */ +bool AsmEmitter::HandleFields(ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities, + const std::unordered_map &primitive_types, + const std::string &name, const Record &rec, ClassItem *record) +{ + for (const auto &f : rec.field_list) { + auto *field_name = items->GetOrCreateStringItem(pandasm::DeMangleName(f.name)); + std::string full_field_name = name + "." + f.name; + auto *type_item = GetTypeItem(items, primitive_types, f.type, program); + if (type_item == nullptr) { + SetLastError("Field " + full_field_name + " has undefined type"); + return false; + } + BaseFieldItem *field; + if (f.metadata->IsForeign()) { + field = items->CreateItem(record, field_name, type_item); + } else { + field = record->AddField(field_name, type_item, f.metadata->GetAccessFlags()); + } + entities.field_items.insert({full_field_name, field}); + } + return true; +} + +/* static */ +bool AsmEmitter::HandleRecord(ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities, + const std::unordered_map &primitive_types, + const std::string &name, const Record &rec) +{ + Type record_type = Type::FromName(name); + auto *record = items->GetOrCreateClassItem(record_type.GetDescriptor(rec.conflict)); + entities.class_items.insert({name, record}); + + record->SetAccessFlags(rec.metadata->GetAccessFlags()); + + SetSourceLang(record, rec.language); + + if (!rec.source_file.empty()) { + auto *source_file_item = items->GetOrCreateStringItem(rec.source_file); + record->SetSourceFile(source_file_item); + } + + if (!HandleBaseRecord(items, program, name, rec, record)) { + return false; + } + + if (!HandleInterfaces(items, program, name, rec, record)) { + return false; + } + + if (!HandleFields(items, program, entities, primitive_types, name, rec, record)) { + return false; + } + + return true; +} + +/* static */ +bool AsmEmitter::MakeRecordItems( + ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities, + const std::unordered_map &primitive_types) +{ + for (const auto &[name, rec] : program.record_table) { + if (rec.metadata->IsForeign()) { + if (!HandleRecordAsForeign(items, program, entities, primitive_types, name, rec)) { + return false; + } + } else { + if (!HandleRecord(items, program, entities, primitive_types, name, rec)) { + return false; + } + } + } + return true; +} + +/* static */ +StringItem *AsmEmitter::GetMethodName(ItemContainer *items, const Function &func, const std::string &name) +{ + if (func.metadata->IsCtor()) { + return items->GetOrCreateStringItem(extensions::GetCtorName(func.language)); + } + + if (func.metadata->IsCctor()) { + return items->GetOrCreateStringItem(extensions::GetCctorName(func.language)); + } + + return items->GetOrCreateStringItem(GetItemName(name)); +} + +/* static */ +bool AsmEmitter::HandleAreaForInner(ItemContainer *items, const Program &program, ClassItem **area, + ForeignClassItem **foreign_area, const std::string &name, + const std::string &record_owner_name) +{ + auto iter = program.record_table.find(record_owner_name); + if (iter != program.record_table.end()) { + auto &rec = iter->second; + Type record_owner_type = Type::FromName(record_owner_name); + auto descriptor = record_owner_type.GetDescriptor(rec.conflict); + if (rec.metadata->IsForeign()) { + *foreign_area = items->GetOrCreateForeignClassItem(descriptor); + if (*foreign_area == nullptr) { + SetLastError("Unable to create external record " + iter->first); + return false; + } + } else { + *area = items->GetOrCreateClassItem(descriptor); + (*area)->SetAccessFlags(rec.metadata->GetAccessFlags()); + } + } else { + SetLastError("Function " + name + " is bound to undefined record " + record_owner_name); + return false; + } + return true; +} + +/* static */ +bool AsmEmitter::HandleRecordOnwer(ItemContainer *items, const Program &program, ClassItem **area, + ForeignClassItem **foreign_area, const std::string &name, + const std::string &record_owner_name) +{ + if (record_owner_name.empty()) { + *area = items->GetOrCreateGlobalClassItem(); + (*area)->SetAccessFlags(ACC_PUBLIC); + SetSourceLang(*area, program.lang); + } else { + if (!HandleAreaForInner(items, program, area, foreign_area, name, record_owner_name)) { + return false; + } + } + return true; +} + +/* static */ +bool AsmEmitter::HandleFunctionParams( + ItemContainer *items, const Program &program, size_t idx, const std::string &name, const Function &func, + const std::unordered_map &primitive_types, + std::vector ¶ms) +{ + for (size_t i = idx; i < func.params.size(); i++) { + const auto &p = func.params[i].type; + auto *type_item = GetTypeItem(items, primitive_types, p, program); + if (type_item == nullptr) { + SetLastError("Argument " + std::to_string(i) + " of function " + name + " has undefined type"); + return false; + } + params.emplace_back(type_item); + } + return true; +} + +/* static */ +bool AsmEmitter::HandleFunctionLocalVariables(ItemContainer *items, const Function &func, const std::string &name) +{ + for (const auto &v : func.local_variable_debug) { + if (v.name.empty()) { + SetLastError("Function '" + name + "' has an empty local variable name"); + return false; + } + if (v.signature.empty()) { + SetLastError("Function '" + name + "' has an empty local variable signature"); + return false; + } + items->GetOrCreateStringItem(v.name); + // Skip signature and signature type for parameters + ASSERT(v.reg >= 0); + if (func.IsParameter(v.reg)) { + continue; + } + items->GetOrCreateStringItem(v.signature); + if (!v.signature_type.empty()) { + items->GetOrCreateStringItem(v.signature_type); + } + } + return true; +} + +/* static */ +bool AsmEmitter::CreateMethodItem(ItemContainer *items, AsmEmitter::AsmEntityCollections &entities, + const Function &func, TypeItem *type_item, ClassItem *area, + ForeignClassItem *foreign_area, uint32_t access_flags, StringItem *method_name, + const std::string &mangled_name, const std::string &name, + std::vector ¶ms) +{ + auto *proto = items->GetOrCreateProtoItem(type_item, params); + BaseMethodItem *method; + if (foreign_area == nullptr) { + if (func.metadata->IsForeign()) { + method = items->CreateItem(area, method_name, proto, access_flags); + } else { + method = area->AddMethod(method_name, proto, access_flags, params); + } + } else { + if (!func.metadata->IsForeign()) { + SetLastError("Non-external function " + name + " is bound to external record"); + return false; + } + method = items->CreateItem(foreign_area, method_name, proto, access_flags); + } + entities.method_items.insert({mangled_name, method}); + if (!func.metadata->IsForeign() && func.metadata->HasImplementation()) { + if (!func.source_file.empty()) { + items->GetOrCreateStringItem(func.source_file); + } + if (!func.source_code.empty()) { + items->GetOrCreateStringItem(func.source_code); + } + } + return true; +} + +/* static */ +bool AsmEmitter::MakeFunctionItems( + ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities, + const std::unordered_map &primitive_types, bool emit_debug_info) +{ + for (const auto &f : program.function_table) { + const auto &[mangled_name, func] = f; + + auto name = pandasm::DeMangleName(mangled_name); + StringItem *method_name = GetMethodName(items, func, name); + + ClassItem *area = nullptr; + ForeignClassItem *foreign_area = nullptr; + + std::string record_owner_name = GetOwnerName(name); + if (!HandleRecordOnwer(items, program, &area, &foreign_area, name, record_owner_name)) { + return false; + } + + auto params = std::vector {}; + uint32_t access_flags = func.metadata->GetAccessFlags(); + if (func.params.empty() || func.params[0].type.GetName() != record_owner_name) { + access_flags |= ACC_STATIC; + } + + bool is_static = (access_flags & ACC_STATIC) != 0; + size_t idx = is_static ? 0 : 1; + if (!HandleFunctionParams(items, program, idx, name, func, primitive_types, params)) { + return false; + } + + if (emit_debug_info && !HandleFunctionLocalVariables(items, func, name)) { + return false; + } + + auto *type_item = GetTypeItem(items, primitive_types, func.return_type, program); + if (type_item == nullptr) { + SetLastError("Function " + name + " has undefined return type"); + return false; + } + + if (!CreateMethodItem(items, entities, func, type_item, area, foreign_area, access_flags, method_name, + mangled_name, name, params)) { + return false; + } + } + return true; +} + +/* static */ +bool AsmEmitter::MakeRecordAnnotations(ItemContainer *items, const Program &program, + const AsmEmitter::AsmEntityCollections &entities) +{ + for (const auto &[name, record] : program.record_table) { + if (record.metadata->IsForeign()) { + continue; + } + + auto *class_item = static_cast(Find(entities.class_items, name)); + if (!AddAnnotations(class_item, items, *record.metadata, program, entities.class_items, entities.field_items, + entities.method_items)) { + SetLastError("Cannot emit annotations for record " + record.name + ": " + GetLastError()); + return false; + } + + for (const auto &field : record.field_list) { + auto field_name = record.name + "." + field.name; + auto *field_item = static_cast(Find(entities.field_items, field_name)); + if (!AddAnnotations(field_item, items, *field.metadata, program, entities.class_items, entities.field_items, + entities.method_items)) { + SetLastError("Cannot emit annotations for field " + field_name + ": " + GetLastError()); + return false; + } + + auto res = field.metadata->GetValue(); + if (res) { + auto value = res.value(); + auto *item = CreateValueItem(items, &value, program, entities.class_items, entities.field_items, + entities.method_items); + field_item->SetValue(item); + } + } + } + return true; +} + +/* static */ +void AsmEmitter::SetCodeAndDebugInfo(ItemContainer *items, MethodItem *method, const Function &func, + bool emit_debug_info) +{ + auto *code = items->CreateItem(); + method->SetCode(code); + + if (!emit_debug_info && !func.CanThrow()) { + return; + } + + auto *line_number_program = items->CreateLineNumberProgramItem(); + auto *debug_info = items->CreateItem(line_number_program); + if (emit_debug_info) { + for (const auto &v : func.local_variable_debug) { + ASSERT(v.reg >= 0); + if (func.IsParameter(v.reg)) { + debug_info->AddParameter(items->GetOrCreateStringItem(v.name)); + } + } + } else { + auto nparams = method->GetParams().size(); + for (size_t i = 0; i < nparams; i++) { + debug_info->AddParameter(nullptr); + } + } + method->SetDebugInfo(debug_info); +} + +/* static */ +void AsmEmitter::SetMethodSourceLang(const Program &program, MethodItem *method, const Function &func, + const std::string &name) +{ + std::string record_name = GetOwnerName(name); + if (!record_name.empty()) { + auto &rec = program.record_table.find(record_name)->second; + if (rec.language != func.language) { + SetSourceLang(method, func.language); + } + } else { + SetSourceLang(method, func.language); + } +} + +/* static */ +bool AsmEmitter::AddMethodAndParamsAnnotations(ItemContainer *items, const Program &program, + const AsmEmitter::AsmEntityCollections &entities, MethodItem *method, + const Function &func) +{ + if (!AddAnnotations(method, items, *func.metadata, program, entities.class_items, entities.field_items, + entities.method_items)) { + SetLastError("Cannot emit annotations for function " + func.name + ": " + GetLastError()); + return false; + } + + auto ¶m_items = method->GetParams(); + for (size_t proto_idx = 0; proto_idx < param_items.size(); proto_idx++) { + size_t param_idx = method->IsStatic() ? proto_idx : proto_idx + 1; + auto ¶m = func.params[param_idx]; + auto ¶m_item = param_items[proto_idx]; + if (!AddAnnotations(¶m_item, items, *param.metadata, program, entities.class_items, entities.field_items, + entities.method_items)) { + SetLastError("Cannot emit annotations for parameter a" + std::to_string(param_idx) + "of function " + + func.name + ": " + GetLastError()); + return false; + } + } + + if (method->HasRuntimeParamAnnotations()) { + items->CreateItem(method, true); + } + + if (method->HasParamAnnotations()) { + items->CreateItem(method, false); + } + + return true; +} + +/* static */ +bool AsmEmitter::MakeFunctionDebugInfoAndAnnotations(ItemContainer *items, const Program &program, + const AsmEmitter::AsmEntityCollections &entities, + bool emit_debug_info) +{ + for (const auto &[name, func] : program.function_table) { + if (func.metadata->IsForeign()) { + continue; + } + auto *method = static_cast(Find(entities.method_items, name)); + + if (func.metadata->HasImplementation()) { + SetCodeAndDebugInfo(items, method, func, emit_debug_info); + AddBytecodeIndexDependencies(method, func, entities); + } + + SetMethodSourceLang(program, method, func, name); + + if (!AddMethodAndParamsAnnotations(items, program, entities, method, func)) { + return false; + } + } + return true; +} + +/* static */ +void AsmEmitter::FillMap(PandaFileToPandaAsmMaps *maps, const AsmEmitter::AsmEntityCollections &entities) +{ + for (const auto &[name, method] : entities.method_items) { + maps->methods.insert({method->GetFileId().GetOffset(), std::string(name)}); + } + + for (const auto &[name, field] : entities.field_items) { + maps->fields.insert({field->GetFileId().GetOffset(), std::string(name)}); + } + + for (const auto &[name, cls] : entities.class_items) { + maps->classes.insert({cls->GetFileId().GetOffset(), std::string(name)}); + } + + for (const auto &[name, str] : entities.string_items) { + maps->strings.insert({str->GetFileId().GetOffset(), std::string(name)}); + } + + for (const auto &[name, arr] : entities.literalarray_items) { + maps->literalarrays.emplace(arr->GetFileId().GetOffset(), name); + } +} + +/* static */ +void AsmEmitter::EmitDebugInfo(ItemContainer *items, const Program &program, const std::vector *bytes, + const MethodItem *method, const Function &func, const std::string &name, + bool emit_debug_info) +{ + auto *debug_info = method->GetDebugInfo(); + if (debug_info == nullptr) { + return; + } + + auto *line_number_program = debug_info->GetLineNumberProgram(); + auto *constant_pool = debug_info->GetConstantPool(); + + std::string record_name = GetOwnerName(name); + std::string record_source_file; + if (!record_name.empty()) { + auto &rec = program.record_table.find(record_name)->second; + record_source_file = rec.source_file; + } + + if (!func.source_file.empty() && func.source_file != record_source_file) { + if (!func.source_code.empty()) { + auto *source_code_item = items->GetOrCreateStringItem(func.source_code); + ASSERT(source_code_item->GetOffset() != 0); + line_number_program->EmitSetSourceCode(constant_pool, source_code_item); + } + auto *source_file_item = items->GetOrCreateStringItem(func.source_file); + ASSERT(source_file_item->GetOffset() != 0); + line_number_program->EmitSetFile(constant_pool, source_file_item); + } + func.BuildLineNumberProgram(debug_info, *bytes, items, constant_pool, emit_debug_info); +} + +/* static */ +bool AsmEmitter::EmitFunctions(ItemContainer *items, const Program &program, + const AsmEmitter::AsmEntityCollections &entities, bool emit_debug_info) +{ + for (const auto &f : program.function_table) { + const auto &[name, func] = f; + + if (func.metadata->IsForeign() || !func.metadata->HasImplementation()) { + continue; + } + + auto emitter = BytecodeEmitter {}; + auto *method = static_cast(Find(entities.method_items, name)); + if (!func.Emit(emitter, method, entities.method_items, entities.field_items, entities.class_items, + entities.string_items, entities.literalarray_items)) { + SetLastError("Internal error during emitting function: " + func.name); + return false; + } + + auto *code = method->GetCode(); + code->SetNumVregs(func.regs_num); + code->SetNumArgs(func.GetParamsNum()); + + size_t num_ins = + std::count_if(func.ins.begin(), func.ins.end(), [](auto it) { return it.opcode != Opcode::INVALID; }); + code->SetNumInstructions(num_ins); + + auto *bytes = code->GetInstructions(); + auto status = emitter.Build(static_cast *>(bytes)); + if (status != BytecodeEmitter::ErrorCode::SUCCESS) { + SetLastError("Internal error during emitting binary code, status=" + + std::to_string(static_cast(status))); + return false; + } + auto try_blocks = func.BuildTryBlocks(method, entities.class_items, *bytes); + for (auto &try_block : try_blocks) { + code->AddTryBlock(try_block); + } + + EmitDebugInfo(items, program, bytes, method, func, name, emit_debug_info); + } + return true; +} + +/* static */ +bool AsmEmitter::Emit(ItemContainer *items, const Program &program, PandaFileToPandaAsmMaps *maps, bool emit_debug_info) +{ + auto primitive_types = CreatePrimitiveTypes(items); + + auto entities = AsmEmitter::AsmEntityCollections {}; + + SetLastError(""); + + MakeStringItems(items, program, entities); + + MakeArrayTypeItems(items, program, entities); + + if (!MakeRecordItems(items, program, entities, primitive_types)) { + return false; + } + + if (!MakeFunctionItems(items, program, entities, primitive_types, emit_debug_info)) { + return false; + } + + MakeLiteralItems(items, program, entities); + + // Add annotations for records and fields + if (!MakeRecordAnnotations(items, program, entities)) { + return false; + } + + // Add Code and DebugInfo items last due to that they have variable size that depends on bytecode + if (!MakeFunctionDebugInfoAndAnnotations(items, program, entities, emit_debug_info)) { + return false; + } + + items->ComputeLayout(); + + if (maps != nullptr) { + FillMap(maps, entities); + } + + if (!EmitFunctions(items, program, entities, emit_debug_info)) { + return false; + } + + return true; +} + +bool AsmEmitter::Emit(Writer *writer, const Program &program, std::map *stat, + PandaFileToPandaAsmMaps *maps, bool debug_info) +{ + auto items = ItemContainer {}; + if (!Emit(&items, program, maps, debug_info)) { + return false; + } + + if (stat != nullptr) { + *stat = items.GetStat(); + } + + return items.Write(writer); +} + +bool AsmEmitter::Emit(const std::string &filename, const Program &program, std::map *stat, + PandaFileToPandaAsmMaps *maps, bool debug_info) +{ + auto writer = FileWriter(filename); + if (!writer) { + SetLastError("Unable to open" + filename + " for writing"); + return false; + } + return Emit(&writer, program, stat, maps, debug_info); +} + +std::unique_ptr AsmEmitter::Emit(const Program &program, PandaFileToPandaAsmMaps *maps) +{ + auto items = ItemContainer {}; + if (!Emit(&items, program, maps)) { + return nullptr; + } + + size_t size = items.ComputeLayout(); + // CODECHECK-NOLINTNEXTLINE(CPP_RULE_ID_SMARTPOINTER_INSTEADOF_ORIGINPOINTER) + auto *buffer = new (std::nothrow) std::byte[size]; + if (buffer == nullptr) { + LOG(ERROR, ASSEMBLER) << "Invalid items size " << size; + return nullptr; + } + + auto writer = MemoryBufferWriter(reinterpret_cast(buffer), size); + if (!items.Write(&writer)) { + return nullptr; + } + + os::mem::ConstBytePtr ptr( + buffer, size, [](std::byte *buffer_ptr, [[maybe_unused]] size_t param_size) noexcept { delete[] buffer_ptr; }); + return panda_file::File::OpenFromMemory(std::move(ptr)); +} + +TypeItem *AsmEmitter::GetTypeItem( + ItemContainer *items, const std::unordered_map &primitive_types, + const Type &type, const Program &program) +{ + if (!type.IsObject()) { + return Find(primitive_types, type.GetId()); + } + + if (type.IsArray()) { + return items->GetOrCreateForeignClassItem(type.GetDescriptor()); + } + + const auto &name = type.GetName(); + auto iter = program.record_table.find(name); + if (iter == program.record_table.end()) { + return nullptr; + } + + auto &rec = iter->second; + if (rec.metadata->IsForeign()) { + return items->GetOrCreateForeignClassItem(type.GetDescriptor()); + } + + return items->GetOrCreateClassItem(type.GetDescriptor()); +} + +bool Function::Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method, + const std::unordered_map &methods, + const std::unordered_map &fields, + const std::unordered_map &classes, + const std::unordered_map &strings, + const std::unordered_map &literalarrays) const +{ + auto labels = std::unordered_map {}; + + for (const auto &insn : ins) { + if (insn.set_label) { + labels.insert_or_assign(insn.label, emitter.CreateLabel()); + } + } + + for (const auto &insn : ins) { + if (insn.set_label) { + auto search = labels.find(insn.label); + ASSERT(search != labels.end()); + emitter.Bind(search->second); + } + + if (insn.opcode != Opcode::INVALID) { + if (!insn.Emit(emitter, method, methods, fields, classes, strings, literalarrays, labels)) { + return false; + } + } + } + + return true; +} + +void Function::EmitLocalVariable(panda_file::LineNumberProgramItem *program, ItemContainer *container, + std::vector *constant_pool, uint32_t &pc_inc, size_t instruction_number) const +{ + auto try_emit_pc = [program, constant_pool, &pc_inc]() -> void { + if (pc_inc) { + program->EmitAdvancePc(constant_pool, pc_inc); + pc_inc = 0; + } + }; + for (auto &v : local_variable_debug) { + if (IsParameter(v.reg)) { + continue; + } + if (instruction_number == v.start) { + try_emit_pc(); + StringItem *variable_name = container->GetOrCreateStringItem(v.name); + StringItem *variable_type = container->GetOrCreateStringItem(v.signature); + if (v.signature_type.empty()) { + program->EmitStartLocal(constant_pool, v.reg, variable_name, variable_type); + } else { + StringItem *type_signature = container->GetOrCreateStringItem(v.signature_type); + program->EmitStartLocalExtended(constant_pool, v.reg, variable_name, variable_type, type_signature); + } + } + if (instruction_number == (v.start + v.length)) { + try_emit_pc(); + program->EmitEndLocal(v.reg); + } + } +} + +size_t Function::GetLineNumber(size_t i) const +{ + return static_cast(ins[i].ins_debug.line_number); +} + +void Function::EmitNumber(panda_file::LineNumberProgramItem *program, std::vector *constant_pool, + uint32_t pc_inc, int32_t line_inc) const +{ + if (!program->EmitSpecialOpcode(pc_inc, line_inc)) { + if (pc_inc) { + program->EmitAdvancePc(constant_pool, pc_inc); + if (!program->EmitSpecialOpcode(0, line_inc)) { + program->EmitAdvanceLine(constant_pool, line_inc); + program->EmitSpecialOpcode(0, 0); + } + } else { + program->EmitAdvanceLine(constant_pool, line_inc); + program->EmitSpecialOpcode(0, 0); + } + } +} + +void Function::EmitLineNumber(panda_file::LineNumberProgramItem *program, std::vector *constant_pool, + int32_t &prev_line_number, uint32_t &pc_inc, size_t instruction_number) const +{ + int32_t line_inc = GetLineNumber(instruction_number) - prev_line_number; + if (line_inc) { + prev_line_number = GetLineNumber(instruction_number); + EmitNumber(program, constant_pool, pc_inc, line_inc); + pc_inc = 0; + } +} + +void Function::BuildLineNumberProgram(panda_file::DebugInfoItem *debug_item, const std::vector &bytecode, + ItemContainer *container, std::vector *constant_pool, + bool emit_debug_info) const +{ + auto *program = debug_item->GetLineNumberProgram(); + + if (ins.empty()) { + program->EmitEnd(); + return; + } + + uint32_t pc_inc = 0; + int32_t prev_line_number = GetLineNumber(0); + BytecodeInstruction bi(bytecode.data()); + debug_item->SetLineNumber(static_cast(prev_line_number)); + + for (size_t i = 0; i < ins.size(); i++) { + if (emit_debug_info) { + EmitLocalVariable(program, container, constant_pool, pc_inc, i); + } + if (ins[i].opcode == Opcode::INVALID) { + continue; + } + + if (emit_debug_info || ins[i].CanThrow()) { + EmitLineNumber(program, constant_pool, prev_line_number, pc_inc, i); + } + + pc_inc += bi.GetSize(); + bi = bi.GetNext(); + } + + program->EmitEnd(); +} + +Function::TryCatchInfo Function::MakeOrderAndOffsets(const std::vector &bytecode) const +{ + std::unordered_map try_catch_labels; + std::unordered_map> try_catch_map; + std::vector try_catch_order; + + for (auto &catch_block : catch_blocks) { + try_catch_labels.insert_or_assign(catch_block.try_begin_label, 0); + try_catch_labels.insert_or_assign(catch_block.try_end_label, 0); + try_catch_labels.insert_or_assign(catch_block.catch_begin_label, 0); + try_catch_labels.insert_or_assign(catch_block.catch_end_label, 0); + + std::string try_key = catch_block.try_begin_label + ":" + catch_block.try_end_label; + auto it = try_catch_map.find(try_key); + if (it == try_catch_map.cend()) { + std::tie(it, std::ignore) = try_catch_map.try_emplace(try_key); + try_catch_order.push_back(try_key); + } + it->second.push_back(&catch_block); + } + + BytecodeInstruction bi(bytecode.data()); + size_t pc_offset = 0; + + for (size_t i = 0; i < ins.size(); i++) { + if (ins[i].set_label) { + auto it = try_catch_labels.find(ins[i].label); + if (it != try_catch_labels.cend()) { + try_catch_labels[ins[i].label] = pc_offset; + } + } + if (ins[i].opcode == Opcode::INVALID) { + continue; + } + + pc_offset += bi.GetSize(); + bi = bi.GetNext(); + } + + return Function::TryCatchInfo {try_catch_labels, try_catch_map, try_catch_order}; +} + +std::vector Function::BuildTryBlocks( + MethodItem *method, const std::unordered_map &class_items, + const std::vector &bytecode) const +{ + std::vector try_blocks; + + if (ins.empty()) { + return try_blocks; + } + + Function::TryCatchInfo tcs = MakeOrderAndOffsets(bytecode); + + for (const auto &t_key : tcs.try_catch_order) { + auto kv = tcs.try_catch_map.find(t_key); + ASSERT(kv != tcs.try_catch_map.cend()); + auto &try_catch_blocks = kv->second; + + ASSERT(!try_catch_blocks.empty()); + + std::vector catch_block_items; + + for (auto *catch_block : try_catch_blocks) { + auto class_name = catch_block->exception_record; + + BaseClassItem *class_item = nullptr; + if (!class_name.empty()) { + auto it = class_items.find(class_name); + ASSERT(it != class_items.cend()); + class_item = it->second; + } + + auto handler_pc_offset = tcs.try_catch_labels[catch_block->catch_begin_label]; + auto handler_code_size = tcs.try_catch_labels[catch_block->catch_end_label] - handler_pc_offset; + catch_block_items.emplace_back(method, class_item, handler_pc_offset, handler_code_size); + } + + auto try_start_pc_offset = tcs.try_catch_labels[try_catch_blocks[0]->try_begin_label]; + auto try_end_pc_offset = tcs.try_catch_labels[try_catch_blocks[0]->try_end_label]; + ASSERT(try_end_pc_offset >= try_start_pc_offset); + try_blocks.emplace_back(try_start_pc_offset, try_end_pc_offset - try_start_pc_offset, catch_block_items); + } + + return try_blocks; +} + +void Function::DebugDump() const +{ + std::cerr << "name: " << name << std::endl; + for (const auto &i : ins) { + std::cerr << i.ToString("\n", true, regs_num); + } +} + +std::string GetOwnerName(const std::string &name) +{ + auto super_pos = name.find_last_of(PARSE_AREA_MARKER); + if (super_pos == std::string::npos) { + return ""; + } + return name.substr(0, super_pos); +} + +std::string GetItemName(const std::string &name) +{ + auto super_pos = name.find_last_of(PARSE_AREA_MARKER); + if (super_pos == std::string::npos) { + return name; + } + return name.substr(super_pos + 1); +} + +} // namespace panda::pandasm diff --git a/assembler/assembly-emitter.h b/assembler/assembly-emitter.h new file mode 100644 index 0000000000..f10656c9f7 --- /dev/null +++ b/assembler/assembly-emitter.h @@ -0,0 +1,241 @@ +/* + * 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_ASSEMBLER_ASSEMBLY_EMITTER_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_EMITTER_H_ + +#include +#include +#include +#include + +#include "assembly-ins.h" +#include "assembly-literals.h" +#include "assembly-program.h" +#include "assembly-type.h" +#include "assembly-function.h" +#include "bytecode_emitter.h" +#include "file_item_container.h" + +namespace panda::pandasm { + +class AsmEmitter { +public: + struct PandaFileToPandaAsmMaps { + std::unordered_map methods; + std::unordered_map fields; + std::unordered_map classes; + std::unordered_map strings; + std::unordered_map literalarrays; + }; + + struct AsmEntityCollections { + std::unordered_map method_items; + std::unordered_map field_items; + std::unordered_map class_items; + std::unordered_map string_items; + std::unordered_map literalarray_items; + }; + + static bool Emit(panda_file::ItemContainer *items, const Program &program, PandaFileToPandaAsmMaps *maps = nullptr, + bool emit_debug_info = true); + + static bool Emit(panda_file::Writer *writer, const Program &program, std::map *stat = nullptr, + PandaFileToPandaAsmMaps *maps = nullptr, bool debug_info = true); + + static bool Emit(const std::string &filename, const Program &program, std::map *stat = nullptr, + PandaFileToPandaAsmMaps *maps = nullptr, bool debug_info = true); + + static std::unique_ptr Emit(const Program &program, + PandaFileToPandaAsmMaps *maps = nullptr); + + static std::string GetLastError() + { + return last_error; + } + +private: + static void MakeStringItems(panda_file::ItemContainer *items, const Program &program, + AsmEntityCollections &entities); + static void MakeLiteralItems(panda_file::ItemContainer *items, const Program &program, + AsmEmitter::AsmEntityCollections &entities); + static void MakeArrayTypeItems(panda_file::ItemContainer *items, const Program &program, + AsmEntityCollections &entities); + static bool HandleRecordAsForeign( + panda_file::ItemContainer *items, const Program &program, AsmEntityCollections &entities, + const std::unordered_map &primitive_types, + const std::string &name, const Record &rec); + static bool HandleBaseRecord(panda_file::ItemContainer *items, const Program &program, const std::string &name, + const Record &rec, panda_file::ClassItem *record); + static bool HandleInterfaces(panda_file::ItemContainer *items, const Program &program, const std::string &name, + const Record &rec, panda_file::ClassItem *record); + static bool HandleFields( + panda_file::ItemContainer *items, const Program &program, AsmEmitter::AsmEntityCollections &entities, + const std::unordered_map &primitive_types, + const std::string &name, const Record &rec, panda_file::ClassItem *record); + static bool HandleRecord( + panda_file::ItemContainer *items, const Program &program, AsmEntityCollections &entities, + const std::unordered_map &primitive_types, + const std::string &name, const Record &rec); + static bool MakeRecordItems( + panda_file::ItemContainer *items, const Program &program, AsmEntityCollections &entities, + const std::unordered_map &primitive_types); + static panda_file::StringItem *GetMethodName(panda_file::ItemContainer *items, const Function &func, + const std::string &name); + static bool HandleAreaForInner(panda_file::ItemContainer *items, const Program &program, + panda_file::ClassItem **area, panda_file::ForeignClassItem **foreign_area, + const std::string &name, const std::string &record_owner_name); + static bool HandleRecordOnwer(panda_file::ItemContainer *items, const Program &program, + panda_file::ClassItem **area, panda_file::ForeignClassItem **foreign_area, + const std::string &name, const std::string &record_owner_name); + static bool HandleFunctionParams( + panda_file::ItemContainer *items, const Program &program, size_t idx, const std::string &name, + const Function &func, + const std::unordered_map &primitive_types, + std::vector ¶ms); + static bool HandleFunctionLocalVariables(panda_file::ItemContainer *items, const Function &func, + const std::string &name); + static bool CreateMethodItem(panda_file::ItemContainer *items, AsmEmitter::AsmEntityCollections &entities, + const Function &func, panda_file::TypeItem *type_item, panda_file::ClassItem *area, + panda_file::ForeignClassItem *foreign_area, uint32_t access_flags, + panda_file::StringItem *method_name, const std::string &mangled_name, + const std::string &name, std::vector ¶ms); + static bool MakeFunctionItems( + panda_file::ItemContainer *items, const Program &program, AsmEntityCollections &entities, + const std::unordered_map &primitive_types, + bool emit_debug_info); + static bool MakeRecordAnnotations(panda_file::ItemContainer *items, const Program &program, + const AsmEntityCollections &entities); + static void SetCodeAndDebugInfo(panda_file::ItemContainer *items, panda_file::MethodItem *method, + const Function &func, bool emit_debug_info); + static void SetMethodSourceLang(const Program &program, panda_file::MethodItem *method, const Function &func, + const std::string &name); + static bool AddMethodAndParamsAnnotations(panda_file::ItemContainer *items, const Program &program, + const AsmEmitter::AsmEntityCollections &entities, + panda_file::MethodItem *method, const Function &func); + static bool MakeFunctionDebugInfoAndAnnotations(panda_file::ItemContainer *items, const Program &program, + const AsmEntityCollections &entities, bool emit_debug_info); + static void FillMap(PandaFileToPandaAsmMaps *maps, const AsmEntityCollections &entities); + static void EmitDebugInfo(panda_file::ItemContainer *items, const Program &program, + const std::vector *bytes, const panda_file::MethodItem *method, + const Function &func, const std::string &name, bool emit_debug_info); + static bool EmitFunctions(panda_file::ItemContainer *items, const Program &program, + const AsmEntityCollections &entities, bool emit_debug_info); + + static panda_file::TypeItem *GetTypeItem( + panda_file::ItemContainer *items, + const std::unordered_map &primitive_types, + const Type &type, const Program &program); + + static void SetLastError(const std::string &message) + { + last_error = message; + } + + static bool CheckValueType(Value::Type value_type, Type type, const Program &program); + + static bool CheckValueEnumCase(const Value *value, Type type, const Program &program); + static bool CheckValueArrayCase(const Value *value, Type type, const Program &program); + static bool CheckValueMethodCase(const Value *value, const Program &program); + static bool CheckValueRecordCase(const Value *value, const Program &program); + static bool CheckValue(const Value *value, Type type, const Program &program); + + static panda_file::LiteralItem *CreateLiteralItem( + panda_file::ItemContainer *container, const Value *value, std::vector *out, + const std::unordered_map &methods); + + template + static panda_file::ScalarValueItem *CreateScalarPrimValueItem(panda_file::ItemContainer *container, + const Value *value, + std::vector *out) + { + static_assert(std::is_arithmetic::value); + auto v = value->GetAsScalar()->GetValue(); + if (out != nullptr) { + out->emplace_back(v); + return &out->back(); + } + + if constexpr (std::is_same::value) { + return container->GetOrCreateIntegerValueItem(v); + } else if constexpr (std::is_same::value) { + return container->GetOrCreateLongValueItem(v); + } else if constexpr (std::is_same::value) { + return container->GetOrCreateFloatValueItem(v); + } else if constexpr (std::is_same::value) { + return container->GetOrCreateDoubleValueItem(v); + } else { + UNREACHABLE(); + return nullptr; + } + } + + static panda_file::ScalarValueItem *CreateScalarStringValueItem(panda_file::ItemContainer *container, + const Value *value, + std::vector *out); + static panda_file::ScalarValueItem *CreateScalarRecordValueItem( + panda_file::ItemContainer *container, const Value *value, std::vector *out, + const std::unordered_map &classes); + static panda_file::ScalarValueItem *CreateScalarMethodValueItem( + panda_file::ItemContainer *container, const Value *value, std::vector *out, + const std::unordered_map &methods); + static panda_file::ScalarValueItem *CreateScalarEnumValueItem( + panda_file::ItemContainer *container, const Value *value, std::vector *out, + const std::unordered_map &fields); + static panda_file::ScalarValueItem *CreateScalarAnnotationValueItem( + panda_file::ItemContainer *container, const Value *value, std::vector *out, + const Program &program, const std::unordered_map &classes, + const std::unordered_map &fields, + const std::unordered_map &methods); + + static panda_file::ScalarValueItem *CreateScalarValueItem( + panda_file::ItemContainer *container, const Value *value, std::vector *out, + const Program &program, const std::unordered_map &classes, + const std::unordered_map &fields, + const std::unordered_map &methods); + + static panda_file::ValueItem *CreateValueItem( + panda_file::ItemContainer *container, const Value *value, const Program &program, + const std::unordered_map &classes, + const std::unordered_map &fields, + const std::unordered_map &methods); + + static panda_file::AnnotationItem *CreateAnnotationItem( + panda_file::ItemContainer *container, const AnnotationData &annotation, const Program &program, + const std::unordered_map &classes, + const std::unordered_map &fields, + const std::unordered_map &methods); + + static panda_file::MethodHandleItem *CreateMethodHandleItem( + panda_file::ItemContainer *container, const MethodHandle &mh, + const std::unordered_map &fields, + const std::unordered_map &methods); + + template + static bool AddAnnotations(T *item, panda_file::ItemContainer *container, const AnnotationMetadata &metadata, + const Program &program, + const std::unordered_map &classes, + const std::unordered_map &fields, + const std::unordered_map &methods); + + static std::string last_error; +}; + +std::string GetOwnerName(const std::string &name); +std::string GetItemName(const std::string &name); + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ASSEMBLY_EMITTER_H_ diff --git a/assembler/assembly-field.h b/assembler/assembly-field.h new file mode 100644 index 0000000000..2847e580cf --- /dev/null +++ b/assembler/assembly-field.h @@ -0,0 +1,44 @@ +/* + * 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_ASSEMBLER_ASSEMBLY_FIELD_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_FIELD_H_ + +#include +#include + +#include "assembly-type.h" +#include "extensions/extensions.h" +#include "meta.h" + +namespace panda::pandasm { + +struct Field { + Type type; + std::string name; + std::unique_ptr metadata; + size_t line_of_def = 0; + std::string whole_line = ""; /* The line in which the field is defined */ + /* Or line in which the field is met, if the field is not defined */ + size_t bound_left = 0; + size_t bound_right = 0; + bool is_defined = true; + + explicit Field(extensions::Language lang) : metadata(extensions::MetadataExtension::CreateFieldMetadata(lang)) {} +}; + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ASSEMBLY_FIELD_H_ diff --git a/assembler/assembly-file-location.h b/assembler/assembly-file-location.h new file mode 100644 index 0000000000..a94aaa574c --- /dev/null +++ b/assembler/assembly-file-location.h @@ -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 PANDA_ASSEMBLER_ASSEMBLY_FILE_LOCATION_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_FILE_LOCATION_H_ + +namespace panda::pandasm { + +class FileLocation { +public: + std::string whole_line = ""; /* The line in which the field is defined */ + /* Or line in which the field is met, if the field is not defined */ + size_t bound_left = 0; + size_t bound_right = 0; + size_t line_number = 0; + bool is_defined = false; + +public: + FileLocation(std::string &f_c, size_t b_l, size_t b_r, size_t l_n, bool d) + : whole_line(std::move(f_c)), bound_left(b_l), bound_right(b_r), line_number(l_n), is_defined(d) + { + } + ~FileLocation() = default; + + DEFAULT_MOVE_SEMANTIC(FileLocation); + DEFAULT_COPY_SEMANTIC(FileLocation); +}; + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ASSEMBLY_FILE_LOCATION_H_ diff --git a/assembler/assembly-function.h b/assembler/assembly-function.h new file mode 100644 index 0000000000..91137d1bf4 --- /dev/null +++ b/assembler/assembly-function.h @@ -0,0 +1,177 @@ +/* + * 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_ASSEMBLER_ASSEMBLY_FUNCTION_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_FUNCTION_H_ + +#include +#include +#include +#include +#include +#include + +#include "assembly-ins.h" +#include "assembly-label.h" +#include "assembly-type.h" +#include "assembly-debug.h" +#include "assembly-file-location.h" +#include "bytecode_emitter.h" +#include "extensions/extensions.h" +#include "file_items.h" +#include "file_item_container.h" +#include "ide_helpers.h" +#include "meta.h" + +namespace panda::pandasm { + +struct Function { + struct CatchBlock { + std::string whole_line; + std::string exception_record; + std::string try_begin_label; + std::string try_end_label; + std::string catch_begin_label; + std::string catch_end_label; + }; + + struct TryCatchInfo { + std::unordered_map try_catch_labels; + std::unordered_map> try_catch_map; + std::vector try_catch_order; + TryCatchInfo(std::unordered_map &labels, + std::unordered_map> &map, + std::vector ¶m_try_catch_order) + : try_catch_labels(labels), try_catch_map(map), try_catch_order(param_try_catch_order) + { + } + }; + + struct Parameter { + Type type; + std::unique_ptr metadata; + + Parameter(Type t, extensions::Language lang) + : type(std::move(t)), metadata(extensions::MetadataExtension::CreateParamMetadata(lang)) + { + } + }; + + std::string name = ""; + extensions::Language language; + std::unique_ptr metadata; + + std::unordered_map label_table; + std::vector ins; /* function instruction list */ + std::vector local_variable_debug; + std::string source_file; /* The file in which the function is defined or empty */ + std::string source_code; + std::vector catch_blocks; + int64_t value_of_first_param = -1; + size_t regs_num = 0; + std::vector params; + bool body_presence = false; + Type return_type; + SourceLocation body_location; + std::optional file_location; + + void SetInsDebug(const std::vector &ins_debug) + { + ASSERT(ins_debug.size() == ins.size()); + for (std::size_t i = 0; i < ins.size(); i++) { + ins[i].ins_debug = ins_debug[i]; + } + } + + void AddInstruction(const panda::pandasm::Ins &instruction) + { + ins.emplace_back(instruction); + } + + Function(std::string s, extensions::Language lang, size_t b_l, size_t b_r, std::string f_c, bool d, size_t l_n) + : name(std::move(s)), + language(lang), + metadata(extensions::MetadataExtension::CreateFunctionMetadata(lang)), + file_location({f_c, b_l, b_r, l_n, d}) + { + } + + Function(std::string s, extensions::Language lang) + : name(std::move(s)), language(lang), metadata(extensions::MetadataExtension::CreateFunctionMetadata(lang)) + { + } + + std::size_t GetParamsNum() const + { + return params.size(); + } + + bool IsStatic() const + { + return (metadata->GetAccessFlags() & ACC_STATIC) != 0; + } + + bool Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method, + const std::unordered_map &methods, + const std::unordered_map &fields, + const std::unordered_map &classes, + const std::unordered_map &strings, + const std::unordered_map &literalarrays) const; + + size_t GetLineNumber(size_t i) const; + + void EmitLocalVariable(panda_file::LineNumberProgramItem *program, panda_file::ItemContainer *container, + std::vector *constant_pool, uint32_t &pc_inc, size_t instruction_number) const; + void EmitNumber(panda_file::LineNumberProgramItem *program, std::vector *constant_pool, uint32_t pc_inc, + int32_t line_inc) const; + void EmitLineNumber(panda_file::LineNumberProgramItem *program, std::vector *constant_pool, + int32_t &prev_line_number, uint32_t &pc_inc, size_t instruction_number) const; + + void BuildLineNumberProgram(panda_file::DebugInfoItem *debug_item, const std::vector &bytecode, + panda_file::ItemContainer *container, std::vector *constant_pool, + bool emit_debug_info) const; + + Function::TryCatchInfo MakeOrderAndOffsets(const std::vector &bytecode) const; + + std::vector BuildTryBlocks( + panda_file::MethodItem *method, const std::unordered_map &class_items, + const std::vector &bytecode) const; + + bool HasImplementation() const + { + return !metadata->IsForeign() && metadata->HasImplementation(); + } + + bool IsParameter(uint32_t reg_number) const + { + return reg_number >= regs_num; + } + + bool CanThrow() const + { + return std::any_of(ins.cbegin(), ins.cend(), [](const Ins &insn) { return insn.CanThrow(); }); + } + + bool HasDebugInfo() const + { + return std::any_of(ins.cbegin(), ins.cend(), [](const Ins &insn) { return insn.HasDebugInfo(); }); + } + + void DebugDump() const; +}; + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ASSEMBLY_FUNCTION_H_ diff --git a/assembler/assembly-ins.cpp b/assembler/assembly-ins.cpp new file mode 100644 index 0000000000..82329411d6 --- /dev/null +++ b/assembler/assembly-ins.cpp @@ -0,0 +1,101 @@ +/** + * 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 "assembly-ins.h" + +namespace panda::pandasm { + +std::string panda::pandasm::Ins::RegsToString(bool &first, bool print_args, size_t first_arg_idx) const +{ + std::stringstream translator; + for (const auto ® : this->regs) { + if (!first) { + translator << ","; + } else { + first = false; + } + + if (print_args && reg >= first_arg_idx) { + translator << " a" << reg - first_arg_idx; + } else { + translator << " v" << reg; + } + } + return translator.str(); +} + +std::string panda::pandasm::Ins::ImmsToString(bool &first) const +{ + std::stringstream translator; + for (const auto &imm : this->imms) { + if (!first) { + translator << ","; + } else { + first = false; + } + + auto *number = std::get_if(&imm); + if (number != nullptr) { + translator << " " << std::scientific << *number; + } else { + translator << " 0x" << std::hex << std::get(imm); + } + translator.clear(); + } + return translator.str(); +} + +std::string panda::pandasm::Ins::IdsToString(bool &first) const +{ + std::stringstream translator; + for (const auto &id : this->ids) { + if (!first) { + translator << ","; + } else { + first = false; + } + + translator << " " << id; + } + return translator.str(); +} + +std::string panda::pandasm::Ins::OperandsToString(PrintKind print_kind, bool print_args, size_t first_arg_idx) const +{ + bool first = true; + std::stringstream ss {}; + + switch (print_kind) { + case PrintKind::CALL: + ss << this->IdsToString(first) << this->RegsToString(first, print_args, first_arg_idx); + if (!imms.empty()) { + ss << ImmsToString(first); + } + break; + case PrintKind::CALLI: + ss << this->IdsToString(first) << this->ImmsToString(first) + << this->RegsToString(first, print_args, first_arg_idx); + break; + case PrintKind::DEFAULT: + default: + ss << this->RegsToString(first, print_args, first_arg_idx) << this->ImmsToString(first) + << this->IdsToString(first); + } + + return ss.str(); +} + +} // namespace panda::pandasm \ No newline at end of file diff --git a/assembler/assembly-ins.h b/assembler/assembly-ins.h new file mode 100644 index 0000000000..0aa6dec28d --- /dev/null +++ b/assembler/assembly-ins.h @@ -0,0 +1,236 @@ +/* + * 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_ASSEMBLER_ASSEMBLY_INS_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_INS_H_ + +#include +#include +#include +#include +#include +#include + +#include "assembly-debug.h" +#include "bytecode_emitter.h" +#include "file_items.h" +#include "isa.h" +#include "lexer.h" + +namespace panda::pandasm { + +enum class Opcode { +#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) opcode, + PANDA_INSTRUCTION_LIST(OPLIST) +#undef OPLIST + INVALID, + NUM_OPCODES = INVALID +}; + +enum InstFlags { + NONE = 0, + JUMP = (1U << 0U), + COND = (1U << 1U), + CALL = (1U << 2U), + RETURN = (1U << 3U), + ACC_READ = (1U << 4U), + ACC_WRITE = (1U << 5U), + PSEUDO = (1U << 6U), + THROWING = (1U << 7U), + METHOD_ID = (1U << 8U), + FIELD_ID = (1U << 9U), + TYPE_ID = (1U << 10U), + STRING_ID = (1U << 11U), + LITERALARRAY_ID = (1U << 12U) +}; + +enum class PrintKind { DEFAULT, CALL, CALLI }; + +constexpr int INVALID_REG_IDX = -1; +constexpr size_t MAX_NUMBER_OF_SRC_REGS = 5; +constexpr size_t NUM_OPCODES = static_cast(Opcode::NUM_OPCODES); + +constexpr InstFlags operator|(InstFlags a, InstFlags b) +{ + using utype = std::underlying_type_t; + return static_cast(static_cast(a) | static_cast(b)); +} + +#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) flags, +constexpr std::array INST_FLAGS_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)}; +#undef OPLIST + +#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) width, +constexpr std::array INST_WIDTH_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)}; +#undef OPLIST + +#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) def_idx, +constexpr std::array DEF_IDX_TABLE = {PANDA_INSTRUCTION_LIST(OPLIST)}; +#undef OPLIST + +#define OPLIST(opcode, name, optype, width, flags, def_idx, use_idxs) use_idxs, +constexpr std::array, NUM_OPCODES> USE_IDXS_TABLE = { + PANDA_INSTRUCTION_LIST(OPLIST)}; +#undef OPLIST + +struct Ins { + using IType = std::variant; + + constexpr static uint16_t ACCUMULATOR = -1; + constexpr static size_t MAX_CALL_SHORT_ARGS = 2; + constexpr static size_t MAX_CALL_ARGS = 4; + constexpr static uint16_t MAX_NON_RANGE_CALL_REG = 15; + constexpr static uint16_t MAX_RANGE_CALL_START_REG = 255; + + Opcode opcode = Opcode::INVALID; /* operation type */ + std::vector regs; /* list of arguments - registers */ + std::vector ids; /* list of arguments - identifiers */ + std::vector imms; /* list of arguments - immediates */ + std::string label; /* label at the beginning of a line */ + bool set_label = false; /* whether this label is defined */ + debuginfo::Ins ins_debug; + + std::string ToString(std::string endline = "", bool print_args = false, size_t first_arg_idx = 0) const; + + bool Emit(BytecodeEmitter &emitter, panda_file::MethodItem *method, + const std::unordered_map &methods, + const std::unordered_map &fields, + const std::unordered_map &classes, + const std::unordered_map &strings, + const std::unordered_map &literalarrays, + const std::unordered_map &labels) const; + + size_t OperandListLength() const + { + return regs.size() + ids.size() + imms.size(); + } + + bool HasFlag(InstFlags flag) const + { + if (opcode == Opcode::INVALID) { + return false; + } + return (INST_FLAGS_TABLE[static_cast(opcode)] & flag) != 0; + } + + bool CanThrow() const + { + return HasFlag(InstFlags::THROWING) || HasFlag(InstFlags::METHOD_ID) || HasFlag(InstFlags::FIELD_ID) || + HasFlag(InstFlags::TYPE_ID) || HasFlag(InstFlags::STRING_ID); + } + + bool IsJump() const + { + return HasFlag(InstFlags::JUMP); + } + + bool IsConditionalJump() const + { + return IsJump() && HasFlag(InstFlags::COND); + } + + bool IsCall() const + { // Non-range call + return HasFlag(InstFlags::CALL); + } + + bool IsBuiltinIdr6() const + { + return opcode == Opcode::BUILTIN_IDR6; + } + + bool IsPseudoCall() const + { + return HasFlag(InstFlags::PSEUDO) && HasFlag(InstFlags::CALL); + } + + bool IsReturn() const + { + return HasFlag(InstFlags::RETURN); + } + + size_t MaxRegEncodingWidth() const + { + if (opcode == Opcode::INVALID) { + return 0; + } + return INST_WIDTH_TABLE[static_cast(opcode)]; + } + + std::vector Uses() const + { + if (IsPseudoCall()) { + return regs; + } + + if (opcode == Opcode::INVALID) { + return {}; + } + + auto use_idxs = USE_IDXS_TABLE[static_cast(opcode)]; + std::vector res; + for (auto idx : use_idxs) { + if (HasFlag(InstFlags::ACC_READ)) { + res.push_back(Ins::ACCUMULATOR); + } + if (idx != INVALID_REG_IDX) { + ASSERT(static_cast(idx) < regs.size()); + res.push_back(regs[idx]); + } + } + return res; + } + + std::optional Def() const + { + if (opcode == Opcode::INVALID) { + return {}; + } + auto def_idx = DEF_IDX_TABLE[static_cast(opcode)]; + if (def_idx != INVALID_REG_IDX) { + return regs[def_idx]; + } + if (HasFlag(InstFlags::ACC_WRITE)) { + return Ins::ACCUMULATOR; + } + return {}; + } + + bool IsValidToEmit() const + { + const auto INVALID_REG_NUM = 1U << MaxRegEncodingWidth(); + for (auto reg : regs) { + if (reg >= INVALID_REG_NUM) { + return false; + } + } + return true; + } + + bool HasDebugInfo() const + { + return ins_debug.line_number != 0; + } + +private: + std::string OperandsToString(PrintKind print_kind = PrintKind::DEFAULT, bool print_args = false, + size_t first_arg_idx = 0) const; + std::string RegsToString(bool &first, bool print_args = false, size_t first_arg_idx = 0) const; + std::string ImmsToString(bool &first) const; + std::string IdsToString(bool &first) const; +}; +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ASSEMBLY_INS_H_ diff --git a/assembler/assembly-label.h b/assembler/assembly-label.h new file mode 100644 index 0000000000..5ea36dac52 --- /dev/null +++ b/assembler/assembly-label.h @@ -0,0 +1,40 @@ +/* + * 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_ASSEMBLER_ASSEMBLY_LABEL_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_LABEL_H_ + +#include +#include + +#include "assembly-file-location.h" + +namespace panda::pandasm { + +struct Label { + std::string name = ""; + std::optional file_location; + + Label(std::string s, size_t b_l, size_t b_r, std::string f_c, bool d, size_t l_n) + : name(std::move(s)), file_location({f_c, b_l, b_r, l_n, d}) + { + } + + explicit Label(std::string s) : name(std::move(s)) {} +}; + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ASSEMBLY_LABEL_H_ diff --git a/assembler/assembly-literals.h b/assembler/assembly-literals.h new file mode 100644 index 0000000000..d58c50a70b --- /dev/null +++ b/assembler/assembly-literals.h @@ -0,0 +1,45 @@ +/* + * 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_ASSEMBLER_ASSEMBLY_LITERALS_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_LITERALS_H_ + +#include +#include +#include + +#include "../libpandafile/literal_data_accessor.h" + +namespace panda::pandasm { + +struct LiteralArray { + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) + struct Literal { + panda_file::LiteralTag tag_; + std::variant value_; + }; + + std::vector + literals_; // NOLINT(misc-non-private-member-variables-in-classes) + + explicit LiteralArray(std::vector literals) : literals_(std::move(literals)) + { + } + explicit LiteralArray() = default; +}; + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ASSEMBLY_LITERALS_H_ diff --git a/assembler/assembly-methodhandle.h b/assembler/assembly-methodhandle.h new file mode 100644 index 0000000000..184092a6b4 --- /dev/null +++ b/assembler/assembly-methodhandle.h @@ -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. + */ + +#ifndef PANDA_ASSEMBLER_ASSEMBLY_METHODHANDLE_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_METHODHANDLE_H_ + +#include + +namespace panda::pandasm { + +struct MethodHandle { + std::string item_name; + panda::panda_file::MethodHandleType type; + MethodHandle(std::string s, panda::panda_file::MethodHandleType t) : item_name(std::move(s)), type(t) {} +}; + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ASSEMBLY_METHODHANDLE_H_ diff --git a/assembler/assembly-parser.cpp b/assembler/assembly-parser.cpp new file mode 100644 index 0000000000..1c9f8ea7ef --- /dev/null +++ b/assembler/assembly-parser.cpp @@ -0,0 +1,1855 @@ +/* + * 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-type.h" +#include "ins_emit.h" +#include "modifiers.h" +#include "opcode_parsing.h" +#include "operand_types_print.h" +#include "utils/number-utils.h" + +namespace panda::pandasm { + +bool Parser::ParseRecordFields() +{ + if (!open_ && *context_ == Token::Type::DEL_BRACE_L) { + curr_record_->body_location.begin = GetCurrentPosition(false); + open_ = true; + ++context_; + } + + curr_record_->body_presence = true; + + if (!open_) { + context_.err = GetError("Expected keyword.", Error::ErrorType::ERR_BAD_KEYWORD); + return false; + } + + if (context_.Mask()) { + return true; + } + + if (open_ && *context_ == Token::Type::DEL_BRACE_R) { + curr_record_->body_location.end = GetCurrentPosition(true); + ++context_; + open_ = false; + return true; + } + + curr_record_->field_list.emplace_back(program_.lang); + curr_fld_ = &(curr_record_->field_list[curr_record_->field_list.size() - 1]); + curr_fld_->line_of_def = line_stric_; + 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; + } + + if (open_ && *context_ == Token::Type::DEL_BRACE_R) { + curr_record_->body_location.end = GetCurrentPosition(true); + ++context_; + open_ = false; + } else { + context_.err = GetError("Expected a new field on the next line.", Error::ErrorType::ERR_BAD_KEYWORD); + return false; + } + } + + return true; +} + +bool Parser::ParseFieldName() +{ + if (PrefixedValidName()) { + std::string field_name = std::string(context_.GiveToken().data(), context_.GiveToken().length()); + + auto match_names = [&field_name](const pandasm::Field &f) { return field_name == f.name; }; + const auto iter = std::find_if(curr_record_->field_list.begin(), curr_record_->field_list.end(), match_names); + if (iter != curr_record_->field_list.end()) { + if (iter->is_defined) { + context_.err = + GetError("Repeated field names in the same record.", Error::ErrorType::ERR_REPEATING_FIELD_NAME); + return false; + } + + curr_record_->field_list.erase(iter); + } + + curr_fld_ = &(curr_record_->field_list[curr_record_->field_list.size() - 1]); + curr_fld_->name = field_name; + + ++context_; + return true; + } + + context_.err = GetError("Invalid field name.", Error::ErrorType::ERR_BAD_OPERATION_NAME); + + return false; +} + +bool Parser::ParseType(Type *type) +{ + ASSERT(TypeValidName()); + + std::string component_name(context_.GiveToken()); + size_t rank = 0; + + ++context_; + + while (*context_ == Token::Type::DEL_SQUARE_BRACKET_L) { + ++context_; + if (*context_ != Token::Type::DEL_SQUARE_BRACKET_R) { + context_.err = GetError("Expected ']'.", Error::ErrorType::ERR_BAD_ARRAY_TYPE_BOUND); + return false; + } + ++context_; + ++rank; + } + + *type = Type(component_name, rank); + if (type->IsArray()) { + program_.array_types.insert(*type); + } + + return true; +} + +bool Parser::ParseFieldType() +{ + LOG(DEBUG, ASSEMBLER) << "started searching for field type value (line " << line_stric_ + << "): " << context_.tokens[context_.number - 1].whole_line; + + if (!TypeValidName()) { + context_.err = GetError("Not a correct type.", Error::ErrorType::ERR_BAD_FIELD_VALUE_TYPE); + return false; + } + + if (!ParseType(&curr_fld_->type)) { + return false; + } + + curr_fld_->metadata->SetFieldType(curr_fld_->type); + + LOG(DEBUG, ASSEMBLER) << "field type found (line " << line_stric_ << "): " << context_.GiveToken(); + + return true; +} + +bool Parser::ParseRecordField() +{ + if (!ParseFieldType()) { + return false; + } + + if (context_.Mask()) { + context_.err = GetError("Expected field name.", Error::ErrorType::ERR_BAD_FIELD_MISSING_NAME, +1); + return false; + } + + if (!ParseFieldName()) { + return false; + } + + if (open_ && *context_ == Token::Type::DEL_BRACE_R) { + curr_record_->body_location.end = GetCurrentPosition(true); + ++context_; + open_ = false; + return true; + } + + metadata_ = curr_fld_->metadata.get(); + ParseMetaDef(); + + return context_.Mask(); +} + +bool Parser::ParseFunctionCode() +{ + if (!open_ && *context_ == Token::Type::DEL_BRACE_L) { + open_ = true; + curr_func_->body_location.begin = GetCurrentPosition(false); + ++context_; + } + + curr_func_->body_presence = true; + + if (!open_) { + context_.err = GetError("Expected keyword.", Error::ErrorType::ERR_BAD_KEYWORD); + return false; + } + + if (context_.Mask()) { + return true; + } + + if (open_ && *context_ == Token::Type::DEL_BRACE_R) { + curr_func_->body_location.end = GetCurrentPosition(true); + ++context_; + open_ = false; + return true; + } + + curr_ins_ = &curr_func_->ins.emplace_back(); + + LOG(DEBUG, ASSEMBLER) << "parse line " << line_stric_ + << " as instruction ([label:] operation [operand,] [# comment])"; + + ParseFunctionInstruction(); + + if (open_ && *context_ == Token::Type::DEL_BRACE_R) { + curr_func_->body_location.end = GetCurrentPosition(true); + ++context_; + open_ = false; + } + + return true; +} + +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; + + if (!open_) { + ++context_; + } else { + context_.err = + GetError("No record can be defined inside another record.", Error::ErrorType::ERR_BAD_DEFINITION); + return; + } + + if (ParseRecordFullSign()) { + metadata_ = curr_record_->metadata.get(); + if (ParseMetaDef()) { + if (!open_ && *context_ == Token::Type::DEL_BRACE_L) { + curr_record_->body_location.begin = GetCurrentPosition(false); + ++context_; + open_ = true; + + LOG(DEBUG, ASSEMBLER) << "record body is open, line " << line_stric_ << ": " << tokens[0].whole_line; + } + + if (open_ && !context_.Mask() && *context_ != Token::Type::DEL_BRACE_R) { + ParseRecordFields(); + } else if (open_) { + curr_record_->body_presence = true; + } + + if (open_ && *context_ == Token::Type::DEL_BRACE_R) { + LOG(DEBUG, ASSEMBLER) << "record body is closed, line " << line_stric_ << ": " << tokens[0].whole_line; + + curr_record_->body_location.end = GetCurrentPosition(true); + ++context_; + open_ = false; + } + } + } +} + +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; + + if (!open_) { + ++context_; + } else { + context_.err = + GetError("No one function can be defined inside another function.", Error::ErrorType::ERR_BAD_DEFINITION); + return; + } + + if (ParseFunctionFullSign()) { + metadata_ = curr_func_->metadata.get(); + if (ParseMetaDef()) { + if (!open_ && *context_ == Token::Type::DEL_BRACE_L) { + curr_func_->body_location.begin = GetCurrentPosition(false); + ++context_; + open_ = true; + + LOG(DEBUG, ASSEMBLER) << "function body is open, line " << line_stric_ << ": " << tokens[0].whole_line; + } + + if (open_ && !context_.Mask() && *context_ != Token::Type::DEL_BRACE_R) { + ParseFunctionCode(); + } else if (open_) { + curr_func_->body_presence = true; + } + + if (open_ && *context_ == Token::Type::DEL_BRACE_R) { + LOG(DEBUG, ASSEMBLER) << "function body is closed, line " << line_stric_ << ": " + << tokens[0].whole_line; + + curr_func_->body_location.end = GetCurrentPosition(true); + ++context_; + open_ = false; + } + } + } +} + +void Parser::ParseAsBraceRight(const std::vector &tokens) +{ + if (!open_) { + context_.err = + GetError("Delimiter '}' for the code area is outside a function.", Error::ErrorType::ERR_BAD_BOUND); + return; + } + + LOG(DEBUG, ASSEMBLER) << "body is closed (line " << line_stric_ << "): " << tokens[0].whole_line; + + open_ = false; + if (func_def_) { + curr_func_->body_location.end = GetCurrentPosition(true); + } else if (record_def_) { + curr_record_->body_location.end = GetCurrentPosition(true); + } else { + LOG(FATAL, ASSEMBLER) << "Internal error: either function or record must be parsed here"; + } + ++context_; +} + +void Parser::ParseResetFunctionLabelsAndParams() +{ + if (open_ || err_.err != Error::ErrorType::ERR_NONE) { + return; + } + + for (const auto &f : program_.function_table) { + for (const auto &k : f.second.label_table) { + if (!k.second.file_location->is_defined) { + context_.err = Error("This label does not exist.", line_stric_, Error::ErrorType::ERR_BAD_LABEL_EXT, "", + k.second.file_location->bound_left, k.second.file_location->bound_right, + k.second.file_location->whole_line); + SetError(); + } + } + } + + for (const auto &t : context_.function_arguments_lists) { + curr_func_ = &(program_.function_table.at(t.first)); + curr_func_->regs_num = curr_func_->value_of_first_param + 1; + + for (const auto &v : t.second) { + if (!curr_func_->ins.empty() && curr_func_->ins.size() >= v.first && + !curr_func_->ins[v.first - 1].regs.empty()) { + curr_func_->ins[v.first - 1].regs[v.second] += curr_func_->value_of_first_param + 1; + size_t max_reg_number = (1 << curr_func_->ins[v.first - 1].MaxRegEncodingWidth()); + if (curr_func_->ins[v.first - 1].regs[v.second] >= max_reg_number) { + const auto &debug = curr_func_->ins[v.first - 1].ins_debug; + context_.err = + Error("Register width mismatch.", debug.line_number, Error::ErrorType::ERR_BAD_NAME_REG, "", + debug.bound_left, debug.bound_right, debug.whole_line); + SetError(); + break; + } + } + } + } +} + +void Parser::ParseResetFunctionTable() +{ + for (const auto &k : program_.function_table) { + if (!k.second.file_location->is_defined) { + context_.err = Error("This function does not exist.", k.second.file_location->line_number, + Error::ErrorType::ERR_BAD_ID_FUNCTION, "", k.second.file_location->bound_left, + k.second.file_location->bound_right, k.second.file_location->whole_line); + SetError(); + } else if (k.second.HasImplementation() != k.second.body_presence) { + context_.err = + Error("Inconsistent definition of the function and its metadata.", k.second.file_location->line_number, + Error::ErrorType::ERR_BAD_DEFINITION_FUNCTION, "", k.second.file_location->bound_left, + k.second.file_location->bound_right, k.second.file_location->whole_line); + SetError(); + } else { + for (auto insn_it = k.second.ins.begin(); insn_it != k.second.ins.end(); ++insn_it) { + bool is_calli = insn_it->opcode == Opcode::CALLI_DYN || insn_it->opcode == Opcode::CALLI_DYN_SHORT || + insn_it->opcode == Opcode::CALLI_DYN_RANGE; + if (is_calli || !insn_it->IsCall()) { + continue; + } + + bool is_initobj = insn_it->opcode == Opcode::INITOBJ || insn_it->opcode == Opcode::INITOBJ_SHORT || + insn_it->opcode == Opcode::INITOBJ_RANGE; + auto diff = is_initobj ? 0 : 1; + if (insn_it->OperandListLength() - diff < program_.function_table.at(insn_it->ids[0]).GetParamsNum()) { + auto insn_idx = std::distance(k.second.ins.begin(), insn_it); + const auto &debug = curr_func_->ins[insn_idx].ins_debug; + context_.err = Error("Function argument mismatch.", debug.line_number, + Error::ErrorType::ERR_FUNCTION_ARGUMENT_MISMATCH, "", debug.bound_left, + debug.bound_right, debug.whole_line); + SetError(); + } + } + } + } +} + +void Parser::ParseResetRecordTable() +{ + for (const auto &k : program_.record_table) { + if (!k.second.file_location->is_defined) { + context_.err = Error("This record does not exist.", k.second.file_location->line_number, + Error::ErrorType::ERR_BAD_ID_RECORD, "", k.second.file_location->bound_left, + k.second.file_location->bound_right, k.second.file_location->whole_line); + SetError(); + } else if (k.second.HasImplementation() != k.second.body_presence) { + context_.err = Error("Inconsistency of the definition of the record and its metadata.", + k.second.file_location->line_number, Error::ErrorType::ERR_BAD_DEFINITION_RECORD, "", + k.second.file_location->bound_left, k.second.file_location->bound_right, + k.second.file_location->whole_line); + SetError(); + } else { + for (const auto &fld : k.second.field_list) { + if (!fld.is_defined) { + context_.err = + Error("This field does not exist.", fld.line_of_def, Error::ErrorType::ERR_BAD_ID_FIELD, "", + fld.bound_left, fld.bound_right, fld.whole_line); + SetError(); + } + } + } + } +} + +void Parser::ParseResetTables() +{ + if (err_.err != Error::ErrorType::ERR_NONE) { + return; + } + + ParseResetFunctionTable(); + + if (err_.err != Error::ErrorType::ERR_NONE) { + return; + } + + ParseResetRecordTable(); +} + +void Parser::ParseAsLanguageDirective() +{ + ++context_; + + if (context_.Mask()) { + context_.err = GetError("Incorrect .language directive: Expected language", + Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); + return; + } + + auto lang = context_.GiveToken(); + auto res = extensions::LanguageFromString(lang); + if (!res) { + context_.err = + GetError("Incorrect .language directive: Unknown language", Error::ErrorType::ERR_UNKNOWN_LANGUAGE); + return; + } + + ++context_; + + if (!context_.Mask()) { + context_.err = GetError("Incorrect .language directive: Unexpected token", + Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); + } + + program_.lang = res.value(); +} + +Function::CatchBlock Parser::PrepareCatchBlock(bool is_catchall, size_t size, size_t catchall_tokens_num, + size_t catch_tokens_num) +{ + constexpr size_t TRY_BEGIN = 0; + constexpr size_t TRY_END = 1; + constexpr size_t CATCH_BEGIN = 2; + constexpr size_t CATCH_END = 3; + + Function::CatchBlock catch_block; + catch_block.whole_line = context_.tokens[0].whole_line; + std::vector label_names {"try block begin", "try block end", "catch block begin"}; + std::vector labels; + bool full_catch_block = (is_catchall && size == catchall_tokens_num) || (!is_catchall && size == catch_tokens_num); + if (full_catch_block) { + label_names.emplace_back("catch block end"); + } + if (!is_catchall) { + catch_block.exception_record = context_.GiveToken(); + ++context_; + } + + bool skip_comma = is_catchall; + for (auto label_name : label_names) { + if (!skip_comma) { + if (*context_ != Token::Type::DEL_COMMA) { + context_.err = GetError("Expected comma.", Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); + return catch_block; + } + ++context_; + } + skip_comma = false; + if (!LabelValidName()) { + context_.err = + GetError(std::string("Invalid name of the ") + label_name + " label.", Error::ErrorType::ERR_BAD_LABEL); + return catch_block; + } + labels.emplace_back(context_.GiveToken()); + AddObjectInTable(false, *label_table_); + ++context_; + } + + ASSERT(context_.Mask()); + catch_block.try_begin_label = labels[TRY_BEGIN]; + catch_block.try_end_label = labels[TRY_END]; + catch_block.catch_begin_label = labels[CATCH_BEGIN]; + if (full_catch_block) { + catch_block.catch_end_label = labels[CATCH_END]; + } else { + catch_block.catch_end_label = labels[CATCH_BEGIN]; + } + + return catch_block; +} + +void Parser::ParseAsCatchDirective() +{ + ASSERT(*context_ == Token::Type::ID_CATCH || *context_ == Token::Type::ID_CATCHALL); + + constexpr size_t CATCH_DIRECTIVE_TOKENS_NUM = 8; + constexpr size_t CATCHALL_DIRECTIVE_TOKENS_NUM = 6; + constexpr size_t CATCH_FULL_DIRECTIVE_TOKENS_NUM = 10; + constexpr size_t CATCHALL_FULL_DIRECTIVE_TOKENS_NUM = 8; + + bool is_catchall = *context_ == Token::Type::ID_CATCHALL; + size_t size = context_.tokens.size(); + if (is_catchall && size != CATCHALL_DIRECTIVE_TOKENS_NUM && size != CATCHALL_FULL_DIRECTIVE_TOKENS_NUM) { + context_.err = GetError( + "Incorrect catch block declaration. Must be in the format: .catchall , , " + "[, ]", + Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); + return; + } + + if (!is_catchall && size != CATCH_DIRECTIVE_TOKENS_NUM && size != CATCH_FULL_DIRECTIVE_TOKENS_NUM) { + context_.err = GetError( + "Incorrect catch block declaration. Must be in the format: .catch , , " + ", [, ]", + Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); + return; + } + + ++context_; + + if (!is_catchall && !RecordValidName()) { + context_.err = GetError("Invalid name of the exception record.", Error::ErrorType::ERR_BAD_RECORD_NAME); + return; + } + + Function::CatchBlock catch_block = + PrepareCatchBlock(is_catchall, size, CATCHALL_FULL_DIRECTIVE_TOKENS_NUM, CATCH_FULL_DIRECTIVE_TOKENS_NUM); + + curr_func_->catch_blocks.push_back(catch_block); +} + +void Parser::ParseAsCatchall(const std::vector &tokens) +{ + std::string directive_name = *context_ == Token::Type::ID_CATCH ? ".catch" : ".catchall"; + if (!func_def_) { + context_.err = GetError(directive_name + " directive is outside a function body.", + Error::ErrorType::ERR_INCORRECT_DIRECTIVE_LOCATION); + return; + } + + LOG(DEBUG, ASSEMBLER) << "started parsing of " << directive_name << " directive (line " << line_stric_ + << "): " << tokens[0].whole_line; + + ParseAsCatchDirective(); +} + +void Parser::ParseAsLanguage(const std::vector &tokens, bool &is_lang_parsed, bool &is_first_statement) +{ + if (is_lang_parsed) { + context_.err = GetError("Multiple .language directives", Error::ErrorType::ERR_MULTIPLE_DIRECTIVES); + return; + } + + if (!is_first_statement) { + context_.err = GetError(".language directive must be specified before any other declarations", + Error::ErrorType::ERR_INCORRECT_DIRECTIVE_LOCATION); + return; + } + + LOG(DEBUG, ASSEMBLER) << "started parsing of .language directive (line " << line_stric_ + << "): " << tokens[0].whole_line; + + ParseAsLanguageDirective(); + + is_lang_parsed = true; +} + +bool Parser::ParseAfterLine(bool &is_first_statement) +{ + SetError(); + + if (!context_.Mask() && err_.err == Error::ErrorType::ERR_NONE) { + context_.err = GetError("There should be nothing after.", Error::ErrorType::ERR_BAD_END); + } + + if (err_.err != Error::ErrorType::ERR_NONE) { + LOG(DEBUG, ASSEMBLER) << "processing aborted (error detected)"; + return false; + } + + LOG(DEBUG, ASSEMBLER) << "parsing of line " << line_stric_ << " is successful"; + + SetError(); + + is_first_statement = false; + + return true; +} + +Expected Parser::ParseAfterMainLoop(const std::string &file_name) +{ + ParseResetFunctionLabelsAndParams(); + + if (open_ && err_.err == Error::ErrorType::ERR_NONE) { + context_.err = Error("Code area is not closed.", curr_func_->file_location->line_number, + Error::ErrorType::ERR_BAD_CLOSE, "", 0, curr_func_->name.size(), curr_func_->name); + SetError(); + } + + ParseResetTables(); + + if (err_.err != Error::ErrorType::ERR_NONE) { + return Unexpected(err_); + } + + for (auto &func : program_.function_table) { + if (func.second.metadata->HasImplementation()) { + func.second.source_file = file_name; + } + } + + for (auto &rec : program_.record_table) { + if (rec.second.HasImplementation()) { + rec.second.source_file = file_name; + } + } + + return std::move(program_); +} + +Expected Parser::Parse(TokenSet &vectors_tokens, const std::string &file_name) +{ + bool is_lang_parsed = false; + bool is_first_statement = true; + + for (const auto &tokens : vectors_tokens) { + ++line_stric_; + + if (tokens.empty()) { + continue; + } + + LOG(DEBUG, ASSEMBLER) << "started parsing of line " << line_stric_ << ": " << tokens[0].whole_line; + + context_.Make(tokens); + switch (*context_) { + case Token::Type::ID_CATCH: + case Token::Type::ID_CATCHALL: { + ParseAsCatchall(tokens); + break; + } + case Token::Type::ID_LANG: { + ParseAsLanguage(tokens, is_lang_parsed, is_first_statement); + break; + } + case Token::Type::ID_REC: { + ParseAsRecord(tokens); + break; + } + case Token::Type::ID_FUN: { + ParseAsFunction(tokens); + break; + } + case Token::Type::DEL_BRACE_R: { + ParseAsBraceRight(tokens); + break; + } + default: { + if (func_def_) { + ParseFunctionCode(); + } else if (record_def_) { + ParseRecordFields(); + } + } + } + + if (!ParseAfterLine(is_first_statement)) { + break; + } + } + + return ParseAfterMainLoop(file_name); +} + +Expected Parser::Parse(const std::string &source, const std::string &file_name) +{ + auto ss = std::stringstream(source); + std::string line; + + Lexer l; + std::vector> v; + + while (std::getline(ss, line)) { + auto [tokens, error] = l.TokenizeString(line); + if (error.err != Error::ErrorType::ERR_NONE) { + return Unexpected(error); + } + + v.push_back(tokens); + } + + return Parse(v, file_name); +} + +void Parser::SetError() +{ + err_ = context_.err; +} + +bool Parser::RegValidName() +{ + if (context_.err.err != Error::ErrorType::ERR_NONE) { + return false; + } + + if (curr_func_->GetParamsNum() > 0) { + return context_.ValidateRegisterName('v') || context_.ValidateRegisterName('a', curr_func_->GetParamsNum() - 1); + } + + return context_.ValidateRegisterName('v'); +} + +bool Parser::ParamValidName() +{ + return context_.ValidateParameterName(curr_func_->GetParamsNum()); +} + +bool IsAlphaNumeric(char c) +{ + return std::isalnum(c) != 0 || c == '_'; +} + +bool IsNonDigit(char c) +{ + return std::isalpha(c) != 0 || c == '_'; +} + +bool Parser::PrefixedValidName() +{ + auto s = context_.GiveToken(); + if (!IsNonDigit(s[0])) { + return false; + } + + size_t i = 1; + while (i < s.size()) { + if (s[i] == '.') { + ++i; + if (i >= s.size() || !IsNonDigit(s[i])) { + return false; + } + } else if (!IsAlphaNumeric(s[i]) && s[i] != '$') { + return false; + } + + ++i; + } + + return true; +} + +bool Parser::RecordValidName() +{ + return PrefixedValidName(); +} + +bool Parser::FunctionValidName() +{ + return PrefixedValidName(); +} + +bool Parser::LabelValidName() +{ + auto token = context_.GiveToken(); + if (!IsNonDigit(token[0])) { + return false; + } + + token.remove_prefix(1); + + for (auto i : token) { + if (!IsAlphaNumeric(i)) { + return false; + } + } + + return true; +} + +bool Parser::ParseLabel() +{ + LOG(DEBUG, ASSEMBLER) << "started searching for label (line " << line_stric_ + << "): " << context_.tokens[0].whole_line; + + context_++; + + if (*context_ == Token::Type::DEL_COLON) { + context_--; + if (LabelValidName()) { + if (AddObjectInTable(true, *label_table_)) { + curr_ins_->set_label = true; + curr_ins_->label = context_.GiveToken(); + + LOG(DEBUG, ASSEMBLER) << "label detected (line " << line_stric_ << "): " << context_.GiveToken(); + + context_++; + context_++; + return !context_.Mask(); + } + + LOG(DEBUG, ASSEMBLER) << "label is detected (line " << line_stric_ << "): " << context_.GiveToken() + << ", but this label already exists"; + + context_.err = GetError("This label already exists.", Error::ErrorType::ERR_BAD_LABEL_EXT); + + } else { + LOG(DEBUG, ASSEMBLER) << "label with non-standard character is detected, attempt to create a label is " + "supported, but this cannot be any label name (line " + << line_stric_ << "): " << context_.GiveToken(); + + context_.err = GetError( + "Invalid name of label. Label can only contain characters: '_', '0' - '9', 'a' - 'z', 'A' - 'Z'; and " + "starts with any letter or with '_'.", + Error::ErrorType::ERR_BAD_LABEL); + } + + return false; + } + + context_--; + + LOG(DEBUG, ASSEMBLER) << "label is not detected (line " << line_stric_ << ")"; + + return true; +} + +static Opcode TokenToOpcode(Token::Type id) +{ + ASSERT(id > Token::Type::OPERATION); + ASSERT(id < Token::Type::KEYWORD); + using utype = std::underlying_type_t; + return static_cast(static_cast(id) - static_cast(Token::Type::OPERATION) - 1); +} + +bool Parser::ParseOperation() +{ + if (context_.Mask()) { + LOG(DEBUG, ASSEMBLER) << "no more tokens (line " << line_stric_ << "): " << context_.tokens[0].whole_line; + + return false; + } + + if (open_ && *context_ == Token::Type::DEL_BRACE_R) { + return false; + } + + LOG(DEBUG, ASSEMBLER) << "started searching for operation (line " << line_stric_ + << "): " << context_.tokens[0].whole_line; + + if (*context_ > Token::Type::OPERATION && *context_ < Token::Type::KEYWORD) { + SetOperationInformation(); + + context_.UpSignOperation(); + curr_ins_->opcode = TokenToOpcode(context_.id); + + LOG(DEBUG, ASSEMBLER) << "operation is detected (line " << line_stric_ << "): " << context_.GiveToken() + << " (operand type: " << OperandTypePrint(curr_ins_->opcode) << ")"; + + context_++; + return true; + } + + LOG(DEBUG, ASSEMBLER) << "founded " << context_.GiveToken() << ", it is not an operation (line " << line_stric_ + << ")"; + + context_.err = GetError("Invalid operation name.", Error::ErrorType::ERR_BAD_OPERATION_NAME); + + return false; +} + +bool Parser::ParseOperandVreg() +{ + if (context_.err.err != Error::ErrorType::ERR_NONE) { + return false; + } + + if (*context_ != Token::Type::ID) { + context_.err = GetError("Expected register.", Error::ErrorType::ERR_BAD_OPERAND, +1); + return false; + } + + std::string_view p = context_.GiveToken(); + + if (p[0] == 'v') { + p.remove_prefix(1); + int64_t number = ToNumber(p); + + if (number > *(context_.max_value_of_reg)) { + *(context_.max_value_of_reg) = number; + } + + curr_ins_->regs.push_back(number); + } else if (p[0] == 'a') { + p.remove_prefix(1); + curr_ins_->regs.push_back(ToNumber(p)); + context_.function_arguments_list->emplace_back(context_.ins_number, curr_ins_->regs.size() - 1); + } + + ++context_; + + return true; +} + +bool Parser::ParseOperandCall() +{ + if (context_.err.err != Error::ErrorType::ERR_NONE) { + return false; + } + + if (!FunctionValidName()) { + context_.err = GetError("Invalid name of function.", Error::ErrorType::ERR_BAD_NAME_REG); + return false; + } + + std::string_view p = context_.GiveToken(); + curr_ins_->ids.emplace_back(p.data(), p.length()); + AddObjectInTable(false, program_.function_table); + + ++context_; + + return true; +} + +static bool IsOctal(char c) +{ + return c >= '0' && c <= '7'; +} + +static bool IsHex(char c) +{ + return std::isxdigit(c) != 0; +} + +static uint8_t FromHex(char c) +{ + constexpr size_t DIGIT_NUM = 10; + + if (c >= '0' && c <= '9') { + return c - '0'; + } + + if (c >= 'A' && c <= 'F') { + return c - 'A' + DIGIT_NUM; + } + + return c - 'a' + DIGIT_NUM; +} + +static uint8_t FromOctal(char c) +{ + return c - '0'; +} + +Expected Parser::ParseOctalEscapeSequence(std::string_view s, size_t *i) +{ + constexpr size_t OCT_SHIFT = 3; + + size_t idx = *i; + size_t n = 0; + uint32_t r = 0; + + while (idx < s.length() && IsOctal(s[idx]) && n < OCT_SHIFT) { + r |= FromOctal(s[idx++]); + r <<= 3U; + ++n; + } + + r >>= 3U; + *i += n; + + return r; +} + +Expected Parser::ParseHexEscapeSequence(std::string_view s, size_t *i) +{ + constexpr size_t HEX_SHIFT = 2; + + uint32_t r = 0; + size_t idx = *i; + + for (size_t j = 0; j < HEX_SHIFT; j++) { + char v = s[(*i)++]; + if (!IsHex(v)) { + return Unexpected(GetError("Invalid hexadecimal escape sequence", + Error::ErrorType::ERR_BAD_STRING_INVALID_HEX_ESCAPE_SEQUENCE, idx - HEX_SHIFT)); + } + + r |= FromHex(v); + r <<= 4U; + } + + r >>= 4U; + + return r; +} + +Expected Parser::ParseEscapeSequence(std::string_view s, size_t *i) +{ + size_t idx = *i; + char c = s[idx]; + if (IsOctal(c)) { + return ParseOctalEscapeSequence(s, i); + } + + ++(*i); + + switch (c) { + case '\'': + case '"': + case '\\': + return c; + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + default: + break; + } + + if (c == 'x') { + return ParseHexEscapeSequence(s, i); + } + + return Unexpected( + GetError("Unknown escape sequence", Error::ErrorType::ERR_BAD_STRING_UNKNOWN_ESCAPE_SEQUENCE, idx - 1)); +} + +std::optional Parser::ParseStringLiteral() +{ + if (*context_ != Token::Type::ID_STRING) { + context_.err = GetError("Expected string literal", Error::ErrorType::ERR_BAD_OPERAND); + return {}; + } + + auto token = context_.GiveToken(); + + size_t i = 1; /* skip leading quote */ + size_t len = token.length(); + + std::string s; + while (i < len - 1) { + char c = token[i++]; + if (c != '\\') { + s.append(1, c); + continue; + } + + auto res = ParseEscapeSequence(token, &i); + if (!res) { + context_.err = res.Error(); + return {}; + } + + s.append(1, res.Value()); + } + + program_.strings.insert(s); + + return s; +} + +bool Parser::ParseOperandString() +{ + if (context_.err.err != Error::ErrorType::ERR_NONE) { + return false; + } + + auto res = ParseStringLiteral(); + if (!res) { + return false; + } + + curr_ins_->ids.push_back(res.value()); + ++context_; + + return true; +} + +bool Parser::ParseOperandComma() +{ + if (context_.err.err != Error::ErrorType::ERR_NONE) { + return false; + } + + if (context_++ != Token::Type::DEL_COMMA) { + if (!context_.Mask() && *context_ != Token::Type::DEL_BRACKET_R) { + --context_; + } + + context_.err = GetError("Expected comma.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); + return false; + } + + return true; +} + +bool Parser::ParseOperandInteger() +{ + if (context_.err.err != Error::ErrorType::ERR_NONE) { + return false; + } + + if (*context_ != Token::Type::ID) { + if (*context_ == Token::Type::DEL_BRACE_R) { + --context_; + } + context_.err = GetError("Expected immediate.", Error::ErrorType::ERR_BAD_OPERAND, +1); + return false; + } + + std::string_view p = context_.GiveToken(); + if (!ValidateInteger(p)) { + context_.err = GetError("Expected integer.", Error::ErrorType::ERR_BAD_INTEGER_NAME); + return false; + } + + int64_t n = IntegerNumber(p); + if (errno == ERANGE) { + context_.err = + GetError("Too large immediate (length is more than 64 bit).", Error::ErrorType::ERR_BAD_INTEGER_WIDTH); + return false; + } + + curr_ins_->imms.push_back(n); + ++context_; + + return true; +} + +bool Parser::ParseOperandFloat() +{ + if (context_.err.err != Error::ErrorType::ERR_NONE) { + return false; + } + + if (*context_ != Token::Type::ID) { + if (*context_ == Token::Type::DEL_BRACE_R) { + --context_; + } + context_.err = GetError("Expected immediate.", Error::ErrorType::ERR_BAD_OPERAND, +1); + return false; + } + + std::string_view p = context_.GiveToken(); + if (!ValidateFloat(p)) { + context_.err = GetError("Expected float.", Error::ErrorType::ERR_BAD_FLOAT_NAME); + return false; + } + + double n = FloatNumber(p); + if (errno == ERANGE) { + context_.err = + GetError("Too large immediate (length is more than 64 bit).", Error::ErrorType::ERR_BAD_FLOAT_WIDTH); + return false; + } + + curr_ins_->imms.push_back(n); + ++context_; + + return true; +} + +bool Parser::ParseOperandLabel() +{ + if (context_.err.err != Error::ErrorType::ERR_NONE) { + return false; + } + + if (!LabelValidName()) { + context_.err = GetError("Invalid name of label.", Error::ErrorType::ERR_BAD_NAME_ID); + return false; + } + + std::string_view p = context_.GiveToken(); + curr_ins_->ids.emplace_back(p.data(), p.length()); + AddObjectInTable(false, *label_table_); + + ++context_; + + return true; +} + +bool Parser::ParseOperandId() +{ + if (context_.err.err != Error::ErrorType::ERR_NONE) { + return false; + } + + if (*context_ != Token::Type::ID) { + context_.err = GetError("Expected label.", Error::ErrorType::ERR_BAD_OPERAND); + return false; + } + + if (!LabelValidName()) { + context_.err = GetError("Invalid name of label.", Error::ErrorType::ERR_BAD_NAME_ID); + return false; + } + + std::string_view p = context_.GiveToken(); + curr_ins_->ids.emplace_back(p.data(), p.length()); + AddObjectInTable(false, *label_table_); + + ++context_; + + return true; +} + +bool Parser::ParseOperandType(Type::VerificationType ver_type) +{ + if (context_.err.err != Error::ErrorType::ERR_NONE) { + return false; + } + + if (*context_ != Token::Type::ID) { + context_.err = GetError("Expected type.", Error::ErrorType::ERR_BAD_OPERAND); + return false; + } + + if (!TypeValidName()) { + context_.err = GetError("Invalid name of type.", Error::ErrorType::ERR_BAD_NAME_ID); + return false; + } + + Type type; + if (!ParseType(&type)) { + return false; + } + + bool is_object = (context_.GiveToken() == "]") ? (false) : (true); + if (is_object) { + AddObjectInTable(false, program_.record_table); + + if (ver_type == Type::VerificationType::TYPE_ID_ARRAY) { + GetWarning("Unexpected type_id received! Expected array, but object given", + Error::ErrorType::WAR_UNEXPECTED_TYPE_ID); + } + } else { + if (!type.IsArrayContainsPrimTypes() && + program_.record_table.find(type.GetComponentName()) == program_.record_table.end()) { + std::string ComponentName = type.GetComponentName(); + context_.token = ComponentName; + AddObjectInTable(false, program_.record_table); + } + + if (ver_type == Type::VerificationType::TYPE_ID_OBJECT) { + GetWarning("Unexpected type_id received! Expected object, but array given", + Error::ErrorType::WAR_UNEXPECTED_TYPE_ID); + } + } + + curr_ins_->ids.push_back(type.GetName()); + + return true; +} + +bool Parser::ParseOperandField() +{ + if (context_.err.err != Error::ErrorType::ERR_NONE) { + return false; + } + + if (*context_ != Token::Type::ID) { + context_.err = GetError("Expected field.", Error::ErrorType::ERR_BAD_OPERAND); + return false; + } + if (!PrefixedValidName()) { + context_.err = GetError("Invalid field name.", Error::ErrorType::ERR_BAD_NAME_ID); + return false; + } + + std::string_view p = context_.GiveToken(); + std::string record_full_name = std::string(p); + // Some names of records in pandastdlib starts with 'panda.', and therefore, + // the record name is before the second dot, and the field name is after the second dot. + auto pos_point = record_full_name.find_last_of('.'); + std::string record_name = record_full_name.substr(0, pos_point); + std::string field_name = record_full_name.substr(pos_point + 1); + + auto it_record = program_.record_table.find(record_name); + if (it_record == program_.record_table.end()) { + context_.token = record_name; + AddObjectInTable(false, program_.record_table); + it_record = program_.record_table.find(record_name); + } + + auto it_field = std::find_if(it_record->second.field_list.begin(), it_record->second.field_list.end(), + [&field_name](pandasm::Field &field) { return field_name == field.name; }); + + if (!field_name.empty() && it_field == it_record->second.field_list.end()) { + it_record->second.field_list.emplace_back(program_.lang); + auto &field = it_record->second.field_list.back(); + field.name = field_name; + field.line_of_def = line_stric_; + field.whole_line = context_.tokens[context_.number - 1].whole_line; + field.bound_left = context_.tokens[context_.number - 1].bound_left + record_name.length() + 1; + field.bound_right = context_.tokens[context_.number - 1].bound_right; + field.is_defined = false; + } + + curr_ins_->ids.emplace_back(p.data(), p.length()); + ++context_; + + return true; +} + +bool Parser::ParseOperandNone() +{ + if (context_.err.err != Error::ErrorType::ERR_NONE) { + return false; + } + + if (open_ && *context_ == Token::Type::DEL_BRACE_R) { + return false; + } + + if (!context_.Mask()) { + context_.err = GetError("Invalid number of operands.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); + --context_; + return false; + } + + return true; +} + +bool Parser::ParseRecordFullSign() +{ + return ParseRecordName(); +} + +bool Parser::ParseFunctionFullSign() +{ + if (!ParseFunctionReturn()) { + return false; + } + + if (!ParseFunctionName()) { + return false; + } + + if (*context_ == Token::Type::DEL_BRACKET_L) { + ++context_; + + if (ParseFunctionArgs()) { + if (*context_ == Token::Type::DEL_BRACKET_R) { + ++context_; + return true; + } + context_.err = GetError("Expected ')'.", Error::ErrorType::ERR_BAD_ARGS_BOUND); + } + } else { + context_.err = GetError("Expected '('.", Error::ErrorType::ERR_BAD_ARGS_BOUND); + } + + return false; +} + +bool Parser::ParseRecordName() +{ + LOG(DEBUG, ASSEMBLER) << "started searching for record name (line " << line_stric_ + << "): " << context_.tokens[context_.number - 1].whole_line; + + if (!RecordValidName()) { + if (*context_ == Token::Type::DEL_BRACKET_L) { + context_.err = GetError("No record name.", Error::ErrorType::ERR_BAD_RECORD_NAME); + return false; + } + context_.err = GetError("Invalid name of the record.", Error::ErrorType::ERR_BAD_RECORD_NAME); + return false; + } + + auto iter = program_.record_table.find(std::string(context_.GiveToken().data(), context_.GiveToken().length())); + if (iter == program_.record_table.end() || !iter->second.file_location->is_defined) { + SetRecordInformation(); + } else { + context_.err = GetError("This record already exists.", Error::ErrorType::ERR_BAD_ID_RECORD); + return false; + } + + LOG(DEBUG, ASSEMBLER) << "record name found (line " << line_stric_ << "): " << context_.GiveToken(); + + ++context_; + + return true; +} + +void Parser::SetRecordInformation() +{ + AddObjectInTable(true, program_.record_table); + curr_record_ = &(program_.record_table.at(std::string(context_.GiveToken().data(), context_.GiveToken().length()))); +} + +bool Parser::ParseFunctionName() +{ + LOG(DEBUG, ASSEMBLER) << "started searching for function name (line " << line_stric_ + << "): " << context_.tokens[context_.number - 1].whole_line; + + if (!FunctionValidName()) { + if (*context_ == Token::Type::DEL_BRACKET_L) { + context_.err = GetError("No function name.", Error::ErrorType::ERR_BAD_FUNCTION_NAME); + return false; + } + context_.err = GetError("Invalid name of the function.", Error::ErrorType::ERR_BAD_FUNCTION_NAME); + return false; + } + + auto iter = program_.function_table.find(std::string(context_.GiveToken().data(), context_.GiveToken().length())); + + if (iter == program_.function_table.end() || !iter->second.file_location->is_defined) { + SetFunctionInformation(); + } else { + context_.err = GetError("This function already exists.", Error::ErrorType::ERR_BAD_ID_FUNCTION); + return false; + } + + LOG(DEBUG, ASSEMBLER) << "function name found (line " << line_stric_ << "): " << context_.GiveToken(); + + ++context_; + + return true; +} + +void Parser::SetFunctionInformation() +{ + std::string p = std::string(context_.GiveToken()); + AddObjectInTable(true, program_.function_table); + curr_func_ = &(program_.function_table.at(p)); + label_table_ = &(curr_func_->label_table); + curr_func_->return_type = context_.curr_func_return_type; + context_.max_value_of_reg = &(curr_func_->value_of_first_param); + context_.function_arguments_list = &(context_.function_arguments_lists[curr_func_->name]); +} + +void Parser::SetOperationInformation() +{ + context_.ins_number = curr_func_->ins.size(); + auto &curr_debug = curr_func_->ins.back().ins_debug; + curr_debug.line_number = line_stric_; + curr_debug.whole_line = context_.tokens[context_.number - 1].whole_line; + curr_debug.bound_left = context_.tokens[context_.number - 1].bound_left; + curr_debug.bound_right = context_.tokens[context_.number - 1].bound_right; +} + +bool Parser::ParseFunctionReturn() +{ + LOG(DEBUG, ASSEMBLER) << "started searching for return function value (line " << line_stric_ + << "): " << context_.tokens[context_.number - 1].whole_line; + + if (!TypeValidName()) { + if (*context_ == Token::Type::DEL_BRACKET_L) { + context_.err = GetError("No return type.", Error::ErrorType::ERR_BAD_FUNCTION_RETURN_VALUE); + return false; + } + context_.err = GetError("Invalid return type.", Error::ErrorType::ERR_BAD_FUNCTION_RETURN_VALUE); + return false; + } + + if (!ParseType(&context_.curr_func_return_type)) { + return false; + } + + LOG(DEBUG, ASSEMBLER) << "return type found (line " << line_stric_ << "): " << context_.GiveToken(); + + return true; +} + +bool Parser::TypeValidName() +{ + if (Type::GetId(context_.GiveToken()) != panda_file::Type::TypeId::REFERENCE) { + return true; + } + + return PrefixedValidName(); +} + +bool Parser::ParseFunctionArg() +{ + if (*context_ != Token::Type::ID) { + context_.err = GetError("Expected identifier.", Error::ErrorType::ERR_BAD_FUNCTION_PARAMETERS); + return false; + } + + if (!TypeValidName()) { + context_.err = GetError("Invalid parameter type.", Error::ErrorType::ERR_BAD_TYPE); + return false; + } + + Type type; + if (!ParseType(&type)) { + return false; + } + + if (context_.Mask()) { + return false; + } + + if (*context_ != Token::Type::ID) { + context_.err = GetError("Expected identifier.", Error::ErrorType::ERR_BAD_FUNCTION_PARAMETERS); + return false; + } + + if (!ParamValidName()) { + context_.err = GetError("Invalid parameter name.", Error::ErrorType::ERR_BAD_PARAM_NAME); + return false; + } + + ++context_; + + Function::Parameter parameter(type, program_.lang); + metadata_ = parameter.metadata.get(); + + if (*context_ == Token::Type::DEL_LT && !ParseMetaDef()) { + return false; + } + + curr_func_->params.push_back(std::move(parameter)); + + return true; +} + +bool Parser::ParseFunctionArgComma(bool &comma) +{ + if (comma && *context_ != Token::Type::DEL_COMMA) { + context_.err = GetError("Expected comma.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); + return false; + } + + if (comma) { + ++context_; + } + + comma = true; + + return true; +} + +bool Parser::ParseFunctionArgs() +{ + LOG(DEBUG, ASSEMBLER) << "started searching for function parameters (line " << line_stric_ + << "): " << context_.tokens[context_.number - 1].whole_line; + + bool comma = false; + + while (true) { + if (context_.Mask()) { + return false; + } + + if (context_.id != Token::Type::DEL_COMMA && context_.id != Token::Type::ID) { + break; + } + + if (!ParseFunctionArgComma(comma)) { + return false; + } + + if (!ParseFunctionArg()) { + return false; + } + } + + LOG(DEBUG, ASSEMBLER) << "parameters found (line " << line_stric_ << "): "; + + return true; +} + +bool Parser::ParseMetaDef() +{ + LOG(DEBUG, ASSEMBLER) << "started searching for meta information (line " << line_stric_ + << "): " << context_.tokens[context_.number - 1].whole_line; + + if (context_.Mask()) { + return false; + } + + bool flag = false; + + if (*context_ == Token::Type::DEL_LT) { + flag = true; + ++context_; + } + + if (!ParseMetaList(flag)) { + return false; + } + + if (!flag && *context_ == Token::Type::DEL_GT) { + context_.err = GetError("Expected '<'.", Error::ErrorType::ERR_BAD_METADATA_BOUND); + ++context_; + return false; + } + + LOG(DEBUG, ASSEMBLER) << "searching for meta information (line " << line_stric_ << ") is successful"; + + if (flag && context_.err.err == Error::ErrorType::ERR_NONE) { + ++context_; + } + + return true; +} + +void Parser::SetMetadataContextError(const Metadata::Error &err, bool has_value) +{ + constexpr int64_t NO_VALUE_OFF = -1; + constexpr int64_t SPECIAL_OFF = -2; + constexpr int64_t STANDARD_OFF = -3; + + switch (err.GetType()) { + case Metadata::Error::Type::UNKNOWN_ATTRIBUTE: { + context_.err = GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_UNKNOWN_ATTRIBUTE, 0, + has_value ? STANDARD_OFF : NO_VALUE_OFF); + break; + } + case Metadata::Error::Type::MISSING_ATTRIBUTE: { + context_.err = GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_MISSING_ATTRIBUTE); + break; + } + case Metadata::Error::Type::MISSING_VALUE: { + context_.err = GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_MISSING_VALUE); + break; + } + case Metadata::Error::Type::UNEXPECTED_ATTRIBUTE: { + context_.err = GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_UNEXPECTED_ATTRIBUTE, 0, + has_value ? STANDARD_OFF : NO_VALUE_OFF); + break; + } + case Metadata::Error::Type::UNEXPECTED_VALUE: { + context_.err = + GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_UNEXPECTED_VALUE, 0, SPECIAL_OFF); + break; + } + case Metadata::Error::Type::INVALID_VALUE: { + context_.err = GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_INVALID_VALUE, 0, -1); + break; + } + case Metadata::Error::Type::MULTIPLE_ATTRIBUTE: { + context_.err = GetError(err.GetMessage(), Error::ErrorType::ERR_BAD_METADATA_MULTIPLE_ATTRIBUTE, 0, + has_value ? STANDARD_OFF : NO_VALUE_OFF); + break; + } + default: { + UNREACHABLE(); + } + } +} + +bool Parser::ParseMetaListComma(bool &comma, bool eq) +{ + if (!eq && comma && *context_ != Token::Type::DEL_COMMA) { + context_.err = GetError("Expected comma.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); + return false; + } + + if (!eq && comma) { + ++context_; + } + + comma = true; + + return true; +} + +bool Parser::MeetExpMetaList(bool eq) +{ + if (!eq && *context_ != Token::Type::ID) { + context_.err = GetError("Expected identifier.", Error::ErrorType::ERR_BAD_DEFINITION_METADATA, +1); + return false; + } + + if (eq && *context_ != Token::Type::ID && *context_ != Token::Type::ID_STRING) { + context_.err = + GetError("Expected identifier or string literal.", Error::ErrorType::ERR_BAD_DEFINITION_METADATA, +1); + return false; + } + + if (!eq && !PrefixedValidName()) { + context_.err = GetError("Invalid attribute name.", Error::ErrorType::ERR_BAD_NAME_ID); + return false; + } + + return true; +} + +bool Parser::BuildMetaListAttr(bool &eq, std::string &attribute_name, std::string &attribute_value) +{ + if (eq && *context_ == Token::Type::ID_STRING) { + auto res = ParseStringLiteral(); + if (!res) { + return false; + } + + attribute_value = res.value(); + } else if (eq) { + attribute_value = context_.GiveToken(); + } else { + attribute_name = context_.GiveToken(); + } + + ++context_; + + if (context_.Mask()) { + return false; + } + + if (*context_ == Token::Type::DEL_EQ) { + if (eq) { + context_.err = GetError("Unexpected '='.", Error::ErrorType::ERR_BAD_NOEXP_DELIM); + return false; + } + + ++context_; + eq = true; + } else { + std::optional res; + bool has_value = eq; + if (has_value) { + res = metadata_->SetAttributeValue(attribute_name, attribute_value); + } else { + res = metadata_->SetAttribute(attribute_name); + } + + eq = false; + + if (res) { + auto err = res.value(); + SetMetadataContextError(err, has_value); + return false; + } + } + + return true; +} + +bool Parser::ParseMetaList(bool flag) +{ + if (!flag && !context_.Mask() && *context_ != Token::Type::DEL_GT && *context_ != Token::Type::DEL_BRACE_L) { + context_.err = GetError("No meta data expected.", Error::ErrorType::ERR_BAD_DEFINITION_METADATA); + return false; + } + + bool comma = false; + bool eq = false; + + std::string attribute_name; + std::string attribute_value; + + while (true) { + if (context_.Mask()) { + context_.err = GetError("Expected '>'.", Error::ErrorType::ERR_BAD_METADATA_BOUND, +1); + return false; + } + + if (context_.id != Token::Type::DEL_COMMA && context_.id != Token::Type::ID && + context_.id != Token::Type::ID_STRING && context_.id != Token::Type::DEL_EQ) { + break; + } + + if (!ParseMetaListComma(comma, eq)) { + return false; + } + + if (!MeetExpMetaList(eq)) { + return false; + } + + if (!BuildMetaListAttr(eq, attribute_name, attribute_value)) { + return false; + } + } + + if (flag && *context_ != Token::Type::DEL_GT) { + context_.err = GetError("Expected '>'.", Error::ErrorType::ERR_BAD_METADATA_BOUND); + ++context_; + + return false; + } + + auto res = metadata_->ValidateData(); + if (res) { + auto err = res.value(); + SetMetadataContextError(err, false); + return false; + } + + return true; +} + +bool Parser::ParseFunctionInstruction() +{ + if (ParseLabel()) { + if (ParseOperation()) { + if (ParseOperands()) { + return true; + } + } + } + + return context_.Mask(); +} + +} // namespace panda::pandasm diff --git a/assembler/assembly-parser.h b/assembler/assembly-parser.h new file mode 100644 index 0000000000..1cfc5ceb11 --- /dev/null +++ b/assembler/assembly-parser.h @@ -0,0 +1,250 @@ +/* + * 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_ASSEMBLER_ASSEMBLY_PARSER_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_PARSER_H_ + +#include +#include +#include +#include + +#include "assembly-context.h" +#include "assembly-emitter.h" +#include "assembly-field.h" +#include "assembly-function.h" +#include "assembly-ins.h" +#include "assembly-label.h" +#include "assembly-program.h" +#include "assembly-record.h" +#include "assembly-type.h" +#include "define.h" +#include "error.h" +#include "ide_helpers.h" +#include "lexer.h" +#include "meta.h" +#include "utils/expected.h" + +namespace panda::pandasm { + +using Instructions = std::pair, Error>; + +using Functions = std::pair, std::unordered_map>; + +class Parser { +public: + Parser() = default; + + NO_MOVE_SEMANTIC(Parser); + NO_COPY_SEMANTIC(Parser); + + ~Parser() = default; + + /* + * The main function of parsing, which takes a vector of token vectors and a name of the source file. + * Returns a program or an error value: Expected + * This function analyzes code containing several functions: + * - Each function used must be declared. + * - The correct function declaration looks like this: .function ret_type fun_name([param_type aN,]) [] + * ([data] shows that this 'data' is optional). + * - N in function parameters must increase when number of parameters increases + * (Possible: a0, a1,..., aN. Impossible: a1, a10, a13). + * - Each function has its own label table. + */ + Expected Parse(TokenSet &vectors_tokens, const std::string &file_name = ""); + + /* + * The main function of parsing, which takes a string with source and a name of the source file. + * Returns a program or an error value: Expected + */ + Expected Parse(const std::string &source, const std::string &file_name = ""); + + /* + * Returns a set error + */ + Error ShowError() const + { + return err_; + } + + ErrorList ShowWarnings() const + { + return war_; + } + +private: + panda::pandasm::Program program_; + std::unordered_map *label_table_ = nullptr; + Metadata *metadata_ = nullptr; + Context context_; /* token iterator */ + panda::pandasm::Record *curr_record_ = nullptr; + panda::pandasm::Function *curr_func_ = nullptr; + panda::pandasm::Ins *curr_ins_ = nullptr; + panda::pandasm::Field *curr_fld_ = nullptr; + size_t line_stric_ = 0; + panda::pandasm::Error err_; + panda::pandasm::ErrorList war_; + bool open_ = false; /* flag of being in a code section */ + bool record_def_ = false; + bool func_def_ = false; + + inline Error GetError(const std::string &mess = "", Error::ErrorType err = Error::ErrorType::ERR_NONE, + int8_t shift = 0, int token_shift = 0, const std::string &add_mess = "") const + { + return Error(mess, line_stric_, err, add_mess, + context_.tokens[context_.number + token_shift - 1].bound_left + shift, + context_.tokens[context_.number + token_shift - 1].bound_right, + context_.tokens[context_.number + token_shift - 1].whole_line); + } + + inline void GetWarning(const std::string &mess = "", Error::ErrorType err = Error::ErrorType::ERR_NONE, + int8_t shift = 0, const std::string &add_mess = "") + { + war_.emplace_back(mess, line_stric_, err, add_mess, context_.tokens[context_.number - 1].bound_left + shift, + context_.tokens[context_.number - 1].bound_right, + context_.tokens[context_.number - 1].whole_line, Error::ErrorClass::WARNING); + } + + SourcePosition GetCurrentPosition(bool left_bound) const + { + if (left_bound) { + return SourcePosition {line_stric_, context_.tokens[context_.number - 1].bound_left}; + } + return SourcePosition {line_stric_, context_.tokens[context_.number - 1].bound_right}; + } + + bool LabelValidName(); + bool TypeValidName(); + bool RegValidName(); + bool ParamValidName(); + bool FunctionValidName(); + bool ParseFunctionName(); + bool ParseLabel(); + bool ParseOperation(); + bool ParseOperands(); + bool ParseFunctionCode(); + bool ParseFunctionInstruction(); + bool ParseFunctionFullSign(); + bool ParseFunctionReturn(); + bool ParseFunctionArg(); + bool ParseFunctionArgComma(bool &comma); + bool ParseFunctionArgs(); + bool ParseType(Type *type); + bool PrefixedValidName(); + bool ParseMetaListComma(bool &comma, bool eq); + bool MeetExpMetaList(bool eq); + bool BuildMetaListAttr(bool &eq, std::string &attribute_name, std::string &attribute_value); + bool ParseMetaList(bool flag); + bool ParseMetaDef(); + bool ParseRecordFullSign(); + bool ParseRecordFields(); + bool ParseRecordField(); + bool ParseRecordName(); + bool RecordValidName(); + bool ParseFieldName(); + bool ParseFieldType(); + std::optional ParseStringLiteral(); + int64_t MnemonicToBuiltinId(); + + bool ParseOperandVreg(); + bool ParseOperandComma(); + bool ParseOperandInteger(); + bool ParseOperandFloat(); + bool ParseOperandId(); + bool ParseOperandLabel(); + bool ParseOperandField(); + bool ParseOperandType(Type::VerificationType ver_type); + bool ParseOperandNone(); + bool ParseOperandString(); + bool ParseOperandCall(); + bool ParseOperandBuiltinMnemonic(); + + void SetFunctionInformation(); + void SetRecordInformation(); + void SetOperationInformation(); + void ParseAsCatchall(const std::vector &tokens); + void ParseAsLanguage(const std::vector &tokens, bool &is_lang_parsed, bool &is_first_statement); + void ParseAsRecord(const std::vector &tokens); + void ParseAsFunction(const std::vector &tokens); + void ParseAsBraceRight(const std::vector &tokens); + bool ParseAfterLine(bool &is_first_statement); + Expected ParseAfterMainLoop(const std::string &file_name); + void ParseResetFunctionLabelsAndParams(); + void ParseResetTables(); + void ParseResetFunctionTable(); + void ParseResetRecordTable(); + void ParseAsLanguageDirective(); + Function::CatchBlock PrepareCatchBlock(bool is_catchall, size_t size, size_t catchall_tokens_num, + size_t catch_tokens_num); + void ParseAsCatchDirective(); + void SetError(); + void SetMetadataContextError(const Metadata::Error &err, bool has_value); + + Expected ParseOctalEscapeSequence(std::string_view s, size_t *i); + Expected ParseHexEscapeSequence(std::string_view s, size_t *i); + Expected ParseEscapeSequence(std::string_view s, size_t *i); + + template + auto TryEmplaceInTable(bool flag, T &item) + { + return item.try_emplace(std::string(context_.GiveToken().data(), context_.GiveToken().length()), + std::string(context_.GiveToken().data(), context_.GiveToken().length()), program_.lang, + context_.tokens[context_.number - 1].bound_left, + context_.tokens[context_.number - 1].bound_right, + context_.tokens[context_.number - 1].whole_line, flag, line_stric_); + } + + template + bool AddObjectInTable(bool flag, T &item) + { + auto [iter, is_inserted] = TryEmplaceInTable(flag, item); + + if (is_inserted) { + return true; + } + + if (iter->second.file_location->is_defined && flag) { + return false; + } + + if (!iter->second.file_location->is_defined && flag) { + iter->second.file_location->is_defined = true; + return true; + } + + if (!iter->second.file_location->is_defined) { + iter->second.file_location->bound_left = context_.tokens[context_.number - 1].bound_left; + iter->second.file_location->bound_right = context_.tokens[context_.number - 1].bound_right; + iter->second.file_location->whole_line = context_.tokens[context_.number - 1].whole_line; + iter->second.file_location->line_number = line_stric_; + } + + return true; + } +}; + +template <> +inline auto Parser::TryEmplaceInTable(bool flag, std::unordered_map &item) +{ + return item.try_emplace(std::string(context_.GiveToken().data(), context_.GiveToken().length()), + std::string(context_.GiveToken().data(), context_.GiveToken().length()), + context_.tokens[context_.number - 1].bound_left, + context_.tokens[context_.number - 1].bound_right, + context_.tokens[context_.number - 1].whole_line, flag, line_stric_); +} + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ASSEMBLY_PARSER_H_ diff --git a/assembler/assembly-program.cpp b/assembler/assembly-program.cpp new file mode 100644 index 0000000000..7347180322 --- /dev/null +++ b/assembler/assembly-program.cpp @@ -0,0 +1,35 @@ +/* + * 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-program.h" + +#include + +#include "ide_helpers.h" + +namespace panda::pandasm { + +std::string Program::JsonDump() const +{ + std::stringstream ss; + ss << "{ \"functions\": "; + ss << JsonSerializeProgramItems(function_table); + ss << ", \"records\": "; + ss << JsonSerializeProgramItems(record_table); + ss << " }"; + return ss.str(); +} + +} // namespace panda::pandasm diff --git a/assembler/assembly-program.h b/assembler/assembly-program.h new file mode 100644 index 0000000000..664c9283aa --- /dev/null +++ b/assembler/assembly-program.h @@ -0,0 +1,48 @@ +/* + * 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_ASSEMBLER_ASSEMBLY_PROGRAM_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_PROGRAM_H_ + +#include +#include + +#include "assembly-function.h" +#include "assembly-record.h" +#include "assembly-type.h" +#include "assembly-methodhandle.h" +#include "assembly-literals.h" +#include "extensions/extensions.h" +#include "macros.h" + +namespace panda::pandasm { + +struct Program { + extensions::Language lang {extensions::Language::PANDA_ASSEMBLY}; + std::unordered_map record_table; + std::unordered_map function_table; + std::map literalarray_table; + std::unordered_set strings; + std::unordered_set array_types; + + /* + * Returns a JSON string with the program structure and scopes locations + */ + std::string JsonDump() const; +}; + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ASSEMBLY_PROGRAM_H_ diff --git a/assembler/assembly-record.h b/assembler/assembly-record.h new file mode 100644 index 0000000000..6e8c8a012e --- /dev/null +++ b/assembler/assembly-record.h @@ -0,0 +1,64 @@ +/* + * 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_ASSEMBLER_ASSEMBLY_RECORD_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_RECORD_H_ + +#include +#include +#include +#include + +#include "assembly-field.h" +#include "assembly-file-location.h" +#include "extensions/extensions.h" +#include "ide_helpers.h" + +namespace panda::pandasm { + +struct Record { + std::string name = ""; + bool conflict = false; /* Name conflicts with panda primitive types. Need special handle. */ + extensions::Language language; + std::unique_ptr metadata; + std::vector field_list; /* class fields list */ + size_t params_num = 0; + bool body_presence = false; + SourceLocation body_location; + std::string source_file; /* The file in which the record is defined or empty */ + std::optional file_location; + + Record(std::string s, extensions::Language lang, size_t b_l, size_t b_r, std::string f_c, bool d, size_t l_n) + : name(std::move(s)), + language(lang), + metadata(extensions::MetadataExtension::CreateRecordMetadata(lang)), + file_location({f_c, b_l, b_r, l_n, d}) + { + } + + Record(std::string s, extensions::Language lang) + : name(std::move(s)), language(lang), metadata(extensions::MetadataExtension::CreateRecordMetadata(lang)) + { + } + + bool HasImplementation() const + { + return !metadata->IsForeign(); + } +}; + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ASSEMBLY_RECORD_H_ diff --git a/assembler/assembly-type.cpp b/assembler/assembly-type.cpp new file mode 100644 index 0000000000..8b69ca5125 --- /dev/null +++ b/assembler/assembly-type.cpp @@ -0,0 +1,124 @@ +/* + * 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 "assembly-type.h" + +namespace panda::pandasm { + +static std::unordered_map primitive_types = { + {"u1", "Z"}, {"i8", "B"}, {"u8", "H"}, {"i16", "S"}, {"u16", "C"}, {"i32", "I"}, {"u32", "U"}, + {"f32", "F"}, {"f64", "D"}, {"i64", "J"}, {"u64", "Q"}, {"void", "V"}, {"any", "A"}}; + +std::string Type::GetDescriptor(bool ignore_primitive) const +{ + if (!ignore_primitive) { + auto it = primitive_types.find(component_name_); + if (it != primitive_types.cend()) { + return std::string(rank_, '[') + it->second.data(); + } + } + + std::string res = std::string(rank_, '[') + "L" + component_name_ + ";"; + std::replace(res.begin(), res.end(), '.', '/'); + return res; +} + +/* static */ +panda_file::Type::TypeId Type::GetId(std::string_view name, bool ignore_primitive) +{ + static std::unordered_map panda_types = { +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define PANDATYPE(name, inst_code) {std::string_view(name), panda_file::Type::TypeId::inst_code}, + PANDA_ASSEMBLER_TYPES(PANDATYPE) +#undef PANDATYPE + }; + + if (!ignore_primitive) { + auto iter = panda_types.find(name); + if (iter == panda_types.end()) { + return panda_file::Type::TypeId::REFERENCE; + } + return iter->second; + } + return panda_file::Type::TypeId::REFERENCE; +} + +/* static */ +std::string Type::GetName(std::string_view component_name, size_t rank) +{ + std::string name(component_name); + while (rank-- > 0) { + name += "[]"; + } + return name; +} + +/* static */ +Type Type::FromDescriptor(std::string_view descriptor) +{ + static std::unordered_map reverse_primitive_types = { + {"Z", "u1"}, {"B", "i8"}, {"H", "u8"}, {"S", "i16"}, {"C", "u16"}, {"I", "i32"}, {"U", "u32"}, + {"F", "f32"}, {"D", "f64"}, {"J", "i64"}, {"Q", "u64"}, {"V", "void"}, {"A", "any"}}; + + size_t i = 0; + while (descriptor[i] == '[') { + ++i; + } + + size_t rank = i; + bool is_ref_type = descriptor[i] == 'L'; + if (is_ref_type) { + descriptor.remove_suffix(1); /* Remove semicolon */ + ++i; + } + + descriptor.remove_prefix(i); + + if (is_ref_type) { + return Type(descriptor, rank); + } + return Type(reverse_primitive_types[descriptor], rank); +} + +/* static */ +Type Type::FromName(std::string_view name, bool ignore_primitive) +{ + constexpr size_t STEP = 2; + + size_t size = name.size(); + size_t i = 0; + + while (name[size - i - 1] == ']') { + i += STEP; + } + + name.remove_suffix(i); + return Type(name, i / STEP, ignore_primitive); +} + +/* static */ +bool Type::IsPandaPrimitiveType(const std::string &name) +{ + auto it = primitive_types.find(name); + if (it != primitive_types.cend()) { + return true; + } else { + return false; + } +} + +} // namespace panda::pandasm diff --git a/assembler/assembly-type.h b/assembler/assembly-type.h new file mode 100644 index 0000000000..d826a55ed0 --- /dev/null +++ b/assembler/assembly-type.h @@ -0,0 +1,187 @@ +/* + * 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_ASSEMBLER_ASSEMBLY_TYPE_H_ +#define PANDA_ASSEMBLER_ASSEMBLY_TYPE_H_ + +#include "define.h" +#include "file_items.h" +#include "isa.h" + +namespace panda::pandasm { + +class Type { +public: + enum VerificationType { + TYPE_ID_OBJECT, + TYPE_ID_ARRAY, + TYPE_ID_ANY_OBJECT, + }; + + Type() = default; + DEFAULT_MOVE_SEMANTIC(Type); + DEFAULT_COPY_SEMANTIC(Type); + ~Type() = default; + + Type(std::string_view component_name, size_t rank, bool ignore_primitive = false) + : component_name_(component_name), rank_(rank) + { + name_ = GetName(component_name_, rank_); + type_id_ = GetId(name_, ignore_primitive); + } + + Type(const Type &component_type, size_t rank) + : Type(component_type.GetComponentName(), component_type.GetRank() + rank) + { + } + + std::string GetDescriptor(bool ignore_primitive = false) const; + + std::string GetName() const + { + return name_; + } + + std::string GetComponentName() const + { + return component_name_; + } + + size_t GetRank() const + { + return rank_; + } + + Type GetComponentType() const + { + return Type(component_name_, rank_ > 0 ? rank_ - 1 : 0); + } + + panda_file::Type::TypeId GetId() const + { + return type_id_; + } + + bool IsArrayContainsPrimTypes() const + { + auto elem = GetId(component_name_); + return elem != panda_file::Type::TypeId::REFERENCE; + } + + bool IsValid() const + { + return !component_name_.empty(); + } + + bool IsArray() const + { + return rank_ > 0; + } + + bool IsObject() const + { + return type_id_ == panda_file::Type::TypeId::REFERENCE; + } + + bool IsTagged() const + { + return type_id_ == panda_file::Type::TypeId::TAGGED; + } + + bool IsIntegral() const + { + return type_id_ == panda_file::Type::TypeId::U1 || type_id_ == panda_file::Type::TypeId::U8 || + type_id_ == panda_file::Type::TypeId::I8 || type_id_ == panda_file::Type::TypeId::U16 || + type_id_ == panda_file::Type::TypeId::I16 || type_id_ == panda_file::Type::TypeId::U32 || + type_id_ == panda_file::Type::TypeId::I32 || type_id_ == panda_file::Type::TypeId::U64 || + type_id_ == panda_file::Type::TypeId::I64; + } + + bool FitsInto32() const + { + return type_id_ == panda_file::Type::TypeId::U1 || type_id_ == panda_file::Type::TypeId::U8 || + type_id_ == panda_file::Type::TypeId::I8 || type_id_ == panda_file::Type::TypeId::U16 || + type_id_ == panda_file::Type::TypeId::I16 || type_id_ == panda_file::Type::TypeId::U32 || + type_id_ == panda_file::Type::TypeId::I32; + } + + bool IsFloat32() const + { + return type_id_ == panda_file::Type::TypeId::F32; + } + + bool IsFloat64() const + { + return type_id_ == panda_file::Type::TypeId::F64; + } + + bool IsPrim32() const + { + return (IsIntegral() && FitsInto32()) || IsFloat32(); + } + + bool IsPrim64() const + { + return (IsIntegral() && !FitsInto32()) || IsFloat64(); + } + + bool IsPrimitive() const + { + return IsPrim64() || IsPrim32(); + } + + bool IsVoid() const + { + return type_id_ == panda_file::Type::TypeId::VOID; + } + + static panda_file::Type::TypeId GetId(std::string_view name, bool ignore_primitive = false); + + bool operator==(const Type &type) const + { + return name_ == type.name_; + } + + static Type FromDescriptor(std::string_view descriptor); + + static Type FromName(std::string_view name, bool ignore_primitive = false); + + static bool IsPandaPrimitiveType(const std::string &name); + +private: + static std::string GetName(std::string_view component_name, size_t rank); + + std::string component_name_; + size_t rank_ {0}; + std::string name_; + panda_file::Type::TypeId type_id_ {panda_file::Type::TypeId::VOID}; +}; + +} // namespace panda::pandasm + +namespace std { + +template <> +class hash { +public: + size_t operator()(const panda::pandasm::Type &type) const + { + return std::hash()(type.GetName()); + } +}; + +} // namespace std + +#endif // PANDA_ASSEMBLER_ASSEMBLY_TYPE_H_ diff --git a/assembler/context.cpp b/assembler/context.cpp new file mode 100644 index 0000000000..9fcd933acc --- /dev/null +++ b/assembler/context.cpp @@ -0,0 +1,196 @@ +/* + * 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 "assembly-parser.h" +#include "utils/number-utils.h" + +namespace panda::pandasm { + +void Context::Make(const std::vector &t) +{ + err = {}; + ins_number = 0; + tokens = t; + number = 1; + end = false; + + token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left), + tokens[number - 1].bound_right - tokens[number - 1].bound_left); + + id = this->tokens[number - 1].type; +} + +size_t Context::Len() const +{ + return token.size(); +} + +bool Context::ValidateRegisterName(char c, size_t n) const +{ + if (token[0] == c) { + std::string_view p = token; + p.remove_prefix(1); + if (p.empty() || (p.size() > 1 && p[0] == '0')) { + return false; + } + + if (c != 'a') { + for (const auto &ch : p) { + if (std::isdigit(ch) == 0) { + return false; + } + } + } else { + if (ToNumber(p) > n) { + return false; + } + } + + return true; + } + + return false; +} + +bool Context::ValidateParameterName(size_t number_of_params_already_is) const +{ + if (number_of_params_already_is >= MAX_DWORD) { + return false; + } + + if (token[0] == 'a') { + std::string_view p = token; + p.remove_prefix(1); + if (ToNumber(p) == number_of_params_already_is) { + return true; + } + } + + return false; +} + +std::string_view Context::GiveToken() +{ + return token; +} + +Token::Type Context::Next() +{ + if (this->tokens.size() > number) { + return this->tokens[number].type; + } + + return this->tokens[number - 1].type; +} + +void Context::UpSignOperation() +{ + signop = id; +} + +Token::Type Context::WaitFor() +{ + return signop; +} + +bool Context::Mask() +{ + return end; +} + +bool Context::NextMask() +{ + if (end) { + return true; + } + + return this->tokens.size() < number + 1; +} + +// NOLINTNEXTLINE(cert-dcl21-cpp) +Token::Type Context::operator++(int) +{ + Token::Type last_id = id; + + if (this->tokens.size() > number) { + ++number; + id = this->tokens[number - 1].type; + + token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left), + tokens[number - 1].bound_right - tokens[number - 1].bound_left); + } else { + end = true; + } + + return last_id; +} + +Token::Type Context::operator++() +{ + if (this->tokens.size() > number) { + ++number; + id = this->tokens[number - 1].type; + + token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left), + tokens[number - 1].bound_right - tokens[number - 1].bound_left); + } else { + end = true; + } + + return id; +} + +// NOLINTNEXTLINE(cert-dcl21-cpp) +Token::Type Context::operator--(int) +{ + Token::Type last_id = id; + + if (number > 1) { + end = false; + --number; + id = this->tokens[number - 1].type; + + token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left), + tokens[number - 1].bound_right - tokens[number - 1].bound_left); + } else { + end = false; + } + + return last_id; +} + +Token::Type Context::operator--() +{ + if (number > 1) { + end = false; + --number; + id = this->tokens[number - 1].type; + + token = std::string_view(&*(tokens[number - 1].whole_line.begin() + tokens[number - 1].bound_left), + tokens[number - 1].bound_right - tokens[number - 1].bound_left); + } else { + end = false; + } + + return id; +} + +Token::Type Context::operator*() +{ + return id; +} + +} // namespace panda::pandasm diff --git a/assembler/define.h b/assembler/define.h new file mode 100644 index 0000000000..f4b76dce97 --- /dev/null +++ b/assembler/define.h @@ -0,0 +1,48 @@ +/* + * 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_ASSEMBLER_DEFINE_H_ +#define PANDA_ASSEMBLER_DEFINE_H_ + +/* Implementation-specific definitions */ + +constexpr char PARSE_COMMENT_MARKER = '#'; + +constexpr char PARSE_AREA_MARKER = '.'; + +#define PANDA_ASSEMBLER_TYPES(_) \ + _("void", VOID) \ + _("u1", U1) \ + _("u8", U8) \ + _("i8", I8) \ + _("u16", U16) \ + _("i16", I16) \ + _("u32", U32) \ + _("i32", I32) \ + _("u64", U64) \ + _("i64", I64) \ + _("f32", F32) \ + _("f64", F64) \ + _("any", TAGGED) + +#define KEYWORDS_LIST(_) \ + _(".catch", CATCH) \ + _(".catchall", CATCHALL) \ + _(".language", LANG) \ + _(".function", FUN) \ + _(".record", REC) \ + _(".field", FLD) + +#endif // PANDA_ASSEMBLER_DEFINE_H_ diff --git a/assembler/error.h b/assembler/error.h new file mode 100644 index 0000000000..57ca90df16 --- /dev/null +++ b/assembler/error.h @@ -0,0 +1,121 @@ +/* + * 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_ASSEMBLER_ERROR_H_ +#define PANDA_ASSEMBLER_ERROR_H_ + +#include + +#include "define.h" + +namespace panda::pandasm { + +struct Error { + enum class ErrorClass { WARNING = 0, ERROR }; + enum class ErrorType { + ERR_NONE = 0, + + // Lexer + ERR_STRING_MISSING_TERMINATING_CHARACTER, + + // Parser + ERR_BAD_LABEL, + ERR_BAD_LABEL_EXT, + ERR_BAD_NAME_ID, + ERR_BAD_NAME_REG, + ERR_BAD_INTEGER_NAME, + ERR_BAD_INTEGER_WIDTH, + ERR_BAD_FLOAT_NAME, + ERR_BAD_FLOAT_WIDTH, + ERR_BAD_NUMBER_OPERANDS, + ERR_BAD_OPERAND, + ERR_BAD_OPERATION_NAME, + ERR_BAD_NONEXISTING_OPERATION, + ERR_BAD_ID_FUNCTION, + ERR_BAD_ID_RECORD, + ERR_BAD_ID_FIELD, + ERR_BAD_FUNCTION_NAME, + ERR_BAD_RECORD_NAME, + ERR_BAD_DEFINITION_METADATA, + ERR_BAD_DEFINITION_FUNCTION, + ERR_BAD_DEFINITION_RECORD, + ERR_BAD_METADATA_BOUND, + ERR_BAD_METADATA_UNKNOWN_ATTRIBUTE, + ERR_BAD_METADATA_INVALID_VALUE, + ERR_BAD_METADATA_MISSING_ATTRIBUTE, + ERR_BAD_METADATA_MISSING_VALUE, + ERR_BAD_METADATA_UNEXPECTED_ATTRIBUTE, + ERR_BAD_METADATA_UNEXPECTED_VALUE, + ERR_BAD_METADATA_MULTIPLE_ATTRIBUTE, + ERR_BAD_FUNCTION_PARAMETERS, + ERR_BAD_FUNCTION_RETURN_VALUE, + ERR_FUNCTION_ARGUMENT_MISMATCH, + ERR_BAD_FIELD_MISSING_NAME, + ERR_BAD_FIELD_VALUE_TYPE, + ERR_BAD_CHARACTER, + ERR_BAD_KEYWORD, + ERR_BAD_DEFINITION, + ERR_BAD_BOUND, + ERR_BAD_END, + ERR_BAD_CLOSE, + ERR_BAD_ARGS_BOUND, + ERR_BAD_TYPE, + ERR_BAD_PARAM_NAME, + ERR_BAD_NOEXP_DELIM, + ERR_BAD_STRING_INVALID_HEX_ESCAPE_SEQUENCE, + ERR_BAD_STRING_UNKNOWN_ESCAPE_SEQUENCE, + ERR_BAD_ARRAY_TYPE_BOUND, + ERR_UNDEFINED_TYPE, + ERR_MULTIPLE_DIRECTIVES, + ERR_INCORRECT_DIRECTIVE_LOCATION, + ERR_BAD_DIRECTIVE_DECLARATION, + ERR_UNKNOWN_LANGUAGE, + ERR_BAD_MNEMONIC_NAME, + ERR_REPEATING_FIELD_NAME, + + // Warnings + WAR_UNEXPECTED_RETURN_TYPE, + WAR_UNEXPECTED_TYPE_ID, + }; + + ErrorClass type; + std::string whole_line; + size_t pos; // position to highlight the word + size_t end; + ErrorType err; + std::string message; + std::string verbose; + size_t line_number; + + inline Error() : Error("No messages", 0, ErrorType::ERR_NONE, "", 0, 0, "") {} + + inline Error(std::string s, size_t line, ErrorType error_type, std::string overinfo, size_t p, size_t e, + std::string buff, ErrorClass class_type = ErrorClass::ERROR) + : type(class_type), + whole_line(std::move(buff)), + pos(p), + end(e), + err(error_type), + message(std::move(s)), + verbose(std::move(overinfo)), + line_number(line) + { + } +}; + +using ErrorList = std::vector; +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_ERROR_H_ diff --git a/assembler/extensions/ecmascript/ecmascript_meta.cpp b/assembler/extensions/ecmascript/ecmascript_meta.cpp new file mode 100644 index 0000000000..412d024ab4 --- /dev/null +++ b/assembler/extensions/ecmascript/ecmascript_meta.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript_meta.h" + +namespace panda::pandasm::extensions::ecmascript { + +#include + +} // namespace panda::pandasm::extensions::ecmascript diff --git a/assembler/extensions/ecmascript/ecmascript_meta.h b/assembler/extensions/ecmascript/ecmascript_meta.h new file mode 100644 index 0000000000..410742467f --- /dev/null +++ b/assembler/extensions/ecmascript/ecmascript_meta.h @@ -0,0 +1,231 @@ +/* + * 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_ASSEMBLER_EXTENSIONS_ECMASCRIPT_ECMASCRIPT_META_H_ +#define PANDA_ASSEMBLER_EXTENSIONS_ECMASCRIPT_ECMASCRIPT_META_H_ + +#include "meta.h" + +namespace panda::pandasm::extensions::ecmascript { + +class RecordMetadata : public pandasm::RecordMetadata { +public: + std::string GetBase() const override + { + auto base = GetAttributeValue("ecmascript.extends"); + if (base) { + return base.value(); + } + + return ""; + } + + std::vector GetInterfaces() const override + { + return {}; + } + + bool IsAnnotation() const override + { + return (GetAccessFlags() & ACC_ANNOTATION) != 0; + } + + bool IsRuntimeAnnotation() const override + { + return false; + } + +protected: + bool IsAnnotationRecordAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationIdAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementNameAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementTypeAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementArrayComponentTypeAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementValueAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + std::optional Validate(std::string_view attribute) const override; + + std::optional Validate(std::string_view attribute, std::string_view value) const override; + + void SetFlags(std::string_view attribute) override; + + void SetFlags(std::string_view attribute, std::string_view value) override; + + void RemoveFlags(std::string_view attribute) override; + + void RemoveFlags(std::string_view attribute, std::string_view value) override; +}; + +class FieldMetadata : public pandasm::FieldMetadata { +protected: + bool IsAnnotationRecordAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationIdAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementNameAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementTypeAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementArrayComponentTypeAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementValueAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + std::optional Validate(std::string_view attribute) const override; + + std::optional Validate(std::string_view attribute, std::string_view value) const override; + + void SetFlags(std::string_view attribute) override; + + void SetFlags(std::string_view attribute, std::string_view value) override; + + void RemoveFlags(std::string_view attribute) override; + + void RemoveFlags(std::string_view attribute, std::string_view value) override; +}; + +class FunctionMetadata : public pandasm::FunctionMetadata { +protected: + bool IsAnnotationRecordAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationIdAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementNameAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementTypeAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementArrayComponentTypeAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementValueAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + std::optional Validate(std::string_view attribute) const override; + + std::optional Validate(std::string_view attribute, std::string_view value) const override; + + void SetFlags(std::string_view attribute) override; + + void SetFlags(std::string_view attribute, std::string_view value) override; + + void RemoveFlags(std::string_view attribute) override; + + void RemoveFlags(std::string_view attribute, std::string_view value) override; +}; + +class ParamMetadata : public pandasm::ParamMetadata { +protected: + bool IsAnnotationRecordAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationIdAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementNameAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementTypeAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementArrayComponentTypeAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + bool IsAnnotationElementValueAttribute([[maybe_unused]] std::string_view attribute) const override + { + return false; + } + + std::optional Validate(std::string_view attribute) const override; + + std::optional Validate(std::string_view attribute, std::string_view value) const override; + + void SetFlags(std::string_view attribute) override; + + void SetFlags(std::string_view attribute, std::string_view value) override; + + void RemoveFlags(std::string_view attribute) override; + + void RemoveFlags(std::string_view attribute, std::string_view value) override; +}; + +} // namespace panda::pandasm::extensions::ecmascript + +#endif // PANDA_ASSEMBLER_EXTENSIONS_ECMASCRIPT_ECMASCRIPT_META_H_ diff --git a/assembler/extensions/ecmascript/metadata.yaml b/assembler/extensions/ecmascript/metadata.yaml new file mode 100644 index 0000000000..5673329fd2 --- /dev/null +++ b/assembler/extensions/ecmascript/metadata.yaml @@ -0,0 +1,27 @@ +# 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. + +language: EcmaScript + +attributes: +- name: annotation + type: bool + flags: [ACC_ANNOTATION] + applicable_to: + - record + +- name: extends + type: record + multiple: false + applicable_to: + - record diff --git a/assembler/extensions/extensions.cpp b/assembler/extensions/extensions.cpp new file mode 100644 index 0000000000..e22ab08989 --- /dev/null +++ b/assembler/extensions/extensions.cpp @@ -0,0 +1,142 @@ +/* + * 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 "extensions.h" +#include "ecmascript/ecmascript_meta.h" +#include "macros.h" + +namespace panda::pandasm::extensions { + +std::optional LanguageFromString(std::string_view lang) +{ + if (lang == "ECMAScript") { + return Language::ECMASCRIPT; + } + + if (lang == "PandaAssembly") { + return Language::PANDA_ASSEMBLY; + } + + return {}; +} + +std::string LanguageToString(const Language &lang) +{ + if (lang == Language::ECMASCRIPT) { + return "ECMAScript"; + } + + if (lang == Language::PANDA_ASSEMBLY) { + return "PandaAssembly"; + } + + return {}; +} + +std::string GetCtorName(Language lang) +{ + switch (lang) { + case Language::ECMASCRIPT: + return ".ctor"; + case Language::PANDA_ASSEMBLY: + return ".ctor"; + default: + break; + } + + UNREACHABLE(); + return {}; +} + +std::string GetCctorName(Language lang) +{ + switch (lang) { + case Language::ECMASCRIPT: + return ".cctor"; + case Language::PANDA_ASSEMBLY: + return ".cctor"; + default: + break; + } + + UNREACHABLE(); + return {}; +} + +/* static */ +std::unique_ptr MetadataExtension::CreateRecordMetadata(Language lang) +{ + switch (lang) { + case Language::ECMASCRIPT: + return std::make_unique(); + case Language::PANDA_ASSEMBLY: + return std::make_unique(); + default: + break; + } + + UNREACHABLE(); + return {}; +} + +/* static */ +std::unique_ptr MetadataExtension::CreateFieldMetadata(Language lang) +{ + switch (lang) { + case Language::ECMASCRIPT: + return std::make_unique(); + case Language::PANDA_ASSEMBLY: + return std::make_unique(); + default: + break; + } + + UNREACHABLE(); + return {}; +} + +/* static */ +std::unique_ptr MetadataExtension::CreateFunctionMetadata(Language lang) +{ + switch (lang) { + case Language::ECMASCRIPT: + return std::make_unique(); + case Language::PANDA_ASSEMBLY: + return std::make_unique(); + default: + break; + } + + UNREACHABLE(); + return {}; +} + +/* static */ +std::unique_ptr MetadataExtension::CreateParamMetadata(Language lang) +{ + switch (lang) { + case Language::ECMASCRIPT: + return std::make_unique(); + case Language::PANDA_ASSEMBLY: + return std::make_unique(); + default: + break; + } + + UNREACHABLE(); + return {}; +} + +} // namespace panda::pandasm::extensions diff --git a/assembler/extensions/extensions.h b/assembler/extensions/extensions.h new file mode 100644 index 0000000000..4e4f2f0366 --- /dev/null +++ b/assembler/extensions/extensions.h @@ -0,0 +1,49 @@ +/* + * 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_ASSEMBLER_EXTENSIONS_EXTENSIONS_H_ +#define PANDA_ASSEMBLER_EXTENSIONS_EXTENSIONS_H_ + +#include +#include + +#include "meta.h" + +namespace panda::pandasm::extensions { + +enum class Language { ECMASCRIPT, PANDA_ASSEMBLY }; + +std::optional LanguageFromString(std::string_view lang); + +std::string LanguageToString(const Language &lang); + +std::string GetCtorName(Language lang); + +std::string GetCctorName(Language lang); + +class MetadataExtension { +public: + static std::unique_ptr CreateRecordMetadata(Language lang); + + static std::unique_ptr CreateFieldMetadata(Language lang); + + static std::unique_ptr CreateFunctionMetadata(Language lang); + + static std::unique_ptr CreateParamMetadata(Language lang); +}; + +} // namespace panda::pandasm::extensions + +#endif // PANDA_ASSEMBLER_EXTENSIONS_EXTENSIONS_H_ diff --git a/assembler/ide_helpers.h b/assembler/ide_helpers.h new file mode 100644 index 0000000000..a9b347ca30 --- /dev/null +++ b/assembler/ide_helpers.h @@ -0,0 +1,86 @@ +/* + * 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_ASSEMBLER_IDE_HELPERS_H_ +#define PANDA_ASSEMBLER_IDE_HELPERS_H_ + +#include + +namespace panda::pandasm { + +struct SourcePosition { + size_t line = 0; + size_t column = 0; + + std::string JsonSerialize() const + { + std::stringstream ss; + ss << "{ " + << "\"line\": " << line << ", " + << "\"column\": " << column << " }"; + return ss.str(); + } +}; + +struct SourceLocation { + SourcePosition begin; + SourcePosition end; + + std::string JsonSerialize() const + { + std::stringstream ss; + ss << "{ " + << "\"begin\": " << begin.JsonSerialize() << ", " + << "\"end\": " << end.JsonSerialize() << " }"; + return ss.str(); + } +}; + +template +std::string JsonSerializeItemBody(const T &item) +{ + std::stringstream ss; + std::string quoted_name = "\"" + item.name + "\""; + ss << "{ " + << "\"name\": " << quoted_name; + if (item.file_location->is_defined) { + ss << ", " + << "\"bodyLocation\": " << item.body_location.JsonSerialize() << " }"; + } else { + ss << " }"; + } + return ss.str(); +} + +template +std::string JsonSerializeProgramItems(const T &item_table) +{ + std::stringstream ss; + ss << "[ "; + auto it = item_table.begin(); + if (it != item_table.end()) { + ss << JsonSerializeItemBody(it->second); + ++it; + } + while (it != item_table.end()) { + ss << ", " << JsonSerializeItemBody(it->second); + ++it; + } + ss << " ]"; + return ss.str(); +} +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_IDE_HELPERS_H_ diff --git a/assembler/lexer.cpp b/assembler/lexer.cpp new file mode 100644 index 0000000000..40664f1ae1 --- /dev/null +++ b/assembler/lexer.cpp @@ -0,0 +1,386 @@ +/* + * 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 "lexer.h" + +namespace panda::pandasm { + +Token::Type FindDelim(char c) +{ + // The map of delimiters + static const std::unordered_map DELIM = {{',', Token::Type::DEL_COMMA}, + {':', Token::Type::DEL_COLON}, + {'{', Token::Type::DEL_BRACE_L}, + {'}', Token::Type::DEL_BRACE_R}, + {'(', Token::Type::DEL_BRACKET_L}, + {')', Token::Type::DEL_BRACKET_R}, + {'<', Token::Type::DEL_LT}, + {'>', Token::Type::DEL_GT}, + {'=', Token::Type::DEL_EQ}, + {'[', Token::Type::DEL_SQUARE_BRACKET_L}, + {']', Token::Type::DEL_SQUARE_BRACKET_R}}; + + auto iter = DELIM.find(c); + if (iter == DELIM.end()) { + return Token::Type::ID_BAD; + } + + return DELIM.at(c); +} + +Token::Type FindOperation(std::string_view s) +{ + // Generate the map of OPERATIONS from ISA + static const std::unordered_map OPERATIONS = { +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define OPLIST(inst_code, name, optype, width, flags, dst_idx, use_idxs) \ + {std::string_view(name), Token::Type::ID_OP_##inst_code}, + PANDA_INSTRUCTION_LIST(OPLIST) +#undef OPLIST + }; + + auto iter = OPERATIONS.find(s); + if (iter == OPERATIONS.end()) { + return Token::Type::ID_BAD; + } + + return OPERATIONS.at(s); +} + +Token::Type Findkeyword(std::string_view s) +{ + // Generate the map of KEYWORDS + static const std::unordered_map KEYWORDS = { +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define KEYWORDS(name, inst_code) {std::string_view(name), Token::Type::ID_##inst_code}, + KEYWORDS_LIST(KEYWORDS) +#undef KEYWORDS + }; + + auto iter = KEYWORDS.find(s); + if (iter == KEYWORDS.end()) { + return Token::Type::ID_BAD; + } + + return KEYWORDS.at(s); +} + +// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE) +std::string_view TokenTypeWhat(Token::Type t) +{ + if (t >= Token::Type::OPERATION && t < Token::Type::KEYWORD) { + return "OPERATION"; + } + + if (t >= Token::Type::KEYWORD) { + return "KEYWORD"; + } + + switch (t) { + case Token::Type::ID_BAD: { + return "ID_BAD"; + } + case Token::Type::DEL_COMMA: { + return "DEL_COMMA"; + } + case Token::Type::DEL_COLON: { + return "DEL_COLON"; + } + case Token::Type::DEL_BRACE_L: { + return "DEL_BRACE_L"; + } + case Token::Type::DEL_BRACE_R: { + return "DEL_BRACE_R"; + } + case Token::Type::DEL_BRACKET_L: { + return "DEL_BRACKET_L"; + } + case Token::Type::DEL_BRACKET_R: { + return "DEL_BRACKET_R"; + } + case Token::Type::DEL_SQUARE_BRACKET_L: { + return "DEL_SQUARE_BRACKET_L"; + } + case Token::Type::DEL_SQUARE_BRACKET_R: { + return "DEL_SQUARE_BRACKET_R"; + } + case Token::Type::DEL_GT: { + return "DEL_GT"; + } + case Token::Type::DEL_LT: { + return "DEL_LT"; + } + case Token::Type::DEL_EQ: { + return "DEL_EQ"; + } + case Token::Type::DEL_DOT: { + return "DEL_DOT"; + } + case Token::Type::ID: { + return "ID"; + } + case Token::Type::ID_STRING: { + return "ID_STRING"; + } + default: + return "NONE"; + } +} + +static bool IsQuote(char c) +{ + return c == '"'; +} + +Lexer::Lexer() : curr_line_(nullptr) +{ + LOG(DEBUG, ASSEMBLER) << "element of class Lexer initialized"; +} + +Lexer::~Lexer() +{ + LOG(DEBUG, ASSEMBLER) << "element of class Lexer destructed"; +} + +Tokens Lexer::TokenizeString(const std::string &source_str) +{ + LOG(DEBUG, ASSEMBLER) << "started tokenizing of line " << lines_.size() + 1 << ": "; + + lines_.emplace_back(source_str); + + curr_line_ = &lines_.back(); + + LOG(DEBUG, ASSEMBLER) << std::string_view(&*(curr_line_->buffer.begin() + curr_line_->pos), + curr_line_->end - curr_line_->pos); + + AnalyzeLine(); + + LOG(DEBUG, ASSEMBLER) << "tokenization of line " << lines_.size() << " is successful"; + LOG(DEBUG, ASSEMBLER) << " tokens identified: "; + + for (const auto &f_i : lines_.back().tokens) { + LOG(DEBUG, ASSEMBLER) << "\n " + << std::string_view(&*(f_i.whole_line.begin() + f_i.bound_left), + f_i.bound_right - f_i.bound_left) + << " (type: " << TokenTypeWhat(f_i.type) << ")"; + + LOG(DEBUG, ASSEMBLER); + LOG(DEBUG, ASSEMBLER); + } + return std::pair, Error>(lines_.back().tokens, err_); +} + +// End of line +bool Lexer::Eol() const +{ + return curr_line_->pos == curr_line_->end; +} + +// Return the type of token +Token::Type Lexer::LexGetType(size_t beg, size_t end) const +{ + if (FindDelim(curr_line_->buffer[beg]) != Token::Type::ID_BAD) { /* delimiter */ + return FindDelim(curr_line_->buffer[beg]); + } + + std::string_view p(&*(curr_line_->buffer.begin() + beg), end - beg); + Token::Type type = Findkeyword(p); + if (type != Token::Type::ID_BAD) { + return type; + } + + type = FindOperation(p); + if (type != Token::Type::ID_BAD) { + return type; + } + + if (IsQuote(curr_line_->buffer[beg])) { + return Token::Type::ID_STRING; + } + + return Token::Type::ID; // other +} + +// Handle string literal +bool Lexer::LexString() +{ + bool is_escape_seq = false; + char quote = curr_line_->buffer[curr_line_->pos]; + size_t begin = curr_line_->pos; + while (!Eol()) { + ++(curr_line_->pos); + + char c = curr_line_->buffer[curr_line_->pos]; + + if (is_escape_seq) { + is_escape_seq = false; + continue; + } + + if (c == '\\') { + is_escape_seq = true; + } + + if (c == quote) { + break; + } + } + + if (curr_line_->buffer[curr_line_->pos] != quote) { + err_ = Error(std::string("Missing terminating ") + quote + " character", 0, + Error::ErrorType::ERR_STRING_MISSING_TERMINATING_CHARACTER, "", begin, curr_line_->pos, + curr_line_->buffer); + return false; + } + + ++(curr_line_->pos); + + return true; +} + +/* + * Tokens handling: set the corresponding + * elements bound_left and bound_right of the array tokens + * to the first and last characters of a corresponding token. + * + * bound_r1 bound_r2 bound_r3 + * | | | + * v v v + * token1 token2 token3 ... token1 token2 token3 ... + * => ^ ^ ^ + * | | | + * bound1 bound2 bound3 ... bound_l1 bound_l2 bound_l3 ... + * + */ +void Lexer::LexTokens() +{ + if (Eol()) { + return; + } + + LOG(DEBUG, ASSEMBLER) << "token search started (line " << lines_.size() << "): " + << std::string_view(&*(curr_line_->buffer.begin() + curr_line_->pos), + curr_line_->end - curr_line_->pos); + + while (curr_line_->end > curr_line_->pos && isspace(curr_line_->buffer[curr_line_->end - 1]) != 0) { + --(curr_line_->end); + } + + while (isspace(curr_line_->buffer[curr_line_->pos]) != 0 && !Eol()) { + ++(curr_line_->pos); + } + + size_t bound_right; + size_t bound_left; + + for (int i = 0; !Eol(); ++i) { + bound_left = curr_line_->pos; + + if (FindDelim(curr_line_->buffer[curr_line_->pos]) != Token::Type::ID_BAD) { + ++(curr_line_->pos); + } else if (IsQuote(curr_line_->buffer[curr_line_->pos])) { + if (!LexString()) { + return; + } + } else { + while (!Eol() && FindDelim(curr_line_->buffer[curr_line_->pos]) == Token::Type::ID_BAD && + isspace(curr_line_->buffer[curr_line_->pos]) == 0) { + ++(curr_line_->pos); + } + } + + bound_right = curr_line_->pos; + + LOG(DEBUG, ASSEMBLER) << "token identified (line " << lines_.size() << ", " + << "token " << curr_line_->tokens.size() + 1 << "): " + << std::string_view(&*(curr_line_->buffer.begin() + bound_left), bound_right - bound_left) + << " (" + << "type: " << TokenTypeWhat(LexGetType(bound_left, bound_right)) << ")"; + + curr_line_->tokens.emplace_back(bound_left, bound_right, LexGetType(bound_left, bound_right), + curr_line_->buffer); + + while (isspace(curr_line_->buffer[curr_line_->pos]) != 0 && !Eol()) { + ++(curr_line_->pos); + } + } + + LOG(DEBUG, ASSEMBLER) << "all tokens identified (line " << lines_.size() << ")"; +} + +/* + * Ignore comments: + * find PARSE_COMMENT_MARKER and move line->end to another position + * next after the last character of the last significant (not a comment) + * element in a current line: line->buffer. + * + * Ex: + * [Label:] operation operand[,operand] [# comment] + * + * L1: mov v0, v1 # moving! L1: mov v0, v1 # moving! + * ^ => ^ + * | | + * end end + */ +void Lexer::LexPreprocess() +{ + LOG(DEBUG, ASSEMBLER) << "started removing comments (line " << lines_.size() << "): " + << std::string_view(&*(curr_line_->buffer.begin() + curr_line_->pos), + curr_line_->end - curr_line_->pos); + + size_t cmt_pos; + bool inside_str_lit; + + // Searching for comment marker located outside of the string literals. + inside_str_lit = curr_line_->buffer.size() > 0 && curr_line_->buffer[0] == '\"'; + cmt_pos = -1; + while ((cmt_pos = curr_line_->buffer.find_first_of("\"#", cmt_pos + 1)) != std::string::npos) { + if (cmt_pos != 0 && curr_line_->buffer[cmt_pos - 1] != '\\' && curr_line_->buffer[cmt_pos] == '\"') { + inside_str_lit = !inside_str_lit; + } else if (curr_line_->buffer[cmt_pos] == PARSE_COMMENT_MARKER && !inside_str_lit) { + break; + } + } + + if (cmt_pos != std::string::npos) { + curr_line_->end = cmt_pos; + } + + while (curr_line_->end > curr_line_->pos && isspace(curr_line_->buffer[curr_line_->end - 1]) != 0) { + --(curr_line_->end); + } + + LOG(DEBUG, ASSEMBLER) << "comments removed (line " << lines_.size() << "): " + << std::string_view(&*(curr_line_->buffer.begin() + curr_line_->pos), + curr_line_->end - curr_line_->pos); +} + +void Lexer::SkipSpace() +{ + while (!Eol() && isspace(curr_line_->buffer[curr_line_->pos]) != 0) { + ++(curr_line_->pos); + } +} + +void Lexer::AnalyzeLine() +{ + LexPreprocess(); + + SkipSpace(); + + LexTokens(); +} + +} // namespace panda::pandasm diff --git a/assembler/lexer.h b/assembler/lexer.h new file mode 100644 index 0000000000..1198dafc96 --- /dev/null +++ b/assembler/lexer.h @@ -0,0 +1,121 @@ +/* + * 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_ASSEMBLER_LEXER_H_ +#define PANDA_ASSEMBLER_LEXER_H_ + +#include +#include +#include +#include +#include +#include + +#include "define.h" +#include "error.h" +#include "isa.h" +#include "utils/logger.h" + +namespace panda::pandasm { + +struct Token { + enum class Type { + ID_BAD = 0, + /* delimiters */ + DEL_COMMA, /* , */ + DEL_COLON, /* : */ + DEL_BRACE_L, /* { */ + DEL_BRACE_R, /* } */ + DEL_BRACKET_L, /* ( */ + DEL_BRACKET_R, /* ) */ + DEL_SQUARE_BRACKET_L, /* [ */ + DEL_SQUARE_BRACKET_R, /* ] */ + DEL_GT, /* > */ + DEL_LT, /* < */ + DEL_EQ, /* = */ + DEL_DOT, /* . */ + ID, /* other */ + ID_STRING, /* string literal */ + OPERATION, /* special */ +#define OPLIST(inst_code, name, optype, width, flags, dst_idx, src_idxs) ID_OP_##inst_code, /* command type list */ + PANDA_INSTRUCTION_LIST(OPLIST) +#undef OPLIST + KEYWORD, /* special */ +#define KEYWORDS(name, inst_code) ID_##inst_code, /* keyword type list */ + KEYWORDS_LIST(KEYWORDS) +#undef KEYWORDS + }; + + std::string whole_line; + size_t bound_left; /* right and left bounds of tokens */ + size_t bound_right; + Type type; + + Token() : Token(0, 0, Type::ID_BAD, "") {} + + Token(size_t b_l, size_t b_r, Type t, std::string beg_of_line) + : whole_line(std::move(beg_of_line)), bound_left(b_l), bound_right(b_r), type(t) + { + } +}; + +using Tokens = std::pair, Error>; + +using TokenSet = const std::vector>; + +struct Line { + std::vector tokens; + std::string buffer; /* raw line, as read from the file */ + size_t pos; /* current line position */ + size_t end; + + explicit Line(std::string str) : buffer(std::move(str)), pos(0), end(buffer.size()) {} +}; + +class Lexer { +public: + Lexer(); + ~Lexer(); + NO_MOVE_SEMANTIC(Lexer); + NO_COPY_SEMANTIC(Lexer); + + /* + * The main function of Tokenizing, which takes a string. + * Returns a vector of tokens. + */ + Tokens TokenizeString(const std::string &); + +private: + std::vector lines_; + Line *curr_line_; + Error err_; + + bool Eol() const; /* end of line */ + bool LexString(); + void LexTokens(); + void LexPreprocess(); + void SkipSpace(); + void AnalyzeLine(); + Token::Type LexGetType(size_t, size_t) const; +}; + +/* + * Returns a string representation of a token type. + */ +std::string_view TokenTypeWhat(Token::Type); + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_LEXER_H_ diff --git a/assembler/mangling.h b/assembler/mangling.h new file mode 100644 index 0000000000..c05aae8a37 --- /dev/null +++ b/assembler/mangling.h @@ -0,0 +1,60 @@ +/* + * 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_ASSEMBLER_MANGLING_H_ +#define PANDA_ASSEMBLER_MANGLING_H_ + +#include "assembly-function.h" + +#include +#include + +namespace panda::pandasm { +static std::string MANGLE_BEGIN = ":"; +static std::string MANGLE_SEPARATOR = ";"; + +inline std::string MangleFunctionName(const std::string &name, const std::vector ¶ms, + const pandasm::Type &return_type) +{ + std::string mangle_name {name}; + mangle_name += MANGLE_BEGIN; + for (const auto &p : params) { + mangle_name += p.type.GetName() + MANGLE_SEPARATOR; + } + mangle_name += return_type.GetName() + MANGLE_SEPARATOR; + + return mangle_name; +} + +inline std::string DeMangleName(const std::string &name) +{ + auto iter = name.find_first_of(MANGLE_BEGIN); + if (iter != std::string::npos) { + return name.substr(0, name.find_first_of(MANGLE_BEGIN)); + } + return name; +} + +inline std::string MangleFieldName(const std::string &name, const pandasm::Type &type) +{ + std::string mangle_name {name}; + mangle_name += MANGLE_BEGIN; + mangle_name += type.GetName() + MANGLE_SEPARATOR; + return mangle_name; +} + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_MANGLING_H_ diff --git a/assembler/meta.cpp b/assembler/meta.cpp new file mode 100644 index 0000000000..eec52ef868 --- /dev/null +++ b/assembler/meta.cpp @@ -0,0 +1,511 @@ +/* + * 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 "meta.h" + +#include + +#include +#include + +#include "utils/expected.h" + +namespace panda::pandasm { + +std::optional Metadata::ValidateSize(std::string_view value) const +{ + constexpr size_t SIZE = 10; + + if (!std::all_of(value.cbegin(), value.cend(), ::isdigit)) { + return Error("Unsigned interger value expected", Error::Type::INVALID_VALUE); + } + + strtoul(value.data(), nullptr, SIZE); + if (errno == ERANGE) { + return Error("Value is out of range", Error::Type::INVALID_VALUE); + } + + return {}; +} + +bool ItemMetadata::IsForeign() const +{ + return GetAttribute("external"); +} + +static panda::pandasm::Value::Type GetType(std::string_view value) +{ + using VType = panda::pandasm::Value::Type; + static std::unordered_map types { + {"u1", VType::U1}, {"i8", VType::I8}, {"u8", VType::U8}, + {"i16", VType::I16}, {"u16", VType::U16}, {"i32", VType::I32}, + {"u32", VType::U32}, {"i64", VType::I64}, {"u64", VType::U64}, + {"f32", VType::F32}, {"f64", VType::F64}, {"string", VType::STRING}, + {"class", VType::RECORD}, {"enum", VType::ENUM}, {"annotation", VType::ANNOTATION}, + {"array", VType::ARRAY}, {"method", VType::METHOD}}; + + return types[value]; +} + +template +static T ConvertFromString(std::string_view value, char **end) +{ + static_assert(std::is_integral_v, "T must be integral type"); + + constexpr T MIN = std::numeric_limits::min(); + constexpr T MAX = std::numeric_limits::max(); + + if constexpr (std::is_signed_v) { + auto v = ConvertFromString(value, end); + if (v < MIN || v > MAX) { + errno = ERANGE; + } + return static_cast(v); + } + + if constexpr (!std::is_signed_v) { + auto v = ConvertFromString(value, end); + if (v < MIN || v > MAX) { + errno = ERANGE; + } + return static_cast(v); + } +} + +template <> +int64_t ConvertFromString(std::string_view value, char **end) +{ + return static_cast(strtoll(value.data(), end, 0)); +} + +template <> +uint64_t ConvertFromString(std::string_view value, char **end) +{ + return static_cast(strtoull(value.data(), end, 0)); +} + +template <> +float ConvertFromString(std::string_view value, char **end) +{ + return strtof(value.data(), end); +} + +template <> +double ConvertFromString(std::string_view value, char **end) +{ + return strtod(value.data(), end); +} + +template +static Expected ConvertFromString(std::string_view value) +{ + static_assert(std::is_arithmetic_v, "T must be arithmetic type"); + + char *end = nullptr; + auto v = ConvertFromString(value, &end); + + if (end != value.data() + value.length()) { + return Unexpected(Metadata::Error("Excepted integer literal", Metadata::Error::Type::INVALID_VALUE)); + } + + if (errno == ERANGE) { + errno = 0; + return Unexpected(Metadata::Error("Value is out of range", Metadata::Error::Type::INVALID_VALUE)); + } + + return static_cast(v); +} + +template > +static Expected CreatePrimitiveValue(std::string_view value, + T max_value = std::numeric_limits::max()) +{ + auto res = ConvertFromString(value); + if (!res) { + return Unexpected(res.Error()); + } + + auto converted = res.Value(); + if (converted > max_value) { + return Unexpected(Metadata::Error("Value is out of range", Metadata::Error::Type::INVALID_VALUE)); + } + + return ScalarValue::Create(converted); +} + +// CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_SIZE) +static Expected CreateValue( + Value::Type type, std::string_view value, + const std::unordered_map> &annotation_id_map = {}) +{ + switch (type) { + case Value::Type::U1: { + return CreatePrimitiveValue(value, 1); + } + case Value::Type::I8: { + return CreatePrimitiveValue(value); + } + case Value::Type::U8: { + return CreatePrimitiveValue(value); + } + case Value::Type::I16: { + return CreatePrimitiveValue(value); + } + case Value::Type::U16: { + return CreatePrimitiveValue(value); + } + case Value::Type::I32: { + return CreatePrimitiveValue(value); + } + case Value::Type::U32: { + return CreatePrimitiveValue(value); + } + case Value::Type::I64: { + return CreatePrimitiveValue(value); + } + case Value::Type::U64: { + return CreatePrimitiveValue(value); + } + case Value::Type::F32: { + return CreatePrimitiveValue(value); + } + case Value::Type::F64: { + return CreatePrimitiveValue(value); + } + case Value::Type::STRING: { + return ScalarValue::Create(value); + } + case Value::Type::RECORD: { + return ScalarValue::Create(Type::FromName(value)); + } + case Value::Type::METHOD: { + return ScalarValue::Create(value); + } + case Value::Type::ENUM: { + return ScalarValue::Create(value); + } + case Value::Type::ANNOTATION: { + auto it = annotation_id_map.find(std::string(value)); + if (it == annotation_id_map.cend()) { + return Unexpected(Metadata::Error("Unknown annotation id", Metadata::Error::Type::INVALID_VALUE)); + } + + auto annotation_value = it->second.get(); + return ScalarValue::Create(*annotation_value); + } + default: { + break; + } + } + + UNREACHABLE(); +} + +std::optional AnnotationMetadata::AnnotationElementBuilder::AddValue( + std::string_view value, const std::unordered_map> &annotation_id_map) +{ + ASSERT(type_.has_value()); + + auto type = type_.value(); + if (type == Value::Type::ARRAY) { + ASSERT(component_type_.has_value()); + type = component_type_.value(); + } + + auto res = CreateValue(type, value, annotation_id_map); + if (!res) { + return res.Error(); + } + + values_.push_back(res.Value()); + + return {}; +} + +std::optional AnnotationMetadata::Store(std::string_view attribute) +{ + if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation element isn't completely defined", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + if (IsParseAnnotation()) { + ResetAnnotationBuilder(); + } + + return Metadata::Store(attribute); +} + +std::optional AnnotationMetadata::MeetExpRecordAttribute(std::string_view attribute, + std::string_view value) +{ + if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation element isn't completely defined", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + InitializeAnnotationBuilder(value); + + return {}; +} + +std::optional AnnotationMetadata::MeetExpIdAttribute(std::string_view attribute, + std::string_view value) +{ + if (!IsParseAnnotation() || IsParseAnnotationElement()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation record attribute must be defined first", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + if (annotation_builder_.HasId()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation id attribute already defined", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + annotation_builder_.SetId(value); + + return {}; +} + +std::optional AnnotationMetadata::MeetExpElementNameAttribute(std::string_view attribute, + std::string_view value) +{ + if (!IsParseAnnotation()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation record attribute must be defined first", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Previous annotation element isn't defined completely", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + InitializeAnnotationElementBuilder(value); + + return {}; +} + +std::optional AnnotationMetadata::MeetExpElementTypeAttribute(std::string_view attribute, + std::string_view value) +{ + if (!IsParseAnnotationElement()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation element name attribute must be defined first", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + if (annotation_element_builder_.IsTypeSet()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation element type attribute already defined", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + annotation_element_builder_.SetType(GetType(value)); + + return {}; +} + +std::optional AnnotationMetadata::MeetExpElementArrayComponentTypeAttribute(std::string_view attribute, + std::string_view value) +{ + if (!IsParseAnnotationElement()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation element name attribute must be defined first", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + if (!annotation_element_builder_.IsArray()) { + return Error(std::string("Unexpected attribute '").append(attribute) + "'. Annotation element type isn't array", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + if (annotation_element_builder_.IsComponentTypeSet()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation element array component type attribute already defined", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + annotation_element_builder_.SetComponentType(GetType(value)); + + return {}; +} + +std::optional AnnotationMetadata::MeetExpElementValueAttribute(std::string_view attribute, + std::string_view value) +{ + if (!IsParseAnnotationElement()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation element name attribute must be defined first", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + if (!annotation_element_builder_.IsTypeSet()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation element type attribute isn't defined", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + if (annotation_element_builder_.IsArray() && !annotation_element_builder_.IsComponentTypeSet()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation element array component type attribute isn't defined", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + if (!annotation_element_builder_.IsArray() && annotation_element_builder_.IsCompleted()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation element is completely defined", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + return annotation_element_builder_.AddValue(value, id_map_); +} + +std::optional AnnotationMetadata::StoreValue(std::string_view attribute, std::string_view value) +{ + auto err = Metadata::StoreValue(attribute, value); + if (err) { + return err; + } + + if (IsAnnotationRecordAttribute(attribute)) { + return MeetExpRecordAttribute(attribute, value); + } + + if (IsAnnotationIdAttribute(attribute)) { + return MeetExpIdAttribute(attribute, value); + } + + if (IsAnnotationElementNameAttribute(attribute)) { + return MeetExpElementNameAttribute(attribute, value); + } + + if (IsAnnotationElementTypeAttribute(attribute)) { + return MeetExpElementTypeAttribute(attribute, value); + } + + if (IsAnnotationElementArrayComponentTypeAttribute(attribute)) { + return MeetExpElementArrayComponentTypeAttribute(attribute, value); + } + + if (IsAnnotationElementValueAttribute(attribute)) { + return MeetExpElementValueAttribute(attribute, value); + } + + if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) { + return Error(std::string("Unexpected attribute '").append(attribute) + + "'. Annotation element isn't completely defined", + Error::Type::UNEXPECTED_ATTRIBUTE); + } + + if (IsParseAnnotation()) { + ResetAnnotationBuilder(); + } + + return {}; +} + +std::optional AnnotationMetadata::ValidateData() +{ + if (IsParseAnnotationElement() && !annotation_element_builder_.IsCompleted()) { + return Error("Annotation element isn't completely defined", Error::Type::MISSING_ATTRIBUTE); + } + + if (IsParseAnnotation()) { + ResetAnnotationBuilder(); + } + + return Metadata::ValidateData(); +} + +std::string RecordMetadata::GetBase() const +{ + return ""; +} + +std::vector RecordMetadata::GetInterfaces() const +{ + return {}; +} + +bool RecordMetadata::IsAnnotation() const +{ + return false; +} + +bool RecordMetadata::IsRuntimeAnnotation() const +{ + return false; +} + +bool RecordMetadata::IsTypeAnnotation() const +{ + return false; +} + +bool RecordMetadata::IsRuntimeTypeAnnotation() const +{ + return false; +} + +bool FunctionMetadata::HasImplementation() const +{ + return !(ACC_ABSTRACT & GetAccessFlags()) && !(ACC_NATIVE & GetAccessFlags()); +} + +bool FunctionMetadata::IsCtor() const +{ + return GetAttribute("ctor"); +} + +bool FunctionMetadata::IsCctor() const +{ + return GetAttribute("cctor"); +} + +std::optional FieldMetadata::StoreValue(std::string_view attribute, std::string_view value) +{ + auto err = ItemMetadata::StoreValue(attribute, value); + if (err) { + return err; + } + + if (IsValueAttribute(attribute)) { + Value::Type value_type; + if (!field_type_.IsObject()) { + value_type = GetType(field_type_.GetName()); + } else { + value_type = Value::Type::STRING; + } + + auto res = CreateValue(value_type, value); + if (!res) { + return res.Error(); + } + + value_ = res.Value(); + } + + return {}; +} + +#include + +} // namespace panda::pandasm diff --git a/assembler/meta.h b/assembler/meta.h new file mode 100644 index 0000000000..fc8da9cf66 --- /dev/null +++ b/assembler/meta.h @@ -0,0 +1,595 @@ +/* + * 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_ASSEMBLER_META_H_ +#define PANDA_ASSEMBLER_META_H_ + +#include +#include +#include +#include +#include +#include +#include + +#include "annotation.h" +#include "modifiers.h" + +#include "assembly-type.h" + +namespace panda::pandasm { + +class Metadata { +public: + class Error { + public: + enum class Type { + INVALID_VALUE, + MISSING_ATTRIBUTE, + MISSING_VALUE, + MULTIPLE_ATTRIBUTE, + UNEXPECTED_ATTRIBUTE, + UNEXPECTED_VALUE, + UNKNOWN_ATTRIBUTE + }; + + Error(std::string msg, Type type) : msg_(std::move(msg)), type_(type) {} + ~Error() = default; + DEFAULT_MOVE_SEMANTIC(Error); + DEFAULT_COPY_SEMANTIC(Error); + + std::string GetMessage() const + { + return msg_; + } + + Type GetType() const + { + return type_; + } + + private: + std::string msg_; + Type type_; + }; + + Metadata() = default; + + virtual ~Metadata() = default; + + std::optional SetAttribute(std::string_view attribute) + { + auto err = Validate(attribute); + if (err) { + return err; + } + + SetFlags(attribute); + + return Store(attribute); + } + + void RemoveAttribute(const std::string &attribute) + { + RemoveFlags(attribute); + + set_attributes_.erase(attribute); + } + + bool GetAttribute(const std::string &attribute) const + { + return set_attributes_.find(attribute) != set_attributes_.cend(); + } + + std::optional SetAttributeValue(std::string_view attribute, std::string_view value) + { + auto err = Validate(attribute, value); + if (err) { + return err; + } + + SetFlags(attribute, value); + + return StoreValue(attribute, value); + } + + std::vector GetAttributeValues(const std::string &attribute) const + { + auto it = attributes_.find(attribute); + if (it == attributes_.cend()) { + return {}; + } + + return it->second; + } + + std::optional GetAttributeValue(const std::string &attribute) const + { + auto values = GetAttributeValues(attribute); + if (!values.empty()) { + return values.front(); + } + + return {}; + } + + const std::unordered_set &GetBoolAttributes() const + { + return set_attributes_; + } + + const std::unordered_map> &GetAttributes() const + { + return attributes_; + } + + virtual std::optional ValidateData() + { + return {}; + } + + DEFAULT_COPY_SEMANTIC(Metadata); + + DEFAULT_MOVE_SEMANTIC(Metadata); + +protected: + virtual std::optional Validate(std::string_view attribute) const = 0; + + virtual std::optional Validate(std::string_view attribute, std::string_view value) const = 0; + + virtual std::optional StoreValue(std::string_view attribute, std::string_view value) + { + std::string key(attribute); + auto it = attributes_.find(key); + if (it == attributes_.cend()) { + std::tie(it, std::ignore) = attributes_.try_emplace(key); + } + + it->second.emplace_back(value); + + return {}; + } + + virtual std::optional Store(std::string_view attribute) + { + set_attributes_.emplace(attribute); + + return {}; + } + + virtual void SetFlags(std::string_view attribute) = 0; + + virtual void SetFlags(std::string_view attribute, std::string_view value) = 0; + + virtual void RemoveFlags(std::string_view attribute) = 0; + + virtual void RemoveFlags(std::string_view attribute, std::string_view value) = 0; + + bool HasAttribute(std::string_view attribute) const + { + std::string key(attribute); + return GetAttribute(key) || GetAttributeValue(key); + } + + std::optional ValidateSize(std::string_view value) const; + +private: + std::unordered_set set_attributes_; + std::unordered_map> attributes_; +}; + +class AnnotationMetadata : public Metadata { +public: + const std::vector &GetAnnotations() const + { + return annotations_; + } + + void SetAnnotations(std::vector &&annotations) + { + annotations_ = std::forward>(annotations); + } + + void AddAnnotations(const std::vector &annotations) + { + annotations_.insert(annotations_.end(), annotations.begin(), annotations.end()); + } + + std::optional ValidateData() override; + +protected: + std::optional Store(std::string_view attribute) override; + + std::optional StoreValue(std::string_view attribute, std::string_view value) override; + + virtual bool IsAnnotationRecordAttribute([[maybe_unused]] std::string_view attribute) const + { + return false; + } + + virtual bool IsAnnotationIdAttribute([[maybe_unused]] std::string_view attribute) const + { + return false; + } + + virtual bool IsAnnotationElementTypeAttribute([[maybe_unused]] std::string_view attribute) const + { + return false; + } + + virtual bool IsAnnotationElementArrayComponentTypeAttribute([[maybe_unused]] std::string_view attribute) const + { + return false; + } + + virtual bool IsAnnotationElementNameAttribute([[maybe_unused]] std::string_view attribute) const + { + return false; + } + + virtual bool IsAnnotationElementValueAttribute([[maybe_unused]] std::string_view attribute) const + { + return false; + } + +private: + class AnnotationElementBuilder { + public: + void Initialize(std::string_view name) + { + name_ = name; + is_initialized_ = true; + } + + void Reset() + { + name_.clear(); + values_.clear(); + type_ = {}; + component_type_ = {}; + is_initialized_ = false; + } + + void SetType(Value::Type type) + { + type_ = type; + } + + void SetComponentType(Value::Type type) + { + ASSERT(type != Value::Type::ARRAY); + component_type_ = type; + } + + std::optional AddValue( + std::string_view value, + const std::unordered_map> &annotation_id_map); + + AnnotationElement CreateAnnotationElement() + { + if (IsArray()) { + return AnnotationElement(name_, + std::make_unique(component_type_.value(), std::move(values_))); + } + + return AnnotationElement(name_, std::make_unique(values_.front())); + } + + bool IsArray() const + { + return type_.value() == Value::Type::ARRAY; + } + + bool IsTypeSet() const + { + return type_.has_value(); + } + + bool IsComponentTypeSet() const + { + return component_type_.has_value(); + } + + bool IsInitialized() const + { + return is_initialized_; + } + + bool IsCompleted() const + { + if (!IsTypeSet()) { + return false; + } + + if (IsArray() && !IsComponentTypeSet()) { + return false; + } + + if (!IsArray() && values_.empty()) { + return false; + } + + return true; + } + + private: + bool is_initialized_ {false}; + std::string name_; + std::optional type_; + std::optional component_type_; + std::vector values_; + }; + + class AnnotationBuilder { + public: + void Initialize(std::string_view name) + { + name_ = name; + is_initialized_ = true; + } + + void Reset() + { + name_.clear(); + elements_.clear(); + id_ = {}; + is_initialized_ = false; + } + + void SetId(std::string_view id) + { + id_ = id; + } + + std::string GetId() const + { + ASSERT(HasId()); + return id_.value(); + } + + void AddElement(AnnotationElement &&element) + { + elements_.push_back(std::forward(element)); + } + + std::unique_ptr CreateAnnotationData() + { + return std::make_unique(name_, std::move(elements_)); + }; + + void AddAnnnotationDataToVector(std::vector *annotations) + { + annotations->emplace_back(name_, std::move(elements_)); + } + + bool HasId() const + { + return id_.has_value(); + } + + bool IsInitialized() const + { + return is_initialized_; + } + + private: + std::string name_; + std::optional id_; + std::vector elements_; + bool is_initialized_ {false}; + }; + + std::optional MeetExpRecordAttribute(std::string_view attribute, std::string_view value); + std::optional MeetExpIdAttribute(std::string_view attribute, std::string_view value); + std::optional MeetExpElementNameAttribute(std::string_view attribute, std::string_view value); + std::optional MeetExpElementTypeAttribute(std::string_view attribute, std::string_view value); + std::optional MeetExpElementArrayComponentTypeAttribute(std::string_view attribute, + std::string_view value); + std::optional MeetExpElementValueAttribute(std::string_view attribute, std::string_view value); + + void InitializeAnnotationBuilder(std::string_view name) + { + if (IsParseAnnotation()) { + ResetAnnotationBuilder(); + } + + annotation_builder_.Initialize(name); + } + + void ResetAnnotationBuilder() + { + ASSERT(IsParseAnnotation()); + + if (IsParseAnnotationElement() && annotation_element_builder_.IsCompleted()) { + ResetAnnotationElementBuilder(); + } + + if (annotation_builder_.HasId()) { + id_map_.insert({annotation_builder_.GetId(), annotation_builder_.CreateAnnotationData()}); + } else { + annotation_builder_.AddAnnnotationDataToVector(&annotations_); + } + + annotation_builder_.Reset(); + } + + bool IsParseAnnotation() const + { + return annotation_builder_.IsInitialized(); + } + + void InitializeAnnotationElementBuilder(std::string_view name) + { + if (IsParseAnnotationElement() && annotation_element_builder_.IsCompleted()) { + ResetAnnotationElementBuilder(); + } + + annotation_element_builder_.Initialize(name); + } + + void ResetAnnotationElementBuilder() + { + ASSERT(IsParseAnnotationElement()); + ASSERT(annotation_element_builder_.IsCompleted()); + + annotation_builder_.AddElement(annotation_element_builder_.CreateAnnotationElement()); + + annotation_element_builder_.Reset(); + } + + bool IsParseAnnotationElement() const + { + return annotation_element_builder_.IsInitialized(); + } + + AnnotationBuilder annotation_builder_; + AnnotationElementBuilder annotation_element_builder_; + std::vector annotations_; + std::unordered_map> id_map_; +}; + +class ItemMetadata : public AnnotationMetadata { +public: + uint32_t GetAccessFlags() const + { + return access_flags_; + } + + void SetAccessFlags(uint32_t access_flags) + { + access_flags_ = access_flags; + } + + bool IsForeign() const; + +private: + uint32_t access_flags_ {0}; +}; + +class RecordMetadata : public ItemMetadata { +public: + virtual std::string GetBase() const; + + virtual std::vector GetInterfaces() const; + + virtual bool IsAnnotation() const; + + virtual bool IsRuntimeAnnotation() const; + + virtual bool IsTypeAnnotation() const; + + virtual bool IsRuntimeTypeAnnotation() const; + +protected: + std::optional Validate(std::string_view attribute) const override; + + std::optional Validate(std::string_view attribute, std::string_view value) const override; + + void SetFlags(std::string_view attribute) override; + + void SetFlags(std::string_view attribute, std::string_view value) override; + + void RemoveFlags(std::string_view attribute) override; + + void RemoveFlags(std::string_view attribute, std::string_view value) override; +}; + +class FieldMetadata : public ItemMetadata { +public: + void SetFieldType(const Type &type) + { + field_type_ = type; + } + + Type GetFieldType() const + { + return field_type_; + } + + void SetValue(const ScalarValue &value) + { + value_ = value; + } + + std::optional GetValue() const + { + return value_; + } + +protected: + std::optional StoreValue(std::string_view attribute, std::string_view value) override; + + std::optional Validate(std::string_view attribute) const override; + + std::optional Validate(std::string_view attribute, std::string_view value) const override; + + void SetFlags(std::string_view attribute) override; + + void SetFlags(std::string_view attribute, std::string_view value) override; + + void RemoveFlags(std::string_view attribute) override; + + void RemoveFlags(std::string_view attribute, std::string_view value) override; + + virtual bool IsValueAttribute(std::string_view attribute) + { + return attribute == "value"; + } + +private: + Type field_type_; + std::optional value_; +}; + +class FunctionMetadata : public ItemMetadata { +public: + virtual bool HasImplementation() const; + + virtual bool IsCtor() const; + + virtual bool IsCctor() const; + +protected: + std::optional Validate(std::string_view attribute) const override; + + std::optional Validate(std::string_view attribute, std::string_view value) const override; + + void SetFlags(std::string_view attribute) override; + + void SetFlags(std::string_view attribute, std::string_view value) override; + + void RemoveFlags(std::string_view attribute) override; + + void RemoveFlags(std::string_view attribute, std::string_view value) override; +}; + +class ParamMetadata : public AnnotationMetadata { +protected: + std::optional Validate(std::string_view attribute) const override; + + std::optional Validate(std::string_view attribute, std::string_view value) const override; + + void SetFlags(std::string_view attribute) override; + + void SetFlags(std::string_view attribute, std::string_view value) override; + + void RemoveFlags(std::string_view attribute) override; + + void RemoveFlags(std::string_view attribute, std::string_view value) override; +}; + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_META_H_ diff --git a/assembler/metadata.yaml b/assembler/metadata.yaml new file mode 100644 index 0000000000..d594fd2c11 --- /dev/null +++ b/assembler/metadata.yaml @@ -0,0 +1,55 @@ +# 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. + +attributes: +- name: external + type: bool + applicable_to: + - record + - field + - function + +- name: native + type: bool + flags: [ACC_NATIVE] + applicable_to: + - function + +- name: noimpl + type: bool + flags: [ACC_ABSTRACT] + applicable_to: + - function + +- name: static + type: bool + flags: [ACC_STATIC] + applicable_to: + - field + - function + +- name: ctor + type: bool + applicable_to: + - function + +- name: cctor + type: bool + applicable_to: + - function + +- name: value + type: any + multiple: false + applicable_to: + - field diff --git a/assembler/pandasm.cpp b/assembler/pandasm.cpp new file mode 100644 index 0000000000..6422f99dc9 --- /dev/null +++ b/assembler/pandasm.cpp @@ -0,0 +1,246 @@ +/* + * 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 +#include +#include +#include + +#include "assembly-emitter.h" +#include "assembly-parser.h" +#include "error.h" +#include "lexer.h" +#include "utils/expected.h" +#include "utils/logger.h" +#include "utils/pandargs.h" + +namespace panda::pandasm { + +void PrintError(const panda::pandasm::Error &e, const std::string &msg) +{ + std::stringstream sos; + std::cerr << msg << ": " << e.message << std::endl; + sos << " Line " << e.line_number << ", Column " << e.pos + 1 << ": "; + std::cerr << sos.str() << e.whole_line << std::endl; + std::cerr << std::setw(static_cast(e.pos + sos.str().size()) + 1) << "^" << std::endl; +} + +void PrintErrors(const panda::pandasm::ErrorList &warnings, const std::string &msg) +{ + for (const auto &iter : warnings) { + PrintError(iter, msg); + } +} + +bool PrepareArgs(panda::PandArgParser &pa_parser, const panda::PandArg &input_file, + const panda::PandArg &output_file, const panda::PandArg &log_file, + const panda::PandArg &help, const panda::PandArg &verbose, std::ifstream &inputfile, + int argc, char **argv) +{ + if (!pa_parser.Parse(argc, const_cast(argv)) || input_file.GetValue().empty() || + output_file.GetValue().empty() || help.GetValue()) { + std::cerr << "Usage:" << std::endl; + std::cerr << "ark_asm [OPTIONS] INPUT_FILE OUTPUT_FILE" << std::endl << std::endl; + std::cerr << "Supported options:" << std::endl << std::endl; + std::cerr << pa_parser.GetHelpString() << std::endl; + return false; + } + + if (verbose.GetValue()) { + if (log_file.GetValue().empty()) { + panda::Logger::ComponentMask component_mask; + component_mask.set(panda::Logger::Component::ASSEMBLER); + panda::Logger::InitializeStdLogging(panda::Logger::Level::DEBUG, component_mask); + } else { + panda::Logger::ComponentMask component_mask; + component_mask.set(panda::Logger::Component::ASSEMBLER); + panda::Logger::InitializeFileLogging(log_file.GetValue(), panda::Logger::Level::DEBUG, component_mask); + } + } + + inputfile.open(input_file.GetValue(), std::ifstream::in); + + if (!inputfile) { + std::cerr << "The input file does not exist." << std::endl; + return false; + } + + return true; +} + +bool Tokenize(panda::pandasm::Lexer &lexer, std::vector> &tokens, + std::ifstream &inputfile) +{ + std::string s; + + while (getline(inputfile, s)) { + panda::pandasm::Tokens q = lexer.TokenizeString(s); + + auto e = q.second; + if (e.err != panda::pandasm::Error::ErrorType::ERR_NONE) { + e.line_number = tokens.size() + 1; + PrintError(e, "ERROR"); + return false; + } + + tokens.push_back(q.first); + } + + return true; +} + +bool ParseProgram(panda::pandasm::Parser &parser, std::vector> &tokens, + const panda::PandArg &input_file, + panda::Expected &res) +{ + res = parser.Parse(tokens, input_file.GetValue()); + if (!res) { + PrintError(res.Error(), "ERROR"); + return false; + } + + return true; +} + +bool DumpProgramInJson(panda::pandasm::Program &program, const panda::PandArg &scopes_file) +{ + if (!scopes_file.GetValue().empty()) { + std::ofstream dump_file; + dump_file.open(scopes_file.GetValue()); + + if (!dump_file) { + std::cerr << "Failed to write scopes into the given file." << std::endl; + return false; + } + dump_file << program.JsonDump(); + } + + return true; +} + +bool EmitProgramInBinary(panda::pandasm::Program &program, panda::PandArgParser &pa_parser, + const panda::PandArg &output_file, panda::PandArg &optimize, + const panda::PandArg &size_stat) +{ + auto emit_debug_info = !optimize.GetValue(); + std::map stat; + std::map *statp = size_stat.GetValue() ? &stat : nullptr; + panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {}; + panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = optimize.GetValue() ? &maps : nullptr; + + if (!panda::pandasm::AsmEmitter::Emit(output_file.GetValue(), program, statp, mapsp, emit_debug_info)) { + std::cerr << "Failed to emit binary data: " << panda::pandasm::AsmEmitter::GetLastError() << std::endl; + return false; + } + + if (size_stat.GetValue()) { + size_t total_size = 0; + std::cout << "Panda file size statistic:" << std::endl; + + for (auto [name, size] : stat) { + std::cout << name << " section: " << size << std::endl; + total_size += size; + } + + std::cout << "total: " << total_size << std::endl; + } + + pa_parser.DisableTail(); + + return true; +} + +bool BuildFiles(panda::pandasm::Program &program, panda::PandArgParser &pa_parser, + const panda::PandArg &output_file, panda::PandArg &optimize, + panda::PandArg &size_stat, panda::PandArg &scopes_file) +{ + if (!DumpProgramInJson(program, scopes_file)) { + return false; + } + + if (!EmitProgramInBinary(program, pa_parser, output_file, optimize, size_stat)) { + return false; + } + + return true; +} + +} // namespace panda::pandasm + +int main(int argc, char *argv[]) +{ + panda::PandArg verbose("verbose", false, "Enable verbose output (will be printed to standard output)"); + panda::PandArg log_file("log-file", "", "(--log-file FILENAME) Set log file name"); + panda::PandArg scopes_file("dump-scopes", "", + "(--dump-scopes FILENAME) Enable dump of scopes to file"); + panda::PandArg help("help", false, "Print this message and exit"); + panda::PandArg size_stat("size-stat", false, "Print panda file size statistic"); + panda::PandArg optimize("optimize", false, "Run the bytecode optimization"); + // tail arguments + panda::PandArg input_file("INPUT_FILE", "", "Path to the source assembly code"); + panda::PandArg output_file("OUTPUT_FILE", "", "Path to the generated binary code"); + panda::PandArgParser pa_parser; + pa_parser.Add(&verbose); + pa_parser.Add(&help); + pa_parser.Add(&log_file); + pa_parser.Add(&scopes_file); + pa_parser.Add(&size_stat); + pa_parser.Add(&optimize); + pa_parser.PushBackTail(&input_file); + pa_parser.PushBackTail(&output_file); + pa_parser.EnableTail(); + + std::ifstream inputfile; + + if (!panda::pandasm::PrepareArgs(pa_parser, input_file, output_file, log_file, help, verbose, inputfile, argc, + argv)) { + return 1; + } + + LOG(DEBUG, ASSEMBLER) << "Lexical analysis:"; + + panda::pandasm::Lexer lexer; + + std::vector> tokens; + + if (!Tokenize(lexer, tokens, inputfile)) { + return 1; + } + + LOG(DEBUG, ASSEMBLER) << "parsing:"; + + panda::pandasm::Parser parser; + + panda::Expected res; + if (!panda::pandasm::ParseProgram(parser, tokens, input_file, res)) { + return 1; + } + + auto &program = res.Value(); + + auto w = parser.ShowWarnings(); + if (!w.empty()) { + panda::pandasm::PrintErrors(w, "WARNING"); + } + + if (!panda::pandasm::BuildFiles(program, pa_parser, output_file, optimize, size_stat, scopes_file)) { + return 1; + } + + return 0; +} diff --git a/assembler/pandasm.h b/assembler/pandasm.h new file mode 100644 index 0000000000..4f6b5e22a9 --- /dev/null +++ b/assembler/pandasm.h @@ -0,0 +1,51 @@ +/* + * 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_ASSEMBLER_PANDASM_H_ +#define PANDA_ASSEMBLER_PANDASM_H_ + +#include "utils/pandargs.h" + +namespace panda::pandasm { + +void PrintError(const panda::pandasm::Error &e, const std::string &msg); + +void PrintErrors(const panda::pandasm::ErrorList &warnings, const std::string &msg); + +bool PrepareArgs(panda::PandArgParser &pa_parser, const panda::PandArg &input_file, + const panda::PandArg &output_file, const panda::PandArg &log_file, + const panda::PandArg &help, const panda::PandArg &verbose, std::ifstream &inputfile, + int argc, char **argv); + +bool Tokenize(panda::pandasm::Lexer &lexer, std::vector> &tokens, + std::ifstream &inputfile); + +bool ParseProgram(panda::pandasm::Parser &parser, std::vector> &tokens, + const panda::PandArg &input_file, + panda::Expected &res); + +bool DumpProgramInJson(panda::pandasm::Program &program, const panda::PandArg &scopes_file); + +bool EmitProgramInBinary(panda::pandasm::Program &program, panda::PandArgParser &pa_parser, + const panda::PandArg &output_file, panda::PandArg &optimize, + panda::PandArg &size_stat); + +bool BuildFiles(panda::pandasm::Program &program, panda::PandArgParser &pa_parser, + const panda::PandArg &output_file, panda::PandArg &optimize, + panda::PandArg &size_stat, panda::PandArg &scopes_file); + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_PANDASM_H_ diff --git a/assembler/samples/Bubblesort.pa b/assembler/samples/Bubblesort.pa new file mode 100644 index 0000000000..1989990b79 --- /dev/null +++ b/assembler/samples/Bubblesort.pa @@ -0,0 +1,83 @@ +# 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 i64 main(){ + ldai 30000 + sta v1 + newarr v1, i64[] + sta.obj v0 + call.short init, v0, v1 + call.short bubblesort, v0, v0 + lda v1 + subi 1 + ldarr.64 v0 + return.64 +} + +.function void init(i64[] a0, i32 a1){ + movi v2, 0 +loop: + lda a1 + jeqz init_exit + subi 1 + sta a1 + starr.64 a0, v2 + inci v2, 1 + lda v2 + jmp loop +init_exit: + return.void +} + +.function void bubblesort(i64[] a0){ + lenarr a0 + sta v1 +outer: + ldai 1 + sta v2 + ldai 1 +inner: + jge v1, inner_exit + sta v3 + ldarr.64 a0 + sta v4 + lda v3 + subi 1 + sta v5 + ldarr.64 a0 + jlt v4, next + call swap, a0, v5, v3, v0 + movi v2, 0 +next: + lda v3 + addi 1 + jmp inner +inner_exit: + inci v1, -1 + lda v2 + jeqz outer + return.void +} + +.function void swap(i64[] a0, i32 a1, i32 a2){ + lda a1 + ldarr.64 a0 + sta v3 + lda a2 + ldarr.64 a0 + starr.64 a0, a1 + lda v3 + starr.64 a0, a2 + return.void +} diff --git a/assembler/samples/Factorial.pa b/assembler/samples/Factorial.pa new file mode 100644 index 0000000000..51ea8a99d3 --- /dev/null +++ b/assembler/samples/Factorial.pa @@ -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. + +.function i32 factorial (i32 a0) <> { #Calculation of factorial from a value in register a0 + ldai.64 1 + sta.64 v8 +while_1: + lda.64 a0 + movi.64 v0, 1 + jle v0, endwhile_3 +body_2: + mul v8, a0 + sta.64 v8 + lda.64 a0 + subi 1 + sta.64 a0 + jmp while_1 +endwhile_3: + lda.64 v8 + return +} + +.function i32 entry () <> { + movi.64 v0, 7 + call.short factorial, v0 + return +} diff --git a/assembler/samples/Fibonacci.pa b/assembler/samples/Fibonacci.pa new file mode 100644 index 0000000000..ffc594a5e0 --- /dev/null +++ b/assembler/samples/Fibonacci.pa @@ -0,0 +1,52 @@ +# 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 i64 main(){ + movi v1, 10 + newarr v0, v1, i64[] + ldai 0 +main_loop: + jge v1, main_ret + sta v2 + call.short fibonacci, v2, v2 + starr.64 v0, v2 + lda v2 + addi 1 + jmp main_loop +main_ret: + lda v1 + subi 1 + ldarr.64 v0 + return.64 +} + +.function i64 fibonacci(i64 a0){ + lda a0 + jnez non_zero + return.64 +non_zero: + ldai 1 + jne a0, non_one + return.64 +non_one: + lda a0 + subi 1 + sta a0 + subi 1 + sta v1 + call.short fibonacci, a0, a0 + sta a0 + call.short fibonacci, v1, a0 + add2.64 a0 + return.64 +} diff --git a/assembler/templates/builtin_parsing.cpp.erb b/assembler/templates/builtin_parsing.cpp.erb new file mode 100644 index 0000000000..00af94da88 --- /dev/null +++ b/assembler/templates/builtin_parsing.cpp.erb @@ -0,0 +1,63 @@ +/* + * 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() { + const auto token = context_.GiveToken(); + + --context_; + 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 \ No newline at end of file diff --git a/assembler/templates/builtin_parsing_tests.cpp.erb b/assembler/templates/builtin_parsing_tests.cpp.erb new file mode 100644 index 0000000000..bb83689662 --- /dev/null +++ b/assembler/templates/builtin_parsing_tests.cpp.erb @@ -0,0 +1,146 @@ +/* + * 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 new file mode 100644 index 0000000000..a269ba0645 --- /dev/null +++ b/assembler/templates/ins_create_api.h.erb @@ -0,0 +1,63 @@ +/* + * 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! + +#include +#include "assembly-ins.h" + +namespace panda::pandasm { + +% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| +% insn = group.first +% signature = assembler_signature(group, insn.jump?) +% signature_str = signature.map { |o| "#{o.type} #{o.name}" }.join(', ') +inline Ins Create_<%= insn.asm_token %>(<%= signature_str %>) + { + Ins <%=insn.emitter_name%>_; + <%=group.first.emitter_name%>_.opcode = Opcode::<%= insn.asm_token %>; +% format = format_ops(insn.format) +% format.each { |o| o.width = storage_width(o.width) } +% count_reg = 0 +% format.each_with_index do |o, i| +% if o.name.start_with?('v') +% count_reg += 1 +% end +% end +% if count_reg > 0 then + <%=group.first.emitter_name%>_.regs.reserve(<%= count_reg %>); +% end +% format.each_with_index do |o, i| +% if o.name.start_with?('imm') +% if insn.jump? == true + <%=group.first.emitter_name%>_.ids.push_back(label); +% else + <%=group.first.emitter_name%>_.imms.emplace_back(<%= o.name %>); +% end +% elsif o.name.start_with?('id') + <%=group.first.emitter_name%>_.ids.push_back(<%= o.name %>); +% else + <%=group.first.emitter_name%>_.regs.push_back(<%= o.name %>); +% end +% end + return <%=insn.emitter_name%>_; + } + +% end + + +} // namespace panda::pandasm + +#include diff --git a/assembler/templates/ins_create_builtins_api.h.erb b/assembler/templates/ins_create_builtins_api.h.erb new file mode 100644 index 0000000000..ba4d69b8cd --- /dev/null +++ b/assembler/templates/ins_create_builtins_api.h.erb @@ -0,0 +1,60 @@ +/* + * 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/ins_emit.h.erb b/assembler/templates/ins_emit.h.erb new file mode 100644 index 0000000000..53ef78957e --- /dev/null +++ b/assembler/templates/ins_emit.h.erb @@ -0,0 +1,192 @@ +/* + * 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-ins.h" +#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, + const std::unordered_map &classes, + const std::unordered_map &strings, + const std::unordered_map &literalarrays, + const std::unordered_map& labels) const { + if (!IsValidToEmit()) { + std::cerr << "Invalid instruction: " << ToString() << std::endl; + LOG(FATAL, ASSEMBLER); + } + switch(opcode) { +% inst_map = Panda::instructions.collect { |i| [i.mnemonic, i] }.to_h +% call_map = { +% "call.short" => ["call.short"], +% "call" => ["call.short", "call"], +% "calli.dyn.short" => ["calli.dyn.short"], +% "calli.dyn" => ["calli.dyn.short", "calli.dyn"], +% "call.acc.short" => ["call.acc.short"], +% "call.acc" => ["call.acc.short", "call.acc"], +% "call.virt.short" => ["call.virt.short"], +% "call.virt" => ["call.virt.short", "call.virt"], +% "call.virt.acc.short" => ["call.virt.acc.short"], +% "call.virt.acc" => ["call.virt.acc.short", "call.virt.acc"], +% "call.dyn.short" => ["call.dyn.short"], +% "call.dyn" => ["call.dyn.short", "call.dyn"], +% "initobj.short" => ["initobj.short"], +% "initobj" => ["initobj"], +% "builtin.idr4" => ["builtin.idr4"], +% "builtin.idr6" => ["builtin.idr6"] +%} +% Panda::instructions.group_by(&:mnemonic).each_pair do |mn, group| +% insn = group[index_of_max(group.map(&:format).map(&:size))] +% +% def type(insn) +% src_acc_ops = insn.acc_and_operands.select(&:src?) +% src_acc_ops.size != 0 ? src_acc_ops.first.type : 'none' +% end +% +% def op_size(insn) +% type(insn)[1..-1].to_i +% end +% +% def operands(insn, regs = "regs") +% ops = [] +% nr = 0 +% ni = 0 +% insn.operands.each do |op| +% if op.reg? +% ops << "#{regs}[#{nr}]" +% nr += 1 +% elsif op.imm? +% if insn.jump? +% ops << 'labels.find(ids[0])->second' +% else +% from_type, to_type = op_size(insn) == 64 ? ['double', 'int64_t'] : ['float', 'int32_t'] +% if insn.float? +% ops << bit_cast("imms[#{ni}]", to_type, from_type) +% elsif type(insn).start_with? 'u' # can hold both float and integer literals +% ops << "std::holds_alternative(imms[#{ni}]) ? #{bit_cast("imms[#{ni}]", to_type, from_type)} : std::get(imms[#{ni}])" +% else +% ops << "std::get(imms[#{ni}])" +% end +% end +% ni += 1 +% elsif op.id? +% if insn.properties.include?('method_id') +% ops << 'methods.find(ids[0])->second->GetIndex(method)' +% elsif insn.properties.include?('field_id') +% ops << 'fields.find(ids[0])->second->GetIndex(method)' +% elsif insn.properties.include?('type_id') +% ops << 'classes.find(ids[0])->second->GetIndex(method)' +% elsif insn.properties.include?('string_id') +% ops << 'strings.find(ids[0])->second->GetOffset()' +% elsif insn.properties.include?('literalarray_id') +% ops << 'static_cast(literalarrays.find(ids[0])->second->GetOffset())' +% else +% raise "Unexpected ID type" +% end +% else +% raise "Unexpected operand type" +% end +% end +% if insn.call? +% ops << ops.shift +% end +% ops +% end + case Opcode::<%= insn.asm_token %>: { +% if insn.properties.include?('method_id') + if ((ids.size() == 0) || (methods.find(ids[0]) == methods.cend())) { + return false; + } +% elsif insn.properties.include?('field_id') + if ((ids.size() == 0) || (fields.find(ids[0]) == fields.cend())) { + return false; + } +% elsif insn.properties.include?('type_id') + if ((ids.size() == 0) || (classes.find(ids[0]) == classes.cend())) { + return false; + } +% elsif insn.properties.include?('string_id') + if ((ids.size() == 0) || (strings.find(ids[0]) == strings.cend())) { + return false; + } +% elsif insn.jump? + if ((ids.size() == 0) || (labels.find(ids[0]) == labels.cend())) { + return false; + } +% end +% regs_num = 0 +% imms_num = 0 +% insn.operands.each do |op| +% if op.reg? +% regs_num += 1 +% elsif op.imm? +% imms_num += 1 +% end +% end +% if (insn.call? && !insn.call_range?) || (insn.calli? && !insn.calli_range?) || insn.builtin_idr4? || insn.builtin_idr6? +% if imms_num > 0 + if (imms.size() < <%= imms_num %>) { + return false; + } +% end +% elsif insn.jump? +% if regs_num > 0 + if (regs.size() < <%= regs_num %>) { + return false; + } +% end +% else +% if regs_num > 0 and imms_num > 0 + if (regs.size() < <%= regs_num %> || imms.size() < <%= imms_num %>) { + return false; + } +% elsif regs_num > 0 + if (regs.size() < <%= regs_num %>) { + return false; + } +% elsif imms_num > 0 + if (imms.size() < <%= imms_num %>) { + return false; + } +% end +% end +% if (insn.call? && !insn.call_range?) || (insn.calli? && !insn.calli_range?) || insn.builtin_idr4? || insn.builtin_idr6? + auto registers = regs; +% call_map[insn.mnemonic].map { |m| inst_map[m] }.each do |i| +% registers = i.operands.select(&:reg?) + if (registers.size() < <%= registers.size + 1 %>) { + while (registers.size() < <%= registers.size %>) { + registers.push_back(0); + } + emitter.<%= i.emitter_name %>(<%= operands(i, "registers").join(", ") %>); + break; + } +% end +% else + emitter.<%= insn.emitter_name %>(<%= operands(insn).join(", ") %>); +% end + break; + } +% end + default: + assert(0); + } + + return true; +} + +} // namespace panda::pandasm diff --git a/assembler/templates/ins_to_string.cpp.erb b/assembler/templates/ins_to_string.cpp.erb new file mode 100644 index 0000000000..d6cd1f9691 --- /dev/null +++ b/assembler/templates/ins_to_string.cpp.erb @@ -0,0 +1,60 @@ +/* + * 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 "assembly-ins.h" + +namespace panda::pandasm { + +std::string panda::pandasm::Ins::ToString(std::string endline, bool print_args /* = false */, + size_t first_arg_idx /* = 0*/) const { + std::string full_operation = ""; + std::string reg_case = ""; + if (this->set_label) { + full_operation += this->label +": "; + } + switch(this->opcode) { +% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| +% insn = group.first +% formats = group.map(&:format) +% operands = insn.operands +% properties = insn.properties + case panda::pandasm::Opcode::<%= insn.asm_token%>: { + full_operation += "<%= insn.mnemonic%>"; +% print_kind = case +% when insn.call? || !insn.public? +% 'PrintKind::CALL' +% when insn.calli? +% 'PrintKind::CALLI' +% else +% 'PrintKind::DEFAULT' +% end + full_operation += this->OperandsToString(<%= print_kind %>, print_args, first_arg_idx); + } break; +% end +% Panda::pseudo_instructions.each do |insn| + case panda::pandasm::Opcode::<%= insn.opcode %>: { + full_operation += "<%= insn.opcode %>"; + full_operation += this->OperandsToString(PrintKind::DEFAULT, print_args, first_arg_idx); + } break; +% end + case panda::pandasm::Opcode::INVALID: { + full_operation += ""; + } break; + } + return full_operation + endline; +} + +} // namespace panda::pandasm diff --git a/assembler/templates/isa.h.erb b/assembler/templates/isa.h.erb new file mode 100644 index 0000000000..bcfb071593 --- /dev/null +++ b/assembler/templates/isa.h.erb @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#define PANDA_INSTRUCTION_LIST(_) \ +% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| +% insn = group.first +% formats = group.map(&:format) +% pretty_format = insn.format.pretty.upcase.gsub(/[0-9]/, '') +% pretty_format.gsub!('IMM', 'ID') if insn.jump? +% pretty_format.gsub!('ID', 'TYPE') if insn.properties.include?('type_id') +% +% flags = ["InstFlags::NONE"] +% flags << "InstFlags::CALL" if insn.simple_call? +% flags << "InstFlags::JUMP" if insn.jump? +% flags << "InstFlags::COND" if insn.conditional? +% flags << "InstFlags::RETURN" if insn.return? +% flags << "InstFlags::ACC_READ" if insn.properties.include? 'acc_read' +% flags << "InstFlags::ACC_WRITE" if insn.properties.include? 'acc_write' +% flags << "InstFlags::THROWING" if insn.throwing? +% flags << "InstFlags::METHOD_ID" if insn.properties.include? 'method_id' +% flags << "InstFlags::FIELD_ID" if insn.properties.include? 'field_id' +% flags << "InstFlags::TYPE_ID" if insn.properties.include? 'type_id' +% flags << "InstFlags::STRING_ID" if insn.properties.include? 'string_id' +% flags << "InstFlags::LITERALARRAY_ID" if insn.properties.include? 'literalarray_id' +% flags = "(#{flags.join(" | ")})" +% +% max_width = group.map do |i| +% i.operands.select(&:reg?).map(&:width).max +% end.max +% max_width ||= 0 +% +% regs = insn.operands.select(&:reg?) +% dst_idx = regs.index(&:dst?) || 'INVALID_REG_IDX' +% use_idxs = regs.size.times.select { |idx| regs[idx].src? } || [] +% use_idxs += (['INVALID_REG_IDX'] * (max_number_of_src_regs - use_idxs.size)) +% use_idxs = "(std::array{{#{use_idxs.join(', ')}}})" +% +_(<%= insn.asm_token %>, "<%= insn.mnemonic %>", <%= pretty_format %>, <%= max_width %>, <%= flags %>, <%= dst_idx %>, <%= use_idxs %>) \ +% end +% Panda::pseudo_instructions.each do |insn| +% use_idxs = insn.use_idxs + ['INVALID_REG_IDX'] * (max_number_of_src_regs - insn.use_idxs.size) +% use_idxs = "(std::array{{#{use_idxs.join(', ')}}})" +_(<%= insn.opcode %> , "<%= insn.opcode %>", NONE, 0, (<%= insn.flags.join(" | ") %>), <%= insn.dst_idx %>, <%= use_idxs %>) \ +% end + diff --git a/assembler/templates/meta_gen.cpp.erb b/assembler/templates/meta_gen.cpp.erb new file mode 100644 index 0000000000..b794f0cf31 --- /dev/null +++ b/assembler/templates/meta_gen.cpp.erb @@ -0,0 +1,46 @@ +/* + * 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. + */ + +% Metadata::item_types.each do |item_type| +std::optional +<%= MetadataGen::class_name(item_type) %>::Validate(<%= MetadataGen::validate_arg_list(item_type, true).join(', ') %>) const { +<%= MetadataGen::validate_body(item_type, true).join("\n") %> +} + +std::optional +<%= MetadataGen::class_name(item_type) %>::Validate(<%= MetadataGen::validate_arg_list(item_type, false).join(', ') %>) const { +<%= MetadataGen::validate_body(item_type, false).join("\n") %> +} + +% end +% +% Metadata::item_types.each do |item_type| +void <%= MetadataGen::class_name(item_type) %>::SetFlags(<%= MetadataGen::flags_arg_list(item_type, true).join(', ') %>) { +<%= MetadataGen::set_flags_body(item_type, true).join("\n") %> +} + +void <%= MetadataGen::class_name(item_type) %>::SetFlags(<%= MetadataGen::flags_arg_list(item_type, false).join(', ') %>) { +<%= MetadataGen::set_flags_body(item_type, false).join("\n") %> +} + +void <%= MetadataGen::class_name(item_type) %>::RemoveFlags(<%= MetadataGen::flags_arg_list(item_type, true).join(', ') %>) { +<%= MetadataGen::remove_flags_body(item_type, true).join("\n") %> +} + +void <%= MetadataGen::class_name(item_type) %>::RemoveFlags(<%= MetadataGen::flags_arg_list(item_type, false).join(', ') %>) { +<%= MetadataGen::remove_flags_body(item_type, false).join("\n") %> +} + +% end diff --git a/assembler/templates/opcode_parsing.h.erb b/assembler/templates/opcode_parsing.h.erb new file mode 100644 index 0000000000..3b69c5867e --- /dev/null +++ b/assembler/templates/opcode_parsing.h.erb @@ -0,0 +1,135 @@ +/* + * 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" +#include "utils/number-utils.h" + +namespace panda::pandasm { + +bool Parser::ParseOperands() +{ + std::string_view p; + uint64_t number; + LOG(DEBUG, ASSEMBLER) << "operand search started (line " << line_stric_ << "): " << context_.tokens[0].whole_line; + switch(context_.WaitFor()) + { +% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| +% insn = group.first +% formats = group.map(&:format) +% operands = insn.operands +% properties = insn.properties +% verification = insn.verification + case Token::Type::ID_OP_<%= insn.asm_token%>: { +% if insn.return? && !insn.properties.include?('dynamic') +% if insn.return_obj? + if (!curr_func_->return_type.IsObject()) { +% elsif insn.return32? + if (!curr_func_->return_type.IsPrim32()) { +% elsif insn.return64? + if (!curr_func_->return_type.IsPrim64()) { +% elsif insn.return_void? + if (!curr_func_->return_type.IsVoid()) { +% end + GetWarning("Unexpected return type. Correct the return type in the function definition: " + + curr_func_->return_type.GetName(), + Error::ErrorType::WAR_UNEXPECTED_RETURN_TYPE); + } +% end +% required_args = operands.size +% required_args = 1 if insn.call? +% required_args = 2 if insn.calli? +% operands.each_with_index do |op, j| +% +% if (j != 0) +% if j >= required_args + if (!context_.Mask()) { + ParseOperandComma(); + } +% else + if (!context_.Mask()) { + ParseOperandComma(); + } else { + context_.err = GetError("Expected comma.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); + } +% end +% end +% + if (!context_.Mask()) { +% if op.reg? + + if (RegValidName()) { + p = context_.GiveToken(); + p.remove_prefix(1); + number = ToNumber(p); + size_t reg_width = curr_func_->ins.back().MaxRegEncodingWidth(); + if ((1ull << reg_width) <= number) { + context_.err = GetError("Register width mismatch.", Error::ErrorType::ERR_BAD_OPERAND); + } + } else if (context_.err.err == Error::ErrorType::ERR_NONE) { + context_.err = GetError("Invalid name of register.", Error::ErrorType::ERR_BAD_NAME_REG); + } + + ParseOperandVreg(); +% elsif op.imm? +% if (!insn.public? && j == 0) + ParseOperandBuiltinMnemonic(); +% elsif properties.include?("jump") + ParseOperandLabel(); +% else +% if properties.include?("float") + ParseOperandFloat(); +% else + ParseOperandInteger(); +% end +% end +% elsif op.id? +% if properties.include?("type_id") +% if (verification.include?("type_id_array")) + ParseOperandType(Type::VerificationType::TYPE_ID_ARRAY); +% elsif (verification.include?("type_id_object")) + ParseOperandType(Type::VerificationType::TYPE_ID_OBJECT); +% elsif (verification.include?("type_id_any_object")) + ParseOperandType(Type::VerificationType::TYPE_ID_ANY_OBJECT); +% end +% elsif properties.include?("string_id") + ParseOperandString(); +% elsif properties.include?("method_id") + ParseOperandCall(); +% elsif properties.include?("field_id") + ParseOperandField(); +% else + ParseOperandId(); +% end +% end +% +% if (j >= required_args) && (operands.size > 0) + } +% elsif operands.size > 0 + } else { + context_.err = GetError("Expected more arguments.", Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); + } +% end +% end + ParseOperandNone(); + } break; +%end + default: + context_.err = GetError("No such operation.", Error::ErrorType::ERR_BAD_NONEXISTING_OPERATION); + return false; + } + return context_.Mask(); +} + +} // namespace panda::pandasm diff --git a/assembler/templates/operand_types_print.h.erb b/assembler/templates/operand_types_print.h.erb new file mode 100644 index 0000000000..dfc62a4983 --- /dev/null +++ b/assembler/templates/operand_types_print.h.erb @@ -0,0 +1,53 @@ +/* + * 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" + +namespace panda::pandasm { + +inline std::string OperandTypePrint(panda::pandasm::Opcode op) { + switch (op) { +% Panda::instructions.group_by(&:mnemonic).each do |mnemonic, group| +% insn = group.first +% operands = insn.operands +% properties = insn.properties + case Opcode::<%= group.first.asm_token%>: { +% operands_list = operands.map do |op| +% if op.reg? +% 'reg' +% elsif op.imm? +% properties.include?('jump') ? 'label' : 'imm' +% elsif op.id? +% if properties.include?('type_id') +% 'type' +% elsif properties.include?('string_id') +% 'string' +% elsif properties.include?('method_id') +% 'call' +% else +% 'id' +% end +% end +% end.join('_') +% operands_list = 'none' if operands_list == '' + return "<%= operands_list%>"; + }; +%end + default: + return "undefined"; + } +} + +} // namespace panda::pandasm diff --git a/assembler/tests/emitter_test.cpp b/assembler/tests/emitter_test.cpp new file mode 100644 index 0000000000..471070a279 --- /dev/null +++ b/assembler/tests/emitter_test.cpp @@ -0,0 +1,871 @@ +/* + * 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 +#include +#include "annotation_data_accessor.h" +#include "assembly-emitter.h" +#include "assembly-parser.h" +#include "class_data_accessor-inl.h" +#include "code_data_accessor-inl.h" +#include "debug_data_accessor-inl.h" +#include "field_data_accessor-inl.h" +#include "file_items.h" +#include "lexer.h" +#include "method_data_accessor-inl.h" +#include "param_annotations_data_accessor.h" +#include "proto_data_accessor-inl.h" +#include "utils/span.h" +#include "utils/leb128.h" +#include "utils/utf.h" + +namespace panda::test { + +using namespace panda::pandasm; + +static const uint8_t *GetTypeDescriptor(const std::string &name, std::string *storage) +{ + *storage = "L" + name + ";"; + std::replace(storage->begin(), storage->end(), '.', '/'); + return utf::CStringAsMutf8(storage->c_str()); +} + +TEST(emittertests, test) +{ + Parser p; + + auto source = R"( # 1 + .record R { # 2 + i32 sf # 3 + i8 if # 4 + } # 5 + # 6 + .function void main() { # 7 + return.void # 8 + } # 9 + )"; + + std::string source_filename = "source.pa"; + auto res = p.Parse(source, source_filename); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_NE(pf, nullptr); + + // Check _GLOBAL class + { + std::string descriptor; + auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor)); + ASSERT_TRUE(class_id.IsValid()); + ASSERT_FALSE(pf->IsExternal(class_id)); + + panda_file::ClassDataAccessor cda(*pf, class_id); + ASSERT_EQ(cda.GetSuperClassId().GetOffset(), 0U); + ASSERT_EQ(cda.GetAccessFlags(), ACC_PUBLIC); + ASSERT_EQ(cda.GetFieldsNumber(), 0U); + ASSERT_EQ(cda.GetMethodsNumber(), 1U); + ASSERT_EQ(cda.GetIfacesNumber(), 0U); + + ASSERT_FALSE(cda.GetSourceFileId().has_value()); + + cda.EnumerateRuntimeAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); }); + + cda.EnumerateAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); }); + + cda.EnumerateFields([](panda_file::FieldDataAccessor &) { ASSERT_TRUE(false); }); + + cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { + ASSERT_FALSE(mda.IsExternal()); + ASSERT_EQ(mda.GetClassId(), class_id); + ASSERT_EQ(utf::CompareMUtf8ToMUtf8(pf->GetStringData(mda.GetNameId()).data, utf::CStringAsMutf8("main")), + 0); + + panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId()); + ASSERT_EQ(pda.GetNumArgs(), 0U); + ASSERT_EQ(pda.GetReturnType().GetId(), panda_file::Type::TypeId::VOID); + + ASSERT_EQ(mda.GetAccessFlags(), ACC_STATIC); + ASSERT_TRUE(mda.GetCodeId().has_value()); + + panda_file::CodeDataAccessor cdacc(*pf, mda.GetCodeId().value()); + ASSERT_EQ(cdacc.GetNumVregs(), 0U); + ASSERT_EQ(cdacc.GetNumArgs(), 0U); + ASSERT_EQ(cdacc.GetCodeSize(), 1U); + ASSERT_EQ(cdacc.GetTriesSize(), 0U); + + ASSERT_FALSE(mda.GetRuntimeParamAnnotationId().has_value()); + ASSERT_FALSE(mda.GetParamAnnotationId().has_value()); + ASSERT_TRUE(mda.GetDebugInfoId().has_value()); + + panda_file::DebugInfoDataAccessor dda(*pf, mda.GetDebugInfoId().value()); + ASSERT_EQ(dda.GetLineStart(), 8U); + ASSERT_EQ(dda.GetNumParams(), 0U); + + mda.EnumerateRuntimeAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); }); + mda.EnumerateAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); }); + }); + } + + // Check R class + { + std::string descriptor; + auto class_id = pf->GetClassId(GetTypeDescriptor("R", &descriptor)); + ASSERT_TRUE(class_id.IsValid()); + ASSERT_FALSE(pf->IsExternal(class_id)); + + panda_file::ClassDataAccessor cda(*pf, class_id); + ASSERT_EQ(cda.GetSuperClassId().GetOffset(), 0U); + ASSERT_EQ(cda.GetAccessFlags(), 0); + ASSERT_EQ(cda.GetFieldsNumber(), 2U); + ASSERT_EQ(cda.GetMethodsNumber(), 0U); + ASSERT_EQ(cda.GetIfacesNumber(), 0U); + + // We emit SET_FILE in debuginfo + ASSERT_TRUE(cda.GetSourceFileId().has_value()); + + EXPECT_EQ(std::string(reinterpret_cast(pf->GetStringData(cda.GetSourceFileId().value()).data)), + source_filename); + + cda.EnumerateRuntimeAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); }); + + cda.EnumerateAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); }); + + struct FieldData { + std::string name; + panda_file::Type::TypeId type_id; + uint32_t access_flags; + }; + + std::vector fields {{"sf", panda_file::Type::TypeId::I32, ACC_STATIC}, + {"if", panda_file::Type::TypeId::I8, 0}}; + + size_t i = 0; + cda.EnumerateFields([&](panda_file::FieldDataAccessor &fda) { + ASSERT_FALSE(fda.IsExternal()); + ASSERT_EQ(fda.GetClassId(), class_id); + ASSERT_EQ(utf::CompareMUtf8ToMUtf8(pf->GetStringData(fda.GetNameId()).data, + utf::CStringAsMutf8(fields[i].name.c_str())), + 0); + + ASSERT_EQ(fda.GetType(), panda_file::Type(fields[i].type_id).GetFieldEncoding()); + ASSERT_EQ(fda.GetAccessFlags(), fields[i].access_flags); + + fda.EnumerateRuntimeAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); }); + fda.EnumerateAnnotations([](panda_file::File::EntityId) { ASSERT_TRUE(false); }); + + ++i; + }); + + cda.EnumerateMethods([&](panda_file::MethodDataAccessor &) { ASSERT_TRUE(false); }); + } +} + +uint8_t GetSpecialOpcode(uint32_t pc_inc, int32_t line_inc) +{ + return (line_inc - panda_file::LineNumberProgramItem::LINE_BASE) + + (pc_inc * panda_file::LineNumberProgramItem::LINE_RANGE) + panda_file::LineNumberProgramItem::OPCODE_BASE; +} + +TEST(emittertests, debuginfo) +{ + Parser p; + + auto source = R"( + .function void main() { + ldai.64 0 # line 3, pc 0 + # line 4 + # line 5 + # line 6 + # line 7 + # line 8 + # line 9 + # line 10 + # line 11 + # line 12 + # line 13 + # line 14 + ldai.64 1 # line 15, pc 9 + return.void # line 16, pc 18 + } + )"; + + std::string source_filename = "source.pa"; + auto res = p.Parse(source, source_filename); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_NE(pf, nullptr); + + std::string descriptor; + auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor)); + ASSERT_TRUE(class_id.IsValid()); + + panda_file::ClassDataAccessor cda(*pf, class_id); + + cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { + panda_file::CodeDataAccessor cdacc(*pf, mda.GetCodeId().value()); + ASSERT_TRUE(mda.GetDebugInfoId().has_value()); + + panda_file::DebugInfoDataAccessor dda(*pf, mda.GetDebugInfoId().value()); + ASSERT_EQ(dda.GetLineStart(), 3U); + ASSERT_EQ(dda.GetNumParams(), 0U); + + const uint8_t *program = dda.GetLineNumberProgram(); + Span constant_pool = dda.GetConstantPool(); + + std::vector opcodes {static_cast(panda_file::LineNumberProgramItem::Opcode::SET_FILE), + static_cast(panda_file::LineNumberProgramItem::Opcode::ADVANCE_PC), + static_cast(panda_file::LineNumberProgramItem::Opcode::ADVANCE_LINE), + GetSpecialOpcode(0, 0), + GetSpecialOpcode(9, 1), + static_cast(panda_file::LineNumberProgramItem::Opcode::END_SEQUENCE)}; + + EXPECT_THAT(opcodes, ::testing::ElementsAreArray(program, opcodes.size())); + + size_t size; + bool is_full; + size_t constant_pool_offset = 0; + + uint32_t offset; + + std::tie(offset, size, is_full) = leb128::DecodeUnsigned(&constant_pool[constant_pool_offset]); + constant_pool_offset += size; + ASSERT_TRUE(is_full); + EXPECT_EQ( + std::string(reinterpret_cast(pf->GetStringData(panda_file::File::EntityId(offset)).data)), + source_filename); + + uint32_t pc_inc; + std::tie(pc_inc, size, is_full) = leb128::DecodeUnsigned(&constant_pool[constant_pool_offset]); + constant_pool_offset += size; + ASSERT_TRUE(is_full); + EXPECT_EQ(pc_inc, 9U); + + int32_t line_inc; + std::tie(line_inc, size, is_full) = leb128::DecodeSigned(&constant_pool[constant_pool_offset]); + constant_pool_offset += size; + ASSERT_TRUE(is_full); + EXPECT_EQ(line_inc, 12); + + EXPECT_EQ(constant_pool_offset, constant_pool.size()); + }); +} + +TEST(emittertests, exceptions) +{ + Parser p; + + auto source = R"( + .record Exception1 {} + .record Exception2 {} + + .function void main() { + ldai.64 0 + try_begin: + ldai.64 1 + ldai.64 2 + try_end: + ldai.64 3 + catch_begin1: + ldai.64 4 + catch_begin2: + ldai.64 5 + catchall_begin: + ldai.64 6 + + .catch Exception1, try_begin, try_end, catch_begin1 + .catch Exception2, try_begin, try_end, catch_begin2 + .catchall try_begin, try_end, catchall_begin + } + )"; + + auto res = p.Parse(source); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_NE(pf, nullptr); + + std::string descriptor; + + auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor)); + ASSERT_TRUE(class_id.IsValid()); + + panda_file::ClassDataAccessor cda(*pf, class_id); + + cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { + panda_file::CodeDataAccessor cdacc(*pf, mda.GetCodeId().value()); + ASSERT_EQ(cdacc.GetNumVregs(), 0U); + ASSERT_EQ(cdacc.GetNumArgs(), 0U); + ASSERT_EQ(cdacc.GetTriesSize(), 1); + + cdacc.EnumerateTryBlocks([&](panda_file::CodeDataAccessor::TryBlock &try_block) { + EXPECT_EQ(try_block.GetStartPc(), 9); + EXPECT_EQ(try_block.GetLength(), 18); + EXPECT_EQ(try_block.GetNumCatches(), 3); + + struct CatchInfo { + panda_file::File::EntityId type_id; + uint32_t handler_pc; + }; + + std::vector catch_infos {{pf->GetClassId(GetTypeDescriptor("Exception1", &descriptor)), 4 * 9}, + {pf->GetClassId(GetTypeDescriptor("Exception2", &descriptor)), 5 * 9}, + {panda_file::File::EntityId(), 6 * 9}}; + + size_t i = 0; + try_block.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catch_block) { + auto idx = catch_block.GetTypeIdx(); + auto id = idx != panda_file::INVALID_INDEX ? pf->ResolveClassIndex(mda.GetMethodId(), idx) + : panda_file::File::EntityId(); + EXPECT_EQ(id, catch_infos[i].type_id); + EXPECT_EQ(catch_block.GetHandlerPc(), catch_infos[i].handler_pc); + ++i; + + return true; + }); + + return true; + }); + }); +} + +TEST(emittertests, errors) +{ + { + Parser p; + auto source = R"( + .record A { + B b + } + )"; + + auto res = p.Parse(source); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_EQ(pf, nullptr); + ASSERT_EQ(AsmEmitter::GetLastError(), "Field A.b has undefined type"); + } + + { + Parser p; + auto source = R"( + .function void A.b() {} + )"; + + auto res = p.Parse(source); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_EQ(pf, nullptr); + ASSERT_EQ(AsmEmitter::GetLastError(), "Function A.b is bound to undefined record A"); + } + + { + Parser p; + auto source = R"( + .function A b() {} + )"; + + auto res = p.Parse(source); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_EQ(pf, nullptr); + ASSERT_EQ(AsmEmitter::GetLastError(), "Function b has undefined return type"); + } + + { + Parser p; + auto source = R"( + .function void a(b a0) {} + )"; + + auto res = p.Parse(source); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_EQ(pf, nullptr); + ASSERT_EQ(AsmEmitter::GetLastError(), "Argument 0 of function a has undefined type"); + } + + { + Parser p; + auto source = R"( + .record A + .function void A.x() {} + )"; + + auto res = p.Parse(source); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_EQ(pf, nullptr); + ASSERT_EQ(AsmEmitter::GetLastError(), "Non-external function A.x is bound to external record"); + } + + { + Ins i; + Function f("test_fuzz_imms", pandasm::extensions::Language::ECMASCRIPT); + Program prog; + i.opcode = Opcode::LDAI_64; + i.imms.clear(); + f.ins.push_back(i); + prog.function_table.emplace("test_fuzz_imms", std::move(f)); + + auto pf = AsmEmitter::Emit(prog); + ASSERT_EQ(pf, nullptr); + ASSERT_EQ(AsmEmitter::GetLastError(), "Internal error during emitting function: test_fuzz_imms"); + } + + { + Ins i; + Function f("test_fuzz_regs", pandasm::extensions::Language::ECMASCRIPT); + Program prog; + i.opcode = Opcode::LDA; + i.regs.clear(); + f.ins.push_back(i); + prog.function_table.emplace("test_fuzz_regs", std::move(f)); + + auto pf = AsmEmitter::Emit(prog); + ASSERT_EQ(pf, nullptr); + ASSERT_EQ(AsmEmitter::GetLastError(), "Internal error during emitting function: test_fuzz_regs"); + } + + { + Ins i; + Function f("test_fuzz_ids", pandasm::extensions::Language::ECMASCRIPT); + Program prog; + i.opcode = Opcode::LDA_STR; + i.ids.push_back("testFuzz"); + f.ins.push_back(i); + prog.function_table.emplace("test_fuzz_ids", std::move(f)); + prog.strings.insert("testFuz_"); + + auto pf = AsmEmitter::Emit(prog); + ASSERT_EQ(pf, nullptr); + ASSERT_EQ(AsmEmitter::GetLastError(), "Internal error during emitting function: test_fuzz_ids"); + } +} + +enum class ItemType { RECORD, FIELD, FUNCTION, PARAMETER }; + +std::string ItemTypeToString(ItemType item_type) +{ + switch (item_type) { + case ItemType::RECORD: + return "record"; + case ItemType::FIELD: + return "field"; + case ItemType::FUNCTION: + return "function"; + case ItemType::PARAMETER: + return "parameter"; + default: + break; + } + + UNREACHABLE(); + return ""; +} + +template +auto GetAnnotationElementValue(size_t idx) +{ + using T = ValueTypeHelperT; + + if constexpr (std::is_arithmetic_v) { + if constexpr (type == Value::Type::U1) { + return static_cast(idx == 0 ? 0 : 1); + } + + auto res = idx == 0 ? std::numeric_limits::min() : std::numeric_limits::max(); + + if constexpr (type == Value::Type::I8) { + return static_cast(res); + } + if constexpr (type == Value::Type::U8) { + return static_cast(res); + } + if constexpr (std::is_floating_point_v) { + return res * (idx == 0 ? 10 : 0.1); + } + + return res; + } else { + switch (type) { + case Value::Type::STRING: + return idx == 0 ? "123" : "456"; + case Value::Type::RECORD: + return idx == 0 ? "A" : "B"; + case Value::Type::ENUM: + return idx == 0 ? "E.E1" : "E.E2"; + case Value::Type::ANNOTATION: + return idx == 0 ? "id_A" : "id_B"; + default: + break; + } + + UNREACHABLE(); + return ""; + } +} + +TEST(emittertests, language) +{ + { + Parser p; + auto source = R"( + .function void foo() {} + )"; + + auto res = p.Parse(source); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_NE(pf, nullptr); + + std::string descriptor; + + auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor)); + ASSERT_TRUE(class_id.IsValid()); + + panda_file::ClassDataAccessor cda(*pf, class_id); + + ASSERT_FALSE(cda.GetSourceLang()); + + cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { ASSERT_FALSE(mda.GetSourceLang()); }); + } +} + +TEST(emittertests, constructors) +{ + { + Parser p; + auto source = R"( + .record R {} + .function void R.foo(R a0) {} + )"; + + auto res = p.Parse(source); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_NE(pf, nullptr); + + std::string descriptor; + + auto class_id = pf->GetClassId(GetTypeDescriptor("R", &descriptor)); + ASSERT_TRUE(class_id.IsValid()); + + panda_file::ClassDataAccessor cda(*pf, class_id); + + cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { + auto *name = utf::Mutf8AsCString(pf->GetStringData(mda.GetNameId()).data); + ASSERT_STREQ(name, ".ctor"); + }); + } + + { + Parser p; + auto source = R"( + .record R {} + .function void R.foo(R a0) {} + )"; + + auto res = p.Parse(source); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_NE(pf, nullptr); + + std::string descriptor; + + auto class_id = pf->GetClassId(GetTypeDescriptor("R", &descriptor)); + ASSERT_TRUE(class_id.IsValid()); + + panda_file::ClassDataAccessor cda(*pf, class_id); + + cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { + auto *name = utf::Mutf8AsCString(pf->GetStringData(mda.GetNameId()).data); + ASSERT_STREQ(name, ".cctor"); + }); + } +} + +TEST(emittertests, field_value) +{ + Parser p; + + auto source = R"( + .record panda.String + + .record R { + u1 f_u1 + i8 f_i8 + u8 f_u8 + i16 f_i16 + u16 f_u16 + i32 f_i32 + u32 f_u32 + i64 f_i64 + u64 f_u64 + f32 f_f32 + f64 f_f64 + panda.String f_str + } + )"; + + struct FieldData { + std::string name; + panda_file::Type::TypeId type_id; + std::variant value; + }; + + std::vector data { + {"f_u1", panda_file::Type::TypeId::U1, static_cast(1)}, + {"f_i8", panda_file::Type::TypeId::I8, static_cast(2)}, + {"f_u8", panda_file::Type::TypeId::U8, static_cast(128)}, + {"f_i16", panda_file::Type::TypeId::I16, static_cast(256)}, + {"f_u16", panda_file::Type::TypeId::U16, static_cast(32768)}, + {"f_i32", panda_file::Type::TypeId::I32, static_cast(65536)}, + {"f_u32", panda_file::Type::TypeId::U32, static_cast(2147483648)}, + {"f_i64", panda_file::Type::TypeId::I64, static_cast(4294967296)}, + {"f_u64", panda_file::Type::TypeId::U64, static_cast(9223372036854775808ULL)}, + {"f_f32", panda_file::Type::TypeId::F32, static_cast(1.0)}, + {"f_f64", panda_file::Type::TypeId::F64, static_cast(2.0)}, + {"f_str", panda_file::Type::TypeId::REFERENCE, "str"}}; + + auto res = p.Parse(source); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_NE(pf, nullptr); + + std::string descriptor; + auto class_id = pf->GetClassId(GetTypeDescriptor("R", &descriptor)); + ASSERT_TRUE(class_id.IsValid()); + ASSERT_FALSE(pf->IsExternal(class_id)); + + panda_file::ClassDataAccessor cda(*pf, class_id); + ASSERT_EQ(cda.GetFieldsNumber(), data.size()); + + auto panda_string_id = pf->GetClassId(GetTypeDescriptor("panda.String", &descriptor)); + + size_t idx = 0; + cda.EnumerateFields([&](panda_file::FieldDataAccessor &fda) { + const FieldData &field_data = data[idx]; + + ASSERT_EQ(utf::CompareMUtf8ToMUtf8(pf->GetStringData(fda.GetNameId()).data, + utf::CStringAsMutf8(field_data.name.c_str())), + 0); + + panda_file::Type type(field_data.type_id); + uint32_t type_value; + if (type.IsReference()) { + type_value = panda_string_id.GetOffset(); + } else { + type_value = type.GetFieldEncoding(); + } + + ASSERT_EQ(fda.GetType(), type_value); + + switch (field_data.type_id) { + case panda_file::Type::TypeId::U1: { + auto result = fda.GetValue(); + ASSERT_TRUE(result); + ASSERT_EQ(result.value(), std::get(field_data.value)); + break; + } + case panda_file::Type::TypeId::I8: { + auto result = fda.GetValue(); + ASSERT_TRUE(result); + ASSERT_EQ(result.value(), std::get(field_data.value)); + break; + } + case panda_file::Type::TypeId::U8: { + auto result = fda.GetValue(); + ASSERT_TRUE(result); + ASSERT_EQ(result.value(), std::get(field_data.value)); + break; + } + case panda_file::Type::TypeId::I16: { + auto result = fda.GetValue(); + ASSERT_TRUE(result); + ASSERT_EQ(result.value(), std::get(field_data.value)); + break; + } + case panda_file::Type::TypeId::U16: { + auto result = fda.GetValue(); + ASSERT_TRUE(result); + ASSERT_EQ(result.value(), std::get(field_data.value)); + break; + } + case panda_file::Type::TypeId::I32: { + auto result = fda.GetValue(); + ASSERT_TRUE(result); + ASSERT_EQ(result.value(), std::get(field_data.value)); + break; + } + case panda_file::Type::TypeId::U32: { + auto result = fda.GetValue(); + ASSERT_TRUE(result); + ASSERT_EQ(result.value(), std::get(field_data.value)); + break; + } + case panda_file::Type::TypeId::I64: { + auto result = fda.GetValue(); + ASSERT_TRUE(result); + ASSERT_EQ(result.value(), std::get(field_data.value)); + break; + } + case panda_file::Type::TypeId::U64: { + auto result = fda.GetValue(); + ASSERT_TRUE(result); + ASSERT_EQ(result.value(), std::get(field_data.value)); + break; + } + case panda_file::Type::TypeId::F32: { + auto result = fda.GetValue(); + ASSERT_TRUE(result); + ASSERT_EQ(result.value(), std::get(field_data.value)); + break; + } + case panda_file::Type::TypeId::F64: { + auto result = fda.GetValue(); + ASSERT_TRUE(result); + ASSERT_EQ(result.value(), std::get(field_data.value)); + break; + } + case panda_file::Type::TypeId::REFERENCE: { + auto result = fda.GetValue(); + ASSERT_TRUE(result); + + panda_file::File::EntityId string_id(result.value()); + auto val = std::get(field_data.value); + + ASSERT_EQ(utf::CompareMUtf8ToMUtf8(pf->GetStringData(string_id).data, utf::CStringAsMutf8(val.c_str())), + 0); + break; + } + default: { + UNREACHABLE(); + break; + } + } + + ++idx; + }); +} + +TEST(emittertests, tagged_in_func_decl) +{ + Parser p; + auto source = R"( + .function any foo(any a0) + )"; + + auto res = p.Parse(source); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_NE(pf, nullptr); + + std::string descriptor; + + auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor)); + ASSERT_TRUE(class_id.IsValid()); + + panda_file::ClassDataAccessor cda(*pf, class_id); + + size_t num_methods = 0; + const auto tagged = panda_file::Type(panda_file::Type::TypeId::TAGGED); + cda.EnumerateMethods([&](panda_file::MethodDataAccessor &mda) { + panda_file::ProtoDataAccessor pda(*pf, mda.GetProtoId()); + ASSERT_EQ(tagged, pda.GetReturnType()); + ASSERT_EQ(1, pda.GetNumArgs()); + ASSERT_EQ(tagged, pda.GetArgType(0)); + + ++num_methods; + }); + ASSERT_EQ(1, num_methods); +} + +TEST(emittertests, tagged_in_field_decl) +{ + Parser p; + auto source = R"( + .record Test { + any foo + } + )"; + + auto res = p.Parse(source); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_NE(pf, nullptr); + + std::string descriptor; + + auto class_id = pf->GetClassId(GetTypeDescriptor("Test", &descriptor)); + ASSERT_TRUE(class_id.IsValid()); + + panda_file::ClassDataAccessor cda(*pf, class_id); + + size_t num_fields = 0; + const auto tagged = panda_file::Type(panda_file::Type::TypeId::TAGGED); + cda.EnumerateFields([&](panda_file::FieldDataAccessor &fda) { + uint32_t type = fda.GetType(); + ASSERT_EQ(tagged.GetFieldEncoding(), type); + + ++num_fields; + }); + ASSERT_EQ(1, num_fields); +} + +TEST(emittertests, get_GLOBAL_lang_for_JS_func) +{ + Parser p; + auto source = R"( + .language ECMAScript + + .function any main() { + return.dyn + } + )"; + + auto res = p.Parse(source); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + auto pf = AsmEmitter::Emit(res.Value()); + ASSERT_NE(pf, nullptr); + + std::string descriptor; + + auto class_id = pf->GetClassId(GetTypeDescriptor("_GLOBAL", &descriptor)); + ASSERT_TRUE(class_id.IsValid()); + + panda_file::ClassDataAccessor cda(*pf, class_id); + + ASSERT_TRUE(cda.GetSourceLang().has_value()); + ASSERT_EQ(cda.GetSourceLang(), panda_file::SourceLang::ECMASCRIPT); +} + +} // namespace panda::test diff --git a/assembler/tests/lexer_test.cpp b/assembler/tests/lexer_test.cpp new file mode 100644 index 0000000000..f613727b4e --- /dev/null +++ b/assembler/tests/lexer_test.cpp @@ -0,0 +1,217 @@ +/* + * 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 "../define.h" +#include "../lexer.h" + +namespace panda::test { + +using namespace panda::pandasm; + +TEST(lexertests, test1) +{ + Lexer l; + std::string s = "mov v1, v2"; + Tokens tok = l.TokenizeString(s); + ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "DEL_COMMA") << "DEL_COMMA expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[3].type), "ID") << "ID expected"; + ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(lexertests, test2) +{ + Lexer l; + std::string s = "ldai 1"; + Tokens tok = l.TokenizeString(s); + ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected"; + ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(lexertests, test3) +{ + Lexer l; + std::string s = "movi\nlda v2 v10 mov v2"; + Tokens tok = l.TokenizeString(s); + ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "OPERATION") << "OPERATION expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "ID") << "ID expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[3].type), "ID") << "ID expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[4].type), "OPERATION") << "OPERATION expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[5].type), "ID") << "ID expected"; + ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(lexertests, test4) +{ + Lexer l; + std::string s = "jmp Iasdfsadkfjhasifhsaiuhdacoisjdaociewhasdasdfkjasdfhjksadhfkhsakdfjhksajhdkfjhskhdfkjahhjdskaj"; + Tokens tok = l.TokenizeString(s); + ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected"; + ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(lexertests, test5) +{ + Lexer l; + std::string s = "call.short 1111, 1"; + Tokens tok = l.TokenizeString(s); + ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "DEL_COMMA") << "DEL_COMMA expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[3].type), "ID") << "ID expected"; + ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(lexertests, test6) +{ + Lexer l; + std::string s = "jle v1 met"; + Tokens tok = l.TokenizeString(s); + ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "OPERATION") << "OPERATION expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "ID") << "ID expected"; + ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(lexertests, test7) +{ + Lexer l; + std::string s = "label:"; + Tokens tok = l.TokenizeString(s); + ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "ID") << "ID expected"; + ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(lexertests, test8) +{ + Lexer l; + std::string s = ","; + Tokens tok = l.TokenizeString(s); + ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "DEL_COMMA") << "DEL_COMMA expected"; + ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(lexertests, test9) +{ + Lexer l; + std::string s = ",:{}()<>="; + Tokens tok = l.TokenizeString(s); + ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "DEL_COMMA") << "DEL_COMMA expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "DEL_COLON") << "DEL_COMMA expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[2].type), "DEL_BRACE_L") << "DEL_COMMA expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[3].type), "DEL_BRACE_R") << "DEL_COMMA expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[4].type), "DEL_BRACKET_L") << "DEL_BRACKET_L expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[5].type), "DEL_BRACKET_R") << "DEL_BRACKET_R expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[6].type), "DEL_LT") << "DEL_LT expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[7].type), "DEL_GT") << "DEL_GT expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[8].type), "DEL_EQ") << "DEL_EQ expected"; + ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(lexertests, test11) +{ + Lexer l; + std::string s = + "i64.to.f32 alsdhashdjskhfka " + "shdkfhkasdhfkhsakdhfkshkfhskahlfkjsdfkjadskhfkshadkhfsdakhfksahdkfaksdfkhaskldhkfashdlfkjhasdkjfhklasjhdfklhsa" + "fhska"; + Tokens tok = l.TokenizeString(s); + ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(lexertests, test12) +{ + Lexer l; + std::string s = ".function asd(u32){}"; + Tokens tok = l.TokenizeString(s); + ASSERT_EQ(TokenTypeWhat(tok.first[0].type), "KEYWORD") << "KEYWORD expected"; + ASSERT_EQ(TokenTypeWhat(tok.first[1].type), "ID") << "ID expected"; + ASSERT_EQ(tok.second.err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(lexertests, string_literal) +{ + { + Lexer l; + std::string s = "\"123"; + Tokens tok = l.TokenizeString(s); + + Error e = tok.second; + + ASSERT_EQ(e.err, Error::ErrorType::ERR_STRING_MISSING_TERMINATING_CHARACTER); + } + + { + Lexer l; + std::string s = "\"123\\\""; + Tokens tok = l.TokenizeString(s); + + Error e = tok.second; + + ASSERT_EQ(e.err, Error::ErrorType::ERR_STRING_MISSING_TERMINATING_CHARACTER); + } + + { + Lexer l; + std::string s = "\" a b \\ c d \""; + Tokens tok = l.TokenizeString(s); + + Error e = tok.second; + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + ASSERT_EQ(tok.first.size(), 1U); + ASSERT_EQ(tok.first[0].type, Token::Type::ID_STRING); + ASSERT_EQ(tok.first[0].bound_left, 0U); + ASSERT_EQ(tok.first[0].bound_right, s.length()); + } + + { + Lexer l; + std::string s = "\"abcd\"1234"; + Tokens tok = l.TokenizeString(s); + + Error e = tok.second; + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + ASSERT_EQ(tok.first.size(), 2U); + ASSERT_EQ(tok.first[0].type, Token::Type::ID_STRING); + ASSERT_EQ(tok.first[0].bound_left, 0U); + ASSERT_EQ(tok.first[0].bound_right, s.find('1')); + } +} + +TEST(lexertests, array_type) +{ + Lexer l; + std::string s = "i32[]"; + Tokens tok = l.TokenizeString(s); + + Error e = tok.second; + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + ASSERT_EQ(tok.first.size(), 3U); + ASSERT_EQ(tok.first[0].type, Token::Type::ID); + ASSERT_EQ(tok.first[1].type, Token::Type::DEL_SQUARE_BRACKET_L); + ASSERT_EQ(tok.first[2].type, Token::Type::DEL_SQUARE_BRACKET_R); +} + +} // namespace panda::test \ No newline at end of file diff --git a/assembler/tests/mangling_tests.cpp b/assembler/tests/mangling_tests.cpp new file mode 100644 index 0000000000..0fe056bff8 --- /dev/null +++ b/assembler/tests/mangling_tests.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 +#include +#include +#include "mangling.h" +#include "assembly-function.h" +#include "extensions/extensions.h" + +namespace panda::test { + +using namespace panda::pandasm; + +TEST(mangling_tests, MangleFunctionName) +{ + std::vector params; + extensions::Language language {extensions::Language::PANDA_ASSEMBLY}; + params.emplace_back(Type {"type1", 0}, language); + params.emplace_back(Type {"type2", 0}, language); + params.emplace_back(Type {"type3", 0}, language); + + auto return_type = Type("type4", 0); + + std::string name = "Asm.main"; + ASSERT_EQ(MangleFunctionName(name, std::move(params), return_type), "Asm.main:type1;type2;type3;type4;"); +} + +TEST(mangling_tests, DeMangleFunctionName) +{ + std::string name = "Asm.main:type1;type2;type3;type4;"; + ASSERT_EQ(DeMangleName(name), "Asm.main"); +} + +} // namespace panda::test \ No newline at end of file diff --git a/assembler/tests/parser_test.cpp b/assembler/tests/parser_test.cpp new file mode 100644 index 0000000000..dda1343e3a --- /dev/null +++ b/assembler/tests/parser_test.cpp @@ -0,0 +1,3706 @@ +/* + * 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 "operand_types_print.h" + +#include +#include + +namespace panda::test { + +using namespace panda::pandasm; + +TEST(parsertests, test1) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("mov v1, v2}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].opcode, Opcode::MOV); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].regs[0], 1) << "1 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[0].regs[1], 2) << "2 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(parsertests, test2) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("label:}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].label, "label") << "label expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[0].set_label, true) << "true expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[0].opcode, Opcode::INVALID) << "NONE expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(parsertests, test3) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("jlt v10, lab123}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_LABEL_EXT) << "ERR_BAD_LABEL_EXT expected"; +} + +TEST(parsertests, test4) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("11111111}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_OPERATION_NAME) << "ERR_BAD_OPERATION_NAME expected"; +} + +TEST(parsertests, test5) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("addi 1}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].opcode, Opcode::ADDI) << "IMM expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(int64_t(1))) << "1 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(parsertests, test6) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("addi 12345}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].opcode, Opcode::ADDI) << "IMM expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(int64_t(12345))) << "12345 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(parsertests, test7) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("addi 11.3}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_INTEGER_NAME) << "ERR_NONE expected"; +} + +TEST(parsertests, test8) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("ashdjbf iashudbfiun as}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_OPERATION_NAME) << "ERR_BAD_OPERATION expected"; +} + +TEST(parsertests, test9) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("lda v1").first); + v.push_back(l.TokenizeString("movi v10, 1001}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].opcode, Opcode::LDA) << "V expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[0].regs[0], 1) << "1 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[1].opcode, Opcode::MOVI) << "V_IMM expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[1].regs[0], 10) << "10 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[1].imms[0], Ins::IType(int64_t(1001))) << "1001 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(parsertests, test10) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u1 main(){").first); + v.push_back(l.TokenizeString("call.short nain, v1, v2}").first); + v.push_back(l.TokenizeString(".function u1 nain(){}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].opcode, Opcode::CALL_SHORT) << "V_V_ID expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[0].ids[0], "nain") << "nain expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[0].regs[0], 1) << "1 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[0].regs[1], 2) << "2 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(parsertests, test11) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("i64tof64}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].opcode, Opcode::I64TOF64) << "NONE expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(parsertests, test12) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("jmp l123}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_LABEL_EXT) << "ERR_BAD_LABEL_EXT expected"; +} + +TEST(parsertests, test13) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("l123: jmp l123}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].opcode, Opcode::JMP) << "ID expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[0].ids[0], "l123") << "l123 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE"; +} + +TEST(parsertests, test14) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("jmp 123}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_NAME_ID) << "ERR_BAD_NAME_ID expected"; +} + +TEST(parsertests, test15) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("shli 12 asd}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_NUMBER_OPERANDS) << "ERR_BAD_NUMBER_OPERANDS expected"; +} + +TEST(parsertests, test17) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("ldarr.8 v120}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].opcode, Opcode::LDARR_8) << "V expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[0].regs[0], 120) << "120 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(parsertests, test18) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("return}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].opcode, Opcode::RETURN) << "NONE expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(parsertests, test19) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("return1}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_OPERATION_NAME) << "ERR_BAD_OPERATION expected"; +} + +TEST(parsertests, test20) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("return 1}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_NUMBER_OPERANDS) << "ERR_BAD_NUMBER_OPERANDS expected"; +} + +TEST(parsertests, test21) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("ashr2.64 1234}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_NAME_REG) << "ERR_BAD_NAME_REG expected"; +} + +TEST(parsertests, test22) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("ashr2.64 v12}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].opcode, Opcode::ASHR2_64) << "V expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[0].regs[0], 12) << "12 expected"; +} + +TEST(parsertests, test23) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("label1:").first); + v.push_back(l.TokenizeString("jle v0, label2").first); + v.push_back(l.TokenizeString("movi v15, 26").first); + v.push_back(l.TokenizeString("label2: mov v0, v1").first); + v.push_back(l.TokenizeString("call m123, v2, v6, v3, v4").first); + v.push_back(l.TokenizeString("}").first); + v.push_back(l.TokenizeString(".function f64 m123(u1 a0, f32 a1){").first); + v.push_back(l.TokenizeString("lda v10").first); + v.push_back(l.TokenizeString("sta a0").first); + v.push_back(l.TokenizeString("la1:").first); + v.push_back(l.TokenizeString("jle a1, la1").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").name, "main"); + ASSERT_EQ(item.Value().function_table.at("m123").name, "m123"); + ASSERT_EQ(item.Value().function_table.at("main").GetParamsNum(), 0U); + ASSERT_EQ(item.Value().function_table.at("m123").GetParamsNum(), 2U); + ASSERT_EQ(item.Value().function_table.at("m123").params[0].type.GetId(), panda::panda_file::Type::TypeId::U1); + ASSERT_EQ(item.Value().function_table.at("m123").params[1].type.GetId(), panda::panda_file::Type::TypeId::F32); + ASSERT_EQ(item.Value().function_table.at("main").return_type.GetId(), panda::panda_file::Type::TypeId::U8); + ASSERT_EQ(item.Value().function_table.at("m123").return_type.GetId(), panda::panda_file::Type::TypeId::F64); + ASSERT_EQ(item.Value().function_table.at("main").label_table.at("label1").file_location->line_number, 2U); + ASSERT_EQ(item.Value().function_table.at("main").label_table.at("label1").file_location->is_defined, true); + ASSERT_EQ(item.Value().function_table.at("main").label_table.at("label2").file_location->line_number, 3U); + ASSERT_EQ(item.Value().function_table.at("main").label_table.at("label2").file_location->is_defined, true); + ASSERT_EQ(item.Value().function_table.at("m123").label_table.at("la1").file_location->line_number, 11U); + ASSERT_EQ(item.Value().function_table.at("m123").label_table.at("la1").file_location->is_defined, true); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].opcode, Opcode::INVALID); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].label, "label1"); + ASSERT_EQ(item.Value().function_table.at("main").ins[1].opcode, Opcode::JLE); + ASSERT_EQ(item.Value().function_table.at("main").ins[1].regs[0], 0); + ASSERT_EQ(item.Value().function_table.at("main").ins[1].ids[0], "label2"); + ASSERT_EQ(item.Value().function_table.at("main").ins[2].opcode, Opcode::MOVI); + ASSERT_EQ(item.Value().function_table.at("main").ins[2].regs[0], 15); + ASSERT_EQ(item.Value().function_table.at("main").ins[2].imms[0], Ins::IType(int64_t(26))); + ASSERT_EQ(item.Value().function_table.at("main").ins[2].set_label, false); + ASSERT_EQ(item.Value().function_table.at("main").ins[3].opcode, Opcode::MOV); + ASSERT_EQ(item.Value().function_table.at("main").ins[3].regs[0], 0); + ASSERT_EQ(item.Value().function_table.at("main").ins[3].regs[1], 1); + ASSERT_EQ(item.Value().function_table.at("main").ins[3].label, "label2"); + ASSERT_EQ(item.Value().function_table.at("main").ins[3].set_label, true); + ASSERT_EQ(item.Value().function_table.at("main").ins[4].opcode, Opcode::CALL); + ASSERT_EQ(item.Value().function_table.at("main").ins[4].regs[0], 2); + ASSERT_EQ(item.Value().function_table.at("main").ins[4].regs[1], 6); + ASSERT_EQ(item.Value().function_table.at("main").ins[4].regs[2], 3); + ASSERT_EQ(item.Value().function_table.at("main").ins[4].regs[3], 4); + ASSERT_EQ(item.Value().function_table.at("main").ins[4].ids[0], "m123"); + ASSERT_EQ(item.Value().function_table.at("m123").ins[0].opcode, Opcode::LDA); + ASSERT_EQ(item.Value().function_table.at("m123").ins[0].regs[0], 10); + ASSERT_EQ(item.Value().function_table.at("m123").ins[1].opcode, Opcode::STA); + ASSERT_EQ(item.Value().function_table.at("m123").ins[1].regs[0], 11); + ASSERT_EQ(item.Value().function_table.at("m123").ins[2].opcode, Opcode::INVALID); + ASSERT_EQ(item.Value().function_table.at("m123").ins[2].label, "la1"); + ASSERT_EQ(item.Value().function_table.at("m123").ins[2].set_label, true); + ASSERT_EQ(item.Value().function_table.at("m123").ins[3].opcode, Opcode::JLE); + ASSERT_EQ(item.Value().function_table.at("m123").ins[3].regs[0], 12); + ASSERT_EQ(item.Value().function_table.at("m123").ins[3].ids[0], "la1"); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; +} + +TEST(parsertests, test24_functions) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void main()").first); + v.push_back(l.TokenizeString("{").first); + v.push_back(l.TokenizeString("movi v0, 0x100").first); + v.push_back(l.TokenizeString("movi v15, 0xffffffff").first); + v.push_back(l.TokenizeString("movi v15, 0xf").first); + v.push_back(l.TokenizeString("fmovi.64 v15, 1e3").first); + v.push_back(l.TokenizeString("movi v15, 0xE994").first); + v.push_back(l.TokenizeString("fmovi.64 v15, 1.1").first); + v.push_back(l.TokenizeString("fmovi.64 v15, 1.").first); + v.push_back(l.TokenizeString("fmovi.64 v15, .1").first); + v.push_back(l.TokenizeString("movi v15, 0").first); + v.push_back(l.TokenizeString("fmovi.64 v15, 0.1").first); + v.push_back(l.TokenizeString("fmovi.64 v15, 00.1").first); + v.push_back(l.TokenizeString("fmovi.64 v15, 00.").first); + v.push_back(l.TokenizeString("}").first); + v.push_back(l.TokenizeString(".function u8 niam(){").first); + v.push_back(l.TokenizeString("ldai -1").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").return_type.GetId(), panda::panda_file::Type::TypeId::VOID); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(int64_t(256))) << "256 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[1].imms[0], Ins::IType(int64_t(4294967295))) + << "4294967295 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[2].imms[0], Ins::IType(int64_t(15))) << "15 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[3].imms[0], Ins::IType(1000.0)) << "1000.0 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[4].imms[0], Ins::IType(int64_t(59796))) << "59796 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[5].imms[0], Ins::IType(1.1)) << "1.1 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[7].imms[0], Ins::IType(.1)) << ".1 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[8].imms[0], Ins::IType(int64_t(0))) << "0 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[9].imms[0], Ins::IType(0.1)) << "0.1 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[10].imms[0], Ins::IType(00.1)) << "00.1 expected"; + ASSERT_EQ(item.Value().function_table.at("main").ins[11].imms[0], Ins::IType(00.)) << "00. expected"; + ASSERT_EQ(item.Value().function_table.at("niam").ins[0].imms[0], Ins::IType(int64_t(-1))) << "-1 expected"; +} + +TEST(parsertests, test25_record_alone) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".record Asm {").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("void asm2").first); + v.push_back(l.TokenizeString("i32 asm3").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().record_table.at("Asm").name, "Asm"); + ASSERT_EQ(item.Value().record_table.at("Asm").field_list[0].name, "asm1"); + ASSERT_EQ(item.Value().record_table.at("Asm").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("Asm").field_list[1].name, "asm2"); + ASSERT_EQ(item.Value().record_table.at("Asm").field_list[1].type.GetId(), panda::panda_file::Type::TypeId::VOID); + ASSERT_EQ(item.Value().record_table.at("Asm").field_list[2].name, "asm3"); + ASSERT_EQ(item.Value().record_table.at("Asm").field_list[2].type.GetId(), panda::panda_file::Type::TypeId::I32); +} +TEST(parsertests, test26_records) +{ + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".record Asm1 {").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("void asm2").first); + v.push_back(l.TokenizeString("i32 asm3").first); + v.push_back(l.TokenizeString("}").first); + v.push_back(l.TokenizeString(".record Asm2 {").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("void asm2").first); + v.push_back(l.TokenizeString("i32 asm3 }").first); + v.push_back(l.TokenizeString(".record Asm3").first); + v.push_back(l.TokenizeString("{").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("void asm2").first); + v.push_back(l.TokenizeString("i32 asm3").first); + v.push_back(l.TokenizeString("}").first); + v.push_back(l.TokenizeString(".record Asm4 { i32 asm1 }").first); + v.push_back(l.TokenizeString(".record Asm5 { i32 asm1").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(item.Value().record_table.at("Asm1").name, "Asm1"); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[0].name, "asm1"); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[1].name, "asm2"); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[1].type.GetId(), panda::panda_file::Type::TypeId::VOID); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[2].name, "asm3"); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[2].type.GetId(), panda::panda_file::Type::TypeId::I32); + ASSERT_EQ(item.Value().record_table.at("Asm2").name, "Asm2"); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[0].name, "asm1"); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[1].name, "asm2"); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[1].type.GetId(), panda::panda_file::Type::TypeId::VOID); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[2].name, "asm3"); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[2].type.GetId(), panda::panda_file::Type::TypeId::I32); + ASSERT_EQ(item.Value().record_table.at("Asm3").name, "Asm3"); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[0].name, "asm1"); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[1].name, "asm2"); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[1].type.GetId(), panda::panda_file::Type::TypeId::VOID); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[2].name, "asm3"); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[2].type.GetId(), panda::panda_file::Type::TypeId::I32); + ASSERT_EQ(item.Value().record_table.at("Asm4").field_list[0].name, "asm1"); + ASSERT_EQ(item.Value().record_table.at("Asm4").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I32); + ASSERT_EQ(item.Value().record_table.at("Asm5").field_list[0].name, "asm1"); + ASSERT_EQ(item.Value().record_table.at("Asm5").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I32); +} + +TEST(parsertests, test27_record_and_function) +{ + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".record Asm1 {").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("void asm2").first); + v.push_back(l.TokenizeString("i32 asm3").first); + v.push_back(l.TokenizeString("}").first); + v.push_back(l.TokenizeString(".function u8 niam(){").first); + v.push_back(l.TokenizeString("ldai -1").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(item.Value().record_table.at("Asm1").name, "Asm1"); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[0].name, "asm1"); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[1].name, "asm2"); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[1].type.GetId(), panda::panda_file::Type::TypeId::VOID); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[2].name, "asm3"); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[2].type.GetId(), panda::panda_file::Type::TypeId::I32); + ASSERT_EQ(item.Value().function_table.at("niam").ins[0].imms[0], Ins::IType(int64_t(-1))) << "-1 expected"; +} + +TEST(parsertests, test28_records_and_functions) +{ + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".record Asm1 {").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("void asm2").first); + v.push_back(l.TokenizeString("i32 asm3").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u8 niam1(){").first); + v.push_back(l.TokenizeString("ldai -1").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".record Asm2 {").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("void asm2").first); + v.push_back(l.TokenizeString("i32 asm3").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u8 niam2(){").first); + v.push_back(l.TokenizeString("ldai -1").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".record Asm3 {").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("void asm2").first); + v.push_back(l.TokenizeString("i32 asm3").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u8 niam3(){").first); + v.push_back(l.TokenizeString("ldai -1").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(item.Value().record_table.at("Asm1").name, "Asm1"); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[0].name, "asm1"); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[1].name, "asm2"); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[1].type.GetId(), panda::panda_file::Type::TypeId::VOID); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[2].name, "asm3"); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[2].type.GetId(), panda::panda_file::Type::TypeId::I32); + + ASSERT_EQ(item.Value().function_table.at("niam1").ins[0].imms[0], Ins::IType(int64_t(-1))) << "-1 expected"; + + ASSERT_EQ(item.Value().record_table.at("Asm2").name, "Asm2"); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[0].name, "asm1"); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[1].name, "asm2"); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[1].type.GetId(), panda::panda_file::Type::TypeId::VOID); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[2].name, "asm3"); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[2].type.GetId(), panda::panda_file::Type::TypeId::I32); + + ASSERT_EQ(item.Value().function_table.at("niam2").ins[0].imms[0], Ins::IType(int64_t(-1))) << "-1 expected"; + + ASSERT_EQ(item.Value().record_table.at("Asm3").name, "Asm3"); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[0].name, "asm1"); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[1].name, "asm2"); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[1].type.GetId(), panda::panda_file::Type::TypeId::VOID); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[2].name, "asm3"); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[2].type.GetId(), panda::panda_file::Type::TypeId::I32); + + ASSERT_EQ(item.Value().function_table.at("niam3").ins[0].imms[0], Ins::IType(int64_t(-1))) << "-1 expected"; +} + +TEST(parsertests, test29_instructions_def_lines) +{ + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".function u8 niam1(){").first); + v.push_back(l.TokenizeString("ldai -1").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u8 niam2(){").first); + v.push_back(l.TokenizeString("ldai -1").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u8 niam3()").first); + v.push_back(l.TokenizeString("{").first); + v.push_back(l.TokenizeString("ldai -1").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u8 niam4(){ldai -1}").first); + + v.push_back(l.TokenizeString(".function u8 niam5(){ldai -1").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(item.Value().function_table.at("niam1").ins[0].ins_debug.line_number, 2U) << "2 expected"; + ASSERT_EQ(item.Value().function_table.at("niam2").ins[0].ins_debug.line_number, 5U) << "5 expected"; + ASSERT_EQ(item.Value().function_table.at("niam3").ins[0].ins_debug.line_number, 9U) << "9 expected"; + ASSERT_EQ(item.Value().function_table.at("niam4").ins[0].ins_debug.line_number, 11U) << "11 expected"; + ASSERT_EQ(item.Value().function_table.at("niam5").ins[0].ins_debug.line_number, 12U) << "12 expected"; +} + +TEST(parsertests, test30_fields_def_lines) +{ + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".record Asm1 {").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("void asm2").first); + v.push_back(l.TokenizeString("i32 asm3").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".record Asm2 {").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("void asm2").first); + v.push_back(l.TokenizeString("i32 asm3 }").first); + + v.push_back(l.TokenizeString(".record Asm3").first); + v.push_back(l.TokenizeString("{").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("void asm2").first); + v.push_back(l.TokenizeString("i32 asm3").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".record Asm4 { i32 asm1 }").first); + + v.push_back(l.TokenizeString(".record Asm5 { i32 asm1").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[0].line_of_def, 2U); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[1].line_of_def, 3U); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[2].line_of_def, 4U); + + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[0].line_of_def, 7U); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[1].line_of_def, 8U); + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[2].line_of_def, 9U); + + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[0].line_of_def, 12U); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[1].line_of_def, 13U); + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[2].line_of_def, 14U); + + ASSERT_EQ(item.Value().record_table.at("Asm4").field_list[0].line_of_def, 16U); + + ASSERT_EQ(item.Value().record_table.at("Asm5").field_list[0].line_of_def, 17U); +} + +TEST(parsertests, test31_own_types) +{ + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".record Asm {").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("void asm2").first); + v.push_back(l.TokenizeString("i32 asm3").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".record Asm1 {").first); + v.push_back(l.TokenizeString("Asm asm1").first); + v.push_back(l.TokenizeString("void asm2").first); + v.push_back(l.TokenizeString("i32 asm3 }").first); + + v.push_back(l.TokenizeString(".record Asm2 { Asm1 asm1 }").first); + + v.push_back(l.TokenizeString(".record Asm3 { Asm2 asm1").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[0].type.GetName(), "Asm"); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[1].type.GetId(), panda::panda_file::Type::TypeId::VOID); + ASSERT_EQ(item.Value().record_table.at("Asm1").field_list[2].type.GetId(), panda::panda_file::Type::TypeId::I32); + + ASSERT_EQ(item.Value().record_table.at("Asm2").field_list[0].type.GetName(), "Asm1"); + + ASSERT_EQ(item.Value().record_table.at("Asm3").field_list[0].type.GetName(), "Asm2"); +} + +TEST(parsertests, test32_names) +{ + ASSERT_EQ(GetOwnerName("Asm.main"), "Asm"); + + ASSERT_EQ(GetOwnerName("main"), ""); + + ASSERT_EQ(GetItemName("Asm.main"), "main"); + + ASSERT_EQ(GetItemName("main"), "main"); +} + +TEST(parsertests, test33_params_number) +{ + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".function u8 niam1(){").first); + v.push_back(l.TokenizeString("ldai -1").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u8 niam2(u1 a0, i64 a1, i32 a2){").first); + v.push_back(l.TokenizeString("mov v0, v3").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(item.Value().function_table.at("niam1").GetParamsNum(), 0U); + ASSERT_EQ(item.Value().function_table.at("niam1").value_of_first_param + 1, 0); + + ASSERT_EQ(item.Value().function_table.at("niam2").GetParamsNum(), 3U); + ASSERT_EQ(item.Value().function_table.at("niam2").value_of_first_param + 1, 4); +} + +TEST(parsertests, test34_vregs_number) +{ + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".function u8 niam1(){").first); + v.push_back(l.TokenizeString("ldai -1").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u8 niam2(u1 a0, i64 a1, i32 a2){").first); + v.push_back(l.TokenizeString("mov v0, v5").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(item.Value().function_table.at("niam1").regs_num, 0U); + + ASSERT_EQ(item.Value().function_table.at("niam2").regs_num, 6U); +} + +TEST(parsertests, test35_functions_bracket) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u1 nain1(i64 a0) <> {").first); + v.push_back(l.TokenizeString("mov v0, a0").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u1 nain2(i64 a0) <> { mov v0, a0}").first); + v.push_back(l.TokenizeString(".function u1 nain3(i64 a0) <> { mov v0, a0").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u1 nain4(i64 a0) ").first); + v.push_back(l.TokenizeString("{").first); + v.push_back(l.TokenizeString("mov v0, a0").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u1 nain5(i64 a0) <>{").first); + v.push_back(l.TokenizeString("mov v0, a0}").first); + + v.push_back(l.TokenizeString(".function u1 nain6(i64 a0) <>").first); + v.push_back(l.TokenizeString("{").first); + v.push_back(l.TokenizeString("mov v0, a0}").first); + + v.push_back(l.TokenizeString(".function u1 nain7(i64 a0) <> {").first); + v.push_back(l.TokenizeString("mov v0, a0").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u1 nain8(i64 a0) { mov v0, a0}").first); + v.push_back(l.TokenizeString(".function u1 nain9(i64 a0) { mov v0, a0").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u1 nain10(i64 a0) <>").first); + v.push_back(l.TokenizeString("{").first); + v.push_back(l.TokenizeString("mov v0, a0").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function u1 nain11(i64 a0) {").first); + v.push_back(l.TokenizeString("mov v0, a0}").first); + + v.push_back(l.TokenizeString(".function u1 nain12(i64 a0)").first); + v.push_back(l.TokenizeString("{").first); + v.push_back(l.TokenizeString("mov v0, a0}").first); + + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("nain1").name, "nain1"); + ASSERT_EQ(item.Value().function_table.at("nain12").name, "nain12"); + ASSERT_EQ(item.Value().function_table.at("nain3").name, "nain3"); + ASSERT_EQ(item.Value().function_table.at("nain2").name, "nain2"); + ASSERT_EQ(item.Value().function_table.at("nain4").name, "nain4"); + ASSERT_EQ(item.Value().function_table.at("nain5").name, "nain5"); + ASSERT_EQ(item.Value().function_table.at("nain6").name, "nain6"); + ASSERT_EQ(item.Value().function_table.at("nain7").name, "nain7"); + ASSERT_EQ(item.Value().function_table.at("nain8").name, "nain8"); + ASSERT_EQ(item.Value().function_table.at("nain9").name, "nain9"); + ASSERT_EQ(item.Value().function_table.at("nain10").name, "nain10"); + ASSERT_EQ(item.Value().function_table.at("nain11").name, "nain11"); + + ASSERT_EQ(item.Value().function_table.at("nain1").ins[0].opcode, Opcode::MOV); + ASSERT_EQ(item.Value().function_table.at("nain2").ins[0].opcode, Opcode::MOV); + ASSERT_EQ(item.Value().function_table.at("nain3").ins[0].opcode, Opcode::MOV); + ASSERT_EQ(item.Value().function_table.at("nain4").ins[0].opcode, Opcode::MOV); + ASSERT_EQ(item.Value().function_table.at("nain5").ins[0].opcode, Opcode::MOV); + ASSERT_EQ(item.Value().function_table.at("nain6").ins[0].opcode, Opcode::MOV); + ASSERT_EQ(item.Value().function_table.at("nain7").ins[0].opcode, Opcode::MOV); + ASSERT_EQ(item.Value().function_table.at("nain8").ins[0].opcode, Opcode::MOV); + ASSERT_EQ(item.Value().function_table.at("nain9").ins[0].opcode, Opcode::MOV); + ASSERT_EQ(item.Value().function_table.at("nain10").ins[0].opcode, Opcode::MOV); + ASSERT_EQ(item.Value().function_table.at("nain11").ins[0].opcode, Opcode::MOV); + ASSERT_EQ(item.Value().function_table.at("nain12").ins[0].opcode, Opcode::MOV); +} + +TEST(parsertests, test36_records_bracket) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".record rec1 <> {").first); + v.push_back(l.TokenizeString("i64 asm1 <>").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".record rec2 <> { i64 asm1}").first); + v.push_back(l.TokenizeString(".record rec3 <> { i64 asm1").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".record rec4").first); + v.push_back(l.TokenizeString("{").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".record rec5{").first); + v.push_back(l.TokenizeString("i64 asm1}").first); + + v.push_back(l.TokenizeString(".record rec6").first); + v.push_back(l.TokenizeString("{").first); + v.push_back(l.TokenizeString("i64 asm1}").first); + + v.push_back(l.TokenizeString(".record rec7{").first); + v.push_back(l.TokenizeString("i64 asm1").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(item.Value().record_table.at("rec1").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("rec2").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("rec3").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("rec4").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("rec5").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("rec6").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); + ASSERT_EQ(item.Value().record_table.at("rec7").field_list[0].type.GetId(), panda::panda_file::Type::TypeId::I64); +} + +TEST(parsertests, test37_operand_type_print) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u1 nain1(i64 a0) <> {").first); + v.push_back(l.TokenizeString("L: mov v0, a0").first); + v.push_back(l.TokenizeString("movi v0, 0").first); + v.push_back(l.TokenizeString("jmp L").first); + v.push_back(l.TokenizeString("sta a0").first); + v.push_back(l.TokenizeString("neg").first); + v.push_back(l.TokenizeString("call.short nain1, v0, v1").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(OperandTypePrint(item.Value().function_table.at("nain1").ins[0].opcode), "reg_reg"); + ASSERT_EQ(OperandTypePrint(item.Value().function_table.at("nain1").ins[1].opcode), "reg_imm"); + ASSERT_EQ(OperandTypePrint(item.Value().function_table.at("nain1").ins[2].opcode), "label"); + ASSERT_EQ(OperandTypePrint(item.Value().function_table.at("nain1").ins[3].opcode), "reg"); + ASSERT_EQ(OperandTypePrint(item.Value().function_table.at("nain1").ins[4].opcode), "none"); + ASSERT_EQ(OperandTypePrint(item.Value().function_table.at("nain1").ins[5].opcode), "call_reg_reg"); +} + +TEST(parsertests, test38_record_invalid_field) +{ + { + std::vector> v; + Lexer l; + Parser p; + + std::string f = "T"; + + v.push_back(l.TokenizeString(".record Rec {").first); + v.push_back(l.TokenizeString(f).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_FIELD_MISSING_NAME); + ASSERT_EQ(e.line_number, 2U); + ASSERT_EQ(e.pos, f.length()); + ASSERT_EQ(e.message, "Expected field name."); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string f = "T f <"; + + v.push_back(l.TokenizeString(".record Rec {").first); + v.push_back(l.TokenizeString(f).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_METADATA_BOUND); + ASSERT_EQ(e.line_number, 2U); + ASSERT_EQ(e.pos, f.length()); + ASSERT_EQ(e.message, "Expected '>'."); + } +} + +TEST(parsertests, test39_parse_operand_string) +{ + { + std::vector> v; + Lexer l; + Parser p; + + std::string op = "lda.str 123"; + + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString(op).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_OPERAND); + ASSERT_EQ(e.line_number, 2U); + ASSERT_EQ(e.pos, op.find(' ') + 1); + ASSERT_EQ(e.message, "Expected string literal"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string op = "lda.str a\"bcd"; + + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString(op).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_OPERAND); + ASSERT_EQ(e.line_number, 2U); + ASSERT_EQ(e.pos, op.find(' ') + 1); + ASSERT_EQ(e.message, "Expected string literal"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("lda.str \" abc123 \"").first); + v.push_back(l.TokenizeString("lda.str \"zxcvb\"").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + std::unordered_set strings = {" abc123 ", "zxcvb"}; + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + ASSERT_TRUE(item.HasValue()); + ASSERT_EQ(item.Value().strings, strings); + } +} + +TEST(parsertests, test40_parse_operand_string_escape_seq) +{ + { + std::vector> v; + Lexer l; + Parser p; + + std::string op = "lda.str \"123\\z\""; + + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString(op).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_STRING_UNKNOWN_ESCAPE_SEQUENCE); + ASSERT_EQ(e.line_number, 2U); + ASSERT_EQ(e.pos, op.find('\\')); + ASSERT_EQ(e.message, "Unknown escape sequence"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string op = "lda.str \" \\\" \\' \\\\ \\a \\b \\f \\n \\r \\t \\v \""; + + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString(op).first); + v.push_back(l.TokenizeString("}").first); + + Error e = p.ShowError(); + + auto item = p.Parse(v); + + std::unordered_set strings = {" \" ' \\ \a \b \f \n \r \t \v "}; + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + ASSERT_TRUE(item.HasValue()); + ASSERT_EQ(item.Value().strings, strings); + } +} + +TEST(parsertests, test41_parse_operand_string_hex_escape_seq) +{ + { + std::vector> v; + Lexer l; + Parser p; + + std::string op = "lda.str \"123\\x\""; + + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString(op).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_STRING_INVALID_HEX_ESCAPE_SEQUENCE); + ASSERT_EQ(e.line_number, 2U); + ASSERT_EQ(e.pos, op.find('\\')); + ASSERT_EQ(e.message, "Invalid hexadecimal escape sequence"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string op = "lda.str \"123\\xZZ\""; + + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString(op).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_STRING_INVALID_HEX_ESCAPE_SEQUENCE); + ASSERT_EQ(e.line_number, 2U); + ASSERT_EQ(e.pos, op.find('\\')); + ASSERT_EQ(e.message, "Invalid hexadecimal escape sequence"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string op = "lda.str \"123\\xAZ\""; + + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString(op).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_STRING_INVALID_HEX_ESCAPE_SEQUENCE); + ASSERT_EQ(e.line_number, 2U); + ASSERT_EQ(e.pos, op.find('\\')); + ASSERT_EQ(e.message, "Invalid hexadecimal escape sequence"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string op = "lda.str \"123\\xZA\""; + + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString(op).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_STRING_INVALID_HEX_ESCAPE_SEQUENCE); + ASSERT_EQ(e.line_number, 2U); + ASSERT_EQ(e.pos, op.find('\\')); + ASSERT_EQ(e.message, "Invalid hexadecimal escape sequence"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string op = "lda.str \"123\\xaa\\x65\""; + + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString(op).first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + std::unordered_set strings = {"123\xaa\x65"}; + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + ASSERT_TRUE(item.HasValue()); + ASSERT_EQ(item.Value().strings, strings); + } +} + +TEST(parsertests, test42_parse_operand_string_octal_escape_seq) +{ + std::vector> v; + Lexer l; + Parser p; + + std::string op = "lda.str \"123\\1\\02\\00123\""; + + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString(op).first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + std::unordered_set strings = {"123\1\02\00123"}; + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + ASSERT_TRUE(item.HasValue()); + ASSERT_EQ(item.Value().strings, strings); +} + +TEST(parsertests, test43_call_short) +{ + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("call.short f").first); + v.push_back(l.TokenizeString("call.virt.short f").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + ASSERT_TRUE(item.HasValue()); + std::vector regs {}; + ASSERT_EQ(item.Value().function_table.at("f").ins[0].regs, regs); + ASSERT_EQ(item.Value().function_table.at("f").ins[1].regs, regs); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("call.short f, v0").first); + v.push_back(l.TokenizeString("call.virt.short f, v0").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + ASSERT_TRUE(item.HasValue()); + std::vector regs {0}; + ASSERT_EQ(item.Value().function_table.at("f").ins[0].regs, regs); + ASSERT_EQ(item.Value().function_table.at("f").ins[1].regs, regs); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("call.short f, v0, v1").first); + v.push_back(l.TokenizeString("call.virt.short f, v0, v1").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + ASSERT_TRUE(item.HasValue()); + std::vector regs {0, 1}; + ASSERT_EQ(item.Value().function_table.at("f").ins[0].regs, regs); + ASSERT_EQ(item.Value().function_table.at("f").ins[1].regs, regs); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("call.short f, v0, v1, v2").first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("call.virt.short f, v0, v1, v2").first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); + } +} + +TEST(parsertests, test44_call) +{ + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("call f").first); + v.push_back(l.TokenizeString("call.virt f").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + ASSERT_TRUE(item.HasValue()); + std::vector regs {}; + ASSERT_EQ(item.Value().function_table.at("f").ins[0].regs, regs); + ASSERT_EQ(item.Value().function_table.at("f").ins[1].regs, regs); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("call f, v0").first); + v.push_back(l.TokenizeString("call.virt f, v0").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + ASSERT_TRUE(item.HasValue()); + std::vector regs {0}; + ASSERT_EQ(item.Value().function_table.at("f").ins[0].regs, regs); + ASSERT_EQ(item.Value().function_table.at("f").ins[1].regs, regs); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("call f, v0, v1").first); + v.push_back(l.TokenizeString("call.virt f, v0, v1").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + ASSERT_TRUE(item.HasValue()); + std::vector regs {0, 1}; + ASSERT_EQ(item.Value().function_table.at("f").ins[0].regs, regs); + ASSERT_EQ(item.Value().function_table.at("f").ins[1].regs, regs); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("call f, v0, v1, v2").first); + v.push_back(l.TokenizeString("call.virt f, v0, v1, v2").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + ASSERT_TRUE(item.HasValue()); + std::vector regs {0, 1, 2}; + ASSERT_EQ(item.Value().function_table.at("f").ins[0].regs, regs); + ASSERT_EQ(item.Value().function_table.at("f").ins[1].regs, regs); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("call f, v0, v1, v2, v3").first); + v.push_back(l.TokenizeString("call.virt f, v0, v1, v2, v3").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + ASSERT_TRUE(item.HasValue()); + std::vector regs {0, 1, 2, 3}; + ASSERT_EQ(item.Value().function_table.at("f").ins[0].regs, regs); + ASSERT_EQ(item.Value().function_table.at("f").ins[1].regs, regs); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("call.short f, v0, v1, v2, v3, v4").first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("call.virt.short f, v0, v1, v2, v3, v4").first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); + } +} + +TEST(parsertests, function_argument_mismatch) +{ + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("call.short nain, v0, v1").first); + v.push_back(l.TokenizeString("}").first); + v.push_back(l.TokenizeString(".function u8 nain(i32 a0, i32 a1){").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("call.range nain, v0").first); + v.push_back(l.TokenizeString("}").first); + v.push_back(l.TokenizeString(".function u8 nain(i32 a0, i32 a1){").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("call nain, v0").first); + v.push_back(l.TokenizeString("}").first); + v.push_back(l.TokenizeString(".function u8 nain(i32 a0, i32 a1){").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_FUNCTION_ARGUMENT_MISMATCH); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("call nain, v0, v1, v2, v3").first); + v.push_back(l.TokenizeString("}").first); + v.push_back(l.TokenizeString(".function u8 nain(i32 a0, i32 a1){").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + } +} + +TEST(parsertests, test45_argument_width_mov) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("mov v67000, v0").first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_OPERAND); +} + +TEST(parsertests, test45_argument_width_call) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("call.range f, v256").first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_OPERAND); +} + +TEST(parsertests, test_argument_width_call_param) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void g(u1 a0, u1 a1) {").first); + v.push_back(l.TokenizeString("call.range f, v256").first); + v.push_back(l.TokenizeString("}").first); + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("movi v5, 0").first); + v.push_back(l.TokenizeString("call g, a1, v15").first); + v.push_back(l.TokenizeString("return").first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_OPERAND); +} + +TEST(parsertests, Naming_function_function) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u1 nain(i64 a0) <> {").first); + v.push_back(l.TokenizeString("L: mov v0, a0").first); + v.push_back(l.TokenizeString("}").first); + v.push_back(l.TokenizeString(".function u1 nain(i64 a0) <> {").first); + v.push_back(l.TokenizeString("L: mov v0, a0").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_ID_FUNCTION); +} + +TEST(parsertests, Naming_label_label) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u1 nain(i64 a0) <> {").first); + v.push_back(l.TokenizeString("SAME: mov v0, a0").first); + v.push_back(l.TokenizeString("SAME: sta v0").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_LABEL_EXT); +} + +TEST(parsertests, Naming_function_label) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u1 nain(i64 a0) <> {").first); + v.push_back(l.TokenizeString("nain: mov v0, a0").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); +} + +TEST(parsertests, Naming_function_operation) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u1 mov(i64 a0) <> {").first); + v.push_back(l.TokenizeString("L: mov v0, a0").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); +} + +TEST(parsertests, Naming_label_operation) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u1 nain(i64 a0) <> {").first); + v.push_back(l.TokenizeString("mov: mov v0, a0").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); +} + +TEST(parsertests, Naming_function_label_operation) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u1 mov(i64 a0) <> {").first); + v.push_back(l.TokenizeString("mov: mov v0, a0").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); +} + +TEST(parsertests, Naming_jump_label) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u1 mov(i64 a0) <> {").first); + v.push_back(l.TokenizeString("jmp mov").first); + v.push_back(l.TokenizeString("mov:").first); + v.push_back(l.TokenizeString("return").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); +} + +TEST(parsertests, Naming_call_function) +{ + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u1 mov(i64 a0) <> {").first); + v.push_back(l.TokenizeString("call.short mov, v0, v1").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); +} + +TEST(parsertests, register_naming_incorr) +{ + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("sta 123").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_NAME_REG); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("sta a0").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_NAME_REG); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f(i32 a0) {").first); + v.push_back(l.TokenizeString("sta a01").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_NAME_REG); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("sta 123").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_NAME_REG); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("sta q0").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_NAME_REG); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("sta vy1").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_NAME_REG); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("sta v01").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_NAME_REG); + } +} +TEST(parsertests, register_naming_corr) +{ + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("sta v123").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f() {").first); + v.push_back(l.TokenizeString("sta v0").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f(i32 a0) {").first); + v.push_back(l.TokenizeString("sta a0").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f(i32 a0) {").first); + v.push_back(l.TokenizeString("mov v0, a0").first); + v.push_back(l.TokenizeString("}").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + } +} + +TEST(parsertests, array_type) +{ + { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".record R {").first); + v.push_back(l.TokenizeString("R[][] f").first); + v.push_back(l.TokenizeString("}").first); + + v.push_back(l.TokenizeString(".function R[] f(i8[ ] a0) {").first); + v.push_back(l.TokenizeString("newarr v0, v0, i32[ ][]").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + + ASSERT_TRUE(item.HasValue()); + + ASSERT_EQ(item.Value().record_table.at("R").field_list.size(), 1U); + ASSERT_TRUE(item.Value().record_table.at("R").field_list[0].type.IsArray()); + ASSERT_TRUE(item.Value().record_table.at("R").field_list[0].type.IsObject()); + ASSERT_EQ(item.Value().record_table.at("R").field_list[0].type.GetName(), "R[][]"); + ASSERT_EQ(item.Value().record_table.at("R").field_list[0].type.GetComponentName(), "R"); + ASSERT_EQ(item.Value().record_table.at("R").field_list[0].type.GetDescriptor(), "[[LR;"); + + ASSERT_TRUE(item.Value().function_table.at("f").return_type.IsArray()); + ASSERT_TRUE(item.Value().function_table.at("f").return_type.IsObject()); + ASSERT_EQ(item.Value().function_table.at("f").return_type.GetName(), "R[]"); + ASSERT_EQ(item.Value().function_table.at("f").return_type.GetComponentName(), "R"); + ASSERT_EQ(item.Value().function_table.at("f").return_type.GetDescriptor(), "[LR;"); + + ASSERT_EQ(item.Value().function_table.at("f").params.size(), 1U); + ASSERT_TRUE(item.Value().function_table.at("f").params[0].type.IsArray()); + ASSERT_TRUE(item.Value().function_table.at("f").params[0].type.IsObject()); + ASSERT_EQ(item.Value().function_table.at("f").params[0].type.GetName(), "i8[]"); + ASSERT_EQ(item.Value().function_table.at("f").params[0].type.GetComponentName(), "i8"); + ASSERT_EQ(item.Value().function_table.at("f").params[0].type.GetDescriptor(), "[B"); + + ASSERT_EQ(item.Value().function_table.at("f").ins[0].ids.size(), 1U); + ASSERT_EQ(item.Value().function_table.at("f").ins[0].ids[0], "i32[][]"); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f(i32 a0) {").first); + v.push_back(l.TokenizeString("newarr v0, v0, i32[][").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_ARRAY_TYPE_BOUND); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function f64[ f(i32 a0) {").first); + v.push_back(l.TokenizeString("newarr v0, v0, i32[]").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_ARRAY_TYPE_BOUND); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void f(i32[][][ a0) {").first); + v.push_back(l.TokenizeString("newarr v0, v0, i32[]").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_ARRAY_TYPE_BOUND); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".record R {").first); + v.push_back(l.TokenizeString("R[][ f").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_ARRAY_TYPE_BOUND); + } +} + +TEST(parsertests, undefined_type) +{ + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void main() <> {").first); + v.push_back(l.TokenizeString("movi v0, 5").first); + v.push_back(l.TokenizeString("newarr v0, v0, panda.String[]").first); + v.push_back(l.TokenizeString("return.void").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_ID_RECORD); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".record panda.String ").first); + v.push_back(l.TokenizeString(".function void main() <> {").first); + v.push_back(l.TokenizeString("movi v0, 5").first); + v.push_back(l.TokenizeString("newarr v0, v0, panda.String[]").first); + v.push_back(l.TokenizeString("return.void").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function void main() <> {").first); + v.push_back(l.TokenizeString("movi v0, 5").first); + v.push_back(l.TokenizeString("newarr v0, v0, i32[]").first); + v.push_back(l.TokenizeString("return.void").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE); + } +} + +TEST(parsertests, parse_undefined_record_field) +{ + { + Parser p; + std::string source = R"( + .function u1 main() { + newobj v0, ObjWrongType + lda.obj v0 + return + } + + .record ObjType {} + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_RECORD); + ASSERT_EQ(e.line_number, 3); + ASSERT_EQ(e.pos, 27); + ASSERT_EQ(e.message, "This record does not exist."); + } + + { + Parser p; + std::string source = R"( + .function u1 main() { + newobj v0, ObjType + lda.obj v0 + return + } + + .record ObjType {} + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + } + + { + Parser p; + std::string source = R"( + .function u1 main() { + ldobj v0, ObjWrongType.fld + return + } + + .record ObjType { + i32 fld + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_RECORD); + ASSERT_EQ(e.line_number, 3); + ASSERT_EQ(e.pos, 26); + ASSERT_EQ(e.message, "This record does not exist."); + } + + { + Parser p; + std::string source = R"( + .function u1 main() { + ldobj v0, ObjType.fldwrong + return + } + + .record ObjType { + i32 fld + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_FIELD); + ASSERT_EQ(e.line_number, 3); + ASSERT_EQ(e.pos, 34); + ASSERT_EQ(e.message, "This field does not exist."); + } + + { + Parser p; + std::string source = R"( + .function u1 main() { + ldobj v0, ObjType.fld + return + } + + .record ObjType { + i32 fld + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + } + + { + Parser p; + std::string source = R"( + .function u1 main() { + lda.type i64[] + return + } + + .record ObjType { + i32 fld + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + } + + { + Parser p; + std::string source = R"( + .record panda.String + + .function panda.String panda.NullPointerException.getMessage(panda.NullPointerException a0) { + ldobj.obj a0, panda.NullPointerException.messagewrong + return.obj + } + + .record panda.NullPointerException { + panda.String message + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_FIELD); + ASSERT_EQ(e.line_number, 5); + ASSERT_EQ(e.pos, 57); + ASSERT_EQ(e.message, "This field does not exist."); + } + + { + Parser p; + std::string source = R"( + .record panda.String + + .function panda.String panda.NullPointerException.getMessage(panda.NullPointerException a0) { + ldobj.obj a0, panda.NullPointerException.message + return.obj + } + + .record panda.NullPointerException { + panda.String message + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + } + + { + Parser p; + std::string source = R"( + .function u1 main(u1 a0) { + newarr a0, a0, ObjWrongType[] + return + } + + .record ObjType {} + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_RECORD); + ASSERT_EQ(e.line_number, 3); + ASSERT_EQ(e.pos, 44); + ASSERT_EQ(e.message, "This record does not exist."); + } + + { + Parser p; + std::string source = R"( + .function u1 main(u1 a0) { + newarr a0, a0, ObjType[] + return + } + + .record ObjType {} + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + } +} + +TEST(parsertests, Vreg_width) +{ + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u1 nain(i64 a0) <> {").first); + v.push_back(l.TokenizeString("mov v999, a0").first); + v.push_back(l.TokenizeString("movi a0, 0").first); + v.push_back(l.TokenizeString("lda a0").first); + v.push_back(l.TokenizeString("return").first); + v.push_back(l.TokenizeString("mov a0, v999").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_NAME_REG); + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u1 nain(i64 a0) <> {").first); + v.push_back(l.TokenizeString("movi.64 v15, 222").first); + v.push_back(l.TokenizeString("call bar, a0, v0").first); + v.push_back(l.TokenizeString("return").first); + v.push_back(l.TokenizeString("}").first); + + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_NAME_REG); + } +} + +TEST(parsertests, Num_vregs) +{ + { + Parser p; + std::string source = R"( + .record KKK{} + + .function u1 main(u1 a0) { + movi v1, 1 + mov v0, a0 + + return + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + + auto &program = res.Value(); + auto it_func = program.function_table.find("main"); + + ASSERT_TRUE(it_func != program.function_table.end()); + ASSERT_EQ(it_func->second.regs_num, 2); + } + + { + Parser p; + std::string source = R"( + .function u1 main(u1 a0) { + movi v1, 1 + mov v0, a0 + + return + } + + .record KKK{} + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + + auto &program = res.Value(); + auto it_func = program.function_table.find("main"); + + ASSERT_TRUE(it_func != program.function_table.end()); + ASSERT_EQ(it_func->second.regs_num, 2); + } + + { + Parser p; + std::string source = R"( + .function u1 main() { + movi v0, 1 + + return + } + + .record KKK{} + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + + auto &program = res.Value(); + auto it_func = program.function_table.find("main"); + + ASSERT_TRUE(it_func != program.function_table.end()); + ASSERT_EQ(it_func->second.regs_num, 1); + } + + { + Parser p; + std::string source = R"( + .function u1 main() { + movi v1, 1 + movi v0, 0 + movi v2, 2 + movi v3, 3 + movi v4, 4 + + return + } + + .record KKK{} + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + + auto &program = res.Value(); + auto it_func = program.function_table.find("main"); + + ASSERT_TRUE(it_func != program.function_table.end()); + ASSERT_EQ(it_func->second.regs_num, 5); + } +} + +TEST(parsertests, Bad_imm_value) +{ + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u n(){movi v0,.").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_INTEGER_NAME); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u n(){movi v0,%").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_INTEGER_NAME); + } + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u n(){movi v0,;").first); + auto item = p.Parse(v); + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_BAD_INTEGER_NAME); + } +} + +TEST(parsertests, parse_language_directive) +{ + { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".language ECMAScript").first); + v.push_back(l.TokenizeString(".language ECMAScript").first); + v.push_back(l.TokenizeString(".function void f() ").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_MULTIPLE_DIRECTIVES); + ASSERT_EQ(e.line_number, 2); + ASSERT_EQ(e.message, "Multiple .language directives"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".language ECMAScript").first); + v.push_back(l.TokenizeString(".function void f() ").first); + v.push_back(l.TokenizeString(".language ECMAScript").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_MULTIPLE_DIRECTIVES); + ASSERT_EQ(e.line_number, 3); + ASSERT_EQ(e.message, "Multiple .language directives"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".function void f() ").first); + v.push_back(l.TokenizeString(".language ECMAScript").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_INCORRECT_DIRECTIVE_LOCATION); + ASSERT_EQ(e.line_number, 2); + ASSERT_EQ(e.message, ".language directive must be specified before any other declarations"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".language ").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); + ASSERT_EQ(e.line_number, 1); + ASSERT_EQ(e.message, "Incorrect .language directive: Expected language"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".language ECMAScript1 123").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_UNKNOWN_LANGUAGE); + ASSERT_EQ(e.line_number, 1); + ASSERT_EQ(e.message, "Incorrect .language directive: Unknown language"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".language ECMAScript 123").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); + ASSERT_EQ(e.line_number, 1); + ASSERT_EQ(e.message, "Incorrect .language directive: Unexpected token"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".language ECMAScript").first); + + auto res = p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + ASSERT_EQ(res.Value().lang, extensions::Language::ECMASCRIPT); + } + + { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".language PandaAssembly").first); + + auto res = p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + ASSERT_EQ(res.Value().lang, extensions::Language::PANDA_ASSEMBLY); + } +} + +TEST(parsertests, parse_metadata) +{ + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = ".record R "; + + v.push_back(l.TokenizeString(s).first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_METADATA_UNKNOWN_ATTRIBUTE); + ASSERT_EQ(e.line_number, 1); + ASSERT_EQ(e.pos, s.find("attr")); + ASSERT_EQ(e.message, "Unknown attribute 'attr'"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = ".record R "; + + v.push_back(l.TokenizeString(s).first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_METADATA_UNKNOWN_ATTRIBUTE); + ASSERT_EQ(e.line_number, 1); + ASSERT_EQ(e.pos, s.find("attr")); + ASSERT_EQ(e.message, "Unknown attribute 'attr'"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = ".record R "; + + v.push_back(l.TokenizeString(s).first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_METADATA_UNKNOWN_ATTRIBUTE); + ASSERT_EQ(e.line_number, 1); + ASSERT_EQ(e.pos, s.find("native")); + ASSERT_EQ(e.message, "Unknown attribute 'native'"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = ".record R "; + + v.push_back(l.TokenizeString(s).first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_METADATA_UNEXPECTED_VALUE); + ASSERT_EQ(e.line_number, 1); + ASSERT_EQ(e.pos, s.find("=")); + ASSERT_EQ(e.message, "Attribute 'external' must not have a value"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = ".record R "; + + v.push_back(l.TokenizeString(s).first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_METADATA_UNKNOWN_ATTRIBUTE); + ASSERT_EQ(e.line_number, 1); + ASSERT_EQ(e.pos, s.find("java")); + ASSERT_EQ(e.message, "Unknown attribute 'java.access'"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = ".record R "; + + v.push_back(l.TokenizeString(".language ECMAScript").first); + v.push_back(l.TokenizeString(s).first); + + auto res = p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_METADATA_MULTIPLE_ATTRIBUTE); + ASSERT_EQ(e.line_number, 2); + ASSERT_EQ(e.pos, s.find(",") + 2); + ASSERT_EQ(e.message, "Attribute 'external' already defined"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = ".record R "; + + v.push_back(l.TokenizeString(s).first); + + auto res = p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + + auto &program = res.Value(); + auto &record = program.record_table.find("R")->second; + + ASSERT_TRUE(record.metadata->GetAttribute("external")); + record.metadata->RemoveAttribute("external"); + ASSERT_FALSE(record.metadata->GetAttribute("external")); + } +} + +TEST(parsertests, parse_catch_directive) +{ + { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".record Exception {}").first); + v.push_back(l.TokenizeString(".catch Exception, try_begin, try_end, catch_begin").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_INCORRECT_DIRECTIVE_LOCATION); + ASSERT_EQ(e.line_number, 2); + ASSERT_EQ(e.message, ".catch directive is outside a function body."); + } + + { + std::vector directives { + ".catch", ".catch R", ".catch R,", ".catch R, t1", + ".catch R, t1,", ".catch R, t1, t2", ".catch R, t1, t2,", ".catch R, t1, t2, c,"}; + + for (auto s : directives) { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".record Exception {}").first); + v.push_back(l.TokenizeString(".function void main() {").first); + v.push_back(l.TokenizeString(s).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); + ASSERT_EQ(e.line_number, 3); + ASSERT_EQ(e.pos, 0); + ASSERT_EQ(e.message, + "Incorrect catch block declaration. Must be in the format: .catch , " + ", , [, ]"); + } + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = ".catch $Exception, try_begin, try_end, catch_begin"; + + v.push_back(l.TokenizeString(".record Exception {}").first); + v.push_back(l.TokenizeString(".function void main() {").first); + v.push_back(l.TokenizeString(s).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_RECORD_NAME); + ASSERT_EQ(e.line_number, 3); + ASSERT_EQ(e.pos, s.find("$")); + ASSERT_EQ(e.message, "Invalid name of the exception record."); + } + + { + std::vector labels {"try_begin", "try_end", "catch_begin"}; + std::vector label_names {"try block begin", "try block end", "catch block begin"}; + + for (size_t i = 0; i < labels.size(); i++) { + std::string s = ".catch Exception"; + + { + std::string directive = s; + for (size_t j = 0; j < labels.size(); j++) { + directive += i == j ? " $ " : " , "; + directive += labels[j]; + } + + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".record Exception {}").first); + v.push_back(l.TokenizeString(".function void main() {").first); + v.push_back(l.TokenizeString(directive).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION) << "Test " << directive; + ASSERT_EQ(e.line_number, 3) << "Test " << directive; + ASSERT_EQ(e.pos, directive.find("$")) << "Test " << directive; + ASSERT_EQ(e.message, "Expected comma.") << "Test " << directive; + } + + { + std::string directive = s; + for (size_t j = 0; j < labels.size(); j++) { + directive += " , "; + directive += i == j ? "$" : labels[j]; + } + + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".record Exception {}").first); + v.push_back(l.TokenizeString(".function void main() {").first); + v.push_back(l.TokenizeString(directive).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_LABEL) << "Test " << directive; + ASSERT_EQ(e.line_number, 3) << "Test " << directive; + ASSERT_EQ(e.pos, directive.find("$")) << "Test " << directive; + ASSERT_EQ(e.message, std::string("Invalid name of the ") + label_names[i] + " label.") + << "Test " << directive; + } + + { + std::stringstream ss; + ss << "Test " << labels[i] << " does not exists"; + + std::vector> v; + Lexer l; + Parser p; + + std::string catch_table = ".catch Exception, try_begin, try_end, catch_begin"; + + v.push_back(l.TokenizeString(".record Exception {}").first); + v.push_back(l.TokenizeString(".function void main() {").first); + for (size_t j = 0; j < labels.size(); j++) { + if (i != j) { + v.push_back(l.TokenizeString(labels[j] + ":").first); + } + } + v.push_back(l.TokenizeString(catch_table).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_LABEL_EXT) << ss.str(); + ASSERT_EQ(e.pos, catch_table.find(labels[i])) << ss.str(); + ASSERT_EQ(e.message, "This label does not exist.") << ss.str(); + } + } + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = ".catch Exception, try_begin, try_end, catch_begin"; + + v.push_back(l.TokenizeString(".record Exception {}").first); + v.push_back(l.TokenizeString(".function void main() {").first); + v.push_back(l.TokenizeString("try_begin:").first); + v.push_back(l.TokenizeString("try_end:").first); + v.push_back(l.TokenizeString("catch_begin:").first); + v.push_back(l.TokenizeString(s).first); + v.push_back(l.TokenizeString("}").first); + + auto res = p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + + auto &program = res.Value(); + auto &function = program.function_table.find("main")->second; + + ASSERT_EQ(function.catch_blocks.size(), 1); + ASSERT_EQ(function.catch_blocks[0].exception_record, "Exception"); + ASSERT_EQ(function.catch_blocks[0].try_begin_label, "try_begin"); + ASSERT_EQ(function.catch_blocks[0].try_end_label, "try_end"); + ASSERT_EQ(function.catch_blocks[0].catch_begin_label, "catch_begin"); + ASSERT_EQ(function.catch_blocks[0].catch_end_label, "catch_begin"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = ".catch Exception, try_begin, try_end, catch_begin, catch_end"; + + v.push_back(l.TokenizeString(".record Exception {}").first); + v.push_back(l.TokenizeString(".function void main() {").first); + v.push_back(l.TokenizeString("try_begin:").first); + v.push_back(l.TokenizeString("try_end:").first); + v.push_back(l.TokenizeString("catch_begin:").first); + v.push_back(l.TokenizeString("catch_end:").first); + v.push_back(l.TokenizeString(s).first); + v.push_back(l.TokenizeString("}").first); + + auto res = p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + + auto &program = res.Value(); + auto &function = program.function_table.find("main")->second; + + ASSERT_EQ(function.catch_blocks.size(), 1); + ASSERT_EQ(function.catch_blocks[0].exception_record, "Exception"); + ASSERT_EQ(function.catch_blocks[0].try_begin_label, "try_begin"); + ASSERT_EQ(function.catch_blocks[0].try_end_label, "try_end"); + ASSERT_EQ(function.catch_blocks[0].catch_begin_label, "catch_begin"); + ASSERT_EQ(function.catch_blocks[0].catch_end_label, "catch_end"); + } +} + +TEST(parsertests, parse_catchall_directive) +{ + { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".catchall try_begin, try_end, catch_begin").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_INCORRECT_DIRECTIVE_LOCATION); + ASSERT_EQ(e.line_number, 1); + ASSERT_EQ(e.message, ".catchall directive is outside a function body."); + } + + { + std::vector directives {".catchall", ".catchall t1", ".catchall t1,", + ".catchall t1, t2", ".catchall t1, t2,", ".catchall t1, t2, c,"}; + + for (auto s : directives) { + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".function void main() {").first); + v.push_back(l.TokenizeString(s).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION); + ASSERT_EQ(e.line_number, 2); + ASSERT_EQ(e.pos, 0); + ASSERT_EQ(e.message, + "Incorrect catch block declaration. Must be in the format: .catchall , " + ", [, ]"); + } + } + + { + std::vector labels {"try_begin", "try_end", "catch_begin"}; + std::vector label_names {"try block begin", "try block end", "catch block begin"}; + + for (size_t i = 0; i < labels.size(); i++) { + std::string s = ".catchall "; + + if (i != 0) { + std::string directive = s; + for (size_t j = 0; j < labels.size(); j++) { + if (j != 0) { + directive += i == j ? " $ " : " , "; + } + directive += labels[j]; + } + + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".function void main() {").first); + v.push_back(l.TokenizeString(directive).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_DIRECTIVE_DECLARATION) << "Test " << directive; + ASSERT_EQ(e.line_number, 2) << "Test " << directive; + ASSERT_EQ(e.pos, directive.find("$")) << "Test " << directive; + ASSERT_EQ(e.message, "Expected comma.") << "Test " << directive; + } + + { + std::string directive = s; + for (size_t j = 0; j < labels.size(); j++) { + if (j != 0) { + directive += " , "; + } + directive += i == j ? "$" : labels[j]; + } + + std::vector> v; + Lexer l; + Parser p; + + v.push_back(l.TokenizeString(".function void main() {").first); + v.push_back(l.TokenizeString(directive).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_LABEL) << "Test " << directive; + ASSERT_EQ(e.line_number, 2) << "Test " << directive; + ASSERT_EQ(e.pos, directive.find("$")) << "Test " << directive; + ASSERT_EQ(e.message, std::string("Invalid name of the ") + label_names[i] + " label.") + << "Test " << directive; + } + + { + std::stringstream ss; + ss << "Test " << labels[i] << " does not exists"; + + std::vector> v; + Lexer l; + Parser p; + + std::string catch_table = ".catchall try_begin, try_end, catch_begin"; + + v.push_back(l.TokenizeString(".function void main() {").first); + for (size_t j = 0; j < labels.size(); j++) { + if (i != j) { + v.push_back(l.TokenizeString(labels[j] + ":").first); + } + } + v.push_back(l.TokenizeString(catch_table).first); + v.push_back(l.TokenizeString("}").first); + + p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_LABEL_EXT) << ss.str(); + ASSERT_EQ(e.pos, catch_table.find(labels[i])) << ss.str(); + ASSERT_EQ(e.message, "This label does not exist.") << ss.str(); + } + } + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = ".catchall try_begin, try_end, catch_begin"; + + v.push_back(l.TokenizeString(".function void main() {").first); + v.push_back(l.TokenizeString("try_begin:").first); + v.push_back(l.TokenizeString("try_end:").first); + v.push_back(l.TokenizeString("catch_begin:").first); + v.push_back(l.TokenizeString(s).first); + v.push_back(l.TokenizeString("}").first); + + auto res = p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + + auto &program = res.Value(); + auto &function = program.function_table.find("main")->second; + + ASSERT_EQ(function.catch_blocks.size(), 1); + ASSERT_EQ(function.catch_blocks[0].exception_record, ""); + ASSERT_EQ(function.catch_blocks[0].try_begin_label, "try_begin"); + ASSERT_EQ(function.catch_blocks[0].try_end_label, "try_end"); + ASSERT_EQ(function.catch_blocks[0].catch_begin_label, "catch_begin"); + } +} + +TEST(parsertests, parse_numbers) +{ + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("movi v0, 12345}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(int64_t(12345))) + << "12345 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("movi v0, 0xFEFfe}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(int64_t(0xFEFfe))) + << "0xFEFfe expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("movi v0, 01237}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(int64_t(01237))) + << "01237 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("movi v0, 0b10101}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(int64_t(0b10101))) + << "0b10101 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("movi v0, -12345}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(int64_t(-12345))) + << "-12345 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("movi v0, -0xFEFfe}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(int64_t(-0xFEFfe))) + << "12345 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("movi v0, -01237}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(int64_t(-01237))) + << "12345 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("movi v0, -0b10101}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(int64_t(-0b10101))) + << "-0b10101 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, 1.0}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(1.0)) << "1.0 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, 1.}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(1.)) << "1. expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, .1}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(.1)) << ".0 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, 1e10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(1e10)) << "1e10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, 1e+10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(1e+10)) << "1e+10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, 1e-10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(1e-10)) << "1e-10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, 1.0e10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(1.0e10)) << "1.0e10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, 1.0e+10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(1.0e+10)) << "1.0e+10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, 1.0e-10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(1.0e-10)) << "12345 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, 1.e10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(1.e10)) << "1.e10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, 1.e+10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(1.e+10)) << "1.e+10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, 1.e-10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(1.e-10)) << "12345 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, -1.0}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(-1.0)) << "-1.0 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, -1.}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(-1.)) << "-1. expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, -.1}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(-.1)) << "-.0 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, -1e10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(-1e10)) << "-1e10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, -1e+10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(-1e+10)) << "-1e+10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, -1e-10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(-1e-10)) << "-1e-10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, -1.0e10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(-1.0e10)) << "-1.0e10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, -1.0e+10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(-1.0e+10)) << "-1.0e+10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, -1.0e-10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(-1.0e-10)) << "-1.0e-10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, -1.e10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(-1.e10)) << "-1.e10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, -1.e+10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(-1.e+10)) << "-1.e+10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } + + { + std::vector> v; + Lexer l; + Parser p; + v.push_back(l.TokenizeString(".function u8 main(){").first); + v.push_back(l.TokenizeString("fmovi.64 v0, -1.e-10}").first); + auto item = p.Parse(v); + ASSERT_EQ(item.Value().function_table.at("main").ins[0].imms[0], Ins::IType(-1.e-10)) << "-1.e-10 expected"; + ASSERT_EQ(p.ShowError().err, Error::ErrorType::ERR_NONE) << "ERR_NONE expected"; + } +} + +TEST(parsertests, field_value) +{ + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = "i32 f "; + + v.push_back(l.TokenizeString(".record A {").first); + v.push_back(l.TokenizeString(s).first); + v.push_back(l.TokenizeString("}").first); + + auto res = p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_METADATA_INVALID_VALUE); + ASSERT_EQ(e.line_number, 2); + ASSERT_EQ(e.pos, s.find("A")); + ASSERT_EQ(e.message, "Excepted integer literal"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = "i32 f "; + + v.push_back(l.TokenizeString(".record A {").first); + v.push_back(l.TokenizeString(s).first); + v.push_back(l.TokenizeString("}").first); + + auto res = p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE) << e.message; + + auto &program = res.Value(); + auto &record = program.record_table.find("A")->second; + auto &field = record.field_list[0]; + + ASSERT_EQ(field.metadata->GetFieldType().GetName(), "i32"); + ASSERT_TRUE(field.metadata->GetValue()); + ASSERT_EQ(field.metadata->GetValue()->GetType(), Value::Type::I32); + ASSERT_EQ(field.metadata->GetValue()->GetValue(), 10); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = "panda.String f "; + + v.push_back(l.TokenizeString(".record A {").first); + v.push_back(l.TokenizeString(s).first); + v.push_back(l.TokenizeString("}").first); + + auto res = p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE) << e.message; + + auto &program = res.Value(); + auto &record = program.record_table.find("A")->second; + auto &field = record.field_list[0]; + + ASSERT_EQ(field.metadata->GetFieldType().GetName(), "panda.String"); + ASSERT_TRUE(field.metadata->GetValue()); + ASSERT_EQ(field.metadata->GetValue()->GetType(), Value::Type::STRING); + ASSERT_EQ(field.metadata->GetValue()->GetValue(), "10"); + } + + { + std::vector> v; + Lexer l; + Parser p; + + std::string s = "panda.String f"; + + v.push_back(l.TokenizeString(".record A {").first); + v.push_back(l.TokenizeString(s).first); + v.push_back(l.TokenizeString("}").first); + + auto res = p.Parse(v); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE) << e.message; + + auto &program = res.Value(); + auto &record = program.record_table.find("A")->second; + auto &field = record.field_list[0]; + + ASSERT_EQ(field.metadata->GetFieldType().GetName(), "panda.String"); + ASSERT_FALSE(field.metadata->GetValue()); + } +} + +TEST(parsertests, calli_dyn_3args) +{ + { + Parser p; + std::string source = R"( + .language ECMAScript + + # a0 - function, a1 - this + .function any main(any a0, any a1) { + calli.dyn.short 1, a0, a1 + return.dyn + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + } +} + +TEST(parsertests, call_short_0args) +{ + { + Parser p; + std::string source = R"( + .function void f() { + call.short + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_NUMBER_OPERANDS); + } +} + +TEST(parsertests, type_id_tests_lda) +{ + { + Parser p; + std::string source = R"( + .function void f() { + lda.type a + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_RECORD); + } + + { + Parser p; + std::string source = R"( + .function void f() { + lda.type a[] + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_RECORD); + } + + { + Parser p; + std::string source = R"( + .record a {} + .function void f() { + lda.type a + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + } +} + +TEST(parsertests, type_id_tests_newarr) +{ + { + Parser p; + std::string source = R"( + .function void f() { + newarr v0, v0, a + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_RECORD); + } + + { + Parser p; + std::string source = R"( + .function void f() { + newarr v0, v0, a[] + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_RECORD); + } + + { + Parser p; + std::string source = R"( + .record a {} + .function void f() { + newarr v0, v0, a[] + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + } + + { + Parser p; + std::string source = R"( + .record a {} + .function void f() { + newarr v0, v0, a + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + Error w = p.ShowWarnings()[0]; + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + ASSERT_EQ(w.err, Error::ErrorType::WAR_UNEXPECTED_TYPE_ID); + } +} + +TEST(parsertests, type_id_tests_newobj) +{ + { + Parser p; + std::string source = R"( + .function void f() { + newobj v0, a + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_RECORD); + } + + { + Parser p; + std::string source = R"( + .function void f() { + newobj v0, a[] + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_RECORD); + } + + { + Parser p; + std::string source = R"( + .record a {} + .function void f() { + newobj v0, a + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + } + + { + Parser p; + std::string source = R"( + .record a {} + .function void f() { + newobj v0, a[] + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + Error w = p.ShowWarnings()[0]; + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + ASSERT_EQ(w.err, Error::ErrorType::WAR_UNEXPECTED_TYPE_ID); + } +} + +TEST(parsertests, type_id_tests_checkcast) +{ + { + Parser p; + std::string source = R"( + .function void f() { + checkcast a + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_RECORD); + } + + { + Parser p; + std::string source = R"( + .function void f() { + checkcast a[] + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_RECORD); + } + + { + Parser p; + std::string source = R"( + .record a {} + .function void f() { + checkcast a + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + } +} + +TEST(parsertests, type_id_tests_isinstance) +{ + { + Parser p; + std::string source = R"( + .function void f() { + isinstance a + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_RECORD); + } + + { + Parser p; + std::string source = R"( + .function void f() { + isinstance a[] + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_BAD_ID_RECORD); + } + + { + Parser p; + std::string source = R"( + .record a {} + .function void f() { + isinstance a + } + )"; + + auto res = p.Parse(source); + + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + } +} + +TEST(parsertests, test_fields_same_name) +{ + { + Parser p; + std::string source = R"( + .record A { + i16 aaa + u8 aaa + i32 aaa + } + )"; + + auto res = p.Parse(source); + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_REPEATING_FIELD_NAME); + } + + { + Parser p; + std::string source = R"( + .function i32 main() { + ldobj.64 v0, A.aaa + ldai 0 + return + } + .record A { + i16 aaa + } + )"; + + auto res = p.Parse(source); + Error e = p.ShowError(); + + ASSERT_EQ(e.err, Error::ErrorType::ERR_NONE); + } +} + +} // namespace panda::test diff --git a/assembler/utils/number-utils.h b/assembler/utils/number-utils.h new file mode 100644 index 0000000000..75aeb1462c --- /dev/null +++ b/assembler/utils/number-utils.h @@ -0,0 +1,207 @@ +/* + * 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_ASSEMBLER_UTILS_NUMBER_UTILS_H_ +#define PANDA_ASSEMBLER_UTILS_NUMBER_UTILS_H_ + +namespace panda::pandasm { + +constexpr size_t HEX_BASE = 16; + +constexpr size_t DEC_BASE = 10; + +constexpr size_t OCT_BASE = 8; + +constexpr size_t BIN_BASE = 2; + +constexpr size_t MAX_DWORD = 65536; + +inline bool ValidateHexInteger(std::string_view p) +{ + std::string_view token = p; + token.remove_prefix(2U); + + for (auto i : token) { + if (!((i >= '0' && i <= '9') || (i >= 'A' && i <= 'F') || (i >= 'a' && i <= 'f'))) { + return false; + } + } + + return true; +} + +inline bool ValidateBinInteger(std::string_view p) +{ + std::string_view token = p; + token.remove_prefix(2U); + if (token.empty()) { + return false; + } + for (auto i : token) { + if (!(i == '0' || i == '1')) { + return false; + } + } + + return true; +} + +inline bool ValidateOctalInteger(std::string_view p) +{ + std::string_view token = p; + token.remove_prefix(1); + + for (auto i : token) { + if (!(i >= '0' && i <= '7')) { + return false; + } + } + + return true; +} + +inline bool ValidateInteger(std::string_view p) +{ + std::string_view token = p; + + if (token.back() == '-' || token.back() == '+' || token.back() == 'x' || token == ".") { + return false; + } + + if (token[0] == '-' || token[0] == '+') { + token.remove_prefix(1); + } + + if (token[0] == '0' && token.size() > 1 && token.find('.') == std::string::npos) { + if (token[1] == 'x') { + return ValidateHexInteger(token); + } + + if (token[1] == 'b') { + return ValidateBinInteger(token); + } + + if (token[1] >= '0' && token[1] <= '9' && token.find('e') == std::string::npos) { + return ValidateOctalInteger(token); + } + } + + for (auto i : token) { + if (!(i >= '0' && i <= '9')) { + return false; + } + } + + return true; +} + +inline int64_t IntegerNumber(std::string_view p) +{ + constexpr size_t GENERAL_SHIFT = 2; + + // expects a valid number + if (p.size() == 1) { + return p[0] - '0'; + } + + size_t minus_shift = 0; + if (p[0] == '-') { + minus_shift++; + } + + if (p[minus_shift + 1] == 'b') { + p.remove_prefix(GENERAL_SHIFT + minus_shift); + return std::strtoull(p.data(), nullptr, BIN_BASE) * (minus_shift == 0 ? 1 : -1); + } + + if (p[minus_shift + 1] == 'x') { + return std::strtoull(p.data(), nullptr, HEX_BASE); + } + + if (p[minus_shift] == '0') { + return std::strtoull(p.data(), nullptr, OCT_BASE); + } + + return std::strtoull(p.data(), nullptr, DEC_BASE); +} + +inline bool ValidateFloat(std::string_view p) +{ + std::string_view token = p; + + if (ValidateInteger(token)) { + return true; + } + + if (token[0] == '-' || token[0] == '+') { + token.remove_prefix(1); + } + + bool dot = false; + bool exp = false; + bool nowexp = false; + + for (auto i : token) { + if (nowexp && (i == '-' || i == '+')) { + nowexp = false; + continue; + } + + if (nowexp) { + nowexp = false; + } + + if (i == '.' && !exp && !dot) { + dot = true; + } else if (!exp && i == 'e') { + nowexp = true; + exp = true; + } else if (!(i >= '0' && i <= '9')) { + return false; + } + } + + return !nowexp; +} + +inline double FloatNumber(std::string_view p) +{ + 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)); + } + return std::strtold(std::string(p.data(), p.length()).c_str(), nullptr); +} + +inline size_t ToNumber(std::string_view p) +{ + size_t sum = 0; + + for (char i : p) { + if (isdigit(i) != 0) { + sum = sum * DEC_BASE + (i - '0'); + } else { + return MAX_DWORD; + } + } + + return sum; +} + +} // namespace panda::pandasm + +#endif // PANDA_ASSEMBLER_UTILS_NUMBER_UTILS_H_ diff --git a/cmake/ClangTidy.cmake b/cmake/ClangTidy.cmake new file mode 100644 index 0000000000..7a1189a394 --- /dev/null +++ b/cmake/ClangTidy.cmake @@ -0,0 +1,179 @@ +# 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. + +option(PANDA_ENABLE_CLANG_TIDY "Enable clang-tidy checks during compilation" true) + +# There seems to be a bug in either clang-tidy or CMake: +# When clang/gcc is used for cross-compilation, it is ran on host and use definitions and options for host +# For example for arm32 cross-compilation Clang-Tidy: +# - don't know about -march=armv7-a +# - believes that size of pointer is 64 instead of 32 for aarch32 +if(CMAKE_CROSSCOMPILING) + set(PANDA_ENABLE_CLANG_TIDY false) +endif() + +if(PANDA_TARGET_MACOS) + set(PANDA_ENABLE_CLANG_TIDY false) +endif() + +if(PANDA_ENABLE_CLANG_TIDY) + # Currently we fix a certain version of clang-tidy to avoid unstable linting, + # which may occur if different versions of the tools are used by developers. + set(panda_clang_tidy "clang-tidy-9") + + # Require clang-tidy + find_program( + CLANG_TIDY + NAMES ${panda_clang_tidy} + DOC "Path to clang-tidy executable") + if(NOT CLANG_TIDY) + message(FATAL_ERROR "clang-tidy not found, but requested for build. Use -DPANDA_ENABLE_CLANG_TIDY=false to suppress.") + endif() + + unset(panda_clang_tidy) + + message(STATUS "clang-tidy found: ${CLANG_TIDY}") + # NB! Even if config is malformed, clang-tidy -dump-config returns 0 on failure. + # Hence we check for ERROR_VARIABLE instead of RESULT_VARIABLE. + execute_process( + COMMAND ${CLANG_TIDY} -dump-config + WORKING_DIRECTORY ${PANDA_ROOT} + ERROR_VARIABLE dump_config_stderr) + if (dump_config_stderr AND NOT "${dump_config_stderr}" STREQUAL "") + message(FATAL_ERROR "${dump_config_stderr}") + endif() + # See https://gitlab.kitware.com/cmake/cmake/issues/18926. + # Create a preprocessor definition that depends on .clang-tidy content so + # the compile command will change when .clang-tidy changes. This ensures + # that a subsequent build re-runs clang-tidy on all sources even if they + # do not otherwise need to be recompiled. Nothing actually uses this + # definition. We add it to targets on which we run clang-tidy just to + # get the build dependency on the .clang-tidy file. + file(SHA1 ${CMAKE_CURRENT_SOURCE_DIR}/.clang-tidy clang_tidy_sha1) + set(CLANG_TIDY_DEFINITIONS "CLANG_TIDY_SHA1=${clang_tidy_sha1}") + unset(clang_tidy_sha1) + configure_file(${PANDA_ROOT}/.clang-tidy ${PANDA_BINARY_ROOT}/.clang-tidy COPYONLY) +endif() + +# Add a target to clang-tidy checks. +# +# Example usage: +# +# panda_add_to_clang_tidy(TARGET target_name +# CHECKS +# "-check-to-be-disabled" +# "-glob-to-be-disabled-*" +# "check-to-be-enabled" +# "glob-to-be-enabled-*" +# ) +# +# This function makes target_name to be co-compiled with clang-tidy. +# The list of CHECKS allows to pass per-target checks in additions to +# global ones (see below). CHECKS follow clang-tidy syntax of checks. +# By default all checks are enabled globally, so the most reasonable use +# case for CHECKS is to pass checks to be suppressed. + +# NB! Important caveats: +# * We use permissive policy for checks, i.e. everything is enabled by default, +# then exceptions are suppressed explicitly. +# * We maintain the list of global exceptions in this function (not in .clang-tidy) +# because of its syntax limitations (in particular, all checks should be passed +# as a single string in YAML, which is not readable). +# * -header-filter is set to check only headers of the target_name. It is supposed +# that each components is responsible for QA'ing only its code base. +function(panda_add_to_clang_tidy) + if(NOT PANDA_ENABLE_CLANG_TIDY) + return() + endif() + + set(prefix ARG) + set(noValues) + set(singleValues TARGET) + set(multiValues CHECKS) + + cmake_parse_arguments(${prefix} + "${noValues}" + "${singleValues}" + "${multiValues}" + ${ARGN}) + + set(clang_tidy_params + "${CLANG_TIDY}" + "-config=" + "-format-style=file" + "-header-filter='^(${CMAKE_SOURCE_DIR}|${CMAKE_BINARY_DIR}).*/(assembler|compiler|debugger|libpandabase|libpandafile|runtime|class2panda)/.*'" + "-p='${PANDA_BINARY_ROOT}'" + ) + + set(clang_tidy_default_exceptions + # aliases for other checks(here full list: https://clang.llvm.org/extra/clang-tidy/checks/list.html): + "-hicpp-braces-around-statements" # alias for readability-braces-around-statements + "-google-readability-braces-around-statements" # alias for readability-braces-around-statements + "-google-readability-function-size" # alias for readability-function-size + "-hicpp-explicit-conversions" # alias for google-explicit-constructor + "-hicpp-function-size" # alias for readability-function-size + "-hicpp-no-array-decay" # alias for cppcoreguidelines-pro-bounds-array-to-pointer-decay + "-hicpp-avoid-c-arrays" # alias for modernize-avoid-c-arrays + "-cppcoreguidelines-avoid-c-arrays" # alias for modernize-avoid-c-arrays + "-cppcoreguidelines-avoid-magic-numbers" # alias for readability-magic-numbers + "-cppcoreguidelines-non-private-member-variables-in-classes" # alias for misc-non-private-member-variables-in-classes + "-cert-dcl03-c" # alias for misc-static-assert + "-hicpp-static-assert" # alias for misc-static-assert + "-hicpp-no-malloc" # alias for cppcoreguidelines-no-malloc + "-hicpp-vararg" # alias for cppcoreguidelines-pro-type-vararg + "-hicpp-member-init" # alias for cppcoreguidelines-pro-type-member-init + "-hicpp-move-const-arg" # alias for performance-move-const-arg + # explicitly disabled checks + "-bugprone-macro-parentheses" # disabled because it is hard to write macroses with types with it + "-llvm-header-guard" # disabled because of incorrect root prefix + "-llvm-include-order" # disabled because conflicts with the clang-format + "-readability-identifier-naming" # disabled because we will use little-hump-style + "google-runtime-references" # disabled to use non-const references + "-fuchsia-trailing-return" # disabled because we have a lot of false positives and it is stylistic check + "-fuchsia-default-arguments-calls" # disabled because we use functions with default arguments a lot + "-fuchsia-default-arguments-declarations" # disabled because we use functions with default arguments a lot + "-modernize-use-trailing-return-type" # disabled as a stylistic check + "-clang-analyzer-optin.cplusplus.UninitializedObject" # disabled due to instability on clang-9 and clang-10 + "-readability-static-accessed-through-instance" + "-readability-convert-member-functions-to-static" + "-bugprone-sizeof-expression" + "-bugprone-branch-clone" + "-cppcoreguidelines-owning-memory" + "-cppcoreguidelines-pro-bounds-array-to-pointer-decay" + "-cppcoreguidelines-pro-bounds-constant-array-index" + "-cppcoreguidelines-pro-type-const-cast" + "-cppcoreguidelines-pro-type-reinterpret-cast" + "-cppcoreguidelines-pro-type-static-cast-downcast" + "-fuchsia-default-arguments" + "-fuchsia-overloaded-operator" + "-modernize-use-nodiscard" + "-cert-dcl50-cpp" # ailas for cppcoreguidelines-pro-type-vararg + # candidates for removal: + "-hicpp-noexcept-move" # For some reason become failed in DEFAULT_MOVE_SEMANTIC + "-performance-noexcept-move-constructor" # Same as above + ) + # NB! Replace with list(JOIN ...) after switching to CMake 3.12+ + string(REPLACE ";" "," default_exceptions "${clang_tidy_default_exceptions}") + + set(clang_tidy_checks "-checks=*,${default_exceptions}") + + if(DEFINED ARG_CHECKS) + # NB! Replace with list(JOIN ...) after switching to CMake 3.12+ + string(REPLACE ";" "," custom_checks "${ARG_CHECKS}") + set(clang_tidy_checks "${clang_tidy_checks},${custom_checks}") + endif() + + list(APPEND clang_tidy_params "${clang_tidy_checks}") + + set_target_properties(${ARG_TARGET} PROPERTIES CXX_CLANG_TIDY "${clang_tidy_params}") +endfunction() diff --git a/cmake/CodeStyle.cmake b/cmake/CodeStyle.cmake new file mode 100644 index 0000000000..010b2f0c6a --- /dev/null +++ b/cmake/CodeStyle.cmake @@ -0,0 +1,108 @@ +# 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. + +# Currently we fix a certain version of clang-format to avoid unstable linting, +# which may occur if different versions of the tools are used by developers. +set(PANDA_CLANG_FORMAT "clang-format-9") + +# Require clang-format +find_program( + CLANG_FORMAT + NAMES "${PANDA_CLANG_FORMAT}" + DOC "Path to clang-format executable" + ) +if(NOT CLANG_FORMAT) + message(WARNING "Clang-format not found.") +else() + message(STATUS "clang-format found: ${CLANG_FORMAT}") +endif() + +# Function to add targets for clang_format, clang_force_format +function(add_check_style dir) + file(GLOB_RECURSE dir_sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${dir}/*.cpp ${dir}/*.cc) + file(GLOB_RECURSE dir_headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${dir}/*.h) + + if (CLANG_FORMAT) + if(TARGET clang_format) + else() + add_custom_target(clang_format) + endif() + if(TARGET clang_force_format) + else() + add_custom_target(clang_force_format) + endif() + endif() + + if(NOT TARGET check_concurrency_format) + add_custom_target(check_concurrency_format) + endif() + + foreach(src ${dir_sources}) + get_filename_component(source ${src} ABSOLUTE) + file(RELATIVE_PATH src ${PANDA_ROOT} ${source}) + STRING(REGEX REPLACE "/" "_" src ${src}) + if (CLANG_FORMAT) + add_clang_format(${source} ${src}) + add_clang_force_format(${source} ${src}) + endif() + add_check_concurrency_format(${source} ${src}) + endforeach() + + # Also add format-target for headers + foreach(src ${dir_headers}) + get_filename_component(source ${src} ABSOLUTE) + file(RELATIVE_PATH src ${PANDA_ROOT} ${source}) + STRING(REGEX REPLACE "/" "_" src ${src}) + if (CLANG_FORMAT) + add_clang_format(${source} ${src}) + add_clang_force_format(${source} ${src}) + add_dependencies(clang_format clang_format_${src}) + add_dependencies(clang_force_format clang_force_format_${src}) + endif() + add_check_concurrency_format(${source} ${src}) + add_dependencies(check_concurrency_format check_concurrency_format_${src}) + endforeach() +endfunction() + +# Function to check through clang-format +function(add_clang_format src tgt) + if (TARGET clang_format_${tgt}) + return() + endif() + add_custom_target(clang_format_${tgt} + COMMAND ${PANDA_ROOT}/scripts/run-clang-format ${PANDA_CLANG_FORMAT} ${src}) + add_dependencies(clang_format clang_format_${tgt}) +endfunction() + +# Function to check correct usage of std primitives. +function(add_check_concurrency_format src tgt) + set(CHECK_CONCURRENCY_FORMAT "${PANDA_ROOT}/scripts/run-check-concurrency-format.sh") + + if (NOT TARGET check_concurrency_format_${tgt}) + add_custom_target(check_concurrency_format_${tgt} + COMMAND ${CHECK_CONCURRENCY_FORMAT} ${src} + ) + add_dependencies(check_concurrency_format check_concurrency_format_${tgt}) + endif() +endfunction() + +# Function to force style through clang-format +function(add_clang_force_format src tgt) + if (NOT TARGET clang_force_format_${tgt}) + add_custom_target(clang_force_format_${tgt} + COMMAND ${CLANG_FORMAT} -i -style=file ${src} + ) + add_dependencies(clang_force_format clang_force_format_${tgt}) + endif() +endfunction() + diff --git a/cmake/CommonTesting.cmake b/cmake/CommonTesting.cmake new file mode 100644 index 0000000000..875dae8630 --- /dev/null +++ b/cmake/CommonTesting.cmake @@ -0,0 +1,149 @@ +# 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. +# Convenience functions for testing Panda. + +include(${CMAKE_CURRENT_LIST_DIR}/PandaCmakeFunctions.cmake) + +function(common_add_gtest) + set(prefix ARG) + set(noValues CONTAINS_MAIN NO_CORES RAPIDCHECK_ON USE_CATCH2) + set(singleValues NAME OUTPUT_DIRECTORY ENCLOSING_TARGET TSAN_EXTRA_OPTIONS PANDA_STD_LIB ARK_BOOTCLASSPATH) + set(multiValues SOURCES INCLUDE_DIRS LIBRARIES SANITIZERS) + + cmake_parse_arguments(${prefix} + "${noValues}" + "${singleValues}" + "${multiValues}" + ${ARGN}) + + if (ARG_RAPIDCHECK_ON AND DEFINED DONT_USE_RAPIDCHECK) + return() + endif() + + if (NOT DEFINED ARG_ENCLOSING_TARGET) + message(FATAL_ERROR "Enclosing target is not defined") + endif() + if (NOT DEFINED ARG_OUTPUT_DIRECTORY) + message(FATAL_ERROR "OUTPUT_DIRECTORY is not defined") + endif() + + if(ARG_USE_CATCH2 AND NOT ARG_CONTAINS_MAIN) + set(ARG_SOURCES ${ARG_SOURCES} ${PANDA_ROOT}/third_party/rapidcheck/test/main.cpp) + endif() + + if (ARG_RAPIDCHECK_ON) + panda_add_executable(${ARG_NAME} RAPIDCHECK_ON ${ARG_SOURCES}) + set_target_properties(${ARG_NAME} PROPERTIES LINK_FLAGS "-frtti -fexceptions") + target_compile_definitions(${ARG_NAME} PRIVATE PANDA_RAPIDCHECK) + target_compile_options(${ARG_NAME} PRIVATE "-frtti" "-fexceptions" "-fPIC") + target_compile_definitions(${ARG_NAME} PUBLIC PANDA_RAPIDCHECK) + else() + panda_add_executable(${ARG_NAME} ${ARG_SOURCES}) + endif() + + if (ARG_USE_CATCH2) + target_compile_definitions(${ARG_NAME} PUBLIC PANDA_CATCH2) + else() + target_compile_definitions(${ARG_NAME} PUBLIC PANDA_GTEST) + endif() + + if(PANDA_CI_TESTING_MODE STREQUAL "Nightly") + target_compile_definitions(${ARG_NAME} PUBLIC PANDA_NIGHTLY_TEST_ON) + endif() + # By default tests are just built, running is available either via an + # umbrella target or via `ctest -R ...`. But one can always do something + # like this if really needed: + # add_custom_target(${ARG_NAME}_run + # COMMENT "Run ${ARG_NAME}" + # COMMAND ${CMAKE_CTEST_COMMAND} + # DEPENDS ${ARG_NAME}) + if (ARG_USE_CATCH2) + foreach(include_dir ${ARG_INCLUDE_DIRS} ${PANDA_ROOT}/third_party/rapidcheck/include) + target_include_directories(${ARG_NAME} PUBLIC ${include_dir}) + endforeach() + else() + foreach(include_dir ${ARG_INCLUDE_DIRS} ${PANDA_THIRD_PARTY_SOURCES_DIR}/googletest/googlemock/include) + target_include_directories(${ARG_NAME} PUBLIC ${include_dir}) + endforeach() + endif() + + if (NOT ARG_USE_CATCH2) + if (ARG_CONTAINS_MAIN) + target_link_libraries(${ARG_NAME} gtest) + else() + target_link_libraries(${ARG_NAME} gtest_main) + endif() + endif() + + if (NOT (PANDA_TARGET_MOBILE OR PANDA_TARGET_OHOS)) + target_link_libraries(${ARG_NAME} pthread) + endif() + target_link_libraries(${ARG_NAME} ${ARG_LIBRARIES}) + add_dependencies(${ARG_ENCLOSING_TARGET} ${ARG_NAME}) + + if (ARG_RAPIDCHECK_ON) + target_link_libraries(${ARG_NAME} rapidcheck) + target_link_libraries(${ARG_NAME} rapidcheck_catch) + target_link_libraries(${ARG_NAME} rapidcheck_gtest) + target_link_libraries(${ARG_NAME} rapidcheck_gmock) + add_dependencies(${ARG_NAME} rapidcheck) + endif() + + panda_add_sanitizers(TARGET ${ARG_NAME} SANITIZERS ${ARG_SANITIZERS}) + + set(prlimit_prefix "") + if (ARG_NO_CORES) + set(prlimit_prefix prlimit --core=0) + endif() + set_target_properties(${ARG_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${ARG_OUTPUT_DIRECTORY}") + + set(tsan_options "") + if ("thread" IN_LIST PANDA_SANITIZERS_LIST) + if (DEFINED ENV{TSAN_OPTIONS}) + set(tsan_options "TSAN_OPTIONS=$ENV{TSAN_OPTIONS},${ARG_TSAN_EXTRA_OPTIONS}") + endif() + endif() + + # Yes, this is hardcoded. No, do not ask for an option. Go and fix your tests. + if (PANDA_CI_TESTING_MODE STREQUAL "Nightly") + set(timeout_prefix timeout --preserve-status --signal=USR1 --kill-after=10s 40m) + else () + set(timeout_prefix timeout --preserve-status --signal=USR1 --kill-after=10s 20m) + endif() + + if (ARG_RAPIDCHECK_ON) + add_custom_target(${ARG_NAME}_rapidcheck_tests + COMMAND ${tsan_options} ${prlimit_prefix} ${timeout_prefix} + ${PANDA_RUN_PREFIX} "${ARG_OUTPUT_DIRECTORY}/${ARG_NAME}" + DEPENDS ${ARG_ENCLOSING_TARGET} + ) + add_dependencies(gtests ${ARG_NAME}_rapidcheck_tests) + else() + set(PANDA_STD_LIB "") + if (DEFINED ARG_PANDA_STD_LIB) + set(PANDA_STD_LIB "PANDA_STD_LIB=${ARG_PANDA_STD_LIB}") + endif() + set(ARK_BOOTCLASSPATH "") + if (DEFINED ARG_ARK_BOOTCLASSPATH) + set(ARK_BOOTCLASSPATH "ARK_BOOTCLASSPATH=${ARG_ARK_BOOTCLASSPATH}") + endif() + add_custom_target(${ARG_NAME}_gtests + COMMAND ${PANDA_STD_LIB} ${ARK_BOOTCLASSPATH} + ${tsan_options} ${prlimit_prefix} ${timeout_prefix} + ${PANDA_RUN_PREFIX} "${ARG_OUTPUT_DIRECTORY}/${ARG_NAME}" + --gtest_shuffle --gtest_death_test_style=threadsafe + DEPENDS ${ARG_ENCLOSING_TARGET} + ) + add_dependencies(gtests ${ARG_NAME}_gtests) + endif() +endfunction() diff --git a/cmake/Definitions.cmake b/cmake/Definitions.cmake new file mode 100644 index 0000000000..3aabf2b26f --- /dev/null +++ b/cmake/Definitions.cmake @@ -0,0 +1,214 @@ +# 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. + +if(CMAKE_SYSTEM_NAME STREQUAL Linux) + set(PANDA_TARGET_LINUX 1) + set(PANDA_TARGET_UNIX 1) +if (NOT PANDA_ENABLE_ADDRESS_SANITIZER) + set(PANDA_USE_FUTEX 1) +endif() + add_definitions(-DPANDA_TARGET_LINUX) + add_definitions(-DPANDA_TARGET_UNIX) +if (NOT PANDA_ENABLE_ADDRESS_SANITIZER) + add_definitions(-DPANDA_USE_FUTEX) +endif() +elseif(CMAKE_SYSTEM_NAME STREQUAL OHOS) + set(PANDA_TARGET_OHOS 1) + set(PANDA_TARGET_UNIX 1) + add_definitions(-DPANDA_TARGET_OHOS) + add_definitions(-DPANDA_TARGET_UNIX) +elseif(CMAKE_SYSTEM_NAME STREQUAL Windows) + set(PANDA_TARGET_WINDOWS 1) + add_definitions(-DPANDA_TARGET_WINDOWS) +elseif(CMAKE_SYSTEM_NAME STREQUAL Darwin) + set(PANDA_TARGET_MACOS 1) + set(PANDA_TARGET_UNIX 1) + add_definitions(-DPANDA_TARGET_MACOS) + add_definitions(-DPANDA_TARGET_UNIX) +else() + message(FATAL_ERROR "Platform ${CMAKE_SYSTEM_NAME} is not supported") +endif() + +if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64" OR CMAKE_SYSTEM_PROCESSOR STREQUAL "AMD64") + if(NOT PANDA_CROSS_AMD64_X86) + set(PANDA_TARGET_AMD64 1) + add_definitions(-DPANDA_TARGET_AMD64) + else() + set(PANDA_TARGET_X86 1) + add_definitions(-DPANDA_TARGET_X86) + endif() +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i[356]86") + set(PANDA_TARGET_X86 1) + add_definitions(-DPANDA_TARGET_X86) +elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64") + set(PANDA_TARGET_ARM64 1) + add_definitions(-DPANDA_TARGET_ARM64) +elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "arm") + set(PANDA_TARGET_ARM32 1) + add_definitions(-DPANDA_TARGET_ARM32) + if(PANDA_TARGET_ARM32_ABI_SOFT) + add_definitions(-DPANDA_TARGET_ARM32_ABI_SOFT) + elseif(PANDA_TARGET_ARM32_ABI_HARD) + add_definitions(-DPANDA_TARGET_ARM32_ABI_HARD) + else() + message(FATAL_ERROR "PANDA_TARGET_ARM32_ABI_* is not set") + endif() +else() + message(FATAL_ERROR "Processor ${CMAKE_SYSTEM_PROCESSOR} is not supported") +endif() + +if(PANDA_TARGET_AMD64 OR PANDA_TARGET_ARM64) + set(PANDA_TARGET_64 1) + add_definitions(-DPANDA_TARGET_64) +elseif(PANDA_TARGET_X86 OR PANDA_TARGET_ARM32) + set(PANDA_TARGET_32 1) + add_definitions(-DPANDA_TARGET_32) +else() + message(FATAL_ERROR "Unknown bitness of the target platform") +endif() + +if (PANDA_TRACK_INTERNAL_ALLOCATIONS) + message(STATUS "Track internal allocations") + add_definitions(-DTRACK_INTERNAL_ALLOCATIONS=${PANDA_TRACK_INTERNAL_ALLOCATIONS}) +endif() + +# Enable global register variables usage only for clang >= 9.0.0 and gcc >= 8.0.0. +# Clang 8.0.0 doesn't support all necessary options -ffixed-. Gcc 7.5.0 freezes +# when compiling release interpreter. +# +# Also calling conventions of funtions that use global register variables are different: +# clang stores and restores registers that are used for global variables in the prolog +# and epilog of such functions and gcc doesn't do it. So it's necessary to inline all +# function that refers to global register variables to interpreter loop. + +# For this reason we disable global register variables usage for clang debug builds as +# ALWAYS_INLINE macro expands to nothing in this mode and we cannot garantee that all +# necessary function will be inlined. +# +if(PANDA_TARGET_ARM64 AND ((CMAKE_CXX_COMPILER_ID STREQUAL "Clang" + AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0.0 + AND CMAKE_BUILD_TYPE MATCHES Release) + OR + (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" + AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0.0))) + set(PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES 1) + add_definitions(-DPANDA_ENABLE_GLOBAL_REGISTER_VARIABLES) +endif() + +if(CMAKE_BUILD_TYPE MATCHES Debug) + # Additional debug information about fp in each frame + add_compile_options(-fno-omit-frame-pointer) +endif() + +if (PANDA_PGO_INSTRUMENT OR PANDA_PGO_OPTIMIZE) + if (NOT PANDA_TARGET_MOBILE OR NOT PANDA_TARGET_ARM64) + message(FATAL_ERROR "PGO supported is not supported on this target") + endif() + + set(PANDA_ENABLE_LTO true) +endif() + +if(PANDA_TARGET_64) + set(PANDA_USE_32_BIT_POINTER 1) + add_definitions(-DPANDA_USE_32_BIT_POINTER) +endif() + +if(PANDA_TARGET_LINUX) + execute_process(COMMAND grep PRETTY_NAME= /etc/os-release + OUTPUT_VARIABLE PANDA_TARGET_LINUX_DISTRO + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(PANDA_TARGET_LINUX_DISTRO MATCHES "Ubuntu") + set(PANDA_TARGET_LINUX_UBUNTU 1) + add_definitions(-DPANDA_TARGET_LINUX_UBUNTU) + endif() + + if(PANDA_TARGET_LINUX_DISTRO MATCHES "Ubuntu 18\\.04") + set(PANDA_TARGET_LINUX_UBUNTU_18_04 1) + add_definitions(-DPANDA_TARGET_LINUX_UBUNTU_18_04) + elseif(PANDA_TARGET_LINUX_DISTRO MATCHES "Ubuntu 20\\.04") + set(PANDA_TARGET_LINUX_UBUNTU_20_04 1) + add_definitions(-DPANDA_TARGET_LINUX_UBUNTU_20_04) + endif() +endif() + +set(PANDA_WITH_RUNTIME true) +set(PANDA_WITH_TOOLCHAIN true) +set(PANDA_WITH_TESTS true) +set(PANDA_WITH_BENCHMARKS true) +set(PANDA_DEFAULT_LIB_TYPE "SHARED") +set(DONT_USE_RAPIDCHECK true) + +option(PANDA_ARK_JS_VM "Build with C intepreter in ecmascript folder" OFF) + +if(PANDA_TARGET_WINDOWS) + set(PANDA_WITH_BENCHMARKS false) + set(PANDA_DEFAULT_LIB_TYPE "STATIC") +endif() + +if(PANDA_TARGET_MACOS) + set(PANDA_DEFAULT_LIB_TYPE "STATIC") + #introduced for "std::filesystem::create_directories" + add_compile_options(-mmacosx-version-min=10.15) +endif() + +if(PANDA_TARGET_OHOS) + set(PANDA_WITH_BENCHMARKS false) +endif() + +if(CMAKE_BUILD_TYPE STREQUAL FastVerify) + add_definitions(-DFAST_VERIFY) +endif() + +# The definition is set for the build which will be delivered to customers. +# Currently this build doesn't contain dependencies to debug libraries +# (like libdwarf.so) +if (NOT DEFINED PANDA_PRODUCT_BUILD) + set(PANDA_PRODUCT_BUILD false) +endif() + +if (PANDA_PRODUCT_BUILD) + add_definitions(-DPANDA_PRODUCT_BUILD) +endif() + +message(STATUS "PANDA_TARGET_UNIX = ${PANDA_TARGET_UNIX}") +message(STATUS "PANDA_TARGET_LINUX = ${PANDA_TARGET_LINUX}") +message(STATUS "PANDA_TARGET_MOBILE = ${PANDA_TARGET_MOBILE}") +message(STATUS "PANDA_USE_FUTEX = ${PANDA_USE_FUTEX}") +message(STATUS "PANDA_TARGET_WINDOWS = ${PANDA_TARGET_WINDOWS}") +message(STATUS "PANDA_TARGET_OHOS = ${PANDA_TARGET_OHOS}") +message(STATUS "PANDA_TARGET_MACOS = ${PANDA_TARGET_MACOS}") +message(STATUS "PANDA_CROSS_AMD64_X86 = ${PANDA_CROSS_AMD64_X86}") +message(STATUS "PANDA_TARGET_AMD64 = ${PANDA_TARGET_AMD64}") +message(STATUS "PANDA_TARGET_X86 = ${PANDA_TARGET_X86}") +message(STATUS "PANDA_TARGET_ARM64 = ${PANDA_TARGET_ARM64}") +message(STATUS "PANDA_TARGET_ARM32 = ${PANDA_TARGET_ARM32}") +if(PANDA_TARGET_ARM32) +message(STATUS "PANDA_TARGET_ARM32_ABI_SOFT = ${PANDA_TARGET_ARM32_ABI_SOFT}") +message(STATUS "PANDA_TARGET_ARM32_ABI_HARD = ${PANDA_TARGET_ARM32_ABI_HARD}") +endif() +message(STATUS "PANDA_TARGET_64 = ${PANDA_TARGET_64}") +message(STATUS "PANDA_TARGET_32 = ${PANDA_TARGET_32}") +message(STATUS "PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES = ${PANDA_ENABLE_GLOBAL_REGISTER_VARIABLES}") +message(STATUS "PANDA_ENABLE_LTO = ${PANDA_ENABLE_LTO}") +if(PANDA_TARGET_MOBILE) +message(STATUS "PANDA_LLVM_REGALLOC = ${PANDA_LLVM_REGALLOC}") +endif() +message(STATUS "PANDA_WITH_RUNTIME = ${PANDA_WITH_RUNTIME}") +message(STATUS "PANDA_WITH_COMPILER = ${PANDA_WITH_COMPILER}") +message(STATUS "PANDA_WITH_TOOLCHAIN = ${PANDA_WITH_TOOLCHAIN}") +message(STATUS "PANDA_WITH_TESTS = ${PANDA_WITH_TESTS}") +message(STATUS "PANDA_WITH_BENCHMARKS = ${PANDA_WITH_BENCHMARKS}") +message(STATUS "PANDA_PGO_INSTRUMENT = ${PANDA_PGO_INSTRUMENT}") +message(STATUS "PANDA_PGO_OPTIMIZE = ${PANDA_PGO_OPTIMIZE}") +message(STATUS "PANDA_PRODUCT_BUILD = ${PANDA_PRODUCT_BUILD}") diff --git a/cmake/HostTools.cmake b/cmake/HostTools.cmake new file mode 100644 index 0000000000..ac9ef2f58d --- /dev/null +++ b/cmake/HostTools.cmake @@ -0,0 +1,59 @@ +# 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. + +# To build parts of the platform written in Panda Assembly, +# we need to have the assembler binary. If we are not +# cross-compiling, we are good to go. Otherwise a subset +# of source tree is exposed as a separate project for +# "host tools", which is built solely for host. + +function(panda_configure_host_tools) + if(NOT CMAKE_CROSSCOMPILING) + return() + endif() + + include(ExternalProject) + + set(host_tools_dir "${CMAKE_CURRENT_BINARY_DIR}/host-tools") + + configure_file( + "${CMAKE_CURRENT_LIST_DIR}/host-tools-CMakeLists.txt" + "${host_tools_dir}/CMakeLists.txt" + @ONLY ESCAPE_QUOTES) + + if ($ENV{NPROC_PER_JOB}) + set(PANDA_HOST_TOOLS_JOBS_NUMBER $ENV{NPROC_PER_JOB}) + else() + set(PANDA_HOST_TOOLS_JOBS_NUMBER 16) + endif() + + add_custom_target(compiler_host_tools-depend) + + ExternalProject_Add(panda_host_tools + DEPENDS compiler_host_tools-depend + SOURCE_DIR "${host_tools_dir}" + BINARY_DIR "${host_tools_dir}-build" + BUILD_IN_SOURCE FALSE + CONFIGURE_COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DPANDA_ROOT_SOURCE_DIR=${PANDA_ROOT} + -DPANDA_ROOT_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR} + -DPANDA_THIRD_PARTY_SOURCES_DIR=${PANDA_THIRD_PARTY_SOURCES_DIR} + -DPANDA_THIRD_PARTY_CONFIG_DIR=${PANDA_THIRD_PARTY_CONFIG_DIR} + -DPANDA_PRODUCT_BUILD=true + BUILD_COMMAND ${CMAKE_COMMAND} --build --target all -- -j${PANDA_HOST_TOOLS_JOBS_NUMBER} + INSTALL_COMMAND ${CMAKE_COMMAND} -E echo "Skipping install step" + ) +endfunction() + +panda_configure_host_tools() diff --git a/cmake/PandaAssembly.cmake b/cmake/PandaAssembly.cmake new file mode 100644 index 0000000000..7122ead933 --- /dev/null +++ b/cmake/PandaAssembly.cmake @@ -0,0 +1,431 @@ +# 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. + +# Add a panda assembly to the project using the specified source file +# +# Example usage: +# +# add_panda_assembly(TARGET SOURCE INDIR OUTDIR TARGETNAME ) +# +# Adds a panda assembly target called to be build from file +# listed in the command invocation. +function(add_panda_assembly) + set(prefix ARG) + set(noValues) + set(singleValues TARGET SOURCE INDIR OUTDIR TARGETNAME) + set(multiValues) + cmake_parse_arguments(${prefix} + "${noValues}" + "${singleValues}" + "${multiValues}" + ${ARGN}) + if (NOT DEFINED ARG_TARGET) + message(FATAL_ERROR "Mandatory TARGET argument is not defined.") + endif() + + if (NOT DEFINED ARG_SOURCE) + message(FATAL_ERROR "Mandatory SOURCE argument is not defined.") + endif() + + set(source_file_dir "${CMAKE_CURRENT_SOURCE_DIR}") + + if (DEFINED ARG_INDIR) + set(source_file_dir "${ARG_INDIR}") + endif() + + set(binary_file_dir "${CMAKE_CURRENT_BINARY_DIR}") + + if (DEFINED ARG_OUTDIR) + set(binary_file_dir "${ARG_OUTDIR}") + endif() + + set(target_file_name "${ARG_TARGET}") + + if (DEFINED ARG_TARGETNAME) + set(target_file_name "${ARG_TARGETNAME}") + endif() + + if (TARGET ARG_TARGET) + message(FATAL_ERROR "Target ${ARG_TARGET} is already defined.") + endif() + + set(source_file "${source_file_dir}/${ARG_SOURCE}") + set(binary_file "${binary_file_dir}/${target_file_name}.abc") + + if(CMAKE_CROSSCOMPILING) + ExternalProject_Get_Property(panda_host_tools binary_dir) + set(assembler_target panda_host_tools) + set(assembler_bin "${binary_dir}/assembler/ark_asm") + else() + set(assembler_target ark_asm) + set(assembler_bin $) + endif() + + add_custom_target(${ARG_TARGET} + COMMENT "Building ${ARG_TARGET}" + COMMAND "${assembler_bin}" "${source_file}" "${binary_file}" + DEPENDS ${assembler_target} "${source_file}") +endfunction() + +# Add a single buildable and runnable Panda Assembly file to the build tree. +# +# Usage: +# +# panda_add_asm_file( +# FILE +# TARGET +# [ENTRY ] +# [SUBDIR ] +# [OUTPUT_FILE_VARIABLE ] +# [ERROR_FILE_VARIABLE ] +# [SKIP_BUILD TRUE|FALSE] +# [AOT_MODE TRUE|FALSE] +# [DEPENDS ...] +# [RUNTIME_OPTIONS