Commit a0913c9d authored by Andreas Haas's avatar Andreas Haas Committed by Commit Bot

[wasm] Refactor memory.fill to do the bounds check in C++

Doing the bounds check in C++ has the advantage that we generate less
code, and that TurboFan graphs get smaller. Additionally it will make
code generation from Liftoff easier. There is not really a downside:
We already called C++ anyways to do the actual memory.fill operation.

R=clemensb@chromium.org

Bug: v8:10281
Change-Id: If4e36d45a3fd1c4c0fef9137d37097a012e7a409
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2100991
Commit-Queue: Andreas Haas <ahaas@chromium.org>
Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66703}
parent ea468d53
......@@ -4890,7 +4890,7 @@ Node* WasmGraphBuilder::MemoryInit(uint32_t data_segment_index, Node* dst,
gasm_->Uint32Constant(data_segment_index)},
{MachineRepresentation::kWord32, size}});
MachineType sig_types[] = {MachineType::Bool(), MachineType::Pointer()};
MachineType sig_types[] = {MachineType::Int32(), MachineType::Pointer()};
MachineSignature sig(1, 1, sig_types);
Node* call = SetEffect(BuildCCall(&sig, function, stack_slot));
return TrapIfFalse(wasm::kTrapMemOutOfBounds, call, position);
......@@ -4943,7 +4943,7 @@ Node* WasmGraphBuilder::MemoryCopy(Node* dst, Node* src, Node* size,
{MachineRepresentation::kWord32, src},
{MachineRepresentation::kWord32, size}});
MachineType sig_types[] = {MachineType::Bool(), MachineType::Pointer()};
MachineType sig_types[] = {MachineType::Int32(), MachineType::Pointer()};
MachineSignature sig(1, 1, sig_types);
Node* call = SetEffect(BuildCCall(&sig, function, stack_slot));
return TrapIfFalse(wasm::kTrapMemOutOfBounds, call, position);
......@@ -4951,15 +4951,19 @@ Node* WasmGraphBuilder::MemoryCopy(Node* dst, Node* src, Node* size,
Node* WasmGraphBuilder::MemoryFill(Node* dst, Node* value, Node* size,
wasm::WasmCodePosition position) {
Node* fail = BoundsCheckMemRange(&dst, &size, position);
TrapIfTrue(wasm::kTrapMemOutOfBounds, fail, position);
Node* function = graph()->NewNode(mcgraph()->common()->ExternalConstant(
ExternalReference::wasm_memory_fill()));
MachineType sig_types[] = {MachineType::Pointer(), MachineType::Uint32(),
MachineType::Uint32()};
MachineSignature sig(0, 3, sig_types);
return SetEffect(BuildCCall(&sig, function, dst, value, size));
Node* stack_slot = StoreArgsInStackSlot(
{{MachineType::PointerRepresentation(), instance_node_.get()},
{MachineRepresentation::kWord32, dst},
{MachineRepresentation::kWord32, value},
{MachineRepresentation::kWord32, size}});
MachineType sig_types[] = {MachineType::Int32(), MachineType::Pointer()};
MachineSignature sig(1, 1, sig_types);
Node* call = SetEffect(BuildCCall(&sig, function, stack_slot));
return TrapIfFalse(wasm::kTrapMemOutOfBounds, call, position);
}
Node* WasmGraphBuilder::TableInit(uint32_t table_index,
......
......@@ -440,17 +440,29 @@ int32_t memory_copy_wrapper(Address data) {
return kSuccess;
}
void memory_fill_wrapper(Address dst, uint32_t value, uint32_t size) {
int32_t memory_fill_wrapper(Address data) {
constexpr int32_t kSuccess = 1;
constexpr int32_t kOutOfBounds = 0;
ThreadNotInWasmScope thread_not_in_wasm_scope;
// Use an explicit forward copy to match the required semantics for the
// memory.fill instruction. It is assumed that the caller of this function
// has already performed bounds checks, so {dst + size} should not overflow.
DCHECK(dst + size >= dst);
uint8_t* dst8 = reinterpret_cast<uint8_t*>(dst);
uint8_t value8 = static_cast<uint8_t>(value);
for (; size > 0; size--) {
*dst8++ = value8;
}
DisallowHeapAllocation disallow_heap_allocation;
size_t offset = 0;
Object raw_instance = ReadUnalignedValue<Object>(data);
WasmInstanceObject instance = WasmInstanceObject::cast(raw_instance);
offset += sizeof(Object);
uint32_t dst = ReadUnalignedValue<uint32_t>(data + offset);
offset += sizeof(uint32_t);
uint8_t value =
static_cast<uint8_t>(ReadUnalignedValue<uint32_t>(data + offset));
offset += sizeof(uint32_t);
size_t size = ReadUnalignedValue<uint32_t>(data + offset);
size_t mem_size = instance.memory_size();
if (!base::IsInBounds(dst, size, mem_size)) return kOutOfBounds;
std::memset(EffectiveAddress(instance, dst), value, size);
return kSuccess;
}
static WasmTrapCallbackForTesting wasm_trap_callback_for_testing = nullptr;
......
......@@ -79,7 +79,9 @@ int32_t memory_init_wrapper(Address data);
// zero-extend the result in the return register.
int32_t memory_copy_wrapper(Address data);
void memory_fill_wrapper(Address dst, uint32_t value, uint32_t size);
// The return type is {int32_t} instead of {bool} to enforce the compiler to
// zero-extend the result in the return register.
int32_t memory_fill_wrapper(Address data);
using WasmTrapCallbackForTesting = void (*)();
......
......@@ -1869,7 +1869,7 @@ class ThreadImpl {
DoTrap(kTrapMemOutOfBounds, pc);
return false;
}
memory_fill_wrapper(dst_addr, value, size);
std::memset(reinterpret_cast<void*>(dst_addr), value, size);
return true;
}
case kExprTableInit: {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment