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",