vendor tsgo
This commit is contained in:
166
tools/tsgo/internal/fswatch/fsevents_darwin_ffi_arm64.s
Normal file
166
tools/tsgo/internal/fswatch/fsevents_darwin_ffi_arm64.s
Normal file
@@ -0,0 +1,166 @@
|
||||
//go:build darwin && arm64
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// fsevents_darwin_ffi_arm64.s: arm64 assembly for the FSEvents backend
|
||||
//
|
||||
// Contains two functions:
|
||||
//
|
||||
// 1. FSEventStreamCreate trampoline: moves the float64 latency bits
|
||||
// from R5 (integer register, where syscall6 puts it) into F0 (the
|
||||
// AAPCS64 first float argument register), and hardcodes flags to
|
||||
// 0x11 (kFSEventStreamCreateFlagUseCFTypes |
|
||||
// kFSEventStreamCreateFlagFileEvents).
|
||||
//
|
||||
// 2. fsEventsCallbackASM: the C-convention callback invoked by FSEvents
|
||||
// on a GCD dispatch queue thread. Retains/copies callback data into a
|
||||
// payload, writes the payload pointer to eventPipe to wake the Go event-loop
|
||||
// goroutine, then returns. Never enters Go ABI. Uses only caller-saved
|
||||
// registers (R0-R17) to avoid
|
||||
// clobbering AAPCS64 callee-saved R19-R28 and platform-reserved R18.
|
||||
// See TestCallbackASMTouchesOnlySafeRegisters for the static check.
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// FSEventStreamCreate trampoline: shuffles the float64 latency argument.
|
||||
//
|
||||
// The runtime's syscall6 trampoline loads 6 args into R0-R5:
|
||||
// R0=allocator R1=callback R2=ctx R3=paths
|
||||
// R4=sinceWhen R5=latency(bits)
|
||||
//
|
||||
// The C function expects latency in F0 (float register) and flags in R5.
|
||||
// flags is always 0x11 (kFSEventStreamCreateFlagUseCFTypes |
|
||||
// kFSEventStreamCreateFlagFileEvents), so we hardcode it.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEXT fse_FSEventStreamCreate_trampoline<>(SB), NOSPLIT, $0-0
|
||||
FMOVD R5, F0
|
||||
MOVD $0x11, R5
|
||||
JMP fse_FSEventStreamCreate(SB)
|
||||
|
||||
GLOBL ·fse_FSEventStreamCreate_trampoline_addr(SB), RODATA, $8
|
||||
DATA ·fse_FSEventStreamCreate_trampoline_addr(SB)/8, $fse_FSEventStreamCreate_trampoline<>(SB)
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// FSEvents callback: called from a GCD dispatch queue with C convention.
|
||||
// R0=streamRef R1=info R2=numEvents R3=paths R4=flags R5=ids
|
||||
//
|
||||
// `info` (R1) is a pointer to a streamCallback struct:
|
||||
// offset 0: eventPipeWrite fd
|
||||
//
|
||||
// Because all memory accesses use offset addressing from R1 (a caller-saved
|
||||
// register), there are no global symbol loads and no REGTMP/R27 hazard.
|
||||
//
|
||||
// Frame layout (80 bytes, 16-byte aligned):
|
||||
// RSP+ 0: saved R29 (FP) ← R29 points here (C frame chain)
|
||||
// RSP+ 8: saved R30 (LR)
|
||||
// RSP+16: payload pointer bytes written to eventPipe
|
||||
// RSP+24: saved info pointer
|
||||
// RSP+32: saved numEvents
|
||||
// RSP+40: saved original flags pointer
|
||||
// RSP+48: retained CFArray paths
|
||||
// RSP+56: copied flags pointer
|
||||
// RSP+64: saved original IDs pointer
|
||||
// RSP+72: copied IDs pointer
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
TEXT fsEventsCallbackASM<>(SB), NOSPLIT|NOFRAME, $0
|
||||
SUB $80, RSP
|
||||
MOVD R29, (RSP)
|
||||
MOVD R30, 8(RSP)
|
||||
MOVD RSP, R29
|
||||
|
||||
MOVD R1, 24(RSP) // info
|
||||
MOVD R2, 32(RSP) // numEvents
|
||||
MOVD R4, 40(RSP) // original flags
|
||||
MOVD R5, 64(RSP) // original IDs
|
||||
|
||||
// Retain the CFArray paths because FSEvents owns the callback argument.
|
||||
MOVD R3, R0
|
||||
BL fse_CFRetain(SB)
|
||||
CBZ R0, done
|
||||
MOVD R0, 48(RSP)
|
||||
|
||||
// Copy the flags array into C heap memory owned by the Go event loop.
|
||||
MOVD 32(RSP), R0
|
||||
LSL $2, R0, R0
|
||||
BL fse_malloc(SB)
|
||||
CBZ R0, releasePaths
|
||||
MOVD R0, 56(RSP)
|
||||
|
||||
MOVD R0, R0
|
||||
MOVD 40(RSP), R1
|
||||
MOVD 32(RSP), R2
|
||||
LSL $2, R2, R2
|
||||
BL fse_memcpy(SB)
|
||||
|
||||
// Copy the event ID array into C heap memory owned by the Go event loop.
|
||||
MOVD 32(RSP), R0
|
||||
LSL $3, R0, R0
|
||||
BL fse_malloc(SB)
|
||||
CBZ R0, freeFlags
|
||||
MOVD R0, 72(RSP)
|
||||
|
||||
MOVD R0, R0
|
||||
MOVD 64(RSP), R1
|
||||
MOVD 32(RSP), R2
|
||||
LSL $3, R2, R2
|
||||
BL fse_memcpy(SB)
|
||||
|
||||
// Allocate and populate fsEventsCallbackPayload.
|
||||
MOVD $32, R0
|
||||
BL fse_malloc(SB)
|
||||
CBZ R0, freeIDs
|
||||
MOVD R0, 16(RSP)
|
||||
|
||||
MOVD 32(RSP), R6
|
||||
MOVD R6, (0*8)(R0)
|
||||
MOVD 48(RSP), R6
|
||||
MOVD R6, (1*8)(R0)
|
||||
MOVD 56(RSP), R6
|
||||
MOVD R6, (2*8)(R0)
|
||||
MOVD 72(RSP), R6
|
||||
MOVD R6, (3*8)(R0)
|
||||
|
||||
// write(info->eventPipeWrite, &payload, sizeof(payload)).
|
||||
writeAgain:
|
||||
MOVD 24(RSP), R6 // reload info
|
||||
MOVD (0*8)(R6), R0 // eventPipeWrite
|
||||
ADD $16, RSP, R1 // buf (payload pointer)
|
||||
MOVD $8, R2 // count
|
||||
BL fse_write(SB)
|
||||
CMP $8, R0
|
||||
BEQ done
|
||||
ADD $1, R0, R6
|
||||
CBNZ R6, freePayload
|
||||
BL fse___error(SB)
|
||||
MOVW (R0), R0
|
||||
CMPW $4, R0 // EINTR
|
||||
BEQ writeAgain
|
||||
B freePayload
|
||||
|
||||
freePayload:
|
||||
MOVD 16(RSP), R0
|
||||
BL fse_free(SB)
|
||||
|
||||
freeIDs:
|
||||
MOVD 72(RSP), R0
|
||||
BL fse_free(SB)
|
||||
|
||||
freeFlags:
|
||||
MOVD 56(RSP), R0
|
||||
BL fse_free(SB)
|
||||
|
||||
releasePaths:
|
||||
MOVD 48(RSP), R0
|
||||
BL fse_CFRelease(SB)
|
||||
|
||||
// Return 0.
|
||||
done:
|
||||
MOVD $0, R0
|
||||
MOVD (RSP), R29
|
||||
MOVD 8(RSP), R30
|
||||
ADD $80, RSP
|
||||
RET
|
||||
|
||||
GLOBL ·fsEventsCallbackAsmAddr(SB), RODATA, $8
|
||||
DATA ·fsEventsCallbackAsmAddr(SB)/8, $fsEventsCallbackASM<>(SB)
|
||||
Reference in New Issue
Block a user