Skip to content

Commit ef577a2

Browse files
DinoVmeta-codesync[bot]
authored andcommitted
Implement static Python thunk helper
Summary: Static Python includes thunks which handle when we need to call to a v-table method which is not directly invokable because it's been overridden by a non-static method or some odd descriptor. This implements the same hydration thunk for ARM64. Reviewed By: kddnewton Differential Revision: D93547839 fbshipit-source-id: 5aaa8ec9210bed422c15b0ff451407b1da9f4d8d
1 parent 1e2ea13 commit ef577a2

1 file changed

Lines changed: 56 additions & 6 deletions

File tree

cinderx/StaticPython/vtable_defs.c

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,21 +235,38 @@ static _PyClassLoader_StaticCallReturn return_to_native_typecode(
235235
return ret;
236236
}
237237

238+
// Number of native arguments passed via registers (excluding the state arg).
239+
// On x86-64: rsi, rdx, rcx, r8, r9 = 5 register args.
240+
// On ARM64: x1-x7 = 7 register args.
241+
#if defined(__aarch64__) || defined(_M_ARM64)
242+
#define NATIVE_REG_ARG_COUNT 7
243+
// The stack arg pointer points directly to the first stack arg.
244+
#define NATIVE_STACK_ARG_OFFSET 0
245+
#elif defined(_M_X64) || defined(_M_AMD64) || defined(__x86_64__)
246+
#define NATIVE_REG_ARG_COUNT 5
247+
// The stack arg pointer points to the saved frame pointer, so we skip
248+
// the frame pointer and the return address to reach the first stack arg.
249+
#define NATIVE_STACK_ARG_OFFSET 2
250+
#endif
251+
238252
int _PyClassLoader_HydrateArgsFromSig(
239253
_PyClassLoader_ThunkSignature* sig,
240254
Py_ssize_t arg_count,
241255
void** args,
242256
PyObject** call_args,
243257
PyObject** free_args) {
244-
PyObject** extra_args = (PyObject**)args[5];
258+
PyObject** extra_args = (PyObject**)args[NATIVE_REG_ARG_COUNT];
245259
for (Py_ssize_t i = 0; i < arg_count; i++) {
246260
void* original;
247-
if (i < 5) {
261+
if (i < NATIVE_REG_ARG_COUNT) {
248262
original = args[i]; // skip the v-table state
249263
} else {
250-
// The original args came in on the stack, so we have to skip the frame
251-
// pointer, the return address and then add one more.
252-
original = extra_args[i - 3];
264+
// The original args came in on the stack. On x86-64 the stack pointer
265+
// saved in the args array points to the frame pointer, so we have to
266+
// skip over it and the return address. On ARM64 the pointer is directly
267+
// to the first stack arg.
268+
original =
269+
extra_args[(i - NATIVE_REG_ARG_COUNT) + NATIVE_STACK_ARG_OFFSET];
253270
}
254271

255272
if (sig->ta_has_primitives && sig->ta_argtype[i] != TYPED_OBJECT) {
@@ -704,10 +721,43 @@ PyObject* _PyVTable_native_entry(PyObject* state, void** args) {
704721
"leave\n"
705722
"ret\n");
706723
}
724+
#elif defined(__aarch64__) || defined(_M_ARM64)
725+
__attribute__((naked))
726+
PyObject* _PyVTable_native_entry(PyObject* state, void** args) {
727+
__asm__(
728+
/* Save frame pointer and link register */
729+
"stp x29, x30, [sp, #-16]!\n"
730+
"mov x29, sp\n"
731+
/* We want to push the arguments passed natively onto the stack */
732+
/* so that we can recover them in hydrate_args. So we store them */
733+
/* in a stack-allocated array and pass the address as the 2nd */
734+
/* argument. Note we don't need to save x0 as it's the state */
735+
/* argument which we're passing in anyway. */
736+
/* Calculate pointer to stack overflow args (original entry sp) */
737+
"add x9, x29, #16\n"
738+
/* Store x1-x7 and the stack arg pointer into the array */
739+
"stp x1, x2, [sp, #-64]!\n"
740+
"stp x3, x4, [sp, #16]\n"
741+
"stp x5, x6, [sp, #32]\n"
742+
"stp x7, x9, [sp, #48]\n"
743+
/* Set x1 to point to the args array */
744+
"mov x1, sp\n"
745+
"bl _PyVTable_thunk_native\n"
746+
/* We don't know if we're returning a floating point value or not */
747+
/* so we assume we are, and always populate the FP registers */
748+
/* even if we don't need to */
749+
"fmov d0, x0\n"
750+
"fmov d1, x1\n"
751+
/* Restore frame and return */
752+
"mov sp, x29\n"
753+
"ldp x29, x30, [sp], #16\n"
754+
"ret\n");
755+
}
707756
#else
708757
PyObject* _PyVTable_native_entry(PyObject* state, void** args) {
709758
PyErr_SetString(
710-
PyExc_RuntimeError, "native entry points not available on non x-64");
759+
PyExc_RuntimeError,
760+
"native entry points not available on this architecture");
711761
return NULL;
712762
}
713763
#endif

0 commit comments

Comments
 (0)