From 9f96aeda6fc48f372b4e3f5bf55d7745ccb0d289 Mon Sep 17 00:00:00 2001 From: Daco Harkes Date: Mon, 16 Nov 2020 16:10:55 +0000 Subject: [PATCH] [test/ffi] Add C++ unit tests for all target ABIs This CL introduces unit tests for the Native* classes in compiler/ffi that can run for all supported target ABIs on any host architecture. The unit tests are compiled for all target ABIs with `tools/build.py run_ffi_unit_tests` and run for all target ABIs with `tools/test.py ffi_unit`. The unit test and tested code do not conceptually depend on having a DartVM. The tests are compiled with a custom `dart::Zone` and `platform/`. This enables compiling for all `TARGET_ARCH_*` and `TARGET_OS_*` on any host, and running unit tests for all target ABIs on any host. Because the `run_ffi_unit_tests` executables do not include the DartVM their build is quick (<10seconds) and they are small (~6MB) when compared to `run_vm_tests` (~250MB). The tests are added to the existing FFI QEMU bot to prevent adding an extra bot which would add checkout overhead. The unit tests themselves are set up to be fairly similar to vm/cc tests. The only difference is the NativeCallingConvention tests which are set up with `.expect` files for easy inspection and updating. TEST=runtime/vm/compiler/ffi/native_calling_convention_test.cc TEST=runtime/vm/compiler/ffi/native_location_test.cc TEST=runtime/vm/compiler/ffi/native_type_test.cc Change-Id: I7b8bf4de9ef070e7546472217e571a60362b9639 Cq-Include-Trybots: luci.dart.try:vm-precomp-ffi-qemu-linux-release-arm-try Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/171725 Commit-Queue: Daco Harkes Reviewed-by: Clement Skau Reviewed-by: Alexander Thomas --- BUILD.gn | 6 + .../lib/src/test_configurations.dart | 6 + pkg/test_runner/lib/src/test_suite.dart | 122 ++++++++++++ runtime/bin/ffi_unit_test/BUILD.gn | 187 ++++++++++++++++++ .../bin/ffi_unit_test/run_ffi_unit_tests.cc | 115 +++++++++++ runtime/platform/globals.h | 10 +- runtime/tools/embedder_layering_check.py | 4 +- runtime/vm/compiler/compiler_sources.gni | 7 + .../compiler/ffi/native_calling_convention.cc | 17 +- .../compiler/ffi/native_calling_convention.h | 2 + .../ffi/native_calling_convention_test.cc | 138 +++++++++++++ runtime/vm/compiler/ffi/native_location.cc | 8 + runtime/vm/compiler/ffi/native_location.h | 24 ++- .../vm/compiler/ffi/native_location_test.cc | 40 ++++ runtime/vm/compiler/ffi/native_type.cc | 18 +- runtime/vm/compiler/ffi/native_type.h | 25 ++- runtime/vm/compiler/ffi/native_type_test.cc | 25 +++ runtime/vm/compiler/ffi/unit_test.h | 85 ++++++++ .../vm/compiler/ffi/unit_test_custom_zone.cc | 45 +++++ .../vm/compiler/ffi/unit_test_custom_zone.h | 51 +++++ .../unit_tests/floatx10/arm64_android.expect | 12 ++ .../ffi/unit_tests/floatx10/arm64_ios.expect | 12 ++ .../unit_tests/floatx10/arm64_linux.expect | 12 ++ .../unit_tests/floatx10/arm64_macos.expect | 12 ++ .../unit_tests/floatx10/arm_android.expect | 12 ++ .../ffi/unit_tests/floatx10/arm_ios.expect | 12 ++ .../ffi/unit_tests/floatx10/arm_linux.expect | 12 ++ .../unit_tests/floatx10/ia32_android.expect | 12 ++ .../ffi/unit_tests/floatx10/ia32_linux.expect | 12 ++ .../ffi/unit_tests/floatx10/ia32_win.expect | 12 ++ .../ffi/unit_tests/floatx10/x64_ios.expect | 12 ++ .../ffi/unit_tests/floatx10/x64_linux.expect | 12 ++ .../ffi/unit_tests/floatx10/x64_macos.expect | 12 ++ .../ffi/unit_tests/floatx10/x64_win.expect | 12 ++ .../unit_tests/int8x10/arm64_android.expect | 12 ++ .../ffi/unit_tests/int8x10/arm64_ios.expect | 12 ++ .../ffi/unit_tests/int8x10/arm64_linux.expect | 12 ++ .../ffi/unit_tests/int8x10/arm64_macos.expect | 12 ++ .../ffi/unit_tests/int8x10/arm_android.expect | 12 ++ .../ffi/unit_tests/int8x10/arm_ios.expect | 12 ++ .../ffi/unit_tests/int8x10/arm_linux.expect | 12 ++ .../unit_tests/int8x10/ia32_android.expect | 12 ++ .../ffi/unit_tests/int8x10/ia32_linux.expect | 12 ++ .../ffi/unit_tests/int8x10/ia32_win.expect | 12 ++ .../ffi/unit_tests/int8x10/x64_ios.expect | 12 ++ .../ffi/unit_tests/int8x10/x64_linux.expect | 12 ++ .../ffi/unit_tests/int8x10/x64_macos.expect | 12 ++ .../ffi/unit_tests/int8x10/x64_win.expect | 12 ++ runtime/vm/compiler/runtime_api.h | 2 + runtime/vm/constants_arm64.h | 2 +- runtime/vm/constants_x64.h | 2 +- runtime/vm/vm_sources.gni | 12 ++ tools/bots/test_matrix.json | 21 +- 53 files changed, 1284 insertions(+), 26 deletions(-) create mode 100644 runtime/bin/ffi_unit_test/BUILD.gn create mode 100644 runtime/bin/ffi_unit_test/run_ffi_unit_tests.cc create mode 100644 runtime/vm/compiler/ffi/native_calling_convention_test.cc create mode 100644 runtime/vm/compiler/ffi/native_location_test.cc create mode 100644 runtime/vm/compiler/ffi/native_type_test.cc create mode 100644 runtime/vm/compiler/ffi/unit_test.h create mode 100644 runtime/vm/compiler/ffi/unit_test_custom_zone.cc create mode 100644 runtime/vm/compiler/ffi/unit_test_custom_zone.h create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_android.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_ios.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_linux.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_macos.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/arm_android.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/arm_ios.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/arm_linux.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/ia32_android.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/ia32_linux.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/ia32_win.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/x64_ios.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/x64_linux.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/x64_macos.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/floatx10/x64_win.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_android.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_ios.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_linux.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_macos.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/arm_android.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/arm_ios.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/arm_linux.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_android.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_linux.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_win.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/x64_ios.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/x64_linux.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/x64_macos.expect create mode 100644 runtime/vm/compiler/ffi/unit_tests/int8x10/x64_win.expect diff --git a/BUILD.gn b/BUILD.gn index f1332bf39d4..3962d404d06 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -68,6 +68,12 @@ group("runtime") { } } +# A separate target and not included in group("runtime"). This way the target\ +# "runtime" does not get many executables extra as build output. +group("run_ffi_unit_tests") { + deps = [ "runtime/bin/ffi_unit_test:run_ffi_unit_tests" ] +} + group("runtime_kernel") { if (targetting_fuchsia) { # Fuchsia has run_vm_tests marked testonly. diff --git a/pkg/test_runner/lib/src/test_configurations.dart b/pkg/test_runner/lib/src/test_configurations.dart index 4d3925afd36..3179fec6ada 100644 --- a/pkg/test_runner/lib/src/test_configurations.dart +++ b/pkg/test_runner/lib/src/test_configurations.dart @@ -149,6 +149,12 @@ Future testConfigurations(List configurations) async { // vm tests contain both cc tests (added here) and dart tests (added // in [TEST_SUITE_DIRECTORIES]). testSuites.add(VMTestSuite(configuration)); + } else if (key == 'ffi_unit') { + // 'ffi_unit' contains cc non-DartVM unit tests. + // + // This is a separate suite from 'ffi', because we want to run the + // 'ffi' suite on many architectures, but 'ffi_unit' only on one. + testSuites.add(FfiTestSuite(configuration)); } else if (configuration.compiler == Compiler.dart2analyzer) { if (key == 'analyze_library') { testSuites.add(AnalyzeLibraryTestSuite(configuration)); diff --git a/pkg/test_runner/lib/src/test_suite.dart b/pkg/test_runner/lib/src/test_suite.dart index e78874471e9..53af2c7c9d2 100644 --- a/pkg/test_runner/lib/src/test_suite.dart +++ b/pkg/test_runner/lib/src/test_suite.dart @@ -364,6 +364,128 @@ class VMUnitTest { VMUnitTest(this.name, this.expectation); } +/// A specialized [TestSuite] that runs tests written in C to unit test +/// the standalone (non-DartVM) C/C++ code. +/// +/// The tests are compiled into an executable for all [targetAbis] by the +/// build step. +/// An executable lists its tests when run with the --list command line flag. +/// Individual tests are run by specifying them on the command line. +class FfiTestSuite extends TestSuite { + Map runnerPaths; + final String dartDir; + + static const targetAbis = [ + "arm64_android", + "arm64_ios", + "arm64_linux", + "arm64_macos", + "arm_android", + "arm_ios", + "arm_linux", + "ia32_android", + "ia32_linux", + "ia32_win", + "x64_ios", + "x64_linux", + "x64_macos", + "x64_win", + ]; + + FfiTestSuite(TestConfiguration configuration) + : dartDir = Repository.dir.toNativePath(), + super(configuration, "ffi_unit", []) { + final binarySuffix = Platform.operatingSystem == 'windows' ? '.exe' : ''; + + // For running the tests we use multiple binaries, one for each target ABI. + runnerPaths = Map.fromIterables( + targetAbis, + targetAbis.map((String config) => + '$buildDir/run_ffi_unit_tests_$config$binarySuffix')); + } + + void findTestCases(TestCaseEvent onTest, Map testCache) { + final statusFiles = + statusFilePaths.map((statusFile) => "$dartDir/$statusFile").toList(); + final expectations = ExpectationSet.read(statusFiles, configuration); + + runnerPaths.forEach((runnerName, runnerPath) { + try { + for (final test in _listTests(runnerName, runnerPath)) { + _addTest(expectations, test, onTest); + } + } catch (error, s) { + print( + "Fatal error occurred while parsing tests from $runnerName: $error"); + print(s); + exit(1); + } + }); + } + + void _addTest( + ExpectationSet testExpectations, FfiUnitTest test, TestCaseEvent onTest) { + final fullName = '${test.runnerName}/${test.name}'; + var expectations = testExpectations.expectations(fullName); + + // Get the expectation from the test itself. + final testExpectation = Expectation.find(test.expectation); + + // Update the legacy status-file based expectations to include + // [testExpectation]. + if (testExpectation != Expectation.pass) { + expectations = {...expectations, testExpectation}; + expectations.remove(Expectation.pass); + } + + // Update the new workflow based expectations to include [testExpectation]. + final testFile = TestFile.vmUnitTest( + hasSyntaxError: false, + hasCompileError: testExpectation == Expectation.compileTimeError, + hasRuntimeError: testExpectation == Expectation.runtimeError, + hasStaticWarning: false, + hasCrash: testExpectation == Expectation.crash); + + final args = [ + // This test has no VM, but pipe through vmOptions as test options. + // Passing `--vm-options=--update` will update all test expectations. + ...configuration.vmOptions, + test.name, + ]; + final command = ProcessCommand( + 'run_ffi_unit_test', test.runnerPath, args, environmentOverrides); + + _addTestCase(testFile, fullName, [command], expectations, onTest); + } + + Iterable _listTests(String runnerName, String runnerPath) { + final result = Process.runSync(runnerPath, ["--list"]); + if (result.exitCode != 0) { + throw "Failed to list tests: '$runnerPath --list'. " + "Process exited with ${result.exitCode}"; + } + + return (result.stdout as String) + .split('\n') + .map((line) => line.trim()) + .where((name) => name.isNotEmpty) + .map((String line) { + final parts = line.split(' '); + assert(parts.length == 2); + return FfiUnitTest(runnerName, runnerPath, parts[0], parts[1]); + }); + } +} + +class FfiUnitTest { + final String runnerName; + final String runnerPath; + final String name; + final String expectation; + + FfiUnitTest(this.runnerName, this.runnerPath, this.name, this.expectation); +} + /// A standard [TestSuite] implementation that searches for tests in a /// directory, and creates [TestCase]s that compile and/or run them. class StandardTestSuite extends TestSuite { diff --git a/runtime/bin/ffi_unit_test/BUILD.gn b/runtime/bin/ffi_unit_test/BUILD.gn new file mode 100644 index 00000000000..d7c93ba05e2 --- /dev/null +++ b/runtime/bin/ffi_unit_test/BUILD.gn @@ -0,0 +1,187 @@ +# Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +import("../../platform/platform_sources.gni") +import("../../vm/compiler/compiler_sources.gni") +import("../../vm/vm_sources.gni") + +template("build_run_ffi_unit_tests") { + extra_configs = [] + if (defined(invoker.extra_configs)) { + extra_configs += invoker.extra_configs + } + + executable(target_name) { + configs += [] + extra_configs + + defines = [ + "TESTING", + "FFI_UNIT_TESTS", + ] + + include_dirs = [ + "../..", + "//third_party", + ] + + constants = rebase_path(constants_sources, ".", "../../vm") + ffi_tests = rebase_path(ffi_sources_tests, ".", "../../vm/compiler") + platform = rebase_path(platform_sources, ".", "../../platform") + + sources = [ "run_ffi_unit_tests.cc" ] + constants + ffi_tests + platform + } +} + +config("define_target_arch_arm") { + defines = [ "TARGET_ARCH_ARM" ] +} + +config("define_target_arch_arm64") { + defines = [ "TARGET_ARCH_ARM64" ] +} + +config("define_target_arch_ia32") { + defines = [ "TARGET_ARCH_IA32" ] +} + +config("define_target_arch_x64") { + defines = [ "TARGET_ARCH_X64" ] +} + +config("define_target_os_android") { + defines = [ "TARGET_OS_ANDROID" ] +} + +config("define_target_os_ios") { + defines = [ "TARGET_OS_IOS" ] +} + +config("define_target_os_linux") { + defines = [ "TARGET_OS_LINUX" ] +} + +config("define_target_os_macos") { + defines = [ "TARGET_OS_MACOS" ] +} + +config("define_target_os_windows") { + defines = [ "TARGET_OS_WINDOWS" ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_arm_android") { + extra_configs = [ + ":define_target_arch_arm", + ":define_target_os_android", + ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_arm_ios") { + extra_configs = [ + ":define_target_arch_arm", + ":define_target_os_ios", + ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_arm_linux") { + extra_configs = [ + ":define_target_arch_arm", + ":define_target_os_linux", + ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_arm64_android") { + extra_configs = [ + ":define_target_arch_arm64", + ":define_target_os_android", + ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_arm64_ios") { + extra_configs = [ + ":define_target_arch_arm64", + ":define_target_os_ios", + ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_arm64_macos") { + extra_configs = [ + ":define_target_arch_arm64", + ":define_target_os_macos", + ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_arm64_linux") { + extra_configs = [ + ":define_target_arch_arm64", + ":define_target_os_linux", + ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_ia32_android") { + extra_configs = [ + ":define_target_arch_ia32", + ":define_target_os_android", + ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_ia32_linux") { + extra_configs = [ + ":define_target_arch_ia32", + ":define_target_os_linux", + ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_ia32_win") { + extra_configs = [ + ":define_target_arch_ia32", + ":define_target_os_windows", + ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_x64_ios") { + extra_configs = [ + ":define_target_arch_x64", + ":define_target_os_ios", + ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_x64_linux") { + extra_configs = [ + ":define_target_arch_x64", + ":define_target_os_linux", + ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_x64_macos") { + extra_configs = [ + ":define_target_arch_x64", + ":define_target_os_macos", + ] +} + +build_run_ffi_unit_tests("run_ffi_unit_tests_x64_win") { + extra_configs = [ + ":define_target_arch_x64", + ":define_target_os_windows", + ] +} + +group("run_ffi_unit_tests") { + deps = [ + ":run_ffi_unit_tests_arm64_android", + ":run_ffi_unit_tests_arm64_ios", # No other test coverage. + ":run_ffi_unit_tests_arm64_linux", + ":run_ffi_unit_tests_arm64_macos", + ":run_ffi_unit_tests_arm_android", # SoftFP + ":run_ffi_unit_tests_arm_ios", # No other test coverage. + ":run_ffi_unit_tests_arm_linux", # HardFP + ":run_ffi_unit_tests_ia32_android", # Emulator, no other test coverage. + ":run_ffi_unit_tests_ia32_linux", + ":run_ffi_unit_tests_ia32_win", + ":run_ffi_unit_tests_x64_ios", # Simulator, no other test coverage. + ":run_ffi_unit_tests_x64_linux", + ":run_ffi_unit_tests_x64_macos", + ":run_ffi_unit_tests_x64_win", + ] +} diff --git a/runtime/bin/ffi_unit_test/run_ffi_unit_tests.cc b/runtime/bin/ffi_unit_test/run_ffi_unit_tests.cc new file mode 100644 index 00000000000..8fe87843c7b --- /dev/null +++ b/runtime/bin/ffi_unit_test/run_ffi_unit_tests.cc @@ -0,0 +1,115 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// A slimmed down version of bin/run_vm_tests.cc that only runs C++ non-DartVM +// unit tests. +// +// By slimming it down to non-VM, we can run with the defines for all target +// architectures and operating systems. + +#include "vm/compiler/ffi/unit_test.h" + +#include "platform/assert.h" +#include "platform/syslog.h" + +namespace dart { +namespace compiler { +namespace ffi { + +static const char* const kNone = "No Test"; +static const char* const kList = "List all Tests"; +static const char* const kAll = "Run all Tests"; +static const char* run_filter = kNone; + +static const char* kCommandAll = "--all"; +static const char* kCommandList = "--list"; +static const char* kCommandUpdate = "--update"; + +static int run_matches = 0; + +TestCaseBase* TestCaseBase::first_ = nullptr; +TestCaseBase* TestCaseBase::tail_ = nullptr; +bool TestCaseBase::update_expectations = false; + +TestCaseBase::TestCaseBase(const char* name, const char* expectation) + : next_(nullptr), name_(name), expectation_(expectation) { + ASSERT(strlen(expectation) > 0); + if (first_ == nullptr) { + first_ = this; + } else { + tail_->next_ = this; + } + tail_ = this; +} + +void TestCaseBase::RunAll() { + TestCaseBase* test = first_; + while (test != nullptr) { + test->RunTest(); + test = test->next_; + } +} + +void TestCaseBase::RunTest() { + if (run_filter == kList) { + Syslog::Print("%s %s\n", this->name(), this->expectation()); + run_matches++; + } else if (run_filter == kAll) { + this->Run(); + run_matches++; + } else if (strcmp(run_filter, this->name()) == 0) { + this->Run(); + run_matches++; + } +} + +void RawTestCase::Run() { + Syslog::Print("Running test: %s\n", name()); + (*run_)(); + Syslog::Print("Done: %s\n", name()); +} + +static int Main(int argc, const char** argv) { + if (argc == 2 && strcmp(argv[1], kCommandList) == 0) { + run_filter = kList; + // List all tests and benchmarks and exit. + TestCaseBase::RunAll(); + fflush(stdout); + return 0; + } + if (argc > 1 && strcmp(argv[1], kCommandUpdate) == 0) { + TestCaseBase::update_expectations = true; + } + if (strcmp(argv[argc - 1], kCommandAll) == 0) { + // Run all tests. + run_filter = kAll; + } else if (argc > 1) { + // Run only test with specific name. + run_filter = argv[argc - 1]; + } + + TestCaseBase::RunAll(); + + // Print a warning message if no tests or benchmarks were matched. + if (run_matches == 0) { + Syslog::PrintErr("No tests matched: %s\n", run_filter); + return 1; + } + if (Expect::failed()) { + Syslog::PrintErr( + "Some tests failed. Run the following command to update " + "expectations.\ntools/test.py --vm-options=--update ffi_unit"); + return 255; + } + + return 0; +} + +} // namespace ffi +} // namespace compiler +} // namespace dart + +int main(int argc, const char** argv) { + return dart::compiler::ffi::Main(argc, argv); +} diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h index ab51780618b..79b6a6bbd9b 100644 --- a/runtime/platform/globals.h +++ b/runtime/platform/globals.h @@ -339,17 +339,17 @@ typedef simd128_value_t fpu_register_t; // Verify that host and target architectures match, we cannot // have a 64 bit Dart VM generating 32 bit code or vice-versa. #if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_ARM64) -#if !defined(ARCH_IS_64_BIT) +#if !defined(ARCH_IS_64_BIT) && !defined(FFI_UNIT_TESTS) #error Mismatched Host/Target architectures. -#endif // !defined(ARCH_IS_64_BIT) +#endif // !defined(ARCH_IS_64_BIT) && !defined(FFI_UNIT_TESTS) #elif defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) #if defined(HOST_ARCH_X64) && defined(TARGET_ARCH_ARM) // This is simarm_x64, which is the only case where host/target architecture -// mismatch is allowed. +// mismatch is allowed. Unless, we're running FFI unit tests. #define IS_SIMARM_X64 1 -#elif !defined(ARCH_IS_32_BIT) +#elif !defined(ARCH_IS_32_BIT) && !defined(FFI_UNIT_TESTS) #error Mismatched Host/Target architectures. -#endif // !defined(ARCH_IS_32_BIT) +#endif // !defined(ARCH_IS_32_BIT) && !defined(FFI_UNIT_TESTS) #endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_ARM) // Determine whether we will be using the simulator. diff --git a/runtime/tools/embedder_layering_check.py b/runtime/tools/embedder_layering_check.py index d49b705bb83..8e33bf09a15 100644 --- a/runtime/tools/embedder_layering_check.py +++ b/runtime/tools/embedder_layering_check.py @@ -20,7 +20,9 @@ BIN_LAYER_RE = re.compile(r'^runtime/bin/') # Tests that don't match the simple case of *_test.cc. EXTRA_TEST_FILES = [ - 'runtime/bin/run_vm_tests.cc', 'runtime/vm/libfuzzer/dart_libfuzzer.cc' + 'runtime/bin/run_vm_tests.cc', + 'runtime/bin/ffi_unit_test/run_ffi_unit_tests.cc', + 'runtime/vm/libfuzzer/dart_libfuzzer.cc' ] diff --git a/runtime/vm/compiler/compiler_sources.gni b/runtime/vm/compiler/compiler_sources.gni index dd1d2fa878e..386dd8618a3 100644 --- a/runtime/vm/compiler/compiler_sources.gni +++ b/runtime/vm/compiler/compiler_sources.gni @@ -204,3 +204,10 @@ disassembler_sources = [ "assembler/disassembler_arm64.cc", "assembler/disassembler_x86.cc", ] + +ffi_sources_tests = [ + "ffi/native_calling_convention_test.cc", + "ffi/native_location_test.cc", + "ffi/native_type_test.cc", + "ffi/unit_test_custom_zone.cc", +] diff --git a/runtime/vm/compiler/ffi/native_calling_convention.cc b/runtime/vm/compiler/ffi/native_calling_convention.cc index fe3881c0b82..5b21cf2b963 100644 --- a/runtime/vm/compiler/ffi/native_calling_convention.cc +++ b/runtime/vm/compiler/ffi/native_calling_convention.cc @@ -6,9 +6,12 @@ #include "vm/compiler/ffi/native_location.h" #include "vm/compiler/ffi/native_type.h" -#include "vm/cpu.h" #include "vm/zone_text_buffer.h" +#if !defined(FFI_UNIT_TESTS) +#include "vm/cpu.h" +#endif + namespace dart { namespace compiler { @@ -17,6 +20,7 @@ namespace ffi { const intptr_t kNoFpuRegister = -1; +#if !defined(FFI_UNIT_TESTS) // In Soft FP, floats and doubles get passed in integer registers. static bool SoftFpAbi() { #if defined(TARGET_ARCH_ARM) @@ -25,6 +29,15 @@ static bool SoftFpAbi() { return false; #endif } +#else // !defined(FFI_UNIT_TESTS) +static bool SoftFpAbi() { +#if defined(TARGET_ARCH_ARM) && defined(TARGET_OS_ANDROID) + return true; +#else + return false; +#endif +} +#endif // !defined(FFI_UNIT_TESTS) // In Soft FP, floats are treated as 4 byte ints, and doubles as 8 byte ints. static const NativeType& ConvertIfSoftFp(Zone* zone, const NativeType& rep) { @@ -293,9 +306,11 @@ const char* NativeCallingConvention::ToCString(Zone* zone, return textBuffer.buffer(); } +#if !defined(FFI_UNIT_TESTS) const char* NativeCallingConvention::ToCString(bool multi_line) const { return ToCString(Thread::Current()->zone(), multi_line); } +#endif } // namespace ffi diff --git a/runtime/vm/compiler/ffi/native_calling_convention.h b/runtime/vm/compiler/ffi/native_calling_convention.h index bb10887b6c7..9faf6207caa 100644 --- a/runtime/vm/compiler/ffi/native_calling_convention.h +++ b/runtime/vm/compiler/ffi/native_calling_convention.h @@ -42,7 +42,9 @@ class NativeCallingConvention : public ZoneAllocated { void PrintTo(BaseTextBuffer* f, bool multi_line = false) const; void PrintToMultiLine(BaseTextBuffer* f) const; const char* ToCString(Zone* zone, bool multi_line = false) const; +#if !defined(FFI_UNIT_TESTS) const char* ToCString(bool multi_line = false) const; +#endif private: NativeCallingConvention(const NativeLocations& argument_locations, diff --git a/runtime/vm/compiler/ffi/native_calling_convention_test.cc b/runtime/vm/compiler/ffi/native_calling_convention_test.cc new file mode 100644 index 00000000000..23ed7776c41 --- /dev/null +++ b/runtime/vm/compiler/ffi/native_calling_convention_test.cc @@ -0,0 +1,138 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include "vm/compiler/ffi/unit_test.h" + +#include "platform/syslog.h" +#include "vm/compiler/ffi/native_calling_convention.h" + +namespace dart { +namespace compiler { +namespace ffi { + +#if defined(TARGET_ARCH_ARM) +const char* kArch = "arm"; +#elif defined(TARGET_ARCH_ARM64) +const char* kArch = "arm64"; +#elif defined(TARGET_ARCH_IA32) +const char* kArch = "ia32"; +#elif defined(TARGET_ARCH_X64) +const char* kArch = "x64"; +#endif + +#if defined(TARGET_OS_ANDROID) +const char* kOs = "android"; +#elif defined(TARGET_OS_IOS) +const char* kOs = "ios"; +#elif defined(TARGET_OS_LINUX) +const char* kOs = "linux"; +#elif defined(TARGET_OS_MACOS) +const char* kOs = "macos"; +#elif defined(TARGET_OS_WINDOWS) +const char* kOs = "win"; +#endif + +void WriteToFile(char* path, const char* contents) { + FILE* file; + file = fopen(path, "w"); + if (file != nullptr) { + fprintf(file, "%s", contents); + } else { + Syslog::Print("Error %d \n", errno); + } + fclose(file); +} + +void ReadFromFile(char* path, char** buffer_pointer) { + FILE* file = fopen(path, "rb"); + if (file == nullptr) { + Syslog::Print("Error %d \n", errno); + return; + } + + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + rewind(file); + + char* buffer = reinterpret_cast(malloc(sizeof(char) * (size + 1))); + + fread(buffer, 1, size, file); + buffer[size] = 0; + + fclose(file); + *buffer_pointer = buffer; +} + +void RunSignatureTest(dart::Zone* zone, + const char* name, + const NativeTypes& argument_types, + const NativeType& return_type) { + const auto& native_signature = + *new (zone) NativeFunctionType(argument_types, return_type); + + const auto& native_calling_convention = + NativeCallingConvention::FromSignature(zone, native_signature); + + const char* test_result = + native_calling_convention.ToCString(zone, /*multi_line=*/true); + + const int kFilePathLength = 100; + char expectation_file_path[kFilePathLength]; + Utils::SNPrint(expectation_file_path, kFilePathLength, + "runtime/vm/compiler/ffi/unit_tests/%s/%s_%s.expect", name, + kArch, kOs); + + if (TestCaseBase::update_expectations) { + Syslog::Print("Updating %s\n", expectation_file_path); + WriteToFile(expectation_file_path, test_result); + } + + char* expectation_file_contents = nullptr; + ReadFromFile(expectation_file_path, &expectation_file_contents); + EXPECT_NOTNULL(expectation_file_contents); + if (expectation_file_contents != nullptr) { + EXPECT_STREQ(expectation_file_contents, test_result); + free(expectation_file_contents); + } +} + +UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_int8x10) { + const auto& int8type = *new (Z) NativePrimitiveType(kInt8); + + auto& arguments = *new (Z) NativeTypes(Z, 10); + arguments.Add(&int8type); + arguments.Add(&int8type); + arguments.Add(&int8type); + arguments.Add(&int8type); + arguments.Add(&int8type); + arguments.Add(&int8type); + arguments.Add(&int8type); + arguments.Add(&int8type); + arguments.Add(&int8type); + arguments.Add(&int8type); + + RunSignatureTest(Z, "int8x10", arguments, int8type); +} + +UNIT_TEST_CASE_WITH_ZONE(NativeCallingConvention_floatx10) { + const auto& floatType = *new (Z) NativePrimitiveType(kFloat); + + auto& arguments = *new (Z) NativeTypes(Z, 10); + arguments.Add(&floatType); + arguments.Add(&floatType); + arguments.Add(&floatType); + arguments.Add(&floatType); + arguments.Add(&floatType); + arguments.Add(&floatType); + arguments.Add(&floatType); + arguments.Add(&floatType); + arguments.Add(&floatType); + arguments.Add(&floatType); + + RunSignatureTest(Z, "floatx10", arguments, floatType); +} + +} // namespace ffi +} // namespace compiler +} // namespace dart diff --git a/runtime/vm/compiler/ffi/native_location.cc b/runtime/vm/compiler/ffi/native_location.cc index dce51c119cd..12439aaf4df 100644 --- a/runtime/vm/compiler/ffi/native_location.cc +++ b/runtime/vm/compiler/ffi/native_location.cc @@ -12,6 +12,7 @@ namespace compiler { namespace ffi { +#if !defined(FFI_UNIT_TESTS) bool NativeLocation::LocationCanBeExpressed(Location loc, Representation rep) { switch (loc.kind()) { case Location::Kind::kRegister: @@ -74,6 +75,7 @@ NativeLocation& NativeLocation::FromPairLocation(Zone* zone, const Location loc = pair_loc.AsPairLocation()->At(index); return FromLocation(zone, loc, rep); } +#endif const NativeRegistersLocation& NativeLocation::AsRegisters() const { ASSERT(IsRegisters()); @@ -90,6 +92,7 @@ const NativeStackLocation& NativeLocation::AsStack() const { return static_cast(*this); } +#if !defined(FFI_UNIT_TESTS) Location NativeRegistersLocation::AsLocation() const { ASSERT(IsExpressibleAsLocation()); switch (num_regs()) { @@ -126,6 +129,7 @@ Location NativeStackLocation::AsLocation() const { } UNREACHABLE(); } +#endif NativeRegistersLocation& NativeRegistersLocation::Split(Zone* zone, intptr_t index) const { @@ -206,10 +210,12 @@ bool NativeStackLocation::Equals(const NativeLocation& other) const { return other_stack.offset_in_bytes_ == offset_in_bytes_; } +#if !defined(FFI_UNIT_TESTS) compiler::Address NativeLocationToStackSlotAddress( const NativeStackLocation& loc) { return compiler::Address(loc.base_register(), loc.offset_in_bytes()); } +#endif static void PrintRepresentations(BaseTextBuffer* f, const NativeLocation& loc) { f->AddString(" "); @@ -271,9 +277,11 @@ const char* NativeLocation::ToCString(Zone* zone) const { return textBuffer.buffer(); } +#if !defined(FFI_UNIT_TESTS) const char* NativeLocation::ToCString() const { return ToCString(Thread::Current()->zone()); } +#endif intptr_t SizeFromFpuRegisterKind(enum FpuRegisterKind kind) { switch (kind) { diff --git a/runtime/vm/compiler/ffi/native_location.h b/runtime/vm/compiler/ffi/native_location.h index c3cce14aa49..3437e5c8593 100644 --- a/runtime/vm/compiler/ffi/native_location.h +++ b/runtime/vm/compiler/ffi/native_location.h @@ -10,17 +10,24 @@ #endif // defined(DART_PRECOMPILED_RUNTIME) #include "platform/assert.h" -#include "vm/compiler/backend/locations.h" #include "vm/compiler/ffi/native_type.h" #include "vm/constants.h" #include "vm/growable_array.h" +#if !defined(FFI_UNIT_TESTS) +#include "vm/compiler/backend/locations.h" +#endif + namespace dart { class BaseTextBuffer; namespace compiler { +namespace target { +extern const int kWordSize; +} + namespace ffi { class NativeRegistersLocation; @@ -55,6 +62,7 @@ class NativeStackLocation; // inequality cannot be used to determine disjointness. class NativeLocation : public ZoneAllocated { public: +#if !defined(FFI_UNIT_TESTS) static bool LocationCanBeExpressed(Location loc, Representation rep); static NativeLocation& FromLocation(Zone* zone, Location loc, @@ -63,6 +71,7 @@ class NativeLocation : public ZoneAllocated { Location loc, Representation rep, intptr_t index); +#endif // The type of the data at this location. const NativeType& payload_type() const { return payload_type_; } @@ -91,14 +100,18 @@ class NativeLocation : public ZoneAllocated { virtual bool IsStack() const { return false; } virtual bool IsExpressibleAsLocation() const { return false; } +#if !defined(FFI_UNIT_TESTS) virtual Location AsLocation() const { ASSERT(IsExpressibleAsLocation()); UNREACHABLE(); } +#endif virtual void PrintTo(BaseTextBuffer* f) const; const char* ToCString(Zone* zone) const; +#if !defined(FFI_UNIT_TESTS) const char* ToCString() const; +#endif const NativeRegistersLocation& AsRegisters() const; const NativeFpuRegistersLocation& AsFpuRegisters() const; @@ -171,7 +184,9 @@ class NativeRegistersLocation : public NativeLocation { virtual bool IsExpressibleAsLocation() const { return num_regs() == 1 || num_regs() == 2; } +#if !defined(FFI_UNIT_TESTS) virtual Location AsLocation() const; +#endif intptr_t num_regs() const { return regs_->length(); } Register reg_at(intptr_t index) const { return regs_->At(index); } @@ -238,10 +253,12 @@ class NativeFpuRegistersLocation : public NativeLocation { virtual bool IsExpressibleAsLocation() const { return fpu_reg_kind_ == kQuadFpuReg; } +#if !defined(FFI_UNIT_TESTS) virtual Location AsLocation() const { ASSERT(IsExpressibleAsLocation()); return Location::FpuRegisterLocation(fpu_reg()); } +#endif FpuRegisterKind fpu_reg_kind() const { return fpu_reg_kind_; } FpuRegister fpu_reg() const { ASSERT(fpu_reg_kind_ == kQuadFpuReg); @@ -299,6 +316,8 @@ class NativeStackLocation : public NativeLocation { size % compiler::target::kWordSize == 0 && (size_slots == 1 || size_slots == 2); } + +#if !defined(FFI_UNIT_TESTS) virtual Location AsLocation() const; // ConstantInstr expects DoubleStackSlot for doubles, even on 64-bit systems. @@ -308,6 +327,7 @@ class NativeStackLocation : public NativeLocation { ASSERT(compiler::target::kWordSize == 8); return Location::DoubleStackSlot(offset_in_words(), base_register_); } +#endif virtual NativeStackLocation& Split(Zone* zone, intptr_t index) const; @@ -334,9 +354,11 @@ class NativeStackLocation : public NativeLocation { DISALLOW_COPY_AND_ASSIGN(NativeStackLocation); }; +#if !defined(FFI_UNIT_TESTS) // Return a memory operand for stack slot locations. compiler::Address NativeLocationToStackSlotAddress( const NativeStackLocation& loc); +#endif } // namespace ffi diff --git a/runtime/vm/compiler/ffi/native_location_test.cc b/runtime/vm/compiler/ffi/native_location_test.cc new file mode 100644 index 00000000000..ea1fb27060c --- /dev/null +++ b/runtime/vm/compiler/ffi/native_location_test.cc @@ -0,0 +1,40 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include "vm/compiler/ffi/unit_test.h" + +#include "vm/compiler/ffi/native_location.h" + +namespace dart { +namespace compiler { +namespace ffi { + +UNIT_TEST_CASE_WITH_ZONE(NativeStackLocation) { + const auto& native_type = *new (Z) NativePrimitiveType(kInt8); + + const int kUnalignedStackLocation = 17; + + const auto& native_location = *new (Z) NativeStackLocation( + native_type, native_type, SPREG, kUnalignedStackLocation); + + EXPECT_EQ(kUnalignedStackLocation + native_type.SizeInBytes(), + native_location.StackTopInBytes()); +} + +UNIT_TEST_CASE_WITH_ZONE(NativeStackLocation_Split) { + const auto& native_type = *new (Z) NativePrimitiveType(kInt64); + + const auto& native_location = + *new (Z) NativeStackLocation(native_type, native_type, SPREG, 0); + + const auto& half_0 = native_location.Split(Z, 0); + const auto& half_1 = native_location.Split(Z, 1); + + EXPECT_EQ(0, half_0.offset_in_bytes()); + EXPECT_EQ(4, half_1.offset_in_bytes()); +} + +} // namespace ffi +} // namespace compiler +} // namespace dart diff --git a/runtime/vm/compiler/ffi/native_type.cc b/runtime/vm/compiler/ffi/native_type.cc index 7c1faaedfa8..db064000e1f 100644 --- a/runtime/vm/compiler/ffi/native_type.cc +++ b/runtime/vm/compiler/ffi/native_type.cc @@ -10,9 +10,9 @@ #include "vm/constants.h" #include "vm/zone_text_buffer.h" -#if !defined(DART_PRECOMPILED_RUNTIME) +#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS) #include "vm/compiler/backend/locations.h" -#endif // !defined(DART_PRECOMPILED_RUNTIME) +#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS) namespace dart { @@ -127,7 +127,7 @@ intptr_t NativePrimitiveType::AlignmentInBytesField() const { } } -#if !defined(DART_PRECOMPILED_RUNTIME) +#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS) bool NativePrimitiveType::IsExpressibleAsRepresentation() const { switch (representation_) { case kInt8: @@ -170,7 +170,7 @@ Representation NativePrimitiveType::AsRepresentation() const { UNREACHABLE(); } } -#endif // !defined(DART_PRECOMPILED_RUNTIME) +#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS) bool NativePrimitiveType::Equals(const NativeType& other) const { if (!other.IsPrimitive()) { @@ -249,12 +249,14 @@ NativeType& NativeType::FromTypedDataClassId(Zone* zone, classid_t class_id) { return *new (zone) NativePrimitiveType(fundamental_rep); } +#if !defined(FFI_UNIT_TESTS) NativeType& NativeType::FromAbstractType(Zone* zone, const AbstractType& type) { // TODO(36730): Support composites. return NativeType::FromTypedDataClassId(zone, type.type_class_id()); } +#endif -#if !defined(DART_PRECOMPILED_RUNTIME) +#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS) static PrimitiveType fundamental_rep(Representation rep) { switch (rep) { case kUnboxedDouble: @@ -277,7 +279,7 @@ NativePrimitiveType& NativeType::FromUnboxedRepresentation(Zone* zone, Representation rep) { return *new (zone) NativePrimitiveType(fundamental_rep(rep)); } -#endif // !defined(DART_PRECOMPILED_RUNTIME) +#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS) const char* NativeType::ToCString(Zone* zone) const { ZoneTextBuffer textBuffer(zone); @@ -285,9 +287,11 @@ const char* NativeType::ToCString(Zone* zone) const { return textBuffer.buffer(); } +#if !defined(FFI_UNIT_TESTS) const char* NativeType::ToCString() const { return ToCString(Thread::Current()->zone()); } +#endif static const char* PrimitiveTypeToCString(PrimitiveType rep) { switch (rep) { @@ -334,9 +338,11 @@ const char* NativeFunctionType::ToCString(Zone* zone) const { return textBuffer.buffer(); } +#if !defined(FFI_UNIT_TESTS) const char* NativeFunctionType::ToCString() const { return ToCString(Thread::Current()->zone()); } +#endif void NativeFunctionType::PrintTo(BaseTextBuffer* f) const { f->AddString("("); diff --git a/runtime/vm/compiler/ffi/native_type.h b/runtime/vm/compiler/ffi/native_type.h index d2ca9c17498..3c11341c4c5 100644 --- a/runtime/vm/compiler/ffi/native_type.h +++ b/runtime/vm/compiler/ffi/native_type.h @@ -9,11 +9,13 @@ #include "platform/globals.h" #include "vm/allocation.h" #include "vm/growable_array.h" -#include "vm/object.h" -#if !defined(DART_PRECOMPILED_RUNTIME) +#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS) #include "vm/compiler/backend/locations.h" #endif +#if !defined(FFI_UNIT_TESTS) +#include "vm/object.h" +#endif namespace dart { @@ -51,13 +53,15 @@ class NativePrimitiveType; // TODO(36730): Add composites. class NativeType : public ZoneAllocated { public: +#if !defined(FFI_UNIT_TESTS) static NativeType& FromAbstractType(Zone* zone, const AbstractType& type); +#endif static NativeType& FromTypedDataClassId(Zone* zone, classid_t class_id); -#if !defined(DART_PRECOMPILED_RUNTIME) +#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS) static NativePrimitiveType& FromUnboxedRepresentation(Zone* zone, Representation rep); -#endif // !defined(DART_PRECOMPILED_RUNTIME) +#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS) virtual bool IsPrimitive() const { return false; } const NativePrimitiveType& AsPrimitive() const; @@ -79,7 +83,7 @@ class NativeType : public ZoneAllocated { // The alignment in bytes of this representation as member of a composite. virtual intptr_t AlignmentInBytesField() const = 0; -#if !defined(DART_PRECOMPILED_RUNTIME) +#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS) // NativeTypes which are available as unboxed Representations. virtual bool IsExpressibleAsRepresentation() const { return false; } @@ -91,7 +95,7 @@ class NativeType : public ZoneAllocated { const auto& widened = WidenTo4Bytes(zone_); return widened.AsRepresentation(); } -#endif // !defined(DART_PRECOMPILED_RUNTIME) +#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS) virtual bool Equals(const NativeType& other) const { UNREACHABLE(); } @@ -104,7 +108,9 @@ class NativeType : public ZoneAllocated { virtual void PrintTo(BaseTextBuffer* f) const; const char* ToCString(Zone* zone) const; +#if !defined(FFI_UNIT_TESTS) const char* ToCString() const; +#endif virtual ~NativeType() {} @@ -152,10 +158,10 @@ class NativePrimitiveType : public NativeType { virtual intptr_t AlignmentInBytesStack() const; virtual intptr_t AlignmentInBytesField() const; -#if !defined(DART_PRECOMPILED_RUNTIME) +#if !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS) virtual bool IsExpressibleAsRepresentation() const; virtual Representation AsRepresentation() const; -#endif // !defined(DART_PRECOMPILED_RUNTIME) +#endif // !defined(DART_PRECOMPILED_RUNTIME) && !defined(FFI_UNIT_TESTS) virtual bool Equals(const NativeType& other) const; virtual NativePrimitiveType& Split(Zone* zone, intptr_t part) const; @@ -181,8 +187,9 @@ class NativeFunctionType : public ZoneAllocated { void PrintTo(BaseTextBuffer* f) const; const char* ToCString(Zone* zone) const; - +#if !defined(FFI_UNIT_TESTS) const char* ToCString() const; +#endif private: const NativeTypes& argument_types_; diff --git a/runtime/vm/compiler/ffi/native_type_test.cc b/runtime/vm/compiler/ffi/native_type_test.cc new file mode 100644 index 00000000000..abf275d82e3 --- /dev/null +++ b/runtime/vm/compiler/ffi/native_type_test.cc @@ -0,0 +1,25 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include "vm/compiler/ffi/unit_test.h" + +#include "vm/compiler/ffi/native_type.h" + +namespace dart { +namespace compiler { +namespace ffi { + +UNIT_TEST_CASE_WITH_ZONE(NativeType) { + const auto& native_type = *new (Z) NativePrimitiveType(kInt8); + + EXPECT_EQ(1, native_type.SizeInBytes()); + EXPECT(native_type.IsInt()); + EXPECT(native_type.IsPrimitive()); + + EXPECT_STREQ("int8", native_type.ToCString(Z)); +} + +} // namespace ffi +} // namespace compiler +} // namespace dart diff --git a/runtime/vm/compiler/ffi/unit_test.h b/runtime/vm/compiler/ffi/unit_test.h new file mode 100644 index 00000000000..44c4f0d57c0 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_test.h @@ -0,0 +1,85 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +// A slimmed down version of runtime/vm/unit_test.h that only runs C++ +// non-DartVM unit tests. + +#ifndef RUNTIME_VM_COMPILER_FFI_UNIT_TEST_H_ +#define RUNTIME_VM_COMPILER_FFI_UNIT_TEST_H_ + +// Don't use the DartVM zone, so include this first. +#include "vm/compiler/ffi/unit_test_custom_zone.h" + +#include "platform/globals.h" + +// The UNIT_TEST_CASE macro is used for tests. +#define UNIT_TEST_CASE_WITH_EXPECTATION(name, expectation) \ + void Dart_Test##name(); \ + static const dart::compiler::ffi::RawTestCase kRegister##name( \ + Dart_Test##name, #name, expectation); \ + void Dart_Test##name() + +#define UNIT_TEST_CASE(name) UNIT_TEST_CASE_WITH_EXPECTATION(name, "Pass") + +// The UNIT_TEST_CASE_WITH_ZONE macro is used for tests that need a custom +// dart::Zone. +#define UNIT_TEST_CASE_WITH_ZONE_WITH_EXPECTATION(name, expectation) \ + static void Dart_TestHelper##name(dart::Zone* Z); \ + UNIT_TEST_CASE_WITH_EXPECTATION(name, expectation) { \ + dart::Zone zone; \ + Dart_TestHelper##name(&zone); \ + } \ + static void Dart_TestHelper##name(dart::Zone* Z) + +#define UNIT_TEST_CASE_WITH_ZONE(name) \ + UNIT_TEST_CASE_WITH_ZONE_WITH_EXPECTATION(name, "Pass") + +namespace dart { +namespace compiler { +namespace ffi { + +class TestCaseBase { + public: + explicit TestCaseBase(const char* name, const char* expectation); + virtual ~TestCaseBase() {} + + const char* name() const { return name_; } + const char* expectation() const { return expectation_; } + + virtual void Run() = 0; + void RunTest(); + + static void RunAll(); + static void RunAllRaw(); + + static bool update_expectations; + + private: + static TestCaseBase* first_; + static TestCaseBase* tail_; + + TestCaseBase* next_; + const char* name_; + const char* expectation_; + + DISALLOW_COPY_AND_ASSIGN(TestCaseBase); +}; + +class RawTestCase : TestCaseBase { + public: + typedef void(RunEntry)(); + + RawTestCase(RunEntry* run, const char* name, const char* expectation) + : TestCaseBase(name, expectation), run_(run) {} + virtual void Run(); + + private: + RunEntry* const run_; +}; + +} // namespace ffi +} // namespace compiler +} // namespace dart + +#endif // RUNTIME_VM_COMPILER_FFI_UNIT_TEST_H_ diff --git a/runtime/vm/compiler/ffi/unit_test_custom_zone.cc b/runtime/vm/compiler/ffi/unit_test_custom_zone.cc new file mode 100644 index 00000000000..90f01cfb677 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_test_custom_zone.cc @@ -0,0 +1,45 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#include "vm/compiler/ffi/unit_test_custom_zone.h" + +#include "vm/compiler/runtime_api.h" + +// Directly compile cc files into the custom zone, so that we do not get linker +// errors from object files compiled against the DartVM Zone. +#include "vm/compiler/ffi/native_calling_convention.cc" // NOLINT +#include "vm/compiler/ffi/native_location.cc" // NOLINT +#include "vm/compiler/ffi/native_type.cc" // NOLINT +#include "vm/zone_text_buffer.cc" // NOLINT + +namespace dart { + +void* ZoneAllocated::operator new(uintptr_t size, dart::Zone* zone) { + return reinterpret_cast(zone->AllocUnsafe(size)); +} + +Zone::~Zone() { + while (buffers_.size() > 0) { + free(buffers_.back()); + buffers_.pop_back(); + } +} + +void* Zone::AllocUnsafe(intptr_t size) { + void* memory = malloc(size); + buffers_.push_back(memory); + return memory; +} + +DART_EXPORT void Dart_PrepareToAbort() { + fprintf(stderr, "Dart_PrepareToAbort() not implemented!\n"); + exit(1); +} + +DART_EXPORT void Dart_DumpNativeStackTrace(void* context) { + fprintf(stderr, "Dart_DumpNativeStackTrace() not implemented!\n"); + exit(1); +} + +} // namespace dart diff --git a/runtime/vm/compiler/ffi/unit_test_custom_zone.h b/runtime/vm/compiler/ffi/unit_test_custom_zone.h new file mode 100644 index 00000000000..ac305a1cb8b --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_test_custom_zone.h @@ -0,0 +1,51 @@ +// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +#ifndef RUNTIME_VM_COMPILER_FFI_UNIT_TEST_CUSTOM_ZONE_H_ +#define RUNTIME_VM_COMPILER_FFI_UNIT_TEST_CUSTOM_ZONE_H_ + +#include + +// We use a custom zone here which doesn't depend on VM internals (e.g. handles, +// thread, ...) +#if defined(RUNTIME_VM_ZONE_H_) +#error "We want our own zone implementation" +#endif +#define RUNTIME_VM_ZONE_H_ + +namespace dart { + +class Zone { + public: + Zone() {} + ~Zone(); + + template + inline ElementType* Alloc(intptr_t length) { + return static_cast(AllocUnsafe(sizeof(ElementType) * length)); + } + + template + inline ElementType* Realloc(ElementType* old_array, + intptr_t old_length, + intptr_t new_length) { + void* memory = AllocUnsafe(sizeof(ElementType) * new_length); + memmove(memory, old_array, sizeof(ElementType) * old_length); + return static_cast(memory); + } + + template + void Free(ElementType* old_array, intptr_t len) {} + + void* AllocUnsafe(intptr_t size); + + private: + Zone(const Zone&) = delete; + void operator=(const Zone&) = delete; + std::vector buffers_; +}; + +} // namespace dart + +#endif // RUNTIME_VM_COMPILER_FFI_UNIT_TEST_CUSTOM_ZONE_H_ diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_android.expect new file mode 100644 index 00000000000..8f237e39312 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_android.expect @@ -0,0 +1,12 @@ +v0 float +v1 float +v2 float +v3 float +v4 float +v5 float +v6 float +v7 float +S+0 float +S+8 float +=> +v0 float diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_ios.expect new file mode 100644 index 00000000000..8f237e39312 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_ios.expect @@ -0,0 +1,12 @@ +v0 float +v1 float +v2 float +v3 float +v4 float +v5 float +v6 float +v7 float +S+0 float +S+8 float +=> +v0 float diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_linux.expect new file mode 100644 index 00000000000..8f237e39312 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_linux.expect @@ -0,0 +1,12 @@ +v0 float +v1 float +v2 float +v3 float +v4 float +v5 float +v6 float +v7 float +S+0 float +S+8 float +=> +v0 float diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_macos.expect new file mode 100644 index 00000000000..8f237e39312 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm64_macos.expect @@ -0,0 +1,12 @@ +v0 float +v1 float +v2 float +v3 float +v4 float +v5 float +v6 float +v7 float +S+0 float +S+8 float +=> +v0 float diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm_android.expect new file mode 100644 index 00000000000..f563dbd4455 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm_android.expect @@ -0,0 +1,12 @@ +r0 int32[float] +r1 int32[float] +r2 int32[float] +r3 int32[float] +S+0 float +S+4 float +S+8 float +S+12 float +S+16 float +S+20 float +=> +r0 int32[float] diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm_ios.expect new file mode 100644 index 00000000000..9ff44a72bd1 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm_ios.expect @@ -0,0 +1,12 @@ +s0 float +s1 float +s2 float +s3 float +s4 float +s5 float +s6 float +s7 float +s8 float +s9 float +=> +q0 float diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm_linux.expect new file mode 100644 index 00000000000..9ff44a72bd1 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/arm_linux.expect @@ -0,0 +1,12 @@ +s0 float +s1 float +s2 float +s3 float +s4 float +s5 float +s6 float +s7 float +s8 float +s9 float +=> +q0 float diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/ia32_android.expect new file mode 100644 index 00000000000..c4390e7fd8b --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/ia32_android.expect @@ -0,0 +1,12 @@ +S+0 float +S+4 float +S+8 float +S+12 float +S+16 float +S+20 float +S+24 float +S+28 float +S+32 float +S+36 float +=> +xmm0 float diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/ia32_linux.expect new file mode 100644 index 00000000000..c4390e7fd8b --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/ia32_linux.expect @@ -0,0 +1,12 @@ +S+0 float +S+4 float +S+8 float +S+12 float +S+16 float +S+20 float +S+24 float +S+28 float +S+32 float +S+36 float +=> +xmm0 float diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/ia32_win.expect new file mode 100644 index 00000000000..c4390e7fd8b --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/ia32_win.expect @@ -0,0 +1,12 @@ +S+0 float +S+4 float +S+8 float +S+12 float +S+16 float +S+20 float +S+24 float +S+28 float +S+32 float +S+36 float +=> +xmm0 float diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/x64_ios.expect new file mode 100644 index 00000000000..b6501304dbc --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/x64_ios.expect @@ -0,0 +1,12 @@ +xmm0 float +xmm1 float +xmm2 float +xmm3 float +xmm4 float +xmm5 float +xmm6 float +xmm7 float +S+0 float +S+8 float +=> +xmm0 float diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/x64_linux.expect new file mode 100644 index 00000000000..b6501304dbc --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/x64_linux.expect @@ -0,0 +1,12 @@ +xmm0 float +xmm1 float +xmm2 float +xmm3 float +xmm4 float +xmm5 float +xmm6 float +xmm7 float +S+0 float +S+8 float +=> +xmm0 float diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/x64_macos.expect new file mode 100644 index 00000000000..b6501304dbc --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/x64_macos.expect @@ -0,0 +1,12 @@ +xmm0 float +xmm1 float +xmm2 float +xmm3 float +xmm4 float +xmm5 float +xmm6 float +xmm7 float +S+0 float +S+8 float +=> +xmm0 float diff --git a/runtime/vm/compiler/ffi/unit_tests/floatx10/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/floatx10/x64_win.expect new file mode 100644 index 00000000000..12445878dc0 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/floatx10/x64_win.expect @@ -0,0 +1,12 @@ +xmm0 float +xmm1 float +xmm2 float +xmm3 float +S+0 float +S+8 float +S+16 float +S+24 float +S+32 float +S+40 float +=> +xmm0 float diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_android.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_android.expect new file mode 100644 index 00000000000..04f72e5fc52 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_android.expect @@ -0,0 +1,12 @@ +r0 int8 +r1 int8 +r2 int8 +r3 int8 +r4 int8 +r5 int8 +r6 int8 +r7 int8 +S+0 int8 +S+8 int8 +=> +r0 int8 diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_ios.expect new file mode 100644 index 00000000000..04f72e5fc52 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_ios.expect @@ -0,0 +1,12 @@ +r0 int8 +r1 int8 +r2 int8 +r3 int8 +r4 int8 +r5 int8 +r6 int8 +r7 int8 +S+0 int8 +S+8 int8 +=> +r0 int8 diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_linux.expect new file mode 100644 index 00000000000..04f72e5fc52 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_linux.expect @@ -0,0 +1,12 @@ +r0 int8 +r1 int8 +r2 int8 +r3 int8 +r4 int8 +r5 int8 +r6 int8 +r7 int8 +S+0 int8 +S+8 int8 +=> +r0 int8 diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_macos.expect new file mode 100644 index 00000000000..04f72e5fc52 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm64_macos.expect @@ -0,0 +1,12 @@ +r0 int8 +r1 int8 +r2 int8 +r3 int8 +r4 int8 +r5 int8 +r6 int8 +r7 int8 +S+0 int8 +S+8 int8 +=> +r0 int8 diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/arm_android.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm_android.expect new file mode 100644 index 00000000000..9307d2f3e08 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm_android.expect @@ -0,0 +1,12 @@ +r0 int32[int8] +r1 int32[int8] +r2 int32[int8] +r3 int32[int8] +S+0 int32[int8] +S+4 int32[int8] +S+8 int32[int8] +S+12 int32[int8] +S+16 int32[int8] +S+20 int32[int8] +=> +r0 int32[int8] diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/arm_ios.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm_ios.expect new file mode 100644 index 00000000000..9307d2f3e08 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm_ios.expect @@ -0,0 +1,12 @@ +r0 int32[int8] +r1 int32[int8] +r2 int32[int8] +r3 int32[int8] +S+0 int32[int8] +S+4 int32[int8] +S+8 int32[int8] +S+12 int32[int8] +S+16 int32[int8] +S+20 int32[int8] +=> +r0 int32[int8] diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/arm_linux.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm_linux.expect new file mode 100644 index 00000000000..9307d2f3e08 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/arm_linux.expect @@ -0,0 +1,12 @@ +r0 int32[int8] +r1 int32[int8] +r2 int32[int8] +r3 int32[int8] +S+0 int32[int8] +S+4 int32[int8] +S+8 int32[int8] +S+12 int32[int8] +S+16 int32[int8] +S+20 int32[int8] +=> +r0 int32[int8] diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_android.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_android.expect new file mode 100644 index 00000000000..bf5f6c46411 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_android.expect @@ -0,0 +1,12 @@ +S+0 int32[int8] +S+4 int32[int8] +S+8 int32[int8] +S+12 int32[int8] +S+16 int32[int8] +S+20 int32[int8] +S+24 int32[int8] +S+28 int32[int8] +S+32 int32[int8] +S+36 int32[int8] +=> +eax int8 diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_linux.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_linux.expect new file mode 100644 index 00000000000..bf5f6c46411 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_linux.expect @@ -0,0 +1,12 @@ +S+0 int32[int8] +S+4 int32[int8] +S+8 int32[int8] +S+12 int32[int8] +S+16 int32[int8] +S+20 int32[int8] +S+24 int32[int8] +S+28 int32[int8] +S+32 int32[int8] +S+36 int32[int8] +=> +eax int8 diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_win.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_win.expect new file mode 100644 index 00000000000..bf5f6c46411 --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/ia32_win.expect @@ -0,0 +1,12 @@ +S+0 int32[int8] +S+4 int32[int8] +S+8 int32[int8] +S+12 int32[int8] +S+16 int32[int8] +S+20 int32[int8] +S+24 int32[int8] +S+28 int32[int8] +S+32 int32[int8] +S+36 int32[int8] +=> +eax int8 diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_ios.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_ios.expect new file mode 100644 index 00000000000..0bcad4b0e9c --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_ios.expect @@ -0,0 +1,12 @@ +rdi int32[int8] +rsi int32[int8] +rdx int32[int8] +rcx int32[int8] +r8 int32[int8] +r9 int32[int8] +S+0 int32[int8] +S+8 int32[int8] +S+16 int32[int8] +S+24 int32[int8] +=> +rax int8 diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_linux.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_linux.expect new file mode 100644 index 00000000000..0bcad4b0e9c --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_linux.expect @@ -0,0 +1,12 @@ +rdi int32[int8] +rsi int32[int8] +rdx int32[int8] +rcx int32[int8] +r8 int32[int8] +r9 int32[int8] +S+0 int32[int8] +S+8 int32[int8] +S+16 int32[int8] +S+24 int32[int8] +=> +rax int8 diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_macos.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_macos.expect new file mode 100644 index 00000000000..0bcad4b0e9c --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_macos.expect @@ -0,0 +1,12 @@ +rdi int32[int8] +rsi int32[int8] +rdx int32[int8] +rcx int32[int8] +r8 int32[int8] +r9 int32[int8] +S+0 int32[int8] +S+8 int32[int8] +S+16 int32[int8] +S+24 int32[int8] +=> +rax int8 diff --git a/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_win.expect b/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_win.expect new file mode 100644 index 00000000000..94704e54a3e --- /dev/null +++ b/runtime/vm/compiler/ffi/unit_tests/int8x10/x64_win.expect @@ -0,0 +1,12 @@ +rcx int8 +rdx int8 +r8 int8 +r9 int8 +S+0 int8 +S+8 int8 +S+16 int8 +S+24 int8 +S+32 int8 +S+40 int8 +=> +rax int8 diff --git a/runtime/vm/compiler/runtime_api.h b/runtime/vm/compiler/runtime_api.h index 7611669c0b3..ce2d16477b4 100644 --- a/runtime/vm/compiler/runtime_api.h +++ b/runtime/vm/compiler/runtime_api.h @@ -288,8 +288,10 @@ static constexpr int kWordSizeLog2 = 3; static constexpr int kWordSize = 1 << kWordSizeLog2; static_assert(kWordSize == sizeof(word), "kWordSize should match sizeof(word)"); // Our compiler code currently assumes this, so formally check it. +#if !defined(FFI_UNIT_TESTS) static_assert(dart::kWordSize >= kWordSize, "Host word size smaller than target word size"); +#endif static constexpr word kBitsPerWordLog2 = kWordSizeLog2 + kBitsPerByteLog2; static constexpr word kBitsPerWord = 1 << kBitsPerWordLog2; diff --git a/runtime/vm/constants_arm64.h b/runtime/vm/constants_arm64.h index 21319caf87d..898f10e09b5 100644 --- a/runtime/vm/constants_arm64.h +++ b/runtime/vm/constants_arm64.h @@ -1400,7 +1400,7 @@ class Instr { DISALLOW_IMPLICIT_CONSTRUCTORS(Instr); }; -const uword kBreakInstructionFiller = 0xD4200000D4200000L; // brk #0; brk #0 +const uint64_t kBreakInstructionFiller = 0xD4200000D4200000L; // brk #0; brk #0 } // namespace dart diff --git a/runtime/vm/constants_x64.h b/runtime/vm/constants_x64.h index ae421fd73eb..80e37abb742 100644 --- a/runtime/vm/constants_x64.h +++ b/runtime/vm/constants_x64.h @@ -473,7 +473,7 @@ class Instr { // becomes important to us. const int MAX_NOP_SIZE = 8; -const uword kBreakInstructionFiller = 0xCCCCCCCCCCCCCCCCL; +const uint64_t kBreakInstructionFiller = 0xCCCCCCCCCCCCCCCCL; } // namespace dart diff --git a/runtime/vm/vm_sources.gni b/runtime/vm/vm_sources.gni index fda79fbd2b1..665d37b694a 100644 --- a/runtime/vm/vm_sources.gni +++ b/runtime/vm/vm_sources.gni @@ -451,3 +451,15 @@ vm_sources_tests = [ "virtual_memory_test.cc", "zone_test.cc", ] + +constants_sources = [ + "constants_arm.cc", + "constants_arm.h", + "constants_arm64.cc", + "constants_arm64.h", + "constants_base.h", + "constants_ia32.cc", + "constants_ia32.h", + "constants_x64.cc", + "constants_x64.h", +] diff --git a/tools/bots/test_matrix.json b/tools/bots/test_matrix.json index 8d4be38c5f1..cfc7b55361e 100644 --- a/tools/bots/test_matrix.json +++ b/tools/bots/test_matrix.json @@ -418,6 +418,9 @@ "flutter-frontend": { "__comment__": "This configuration is only used for a custom test runner. If it conflicts with a new configuration you are adding, you can make this configuration more specific by adding options." }, + "vm-ffi-unit-test": { + "__comment__": "This configuration is only used for a custom test runner. If it conflicts with a new configuration you are adding, you can make this configuration more specific by adding options." + }, "unittest-asserts-no-sdk-(linux|mac|win)": { "options": { "compiler": "dartk", @@ -1102,9 +1105,25 @@ "vm-precomp-ffi-qemu-linux-release-arm" ], "meta": { - "description": "This configuration is used for running FFI tests on qemu." + "description": "This configuration is used for running FFI tests on qemu and FFI unit tests." }, "steps": [ + { + "name": "build run_ffi_unit_tests", + "script": "tools/build.py", + "arguments": [ + "--arch=x64", + "--mode=debug", + "run_ffi_unit_tests" + ] + }, + { + "name": "ffi unit tests", + "arguments": [ + "-nvm-ffi-unit-test", + "ffi_unit" + ] + }, { "name": "build dart", "script": "tools/build.py",