Skip to content

Commit 62aeb0e

Browse files
authored
GH-117512: Allow 64-bit JIT operands on 32-bit platforms (GH-117527)
1 parent df4d84c commit 62aeb0e

File tree

4 files changed

+47
-31
lines changed

4 files changed

+47
-31
lines changed

Python/jit.c

Lines changed: 34 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -149,12 +149,12 @@ set_bits(uint32_t *loc, uint8_t loc_start, uint64_t value, uint8_t value_start,
149149
// Fill all of stencil's holes in the memory pointed to by base, using the
150150
// values in patches.
151151
static void
152-
patch(unsigned char *base, const Stencil *stencil, uint64_t *patches)
152+
patch(unsigned char *base, const Stencil *stencil, uintptr_t patches[])
153153
{
154-
for (uint64_t i = 0; i < stencil->holes_size; i++) {
154+
for (size_t i = 0; i < stencil->holes_size; i++) {
155155
const Hole *hole = &stencil->holes[i];
156156
unsigned char *location = base + hole->offset;
157-
uint64_t value = patches[hole->value] + (uint64_t)hole->symbol + hole->addend;
157+
uint64_t value = patches[hole->value] + (uintptr_t)hole->symbol + hole->addend;
158158
uint8_t *loc8 = (uint8_t *)location;
159159
uint32_t *loc32 = (uint32_t *)location;
160160
uint64_t *loc64 = (uint64_t *)location;
@@ -228,7 +228,7 @@ patch(unsigned char *base, const Stencil *stencil, uint64_t *patches)
228228
case HoleKind_X86_64_RELOC_SIGNED:
229229
case HoleKind_X86_64_RELOC_BRANCH:
230230
// 32-bit relative address.
231-
value -= (uint64_t)location;
231+
value -= (uintptr_t)location;
232232
// Check that we're not out of range of 32 signed bits:
233233
assert((int64_t)value >= -(1LL << 31));
234234
assert((int64_t)value < (1LL << 31));
@@ -239,7 +239,7 @@ patch(unsigned char *base, const Stencil *stencil, uint64_t *patches)
239239
case HoleKind_R_AARCH64_JUMP26:
240240
// 28-bit relative branch.
241241
assert(IS_AARCH64_BRANCH(*loc32));
242-
value -= (uint64_t)location;
242+
value -= (uintptr_t)location;
243243
// Check that we're not out of range of 28 signed bits:
244244
assert((int64_t)value >= -(1 << 27));
245245
assert((int64_t)value < (1 << 27));
@@ -313,7 +313,7 @@ patch(unsigned char *base, const Stencil *stencil, uint64_t *patches)
313313
i++;
314314
continue;
315315
}
316-
relaxed = (uint64_t)value - (uint64_t)location;
316+
relaxed = value - (uintptr_t)location;
317317
if ((relaxed & 0x3) == 0 &&
318318
(int64_t)relaxed >= -(1L << 19) &&
319319
(int64_t)relaxed < (1L << 19))
@@ -328,7 +328,7 @@ patch(unsigned char *base, const Stencil *stencil, uint64_t *patches)
328328
// Fall through...
329329
case HoleKind_ARM64_RELOC_PAGE21:
330330
// Number of pages between this page and the value's page:
331-
value = (value >> 12) - ((uint64_t)location >> 12);
331+
value = (value >> 12) - ((uintptr_t)location >> 12);
332332
// Check that we're not out of range of 21 signed bits:
333333
assert((int64_t)value >= -(1 << 20));
334334
assert((int64_t)value < (1 << 20));
@@ -363,14 +363,14 @@ patch(unsigned char *base, const Stencil *stencil, uint64_t *patches)
363363
}
364364

365365
static void
366-
copy_and_patch(unsigned char *base, const Stencil *stencil, uint64_t *patches)
366+
copy_and_patch(unsigned char *base, const Stencil *stencil, uintptr_t patches[])
367367
{
368368
memcpy(base, stencil->body, stencil->body_size);
369369
patch(base, stencil, patches);
370370
}
371371

372372
static void
373-
emit(const StencilGroup *group, uint64_t patches[])
373+
emit(const StencilGroup *group, uintptr_t patches[])
374374
{
375375
copy_and_patch((unsigned char *)patches[HoleValue_DATA], &group->data, patches);
376376
copy_and_patch((unsigned char *)patches[HoleValue_CODE], &group->code, patches);
@@ -381,9 +381,9 @@ int
381381
_PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length)
382382
{
383383
// Loop once to find the total compiled size:
384-
uint32_t instruction_starts[UOP_MAX_TRACE_LENGTH];
385-
uint32_t code_size = 0;
386-
uint32_t data_size = 0;
384+
size_t instruction_starts[UOP_MAX_TRACE_LENGTH];
385+
size_t code_size = 0;
386+
size_t data_size = 0;
387387
for (size_t i = 0; i < length; i++) {
388388
_PyUOpInstruction *instruction = (_PyUOpInstruction *)&trace[i];
389389
const StencilGroup *group = &stencil_groups[instruction->opcode];
@@ -409,14 +409,20 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size
409409
for (size_t i = 0; i < length; i++) {
410410
_PyUOpInstruction *instruction = (_PyUOpInstruction *)&trace[i];
411411
const StencilGroup *group = &stencil_groups[instruction->opcode];
412-
// Think of patches as a dictionary mapping HoleValue to uint64_t:
413-
uint64_t patches[] = GET_PATCHES();
414-
patches[HoleValue_CODE] = (uint64_t)code;
415-
patches[HoleValue_CONTINUE] = (uint64_t)code + group->code.body_size;
416-
patches[HoleValue_DATA] = (uint64_t)data;
417-
patches[HoleValue_EXECUTOR] = (uint64_t)executor;
412+
// Think of patches as a dictionary mapping HoleValue to uintptr_t:
413+
uintptr_t patches[] = GET_PATCHES();
414+
patches[HoleValue_CODE] = (uintptr_t)code;
415+
patches[HoleValue_CONTINUE] = (uintptr_t)code + group->code.body_size;
416+
patches[HoleValue_DATA] = (uintptr_t)data;
417+
patches[HoleValue_EXECUTOR] = (uintptr_t)executor;
418418
patches[HoleValue_OPARG] = instruction->oparg;
419+
#if SIZEOF_VOID_P == 8
419420
patches[HoleValue_OPERAND] = instruction->operand;
421+
#else
422+
assert(SIZEOF_VOID_P == 4);
423+
patches[HoleValue_OPERAND_HI] = instruction->operand >> 32;
424+
patches[HoleValue_OPERAND_LO] = instruction->operand & UINT32_MAX;
425+
#endif
420426
switch (instruction->format) {
421427
case UOP_FORMAT_TARGET:
422428
patches[HoleValue_TARGET] = instruction->target;
@@ -425,34 +431,34 @@ _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size
425431
assert(instruction->exit_index < executor->exit_count);
426432
patches[HoleValue_EXIT_INDEX] = instruction->exit_index;
427433
if (instruction->error_target < length) {
428-
patches[HoleValue_ERROR_TARGET] = (uint64_t)memory + instruction_starts[instruction->error_target];
434+
patches[HoleValue_ERROR_TARGET] = (uintptr_t)memory + instruction_starts[instruction->error_target];
429435
}
430436
break;
431437
case UOP_FORMAT_JUMP:
432438
assert(instruction->jump_target < length);
433-
patches[HoleValue_JUMP_TARGET] = (uint64_t)memory + instruction_starts[instruction->jump_target];
439+
patches[HoleValue_JUMP_TARGET] = (uintptr_t)memory + instruction_starts[instruction->jump_target];
434440
if (instruction->error_target < length) {
435-
patches[HoleValue_ERROR_TARGET] = (uint64_t)memory + instruction_starts[instruction->error_target];
441+
patches[HoleValue_ERROR_TARGET] = (uintptr_t)memory + instruction_starts[instruction->error_target];
436442
}
437443
break;
438444
default:
439445
assert(0);
440446
Py_FatalError("Illegal instruction format");
441447
}
442-
patches[HoleValue_TOP] = (uint64_t)memory + instruction_starts[1];
448+
patches[HoleValue_TOP] = (uintptr_t)memory + instruction_starts[1];
443449
patches[HoleValue_ZERO] = 0;
444450
emit(group, patches);
445451
code += group->code.body_size;
446452
data += group->data.body_size;
447453
}
448454
// Protect against accidental buffer overrun into data:
449455
const StencilGroup *group = &stencil_groups[_FATAL_ERROR];
450-
uint64_t patches[] = GET_PATCHES();
451-
patches[HoleValue_CODE] = (uint64_t)code;
452-
patches[HoleValue_CONTINUE] = (uint64_t)code;
453-
patches[HoleValue_DATA] = (uint64_t)data;
454-
patches[HoleValue_EXECUTOR] = (uint64_t)executor;
455-
patches[HoleValue_TOP] = (uint64_t)code;
456+
uintptr_t patches[] = GET_PATCHES();
457+
patches[HoleValue_CODE] = (uintptr_t)code;
458+
patches[HoleValue_CONTINUE] = (uintptr_t)code;
459+
patches[HoleValue_DATA] = (uintptr_t)data;
460+
patches[HoleValue_EXECUTOR] = (uintptr_t)executor;
461+
patches[HoleValue_TOP] = (uintptr_t)code;
456462
patches[HoleValue_ZERO] = 0;
457463
emit(group, patches);
458464
code += group->code.body_size;

Tools/jit/_stencils.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,11 @@ class HoleValue(enum.Enum):
2727
GOT = enum.auto()
2828
# The current uop's oparg (exposed as _JIT_OPARG):
2929
OPARG = enum.auto()
30-
# The current uop's operand (exposed as _JIT_OPERAND):
30+
# The current uop's operand on 64-bit platforms (exposed as _JIT_OPERAND):
3131
OPERAND = enum.auto()
32+
# The current uop's operand on 32-bit platforms (exposed as _JIT_OPERAND_HI and _JIT_OPERAND_LO):
33+
OPERAND_HI = enum.auto()
34+
OPERAND_LO = enum.auto()
3235
# The current uop's target (exposed as _JIT_TARGET):
3336
TARGET = enum.auto()
3437
# The base address of the machine code for the jump target (exposed as _JIT_JUMP_TARGET):

Tools/jit/_writer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ def _dump_header() -> typing.Iterator[str]:
1717
yield "} HoleValue;"
1818
yield ""
1919
yield "typedef struct {"
20-
yield " const uint64_t offset;"
20+
yield " const size_t offset;"
2121
yield " const HoleKind kind;"
2222
yield " const HoleValue value;"
2323
yield " const void *symbol;"
@@ -58,7 +58,7 @@ def _dump_footer(opnames: typing.Iterable[str]) -> typing.Iterator[str]:
5858
yield ""
5959
yield "#define GET_PATCHES() { \\"
6060
for value in _stencils.HoleValue:
61-
yield f" [HoleValue_{value.name}] = (uint64_t)0xBADBADBADBADBADB, \\"
61+
yield f" [HoleValue_{value.name}] = (uintptr_t)0xBADBADBADBADBADB, \\"
6262
yield "}"
6363

6464

Tools/jit/template.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,14 @@ _JIT_ENTRY(_PyInterpreterFrame *frame, PyObject **stack_pointer, PyThreadState *
8888
int uopcode = _JIT_OPCODE;
8989
// Other stuff we need handy:
9090
PATCH_VALUE(uint16_t, _oparg, _JIT_OPARG)
91+
#if SIZEOF_VOID_P == 8
9192
PATCH_VALUE(uint64_t, _operand, _JIT_OPERAND)
93+
#else
94+
assert(SIZEOF_VOID_P == 4);
95+
PATCH_VALUE(uint32_t, _operand_hi, _JIT_OPERAND_HI)
96+
PATCH_VALUE(uint32_t, _operand_lo, _JIT_OPERAND_LO)
97+
uint64_t _operand = ((uint64_t)_operand_hi << 32) | _operand_lo;
98+
#endif
9299
PATCH_VALUE(uint32_t, _target, _JIT_TARGET)
93100
PATCH_VALUE(uint16_t, _exit_index, _JIT_EXIT_INDEX)
94101

0 commit comments

Comments
 (0)