From dd031886619cfff6167f6c39a7e241094751fea1 Mon Sep 17 00:00:00 2001 From: Ryan Macnak Date: Thu, 16 Nov 2023 20:56:29 +0000 Subject: [PATCH] [vm, compiler] Also don't go out-of-bounds for PointerToMemory. TEST=windows-x64 Bug: https://github.com/dart-lang/sdk/issues/53829 Change-Id: Ic7a3cd6e1e8d49a138a74a67c9d30680e91a86a6 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/336620 Commit-Queue: Ryan Macnak Reviewed-by: Daco Harkes --- .../vm/compiler/assembler/assembler_base.cc | 36 +++++++++++++++++++ .../vm/compiler/assembler/assembler_base.h | 6 ++++ runtime/vm/compiler/backend/il.cc | 15 ++++---- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/runtime/vm/compiler/assembler/assembler_base.cc b/runtime/vm/compiler/assembler/assembler_base.cc index 9d738e67482..25e8390812e 100644 --- a/runtime/vm/compiler/assembler/assembler_base.cc +++ b/runtime/vm/compiler/assembler/assembler_base.cc @@ -80,6 +80,42 @@ void AssemblerBase::StoreToSlotNoBarrier(Register src, return StoreIntoObjectNoBarrier(base, address, src); } +void AssemblerBase::UnrolledMemCopy(Register dst_base, + intptr_t dst_offset, + Register src_base, + intptr_t src_offset, + intptr_t size, + Register temp) { + intptr_t offset = 0; + if (target::kWordSize >= 8) { + while (offset + 8 <= size) { + LoadFromOffset(temp, Address(src_base, src_offset + offset), kEightBytes); + StoreToOffset(temp, Address(dst_base, dst_offset + offset), kEightBytes); + offset += 8; + } + } + while (offset + 4 <= size) { + LoadFromOffset(temp, Address(src_base, src_offset + offset), + kUnsignedFourBytes); + StoreToOffset(temp, Address(dst_base, dst_offset + offset), + kUnsignedFourBytes); + offset += 4; + } + while (offset + 2 <= size) { + LoadFromOffset(temp, Address(src_base, src_offset + offset), + kUnsignedTwoBytes); + StoreToOffset(temp, Address(dst_base, dst_offset + offset), + kUnsignedTwoBytes); + offset += 2; + } + while (offset + 1 <= size) { + LoadFromOffset(temp, Address(src_base, src_offset + offset), kUnsignedByte); + StoreToOffset(temp, Address(dst_base, dst_offset + offset), kUnsignedByte); + offset += 1; + } + ASSERT(offset == size); +} + void AssemblerBase::LoadTypeClassId(Register dst, Register src) { if (dst != src) { EnsureHasClassIdInDEBUG(kTypeCid, src, dst); diff --git a/runtime/vm/compiler/assembler/assembler_base.h b/runtime/vm/compiler/assembler/assembler_base.h index 1da34fc1564..7b94081ffe7 100644 --- a/runtime/vm/compiler/assembler/assembler_base.h +++ b/runtime/vm/compiler/assembler/assembler_base.h @@ -724,6 +724,12 @@ class AssemblerBase : public StackResource { Register temp, Label* equals) = 0; + void UnrolledMemCopy(Register dst_base, + intptr_t dst_offset, + Register src_base, + intptr_t src_offset, + intptr_t size, + Register temp); enum CanBeSmi { kValueCanBeSmi, kValueIsNotSmi, diff --git a/runtime/vm/compiler/backend/il.cc b/runtime/vm/compiler/backend/il.cc index c2c1bca7165..2852975e698 100644 --- a/runtime/vm/compiler/backend/il.cc +++ b/runtime/vm/compiler/backend/il.cc @@ -7473,17 +7473,14 @@ void FfiCallInstr::EmitParamMoves(FlowGraphCompiler* compiler, compiler->EmitNativeMove(dst, pointer_loc, &temp_alloc); __ LoadFromSlot(temp0, temp0, Slot::PointerBase_data()); - // Copy chunks. + // Copy chunks. The destination may be rounded up to a multiple of the + // word size, because we do the same rounding when we allocate the space + // on the stack. But source may not be allocated by the VM and end at a + // page boundary. const intptr_t sp_offset = marshaller_.PassByPointerStackOffset(arg_index); - // Struct size is rounded up to a multiple of target::kWordSize. - // This is safe because we do the same rounding when we allocate the - // space on the stack. - for (intptr_t i = 0; i < arg_target.payload_type().SizeInBytes(); - i += compiler::target::kWordSize) { - __ LoadMemoryValue(temp1, temp0, i); - __ StoreMemoryValue(temp1, SPREG, i + sp_offset); - } + __ UnrolledMemCopy(SPREG, sp_offset, temp0, 0, + arg_target.payload_type().SizeInBytes(), temp1); // Store the stack address in the argument location. __ MoveRegister(temp0, SPREG);