cppgc: Fix test IteratePointersFindsCalleeSavedRegisters

call the compiler can clobber the tested register. Moving this tricky
part into a noninlinable lambda allows to reduce pressure from the
register allocator and thereby avoid such clobbering.

Subtle: between the first inline assembly and the IteratePointers()
Change-Id: Ibeca8fa2f4fd54d07c2f585a4e876504a6a991b7
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2859843
Commit-Queue: Anton Bikineev <bikineev@chromium.org>
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74280}
This commit is contained in:
Anton Bikineev 2021-04-29 15:43:06 +02:00 committed by V8 LUCI CQ
parent 530080c44a
commit 4ff37d3a3f

View File

@ -308,6 +308,8 @@ TEST_F(GCStackTest, IteratePointersFindsParameterNesting8) {
#ifdef FOR_ALL_CALLEE_SAVED_REGS
// Note: the test is brittle and can fail on some archs/configurations (see
// below).
TEST_F(GCStackTest, IteratePointersFindsCalleeSavedRegisters) {
auto scanner = std::make_unique<StackScanner>();
@ -327,17 +329,32 @@ TEST_F(GCStackTest, IteratePointersFindsCalleeSavedRegisters) {
// Moves |local_scanner->needle()| into a callee-saved register, leaving the
// callee-saved register as the only register referencing the needle.
// (Ignoring implementation-dependent dirty registers/stack.)
//
// Subtle: between the first inline assembly and the IteratePointers() call the
// compiler can clobber the tested register. Moving this tricky part into a
// noninlinable lambda allows to reduce pressure from the register allocator and
// thereby avoid such clobbering.
#define KEEP_ALIVE_FROM_CALLEE_SAVED(reg) \
{ \
local_scanner->Reset(); \
/* This moves the temporary into the calee-saved register. */ \
asm("mov %0, %%" reg : : "r"(local_scanner->needle()) : reg); \
/* Register is unprotected from here till the actual invocation. */ \
const bool found = [local_scanner, local_stack]() V8_NOINLINE { \
/* This moves the temporary into the callee-saved register. */ \
asm volatile("mov %0, %%" reg \
: \
: "r"(local_scanner->needle()) \
: "memory", reg); \
/* Register is unprotected from here till the actual invocation. The \
* compiler is free to clobber the register which makes the test \
* fail. */ \
local_stack->IteratePointers(local_scanner); \
EXPECT_TRUE(local_scanner->found()) \
/* Clear out the register again */ \
asm volatile("mov $0, %%" reg : : : "memory", reg); \
return local_scanner->found(); \
}(); \
EXPECT_TRUE(found) \
<< "pointer in callee-saved register not found. register: " << reg \
<< std::endl; \
/* Clear out the register again */ \
asm("mov $0, %%" reg : : : reg);
}
FOR_ALL_CALLEE_SAVED_REGS(KEEP_ALIVE_FROM_CALLEE_SAVED)
#undef KEEP_ALIVE_FROM_CALLEE_SAVED