[vm] Use _setjmp instead of setjmp on MacOS/iOS

setjmp is extremely expensive on MacOS/iOS as it always saves
signal mask.

Introduce DART_SETJMP / DART_LONGJMP macros to use _setjmp instead of
setjmp on MacOS/iOS.

DeltaBlue on Mac/arm64 on the interpreter:
179585.3 us -> 58347.9 us. (3x faster)

TEST=ci
Issue: https://github.com/dart-lang/sdk/issues/60205

Change-Id: I2122f2eb4d5de66ae2ef904a7034af1ed09f1d07
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/412320
Reviewed-by: Ryan Macnak <rmacnak@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
This commit is contained in:
Alexander Markov
2025-02-26 14:01:44 -08:00
committed by Commit Queue
parent 462bcaf52a
commit ebb7e1061c
24 changed files with 48 additions and 39 deletions
+9
View File
@@ -297,6 +297,15 @@ struct simd128_value_t {
#error Automatic compiler detection failed.
#endif
#if defined(__APPLE__)
// Avoid expensive saving of sigmask in setjmp/longjmp.
#define DART_SETJMP _setjmp
#define DART_LONGJMP _longjmp
#else
#define DART_SETJMP setjmp
#define DART_LONGJMP longjmp
#endif
#if !defined(TARGET_ARCH_ARM) && !defined(TARGET_ARCH_X64) && \
!defined(TARGET_ARCH_IA32) && !defined(TARGET_ARCH_ARM64) && \
!defined(TARGET_ARCH_RISCV32) && !defined(TARGET_ARCH_RISCV64)
+2 -2
View File
@@ -92,7 +92,7 @@ static void StackAllocatedLongJumpHelper(int* ptr, LongJumpScope* jump) {
ISOLATE_UNIT_TEST_CASE(StackAllocatedLongJump) {
LongJumpScope jump;
int data = 1;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
StackAllocatedLongJumpHelper(&data, &jump);
UNREACHABLE();
} else {
@@ -145,7 +145,7 @@ ISOLATE_UNIT_TEST_CASE(StackResourceLongJump) {
{
LongJumpScope jump;
int data = 1;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
StackResourceLongJumpHelper(&data, &jump);
UNREACHABLE();
} else {
+1 -1
View File
@@ -114,7 +114,7 @@ static ErrorPtr BootstrapFromKernelSingleProgram(
std::unique_ptr<kernel::Program> program) {
Zone* zone = thread->zone();
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
kernel::KernelLoader loader(program.get(), /*uri_to_source_table=*/nullptr);
auto isolate_group = thread->isolate_group();
+2 -2
View File
@@ -199,7 +199,7 @@ bool ClassFinalizer::ProcessPendingClasses() {
}
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
GrowableObjectArray& class_array = GrowableObjectArray::Handle();
class_array = object_store->pending_classes();
ASSERT(!class_array.IsNull());
@@ -827,7 +827,7 @@ ErrorPtr ClassFinalizer::LoadClassMembers(const Class& cls) {
ASSERT(!cls.is_finalized());
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
cls.EnsureDeclarationLoaded();
ASSERT(cls.is_type_finalized());
ClassFinalizer::FinalizeClass(cls);
+2 -2
View File
@@ -364,7 +364,7 @@ static void Jump(const Error& error) {
ErrorPtr Precompiler::CompileAll() {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
Precompiler precompiler(Thread::Current());
precompiler.DoCompileAll();
precompiler.ReportStats();
@@ -3486,7 +3486,7 @@ bool PrecompileParsedFunctionHelper::GenerateCode(FlowGraph* flow_graph) {
while (!done) {
LongJumpScope jump;
const intptr_t val = setjmp(*jump.Set());
const intptr_t val = DART_SETJMP(*jump.Set());
if (val == 0) {
// Even in bare instructions mode we don't directly add objects into
// the global object pool because code generation can bail out
+1 -1
View File
@@ -1278,7 +1278,7 @@ class CallSiteInliner : public ValueObject {
// Install bailout jump.
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
// Load IC data for the callee.
ZoneGrowableArray<const ICData*>* ic_data_array =
new (Z) ZoneGrowableArray<const ICData*>();
+3 -3
View File
@@ -498,7 +498,7 @@ CodePtr CompileParsedFunctionHelper::Compile() {
while (!done) {
*result = Code::null();
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
FlowGraph* flow_graph = nullptr;
ZoneGrowableArray<const ICData*>* ic_data_array = nullptr;
@@ -673,7 +673,7 @@ static ObjectPtr CompileFunctionHelper(const Function& function,
ASSERT(!FLAG_precompiled_mode);
ASSERT(!optimized || function.WasCompiled() || function.ForceOptimize());
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
StackZone stack_zone(thread);
Zone* const zone = stack_zone.GetZone();
const bool trace_compiler =
@@ -889,7 +889,7 @@ void Compiler::ComputeLocalVarDescriptors(const Code& code) {
Zone* zone = thread->zone();
CompilerState state(thread, /*is_aot=*/false, /*is_optimizing=*/false);
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
ParsedFunction* parsed_function =
new ParsedFunction(thread, Function::ZoneHandle(zone, function.ptr()));
ZoneGrowableArray<const ICData*>* ic_data_array =
+1 -1
View File
@@ -671,7 +671,7 @@ NO_SANITIZE_SAFE_STACK // This function manipulates the safestack pointer.
tsan_utils->exception_pc = program_counter;
tsan_utils->exception_sp = stack_pointer;
tsan_utils->exception_fp = frame_pointer;
longjmp(*(tsan_utils->setjmp_buffer), 1);
DART_LONGJMP(*(tsan_utils->setjmp_buffer), 1);
}
#endif // defined(USING_THREAD_SANITIZER)
+4 -4
View File
@@ -282,7 +282,7 @@ class ScavengerVisitorBase : public ObjectPointerVisitor,
page_space_->AcquireLock(freelist_);
LongJumpScope jump(thread_);
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
scavenger_->IterateRoots(this);
} else {
ASSERT(scavenger_->abort_);
@@ -291,7 +291,7 @@ class ScavengerVisitorBase : public ObjectPointerVisitor,
void ProcessSurvivors() {
LongJumpScope jump(thread_);
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
// Iterate until all work has been drained.
do {
ProcessToSpace();
@@ -305,7 +305,7 @@ class ScavengerVisitorBase : public ObjectPointerVisitor,
void ProcessAll() {
TIMELINE_FUNCTION_GC_DURATION(thread_, "ProcessToSpace");
LongJumpScope jump(thread_);
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
do {
do {
ProcessToSpace();
@@ -320,7 +320,7 @@ class ScavengerVisitorBase : public ObjectPointerVisitor,
void ProcessWeakProperties() {
LongJumpScope jump(thread_);
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
ProcessWeakPropertiesScoped();
} else {
ASSERT(scavenger_->abort_);
+3 -3
View File
@@ -51,7 +51,7 @@ class InterpreterSetjmpBuffer {
void Longjmp() {
// "This" is now the last setjmp buffer.
interpreter_->set_last_setjmp_buffer(this);
longjmp(buffer_, 1);
DART_LONGJMP(buffer_, 1);
}
explicit InterpreterSetjmpBuffer(Interpreter* interpreter) {
@@ -532,7 +532,7 @@ static DART_NOINLINE bool InvokeRuntime(Thread* thread,
RuntimeFunction drt,
const NativeArguments& args) {
InterpreterSetjmpBuffer buffer(interpreter);
if (!setjmp(buffer.buffer_)) {
if (!DART_SETJMP(buffer.buffer_)) {
thread->set_vm_tag(reinterpret_cast<uword>(drt));
drt(args);
thread->set_vm_tag(VMTag::kDartInterpretedTagId);
@@ -581,7 +581,7 @@ DART_NOINLINE bool Interpreter::InvokeCompiled(Thread* thread,
Exit(thread, *FP, call_top + 1, *pc);
{
InterpreterSetjmpBuffer buffer(this);
if (!setjmp(buffer.buffer_)) {
if (!DART_SETJMP(buffer.buffer_)) {
#if defined(USING_SIMULATOR)
// We need to beware that bouncing between the interpreter and the
// simulator may exhaust the C stack before exhausting either the
+1 -1
View File
@@ -1218,7 +1218,7 @@ ObjectPtr ProgramReloadContext::ReloadPhase2LoadKernel(
Thread* thread = Thread::Current();
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
const Object& tmp = kernel::KernelLoader::LoadEntireProgram(program);
if (tmp.IsError()) {
return tmp.ptr();
+3 -3
View File
@@ -382,7 +382,7 @@ ObjectPtr EvaluateStaticConstFieldInitializer(const Field& field) {
ASSERT(field.is_static() && field.is_const());
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
TranslationHelper helper(thread);
@@ -468,7 +468,7 @@ ObjectPtr EvaluateMetadata(const Library& library,
intptr_t kernel_offset,
bool is_annotations_offset) {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
TranslationHelper helper(thread);
@@ -572,7 +572,7 @@ ObjectPtr ParameterDescriptorBuilder::BuildParameterDescriptor(
ObjectPtr BuildParameterDescriptor(const Function& function) {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
+2 -2
View File
@@ -526,7 +526,7 @@ ObjectPtr KernelLoader::LoadProgram(bool process_pending_classes) {
}
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
// Note that `problemsAsJson` on Component is implicitly skipped.
const intptr_t length = program_->library_count();
for (intptr_t i = 0; i < length; i++) {
@@ -652,7 +652,7 @@ void KernelLoader::FindModifiedLibraries(Program* program,
intptr_t* p_num_procedures) {
LongJumpScope jump;
Zone* zone = Thread::Current()->zone();
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
if (force_reload) {
// If a reload is being forced we mark all libraries as having
// been modified.
+1 -1
View File
@@ -38,7 +38,7 @@ void LongJumpScope::Jump(int value) {
// Destruct all the active StackResource objects.
StackResource::UnwindAbove(thread, top_);
longjmp(environment_, value);
DART_LONGJMP(environment_, value);
UNREACHABLE();
}
+1 -1
View File
@@ -19,7 +19,7 @@ ISOLATE_UNIT_TEST_CASE(LongJump) {
LongJumpScope* base = Thread::Current()->long_jump_base();
{
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
LongJumpHelper(&jump);
UNREACHABLE();
} else {
+1 -1
View File
@@ -3483,7 +3483,7 @@ ObjectPtr ReadMessage(Thread* thread, Message* message) {
} else {
RELEASE_ASSERT(message->IsSnapshot());
LongJumpScope jump(thread);
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
MessageDeserializer deserializer(thread, message);
return deserializer.Deserialize();
} else {
+1 -1
View File
@@ -2441,7 +2441,7 @@ class ObjectGraphCopier : public StackResource {
{
LongJumpScope jump; // e.g. for OOMs.
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
result = CopyObjectGraphInternal(root, &exception_msg);
// Any allocated external typed data must have finalizers attached so
// memory will get free()ed.
+2 -2
View File
@@ -55,7 +55,7 @@ class SimulatorSetjmpBuffer {
void Longjmp() {
// "This" is now the last setjmp buffer.
simulator_->set_last_setjmp_buffer(this);
longjmp(buffer_, 1);
DART_LONGJMP(buffer_, 1);
}
explicit SimulatorSetjmpBuffer(Simulator* sim) {
@@ -1416,7 +1416,7 @@ void Simulator::SupervisorCall(Instr* instr) {
case Instr::kSimulatorRedirectCode: {
SimulatorSetjmpBuffer buffer(this);
if (!setjmp(buffer.buffer_)) {
if (!DART_SETJMP(buffer.buffer_)) {
int32_t saved_lr = get_register(LR);
Redirection* redirection = Redirection::FromSvcInstruction(instr);
uword external = redirection->external_function();
+2 -2
View File
@@ -58,7 +58,7 @@ class SimulatorSetjmpBuffer {
void Longjmp() {
// "This" is now the last setjmp buffer.
simulator_->set_last_setjmp_buffer(this);
longjmp(buffer_, 1);
DART_LONGJMP(buffer_, 1);
}
explicit SimulatorSetjmpBuffer(Simulator* sim) {
@@ -1677,7 +1677,7 @@ void Simulator::DoRedirectedCall(Instr* instr) {
memory_.FlushAll();
SimulatorSetjmpBuffer buffer(this);
if (!setjmp(buffer.buffer_)) {
if (!DART_SETJMP(buffer.buffer_)) {
int64_t saved_lr = get_register(LR);
Redirection* redirection = Redirection::FromHltInstruction(instr);
uword external = redirection->external_function();
+2 -2
View File
@@ -43,7 +43,7 @@ class SimulatorSetjmpBuffer {
void Longjmp() {
// "This" is now the last setjmp buffer.
simulator_->set_last_setjmp_buffer(this);
longjmp(buffer_, 1);
DART_LONGJMP(buffer_, 1);
}
explicit SimulatorSetjmpBuffer(Simulator* sim) {
@@ -2109,7 +2109,7 @@ void Simulator::InterpretECALL(Instr instr) {
memory_.FlushAll();
SimulatorSetjmpBuffer buffer(this);
if (!setjmp(buffer.buffer_)) {
if (!DART_SETJMP(buffer.buffer_)) {
uintx_t saved_ra = get_xreg(RA);
Redirection* redirection = Redirection::FromECallInstruction(pc_);
uword external = redirection->external_function();
+1 -1
View File
@@ -321,7 +321,7 @@ struct TsanUtils {
// implementation.
// -> See https://dartbug.com/47472#issuecomment-948235479 for details.
#if defined(USING_THREAD_SANITIZER)
void* setjmp_function = reinterpret_cast<void*>(&setjmp);
void* setjmp_function = reinterpret_cast<void*>(&DART_SETJMP);
#else
// MSVC (on Windows) is not happy with getting address of purely intrinsic.
void* setjmp_function = nullptr;
+1 -1
View File
@@ -1034,7 +1034,7 @@ static void RunLockerWithLongJumpTest() {
LockType lock;
for (intptr_t i = 0; i < kNumIterations; ++i) {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
LockerType locker(Thread::Current(), &lock);
execution_count = execution_count + 1;
Thread::Current()->long_jump_base()->Jump(
+1 -1
View File
@@ -223,7 +223,7 @@ static CodePtr RetryCompilationWithFarBranches(
volatile intptr_t far_branch_level = 0;
while (true) {
LongJumpScope jump;
if (setjmp(*jump.Set()) == 0) {
if (DART_SETJMP(*jump.Set()) == 0) {
// To use the already-defined __ Macro !
compiler::Assembler assembler(nullptr, far_branch_level);
return fun(assembler);
+1 -1
View File
@@ -103,7 +103,7 @@
volatile intptr_t far_branch_level = 0; \
while (true) { \
LongJumpScope jump(thread); \
if (setjmp(*jump.Set()) == 0) { \
if (DART_SETJMP(*jump.Set()) == 0) { \
compiler::ObjectPoolBuilder object_pool_builder; \
compiler::Assembler assembler(&object_pool_builder, far_branch_level); \
AssemblerTest test("" #name, &assembler, thread->zone()); \