본문으로 건너뛰기

[CPython] JIT stencil에서 frame pointer 보존 검증 추가

PR 링크: python/cpython#146524 상태: Merged | 변경: +52 / -32

들어가며

네이티브 프로파일러(perf, Instruments 등)가 JIT 컴파일된 Python 코드를 올바르게 프로파일링하려면, JIT이 생성하는 기계어 코드가 frame pointer를 보존해야 합니다. 이 PR은 JIT stencil 최적화 파이프라인에 frame pointer 변경을 감지하는 validation 단계를 추가합니다.

핵심 코드 분석

1. _Py_get_machine_stack_pointer를 인라인으로 전환

Before:

// pystate.c (별도 함수)
uintptr_t
_Py_get_machine_stack_pointer(void) {
    return (uintptr_t)__builtin_frame_address(0);
}

After:

// pycore_pystate.h (인라인 함수)
static inline uintptr_t
_Py_get_machine_stack_pointer(void) {
#if _Py__has_builtin(__builtin_frame_address) || defined(__GNUC__)
    return (uintptr_t)__builtin_frame_address(0);
#elif defined(_MSC_VER)
    return (uintptr_t)_AddressOfReturnAddress();
#else
    char here;
    return return_pointer_as_int(&here);
#endif
}

_Py_ReachedRecursionLimitPy_NO_INLINE으로 분리하여, frame pointer를 읽는 함수가 인라인되어도 recursion limit 체크는 올바른 스택 위치를 반환하도록 합니다.

2. Frame pointer 변경 감지 validator

# Tools/jit/_optimizers.py
class Optimizer:
    frame_pointers: bool
    _frame_pointer_modify: typing.ClassVar[re.Pattern[str]] = _RE_NEVER_MATCH

    def _validate(self) -> None:
        for block in self._blocks():
            for inst in block.instructions:
                if self.frame_pointers:
                    assert (
                        self._frame_pointer_modify.match(inst.text) is None
                    ), "Frame pointer should not be modified"

class OptimizerAArch64(Optimizer):
    _frame_pointer_modify = re.compile(r"\s*stp\s+x29.*")

class OptimizerX86(Optimizer):
    _frame_pointer_modify = re.compile(r"\s*movq?\s+%(\w+),\s+%rbp.*")

각 아키텍처별로 frame pointer를 수정하는 명령어 패턴을 정규식으로 정의합니다. AArch64에서는 stp x29,...(x29가 frame pointer), x86에서는 mov %reg, %rbp를 감지합니다. _validate()는 최적화 파이프라인 마지막에 실행되어, 최적화 과정에서 frame pointer가 변경되지 않았음을 보장합니다.

왜 이게 좋은가

  • CI에서 regression 방지: 새로운 JIT 최적화가 frame pointer를 깨뜨리면 빌드 시점에 바로 감지됩니다.
  • 프로파일링 지원 보장: frame pointer가 보존되면 perf recordpy-spy 같은 도구가 JIT 코드의 call stack을 정확하게 추적할 수 있습니다.
  • 아키텍처별 분리: AArch64와 x86의 frame pointer 규약이 다르므로, 각각 별도의 정규식 패턴으로 처리합니다.

정리

JIT 컴파일러에서 frame pointer 보존은 디버깅과 프로파일링의 기본 전제입니다. 이 PR은 빌드 타임 validation을 통해 이 불변성을 자동으로 검증하며, CPython JIT의 성숙도를 한 단계 높입니다.

참고 자료


이 포스트는 AI가 작성하였으며, 사실과 다를 수 있습니다. 정확한 정보는 원본 PR을 참고해 주세요.

댓글

관련 포스트

PR Analysis 의 다른글