Fix Wasm atomic waits on big endian platforms

Wasm values are stored in memory in little endian order even
on BE machines and as a result they need to be manually reversed
after a load.

Other such atomic ops get patched during Wasm compilation or
during code-gen, this is one of the few places where a runtime call is
made to C++ which requires this fix.

As the the runtime stub is used on both TurboFan and Liftoff this
patch will fix both cases.

Up until now the cctest was passing incorrectly as it's mixing the
Wasm memory buffer with TypedArrays. TypedArrays don't have the
LE enforcement and use the native byte order.

With this patch the test is now failing as expected
and is being skipped for now.

Bug: v8:12505
Change-Id: I49fac208f1fab7396b7d9911e803bc047b3b8263
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3350744
Reviewed-by: Andreas Haas <ahaas@chromium.org>
Reviewed-by: Shu-yu Guo <syg@chromium.org>
Reviewed-by: Igor Sheludko <ishell@chromium.org>
Commit-Queue: Milad Farazmand <mfarazma@redhat.com>
Cr-Commit-Position: refs/heads/main@{#78433}
This commit is contained in:
Milad Fa 2021-12-22 11:23:34 -05:00 committed by V8 LUCI CQ
parent 099cb420b9
commit 183a2abc21
3 changed files with 34 additions and 12 deletions

View File

@ -297,7 +297,7 @@ Object FutexEmulation::WaitWasm32(Isolate* isolate,
size_t addr, int32_t value,
int64_t rel_timeout_ns) {
return Wait<int32_t>(isolate, WaitMode::kSync, array_buffer, addr, value,
rel_timeout_ns >= 0, rel_timeout_ns);
rel_timeout_ns >= 0, rel_timeout_ns, CallType::kIsWasm);
}
Object FutexEmulation::WaitWasm64(Isolate* isolate,
@ -305,7 +305,7 @@ Object FutexEmulation::WaitWasm64(Isolate* isolate,
size_t addr, int64_t value,
int64_t rel_timeout_ns) {
return Wait<int64_t>(isolate, WaitMode::kSync, array_buffer, addr, value,
rel_timeout_ns >= 0, rel_timeout_ns);
rel_timeout_ns >= 0, rel_timeout_ns, CallType::kIsWasm);
}
template <typename T>
@ -346,21 +346,22 @@ double WaitTimeoutInMs(double timeout_ns) {
template <typename T>
Object FutexEmulation::Wait(Isolate* isolate, WaitMode mode,
Handle<JSArrayBuffer> array_buffer, size_t addr,
T value, bool use_timeout, int64_t rel_timeout_ns) {
T value, bool use_timeout, int64_t rel_timeout_ns,
CallType call_type) {
if (mode == WaitMode::kSync) {
return WaitSync(isolate, array_buffer, addr, value, use_timeout,
rel_timeout_ns);
rel_timeout_ns, call_type);
}
DCHECK_EQ(mode, WaitMode::kAsync);
return WaitAsync(isolate, array_buffer, addr, value, use_timeout,
rel_timeout_ns);
rel_timeout_ns, call_type);
}
template <typename T>
Object FutexEmulation::WaitSync(Isolate* isolate,
Handle<JSArrayBuffer> array_buffer, size_t addr,
T value, bool use_timeout,
int64_t rel_timeout_ns) {
int64_t rel_timeout_ns, CallType call_type) {
VMState<ATOMICS_WAIT> state(isolate);
base::TimeDelta rel_timeout =
base::TimeDelta::FromNanoseconds(rel_timeout_ns);
@ -398,7 +399,15 @@ Object FutexEmulation::WaitSync(Isolate* isolate,
FutexWaitListNode::ResetWaitingOnScopeExit reset_waiting(node);
std::atomic<T>* p = reinterpret_cast<std::atomic<T>*>(wait_location);
if (p->load() != value) {
T loaded_value = p->load();
#if defined(V8_TARGET_BIG_ENDIAN)
// If loading a Wasm value, it needs to be reversed on Big Endian platforms.
if (call_type == CallType::kIsWasm) {
DCHECK(sizeof(T) == kInt32Size || sizeof(T) == kInt64Size);
loaded_value = ByteReverse(loaded_value);
}
#endif
if (loaded_value != value) {
result = handle(Smi::FromInt(WaitReturnValue::kNotEqual), isolate);
callback_result = AtomicsWaitEvent::kNotEqual;
break;
@ -523,7 +532,7 @@ template <typename T>
Object FutexEmulation::WaitAsync(Isolate* isolate,
Handle<JSArrayBuffer> array_buffer,
size_t addr, T value, bool use_timeout,
int64_t rel_timeout_ns) {
int64_t rel_timeout_ns, CallType call_type) {
base::TimeDelta rel_timeout =
base::TimeDelta::FromNanoseconds(rel_timeout_ns);
@ -543,7 +552,15 @@ Object FutexEmulation::WaitAsync(Isolate* isolate,
// 17. Let w be ! AtomicLoad(typedArray, i).
std::atomic<T>* p = reinterpret_cast<std::atomic<T>*>(
static_cast<int8_t*>(backing_store->buffer_start()) + addr);
if (p->load() != value) {
T loaded_value = p->load();
#if defined(V8_TARGET_BIG_ENDIAN)
// If loading a Wasm value, it needs to be reversed on Big Endian platforms.
if (call_type == CallType::kIsWasm) {
DCHECK(sizeof(T) == kInt32Size || sizeof(T) == kInt64Size);
loaded_value = ByteReverse(loaded_value);
}
#endif
if (loaded_value != value) {
result_kind = ResultKind::kNotEqual;
} else if (use_timeout && rel_timeout_ns == 0) {
result_kind = ResultKind::kTimedOut;

View File

@ -141,6 +141,7 @@ class FutexWaitListNode {
class FutexEmulation : public AllStatic {
public:
enum WaitMode { kSync = 0, kAsync };
enum class CallType { kIsNotWasm = 0, kIsWasm };
// Pass to Wake() to wake all waiters.
static const uint32_t kWakeAll = UINT32_MAX;
@ -214,17 +215,18 @@ class FutexEmulation : public AllStatic {
template <typename T>
static Object Wait(Isolate* isolate, WaitMode mode,
Handle<JSArrayBuffer> array_buffer, size_t addr, T value,
bool use_timeout, int64_t rel_timeout_ns);
bool use_timeout, int64_t rel_timeout_ns,
CallType call_type = CallType::kIsNotWasm);
template <typename T>
static Object WaitSync(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
size_t addr, T value, bool use_timeout,
int64_t rel_timeout_ns);
int64_t rel_timeout_ns, CallType call_type);
template <typename T>
static Object WaitAsync(Isolate* isolate, Handle<JSArrayBuffer> array_buffer,
size_t addr, T value, bool use_timeout,
int64_t rel_timeout_ns);
int64_t rel_timeout_ns, CallType call_type);
// Resolve the Promises of the async waiters which belong to |isolate|.
static void ResolveAsyncWaiterPromises(Isolate* isolate);

View File

@ -282,6 +282,9 @@
##############################################################################
['byteorder == big', {
# BUG(v8:12505). Tests which share Wasm memory buffer with Js Typed arrays.
'test-api/WasmI32AtomicWaitCallback': [SKIP],
'test-api/WasmI64AtomicWaitCallback': [SKIP],
# Peephole optimization not supported on big-endian machines.
'test-regexp/Peephole*': [SKIP],
}], # 'byteorder == big'