Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use CRT implementation of memset/memcpy #67788

Merged
merged 2 commits into from
Apr 10, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 74 additions & 159 deletions src/coreclr/vm/arm64/crthelpers.asm
Original file line number Diff line number Diff line change
@@ -1,176 +1,91 @@
; Licensed to the .NET Foundation under one or more agreements.
; The .NET Foundation licenses this file to you under the MIT license.

;; ==++==
;;
; ==++==
;

;;
;; ==--==
;
; ==--==
; ***********************************************************************
; File: CrtHelpers.asm, see history in asmhelpers.asm
;
; ***********************************************************************

#include "ksarm64.h"
#include "asmconstants.h"
#include "asmmacros.h"

TEXTAREA
IMPORT memset
IMPORT memmove

; JIT_MemSet/JIT_MemCpy
;
; It is IMPORTANT that the exception handling code is able to find these guys
; on the stack, but on windows platforms we can just defer to the platform
; implementation.
;

;void JIT_MemSet(void *dst, int val, SIZE_T count)
;{
; uint64_t valEx = (unsigned char)val;
; valEx = valEx | valEx << 8;
; valEx = valEx | valEx << 16;
; valEx = valEx | valEx << 32;
;
; count-=16;
;
; while(count >= 0)
; {
; *(uint64_t*)dst = valEx;
; dst = (uint64_t*)dst + 1;
; *(uint64_t*)dst = valEx;
; dst = (uint64_t*)dst + 1;
; count-=16;
; }
;
; if(count & 8)
; {
; *(uint64_t*)dst = valEx;
; dst = (uint64_t*)dst + 1;
; }
;
; if(count & 4)
; {
; *(uint32_t*)dst = (uint32_t)valEx;
; dst = (uint32_t*)dst + 1;
; }
;
; if(count & 2)
; {
; *(uint16_t*)dst = (uint16_t)valEx;
; dst = (uint16_t*)dst + 1;
; }
;
; if(count & 1)
; {
; *(uint8_t*)dst = (uint8_t)valEx;
; }
;}
;

; Assembly code corresponding to above C++ method. JIT_MemSet can AV and clr exception personality routine needs to
; determine if the exception has taken place inside JIT_Memset in order to throw corresponding managed exception.
; Determining this is slow if the method were implemented as C++ method (using unwind info). In .asm file by adding JIT_MemSet_End
; marker it can be easily determined if exception happened in JIT_MemSet. Therefore, JIT_MemSet has been written in assembly instead of
; as C++ method.
; void JIT_MemSet(void* dest, int c, size_t count)
;
; Purpose:
; Sets the first "count" bytes of the block of memory pointed byte
; "dest" to the specified value (interpreted as an unsigned char).
;
; Entry:
; RCX: void* dest - Pointer to the block of memory to fill.
; RDX: int c - Value to be set.
; R8: size_t count - Number of bytes to be set to the value.
;
; Exit:
;
; Uses:
;
; Exceptions:
;

TEXTAREA

LEAF_ENTRY JIT_MemSet
ands w1, w1, #0xff
orr w1, w1, w1, lsl #8
orr w1, w1, w1, lsl #0x10
orr x1, x1, x1, lsl #0x20

b JIT_MemSet_bottom
JIT_MemSet_top
stp x1, x1, [x0], #16
JIT_MemSet_bottom
subs x2, x2, #16
bge JIT_MemSet_top

tbz x2, #3, JIT_MemSet_tbz4
str x1, [x0], #8
JIT_MemSet_tbz4
tbz x2, #2, JIT_MemSet_tbz2
str w1, [x0], #4
JIT_MemSet_tbz2
tbz x2, #1, JIT_MemSet_tbz1
strh w1, [x0], #2
JIT_MemSet_tbz1
tbz x2, #0, JIT_MemSet_ret
strb w1, [x0]
cbz x2, JIT_MemSet_ret ; check if count is zero, no bytes to set

ldrb wzr, [x0] ; check dest for null

b memset ; forward to the CRT implementation

JIT_MemSet_ret
ret lr
LEAF_END

LEAF_ENTRY JIT_MemSet_End
nop
LEAF_END


; See comments above for JIT_MemSet

;void JIT_MemCpy(void *dst, const void *src, SIZE_T count)
;{
; count-=16;
;
; while(count >= 0)
; {
; *(unit64_t*)dst = *(unit64_t*)src;
; dst = (unit64_t*)dst + 1;
; src = (unit64_t*)src + 1;
; *(unit64_t*)dst = *(unit64_t*)src;
; dst = (unit64_t*)dst + 1;
; src = (unit64_t*)src + 1;
; count-=16;
; }
;
; if(count & 8)
; {
; *(unit64_t*)dst = *(unit64_t*)src;
; dst = (unit64_t*)dst + 1;
; src = (unit64_t*)src + 1;
; }
;
; if(count & 4)
; {
; *(unit32_t*)dst = *(unit32_t*)src;
; dst = (unit32_t*)dst + 1;
; src = (unit32_t*)src + 1;
; }
;
; if(count & 2)
; {
; *(unit16_t*)dst = *(unit16_t*)src;
; dst = (unit16_t*)dst + 1;
; src = (unit16_t*)src + 1;
; }
;
; if(count & 1)
; {
; *(unit8_t*)dst = *(unit8_t*)src;
; }
;}
;

; Assembly code corresponding to above C++ method.
; See comments above for JIT_MemSet method
ret lr

LEAF_END_MARKED JIT_MemSet

; void JIT_MemCpy(void* dest, const void* src, size_t count)
;
; Purpose:
; Copies the values of "count" bytes from the location pointed to
; by "src" to the memory block pointed by "dest".
;
; Entry:
; RCX: void* dest - Pointer to the destination array where content is to be copied.
; RDX: const void* src - Pointer to the source of the data to be copied.
; R8: size_t count - Number of bytes to copy.
;
; Exit:
;
; Uses:
;
; Exceptions:
;
LEAF_ENTRY JIT_MemCpy
b JIT_MemCpy_bottom
JIT_MemCpy_top
ldp x8, x9, [x1], #16
stp x8, x9, [x0], #16
JIT_MemCpy_bottom
subs x2, x2, #16
bge JIT_MemCpy_top

tbz x2, #3, JIT_MemCpy_tbz4
ldr x8, [x1], #8
str x8, [x0], #8
JIT_MemCpy_tbz4
tbz x2, #2, JIT_MemCpy_tbz2
ldr w8, [x1], #4
str w8, [x0], #4
JIT_MemCpy_tbz2
tbz x2, #1, JIT_MemCpy_tbz1
ldrsh w8, [x1], #2
strh w8, [x0], #2
JIT_MemCpy_tbz1
tbz x2, #0, JIT_MemCpy_ret
ldrsb w8, [x1]
strb w8, [x0]
cbz x2, JIT_MemCpy_ret ; check if count is zero, no bytes to set

ldrb wzr, [x0] ; check dest for null
ldrb wzr, [x1] ; check src for null

b memmove ; forward to the CRT implementation

JIT_MemCpy_ret
ret lr
LEAF_END

LEAF_ENTRY JIT_MemCpy_End
nop
LEAF_END
LEAF_END_MARKED JIT_MemCpy

; Must be at very end of file
END
END