From 40bfb6b8fffaebf5d258918977ce028e4748cfd3 Mon Sep 17 00:00:00 2001 From: lethosor Date: Thu, 31 Aug 2023 17:24:02 -0400 Subject: [PATCH] Hack to force GCC to invoke cancel_job() through DF's vtable GCC appears to be optimizing the call to `cancel_job()` to use the stub in *DFHack's* job_handler vtable, which is a no-op. Lua was unaffected because it invokes vmethods through method pointers (without knowing the target instance at compile time), so use a similar approach here for now. As mentioned by @ab9rf on Discord, we should pursue an alternative like asking Bay12 to expose the relevant code through a global `std::function` instead of a vmethod. --- library/modules/Job.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/library/modules/Job.cpp b/library/modules/Job.cpp index 1976d2e12..869a6b329 100644 --- a/library/modules/Job.cpp +++ b/library/modules/Job.cpp @@ -387,7 +387,14 @@ bool DFHack::Job::removeJob(df::job* job) { // call the job cancel vmethod graciously provided by The Toady One. // job_handler::cancel_job calls job::~job, and then deletes job (this has // been confirmed by disassembly). - world->jobs.cancel_job(job); + + // HACK: GCC (starting around GCC 10 targeting C++20 as of v50.09) optimizes + // out the vmethod call here regardless of optimization level, so we need to + // invoke the vmethod manually through a pointer, as the Lua wrapper does. + // `volatile` does not seem to be necessary but is included for good + // measure. + volatile auto cancel_job_method = &df::job_handler::cancel_job; + (world->jobs.*cancel_job_method)(job); return true; }