forked from weaselab/conflict-set
Use a trampoline if musttail not available
For the previous approach to work, we would have had to lock in the generated code for every function that needs to make tail calls in assembly.
This commit is contained in:
+20
-19
@@ -3260,35 +3260,28 @@ struct CheckContext {
|
||||
ConflictSet::Result *results;
|
||||
int64_t started;
|
||||
ReadContext *tls;
|
||||
#if !__has_attribute(musttail)
|
||||
CheckJob *job;
|
||||
bool done;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if __has_attribute(musttail)
|
||||
FLATTEN PRESERVE_NONE void keepGoing(CheckJob *job, CheckContext *context) {
|
||||
#if __has_attribute(musttail)
|
||||
job = job->next;
|
||||
MUSTTAIL return job->continuation(job, context);
|
||||
#else
|
||||
context->job = job->next;
|
||||
return;
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
static_assert(offsetof(CheckJob, next) == 0x38);
|
||||
static_assert(offsetof(CheckJob, continuation) == 0x28);
|
||||
extern "C" void keepGoing(CheckJob *, CheckContext *);
|
||||
|
||||
#if defined(__x86_64__)
|
||||
asm("keepGoing:\n"
|
||||
" mov 0x38(%rdi),%rdi\n"
|
||||
" jmp *0x28(%rdi)\n");
|
||||
#elif defined(__aarch64__)
|
||||
asm("keepGoing:\n"
|
||||
" ldr x0, [x0, #0x38]\n"
|
||||
" ldr x16, [x0, #0x28]\n"
|
||||
" br x16\n");
|
||||
#else
|
||||
#error "Only x64 and aarch64 are supported"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
FLATTEN PRESERVE_NONE void complete(CheckJob *job, CheckContext *context) {
|
||||
if (context->started == context->count) {
|
||||
if (job->prev == job) {
|
||||
#if !__has_attribute(musttail)
|
||||
context->done = true;
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
job->prev->next = job->next;
|
||||
@@ -3495,9 +3488,17 @@ struct __attribute__((visibility("hidden"))) ConflictSet::Impl {
|
||||
inProgress[0].prev = inProgress + started - 1;
|
||||
inProgress[started - 1].next = inProgress;
|
||||
|
||||
#if __has_attribute(musttail)
|
||||
// Kick off the sequence of tail calls that finally returns once all jobs
|
||||
// are done
|
||||
inProgress->continuation(inProgress, &context);
|
||||
#else
|
||||
context.job = inProgress;
|
||||
context.done = false;
|
||||
while (!context.done) {
|
||||
context.job->continuation(context.job, &context);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < count; ++i) {
|
||||
assert(reads[i].readVersion >= 0);
|
||||
|
||||
Reference in New Issue
Block a user