[vm] Runtime option to not use the simulator for simarm64_arm64.

TEST=ci
Cq-Include-Trybots: luci.dart.try:vm-ffi-mac-debug-simarm64_arm64-try,vm-ffi-mac-release-simarm64_arm64-try
Change-Id: Id98d337ce16ba4b434b5c69016f01eec9b85f9d2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/434982
Reviewed-by: Slava Egorov <vegorov@google.com>
Commit-Queue: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
Ryan Macnak
2025-06-18 10:45:05 -07:00
committed by Commit Queue
parent 69b99822de
commit f5eaefd5b6
12 changed files with 194 additions and 86 deletions
+4 -2
View File
@@ -1429,8 +1429,10 @@ void FfiCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
__ mov(CSP, SP);
#if defined(SIMULATOR_FFI)
__ Emit(Instr::kSimulatorFfiRedirectInstruction);
ASSERT(branch == R9);
if (FLAG_use_simulator) {
__ Emit(Instr::kSimulatorFfiRedirectInstruction);
ASSERT(branch == R9);
}
#endif
__ blr(branch);
@@ -417,7 +417,9 @@ void StubCodeCompiler::GenerateCallNativeThroughSafepointStub() {
#endif
#if defined(SIMULATOR_FFI)
__ Emit(Instr::kSimulatorFfiRedirectInstruction);
if (FLAG_use_simulator) {
__ Emit(Instr::kSimulatorFfiRedirectInstruction);
}
#endif
__ blr(R9);
@@ -469,11 +471,6 @@ void StubCodeCompiler::GenerateLoadFfiCallbackMetadataRuntimeFunction(
}
void StubCodeCompiler::GenerateFfiCallbackTrampolineStub() {
#if defined(USING_SIMULATOR) && !defined(DART_PRECOMPILER)
// TODO(37299): FFI is not supported in SIMARM64.
// See Simulator::DoDirectedFfiCallback.
__ Breakpoint();
#else
Label body;
// R9 is volatile and not used for passing any arguments.
@@ -705,7 +702,6 @@ void StubCodeCompiler::GenerateFfiCallbackTrampolineStub() {
__ Breakpoint();
}
#endif
#endif // !defined(HOST_ARCH_ARM64)
}
void StubCodeCompiler::GenerateDispatchTableNullErrorStub() {
+7 -3
View File
@@ -10,7 +10,6 @@
#include "vm/cpuinfo.h"
#if !defined(USING_SIMULATOR)
#if defined(DART_HOST_OS_FUCHSIA)
#include <zircon/syscalls.h>
#elif defined(DART_HOST_OS_MACOS) || defined(DART_HOST_OS_IOS)
@@ -18,14 +17,19 @@
#elif defined(DART_HOST_OS_WINDOWS)
#include <processthreadsapi.h>
#endif
#endif
namespace dart {
void CPU::FlushICache(uword start, uword size) {
#if defined(DART_PRECOMPILED_RUNTIME)
UNREACHABLE();
#elif !defined(USING_SIMULATOR)
#else
#if defined(USING_SIMULATOR)
if (FLAG_use_simulator) {
return;
}
#endif
// Nothing to do. Flushing no instructions.
if (size == 0) {
return;
+13 -8
View File
@@ -104,15 +104,20 @@ static ObjectPtr InvokeDartCode(uword entry_point,
const uword stub = StubCode::InvokeDartCode().EntryPoint();
#if defined(USING_SIMULATOR)
auto invoke = [&](uword entry_point, uword arguments_descriptor,
uword arguments, Thread* thread) -> uword {
return Simulator::Current()->Call(stub, entry_point, arguments_descriptor,
arguments,
reinterpret_cast<int64_t>(thread));
};
#else
auto invoke = reinterpret_cast<invokestub>(stub);
if (FLAG_use_simulator) {
auto invoke = [&](uword entry_point, uword arguments_descriptor,
uword arguments, Thread* thread) -> uword {
return Simulator::Current()->Call(stub, entry_point, arguments_descriptor,
arguments,
reinterpret_cast<int64_t>(thread));
};
uword result =
invoke(entry_point, static_cast<uword>(arguments_descriptor.ptr()),
static_cast<uword>(arguments.ptr()), thread);
return static_cast<ObjectPtr>(result);
}
#endif
auto invoke = reinterpret_cast<invokestub>(stub);
uword result =
invoke(entry_point, static_cast<uword>(arguments_descriptor.ptr()),
static_cast<uword>(arguments.ptr()), thread);
+6 -4
View File
@@ -627,9 +627,12 @@ NO_SANITIZE_SAFE_STACK // This function manipulates the safestack pointer.
// exception object in the kExceptionObjectReg register and the stacktrace
// object (may be raw null) in the kStackTraceObjectReg register.
Simulator::Current()->JumpToFrame(program_counter, stack_pointer,
frame_pointer, thread);
#else
if (FLAG_use_simulator) {
Simulator::Current()->JumpToFrame(program_counter, stack_pointer,
frame_pointer, thread);
UNREACHABLE();
}
#endif
// Zero out HWASAN tags from the current stack pointer to the destination.
//
@@ -677,7 +680,6 @@ NO_SANITIZE_SAFE_STACK // This function manipulates the safestack pointer.
}
func(program_counter, stack_pointer, frame_pointer, thread);
#endif
UNREACHABLE();
}
+61 -13
View File
@@ -29,11 +29,19 @@ void FfiCallbackMetadata::EnsureStubPageLocked() {
ASSERT_LESS_OR_EQUAL(VirtualMemory::PageSize(), kPageSize);
#if defined(SIMULATOR_FFI) && defined(HOST_ARCH_ARM64)
const uword code_start =
reinterpret_cast<uword>(SimulatorFfiCallbackTrampoline);
const uword code_end =
reinterpret_cast<uword>(SimulatorFfiCallbackTrampolineEnd);
const uword page_start = code_start & ~(VirtualMemory::PageSize() - 1);
uword code_start, code_end, page_start;
if (FLAG_use_simulator) {
code_start = reinterpret_cast<uword>(SimulatorFfiCallbackTrampoline);
code_end = reinterpret_cast<uword>(SimulatorFfiCallbackTrampolineEnd);
page_start = code_start & ~(VirtualMemory::PageSize() - 1);
} else {
const Code& trampoline_code = StubCode::FfiCallbackTrampoline();
code_start = trampoline_code.EntryPoint();
code_end = code_start + trampoline_code.Size();
page_start = code_start & ~(VirtualMemory::PageSize() - 1);
ASSERT_LESS_OR_EQUAL((code_start - page_start) + trampoline_code.Size(),
RXMappingSize());
}
#else
const Code& trampoline_code = StubCode::FfiCallbackTrampoline();
const uword code_start = trampoline_code.EntryPoint();
@@ -50,8 +58,7 @@ void FfiCallbackMetadata::EnsureStubPageLocked() {
offset_of_first_trampoline_in_page_ = code_start - page_start;
#if defined(DART_TARGET_OS_FUCHSIA) || \
(defined(SIMULATOR_FFI) && defined(HOST_ARCH_ARM64))
#if defined(DART_TARGET_OS_FUCHSIA)
// On Fuchsia we can't currently duplicate pages, so use the first page of
// trampolines. Store the stub page's metadata in a separately allocated RW
// page.
@@ -64,6 +71,17 @@ void FfiCallbackMetadata::EnsureStubPageLocked() {
for (intptr_t i = 0; i < NumCallbackTrampolinesPerPage(); ++i) {
AddToFreeListLocked(&metadata_entry[i]);
}
#elif defined(SIMULATOR_FFI) && defined(HOST_ARCH_ARM64)
if (FLAG_use_simulator) {
original_metadata_page_ = VirtualMemory::AllocateAligned(
MappingSize(), MappingAlignment(), /*is_executable=*/false,
/*is_compressed=*/false, "FfiCallbackMetadata::TrampolinePage");
MetadataEntry* metadata_entry = reinterpret_cast<MetadataEntry*>(
original_metadata_page_->start() + MetadataOffset());
for (intptr_t i = 0; i < NumCallbackTrampolinesPerPage(); ++i) {
AddToFreeListLocked(&metadata_entry[i]);
}
}
#endif // defined(DART_TARGET_OS_FUCHSIA)
}
@@ -112,12 +130,17 @@ void FfiCallbackMetadata::FillRuntimeFunction(VirtualMemory* page,
}
VirtualMemory* FfiCallbackMetadata::AllocateTrampolinePage() {
#if defined(DART_TARGET_OS_FUCHSIA) || \
(defined(SIMULATOR_FFI) && defined(HOST_ARCH_ARM64))
#if defined(DART_TARGET_OS_FUCHSIA)
// TODO(https://dartbug.com/52579): Remove.
UNREACHABLE();
return nullptr;
#else
#if defined(SIMULATOR_FFI) && defined(HOST_ARCH_ARM64)
if (FLAG_use_simulator) {
UNREACHABLE();
return nullptr;
}
#endif
#if defined(DART_HOST_OS_MACOS) && defined(DART_PRECOMPILED_RUNTIME)
const bool should_remap_stub_page = true;
@@ -413,8 +436,13 @@ FfiCallbackMetadata::Trampoline FfiCallbackMetadata::TrampolineOfMetadataEntry(
reinterpret_cast<MetadataEntry*>(start + MetadataOffset());
const uword index = metadata_entry - metadata_entries;
#if defined(SIMULATOR_FFI) && defined(HOST_ARCH_ARM64)
return reinterpret_cast<uword>(SimulatorFfiCallbackTrampoline) +
index * kNativeCallbackTrampolineSize;
if (FLAG_use_simulator) {
return reinterpret_cast<uword>(SimulatorFfiCallbackTrampoline) +
index * kNativeCallbackTrampolineSize;
} else {
return start + offset_of_first_trampoline_in_page_ +
index * kNativeCallbackTrampolineSize;
}
#elif defined(DART_TARGET_OS_FUCHSIA)
return StubCode::FfiCallbackTrampoline().EntryPoint() +
index * kNativeCallbackTrampolineSize;
@@ -426,8 +454,7 @@ FfiCallbackMetadata::Trampoline FfiCallbackMetadata::TrampolineOfMetadataEntry(
FfiCallbackMetadata::MetadataEntry*
FfiCallbackMetadata::MetadataEntryOfTrampoline(Trampoline trampoline) const {
#if defined(DART_TARGET_OS_FUCHSIA) || \
(defined(SIMULATOR_FFI) && defined(HOST_ARCH_ARM64))
#if defined(DART_TARGET_OS_FUCHSIA)
// On Fuchsia the metadata page is separate to the trampoline page.
// TODO(https://dartbug.com/52579): Remove.
const uword page_start =
@@ -440,6 +467,27 @@ FfiCallbackMetadata::MetadataEntryOfTrampoline(Trampoline trampoline) const {
MetadataEntry* metadata_etnry_table = reinterpret_cast<MetadataEntry*>(
original_metadata_page_->start() + MetadataOffset());
return metadata_etnry_table + index;
#elif defined(SIMULATOR_FFI) && defined(HOST_ARCH_ARM64)
if (FLAG_use_simulator) {
const uword page_start =
Utils::RoundDown(trampoline - offset_of_first_trampoline_in_page_,
VirtualMemory::PageSize());
const uword index =
(trampoline - offset_of_first_trampoline_in_page_ - page_start) /
kNativeCallbackTrampolineSize;
ASSERT(index < NumCallbackTrampolinesPerPage());
MetadataEntry* metadata_etnry_table = reinterpret_cast<MetadataEntry*>(
original_metadata_page_->start() + MetadataOffset());
return metadata_etnry_table + index;
} else {
const uword start = MappingStart(trampoline);
MetadataEntry* metadata_entries =
reinterpret_cast<MetadataEntry*>(start + MetadataOffset());
const uword index =
(trampoline - start - offset_of_first_trampoline_in_page_) /
kNativeCallbackTrampolineSize;
return &metadata_entries[index];
}
#else
const uword start = MappingStart(trampoline);
MetadataEntry* metadata_entries =
+2 -1
View File
@@ -249,6 +249,7 @@ constexpr bool FLAG_support_il_printer = false;
"Throw API error on invalid member access through native API. See " \
"entry_point_pragma.md") \
C(branch_coverage, false, false, bool, false, "Enable branch coverage") \
C(coverage, false, false, bool, true, "Enable coverage")
C(coverage, false, false, bool, true, "Enable coverage") \
P(use_simulator, bool, true, "Use simulator if available")
#endif // RUNTIME_VM_FLAG_LIST_H_
+15 -9
View File
@@ -120,9 +120,11 @@ extern "C" void DRT_BootstrapNativeCall(Dart_NativeArguments args,
uword NativeEntry::BootstrapNativeCallWrapperEntry() {
uword entry = reinterpret_cast<uword>(DRT_BootstrapNativeCall);
#if defined(USING_SIMULATOR)
entry = Simulator::RedirectExternalReference(
entry, Simulator::kNativeCallWrapper,
NativeEntry::kNumCallWrapperArguments);
if (FLAG_use_simulator) {
entry = Simulator::RedirectExternalReference(
entry, Simulator::kNativeCallWrapper,
NativeEntry::kNumCallWrapperArguments);
}
#endif
return entry;
}
@@ -164,9 +166,11 @@ extern "C" void DRT_NoScopeNativeCall(Dart_NativeArguments args,
uword NativeEntry::NoScopeNativeCallWrapperEntry() {
uword entry = reinterpret_cast<uword>(DRT_NoScopeNativeCall);
#if defined(USING_SIMULATOR)
entry = Simulator::RedirectExternalReference(
entry, Simulator::kNativeCallWrapper,
NativeEntry::kNumCallWrapperArguments);
if (FLAG_use_simulator) {
entry = Simulator::RedirectExternalReference(
entry, Simulator::kNativeCallWrapper,
NativeEntry::kNumCallWrapperArguments);
}
#endif
return entry;
}
@@ -195,9 +199,11 @@ extern "C" void DRT_AutoScopeNativeCall(Dart_NativeArguments args,
uword NativeEntry::AutoScopeNativeCallWrapperEntry() {
uword entry = reinterpret_cast<uword>(DRT_AutoScopeNativeCall);
#if defined(USING_SIMULATOR)
entry = Simulator::RedirectExternalReference(
entry, Simulator::kNativeCallWrapper,
NativeEntry::kNumCallWrapperArguments);
if (FLAG_use_simulator) {
entry = Simulator::RedirectExternalReference(
entry, Simulator::kNativeCallWrapper,
NativeEntry::kNumCallWrapperArguments);
}
#endif
return entry;
}
+16 -13
View File
@@ -365,7 +365,7 @@ static bool GetAndValidateThreadStackBounds(OSThread* os_thread,
#if defined(USING_SIMULATOR)
const bool use_simulator_stack_bounds =
thread != nullptr && thread->IsExecutingDartCode();
FLAG_use_simulator && thread != nullptr && thread->IsExecutingDartCode();
if (use_simulator_stack_bounds) {
Isolate* isolate = thread->isolate();
ASSERT(isolate != nullptr);
@@ -1253,9 +1253,11 @@ static Sample* SetupSample(Thread* thread,
// When running in the simulator, the runtime entry function address
// (stored as the vm tag) is the address of a redirect function.
// Attempt to find the real runtime entry function address and use that.
uword redirect_vm_tag = Simulator::FunctionForRedirect(vm_tag);
if (redirect_vm_tag != 0) {
vm_tag = redirect_vm_tag;
if (FLAG_use_simulator) {
uword redirect_vm_tag = Simulator::FunctionForRedirect(vm_tag);
if (redirect_vm_tag != 0) {
vm_tag = redirect_vm_tag;
}
}
#endif
sample->set_vm_tag(vm_tag);
@@ -1388,18 +1390,19 @@ void Profiler::SampleThread(Thread* thread,
uintptr_t fp = state.fp;
uintptr_t pc = state.pc;
uintptr_t lr = state.lr;
#if defined(USING_SIMULATOR)
Simulator* simulator = nullptr;
#endif
if (in_dart_code) {
// If we're in Dart code, use the Dart stack pointer.
// If we're in Dart code, use the Dart stack pointer.
#if defined(USING_SIMULATOR)
simulator = isolate->simulator();
sp = simulator->get_register(SPREG);
fp = simulator->get_register(FPREG);
pc = simulator->get_pc();
lr = simulator->get_lr();
if (FLAG_use_simulator) {
Simulator* simulator = isolate->simulator();
sp = simulator->get_register(SPREG);
fp = simulator->get_register(FPREG);
pc = simulator->get_pc();
lr = simulator->get_lr();
} else {
sp = state.dsp;
}
#else
sp = state.dsp;
#endif
+29 -23
View File
@@ -124,17 +124,20 @@ uword RuntimeEntry::GetEntryPoint() const {
// into the runtime system.
uword entry = reinterpret_cast<uword>(function());
#if defined(USING_SIMULATOR)
// Redirection to leaf runtime calls supports a maximum of 4 arguments passed
// in registers (maximum 2 double arguments for leaf float runtime calls).
ASSERT(argument_count() >= 0);
ASSERT(!is_leaf() || (!is_float() && (argument_count() <= 4)) ||
(argument_count() <= 2));
Simulator::CallKind call_kind =
is_leaf() ? (is_float() ? Simulator::kLeafFloatRuntimeCall
: Simulator::kLeafRuntimeCall)
: Simulator::kRuntimeCall;
entry =
Simulator::RedirectExternalReference(entry, call_kind, argument_count());
if (FLAG_use_simulator) {
// Redirection to leaf runtime calls supports a maximum of 4 arguments
// passed in registers (maximum 2 double arguments for leaf float runtime
// calls).
ASSERT(argument_count() >= 0);
ASSERT(!is_leaf() || (!is_float() && (argument_count() <= 4)) ||
(argument_count() <= 2));
Simulator::CallKind call_kind =
is_leaf() ? (is_float() ? Simulator::kLeafFloatRuntimeCall
: Simulator::kLeafRuntimeCall)
: Simulator::kRuntimeCall;
entry = Simulator::RedirectExternalReference(entry, call_kind,
argument_count());
}
#endif
return entry;
}
@@ -152,7 +155,7 @@ uword RuntimeEntry::GetEntryPoint() const {
#if defined(USING_SIMULATOR)
#define CHECK_SIMULATOR_STACK_OVERFLOW() \
if (!OSThread::Current()->HasStackHeadroom()) { \
if (FLAG_use_simulator && !OSThread::Current()->HasStackHeadroom()) { \
Exceptions::ThrowStackOverflow(); \
}
#else
@@ -3486,16 +3489,17 @@ static void HandleOSRRequest(Thread* thread) {
#endif // !defined(DART_PRECOMPILED_RUNTIME)
DEFINE_RUNTIME_ENTRY(InterruptOrStackOverflow, 0) {
#if defined(USING_SIMULATOR)
uword stack_pos = Simulator::Current()->get_sp();
// If simulator was never called it may return 0 as a value of SPREG.
if (stack_pos == 0) {
// Use any reasonable value which would not be treated
// as stack overflow.
stack_pos = thread->saved_stack_limit();
}
#else
uword stack_pos = OSThread::GetCurrentStackPointer();
#if defined(USING_SIMULATOR)
if (FLAG_use_simulator) {
stack_pos = Simulator::Current()->get_sp();
// If simulator was never called it may return 0 as a value of SPREG.
if (stack_pos == 0) {
// Use any reasonable value which would not be treated
// as stack overflow.
stack_pos = thread->saved_stack_limit();
}
}
#endif
// Always clear the stack overflow flags. They are meant for this
// particular stack overflow runtime call and are not meant to
@@ -4381,8 +4385,10 @@ uword RuntimeEntry::InterpretCallEntry() {
#if defined(DART_DYNAMIC_MODULES)
uword entry = reinterpret_cast<uword>(InterpretCall);
#if defined(USING_SIMULATOR)
entry = Simulator::RedirectExternalReference(entry,
Simulator::kLeafRuntimeCall, 5);
if (FLAG_use_simulator) {
entry = Simulator::RedirectExternalReference(
entry, Simulator::kLeafRuntimeCall, 5);
}
#endif
return entry;
#else
+10 -2
View File
@@ -533,7 +533,11 @@ void Thread::EnterIsolateGroupAsMutator(IsolateGroup* isolate_group,
ResumeThreadInternal(thread);
#if defined(USING_SIMULATOR)
thread->SetStackLimit(Simulator::Current()->overflow_stack_limit());
if (FLAG_use_simulator) {
thread->SetStackLimit(Simulator::Current()->overflow_stack_limit());
} else {
thread->SetStackLimit(OSThread::Current()->overflow_stack_limit());
}
#else
thread->SetStackLimit(OSThread::Current()->overflow_stack_limit());
#endif
@@ -583,7 +587,11 @@ void Thread::ResumeDartMutatorThreadInternal(Thread* thread) {
if (Dart::vm_isolate() != nullptr &&
thread->isolate() != Dart::vm_isolate()) {
#if defined(USING_SIMULATOR)
thread->SetStackLimit(Simulator::Current()->overflow_stack_limit());
if (FLAG_use_simulator) {
thread->SetStackLimit(Simulator::Current()->overflow_stack_limit());
} else {
thread->SetStackLimit(OSThread::Current()->overflow_stack_limit());
}
#else
thread->SetStackLimit(OSThread::Current()->overflow_stack_limit());
#endif
+28 -1
View File
@@ -297,7 +297,7 @@
"builder-tag": "ffi"
}
},
"vm-(linux|mac|win|android|fuchsia)-(debug|product|release)-(ia32|x64|x64c|arm|arm64|arm64c|simarm|simarm64|simarm64_arm64|simriscv32|simriscv64)": {
"vm-(linux|mac|win|android|fuchsia)-(debug|product|release)-(ia32|x64|x64c|arm|arm64|arm64c|simarm|simarm64|simriscv32|simriscv64)": {
"options": {}
},
"vm-checked-(linux|mac|win|fuchsia)-(debug|product|release)-(ia32|x64|x64c|arm64|arm64c|simarm|simarm64|simriscv32|simriscv64)": {
@@ -348,6 +348,26 @@
"gen-snapshot-format" : "elf"
}
},
"vm-linux-(debug|product|release)-simarm64_arm64": {
"options": {
"vm-options": ["--use_simulator=true"], "use-qemu": true
}
},
"vm-linux-(debug|product|release)-simarm64_arm64-nosim": {
"options": {
"vm-options": ["--use_simulator=false"], "use-qemu": true
}
},
"vm-mac-(debug|product|release)-simarm64_arm64": {
"options": {
"vm-options": ["--use_simulator=true"]
}
},
"vm-mac-(debug|product|release)-simarm64_arm64-nosim": {
"options": {
"vm-options": ["--use_simulator=false"]
}
},
"dart2js-(linux|win)-chrome": {
"options": {
"use-sdk": true
@@ -814,6 +834,13 @@
"-nvm-${system}-${mode}-${arch}",
"ffi"
]
},
{
"name": "vm ffi tests",
"arguments": [
"-nvm-${system}-${mode}-${arch}-nosim",
"ffi"
]
}
]
},