port: advance VC6 frontier into frameobject
This commit is contained in:
+26
-1
@@ -1,4 +1,29 @@
|
||||
## Latest revision (`dict_keys()` C89 declarations hoisted; frontier advances in dictobject.c)
|
||||
## Latest revision (frameobject C89 work; frontier advances past floatobject)
|
||||
|
||||
Date: 2026-10-02 19:09 UTC
|
||||
|
||||
The CPython checkout remains at baseline tag `v3.11.16`, commit `41388c9cb160d0886d5ca00d2e6c878260a8a4549`. Preserved the existing outer and detached CPython working trees; no reset, clean, stash, or discard. Regenerated `compat/msvc600/cpython-3.11.16-vc6-headers.patch` from the complete nested CPython diff and verified byte-for-byte. The outer Gitea commit will contain that patch, focused tests, and this status log; the nested checkout remains detached/uncommitted.
|
||||
|
||||
Continued the C89 port after a fresh forced VC6 probe found `Objects/exceptions.c` at 84/85. Exception-group and exception metadata declarations were hoisted in earlier edits; subsequent forced probes compiled past exceptions, fileobject, and floatobject. In this continuation:
|
||||
|
||||
- `Objects/fileobject.c`: hoisted `Py_OpenCodeHookFunction hook` in `PyFile_OpenCodeObject()` while leaving lookup after path validation.
|
||||
- `Objects/clinic/floatobject.c.h` and `Objects/floatobject.c`: moved the `typestr_length` declaration; corrected C89 declarations in float packing, exact deallocation, `PyFloat_AsDouble`, vectorcall, and format detection; replaced the designated `PyFloat_Type.tp_vectorcall` initializer with positional trailing slots; replaced `1ULL`-style concern in frame stack threshold via `PY_ULL(1)`.
|
||||
- `Objects/frameobject.c`: corrected `frame_getlocals`, stack-swap helpers, overflow literal, stack analysis (`mark_stacks`), incompatible-stack lookup, line marking, and loop-local declarations. Execution/ownership order was retained in the focused checked paths.
|
||||
|
||||
Focused regressions pass:
|
||||
|
||||
- `python3 scripts/vc6-fileobject-opencode-c89.test.py cpython/Objects/fileobject.c`
|
||||
- `python3 scripts/vc6-floatobject-pack4-c89.test.py cpython/Objects/floatobject.c cpython/Objects/clinic/floatobject.c.h`
|
||||
- `python3 scripts/vc6-frameobject-c89.test.py cpython/Objects/frameobject.c`
|
||||
- `git -C cpython diff --check`
|
||||
|
||||
The latest forced probe compiled **87/88** translation units and moved the first blocker to `Objects/frameobject.c`. First diagnostics are C2275/C2146/C2065 for late `PyFrameState state` in `frame_setlineno()` at line 686; further diagnostics in that function and later frameobject code are follow-on C89 issues. Full log: `build/current-recheck/frontier-frame-current.log`. Next step is test-first declaration hoisting in `frame_setlineno()`, preserving validation/cleanup order, then re-probe.
|
||||
|
||||
This is compile-frontier evidence only. No interpreter has been linked or runtime-tested under Wine or Windows 98 SE. No commit or push has yet been made for this continuation.
|
||||
|
||||
---
|
||||
|
||||
## Previous revision (fresh frontier recheck; floatobject declarations already fixed)
|
||||
|
||||
Date: 2026-10-02 16:22 UTC
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,45 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Guard VC6 C89 declaration order in PyFile_OpenCodeObject."""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import NoReturn
|
||||
|
||||
|
||||
def fail(message: str) -> NoReturn:
|
||||
print(message, file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
def function_body(source, signature):
|
||||
start = source.find(signature)
|
||||
if start < 0:
|
||||
fail(f"missing function signature: {signature}")
|
||||
brace = source.find("{", start + len(signature))
|
||||
if brace < 0:
|
||||
fail("missing function body")
|
||||
depth = 0
|
||||
for end in range(brace, len(source)):
|
||||
if source[end] == "{":
|
||||
depth += 1
|
||||
elif source[end] == "}":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
return source[brace + 1:end]
|
||||
fail("unterminated function body")
|
||||
|
||||
|
||||
path = Path(sys.argv[1])
|
||||
source = path.read_text(encoding="utf-8")
|
||||
body = function_body(source, "PyFile_OpenCodeObject(PyObject *path)")
|
||||
expected_decl = " Py_OpenCodeHookFunction hook;"
|
||||
if expected_decl not in body:
|
||||
fail("hook must be declared without initializer at function entry")
|
||||
if "Py_OpenCodeHookFunction hook =" in body:
|
||||
fail("hook declaration must not be initialized at declaration")
|
||||
validation = body.find("if (!PyUnicode_Check(path))")
|
||||
assignment = body.find("hook = _PyRuntime.open_code_hook;")
|
||||
if validation < 0 or assignment < 0 or assignment < validation:
|
||||
fail("hook lookup must remain after path validation")
|
||||
if body.find("return NULL;", validation) > assignment:
|
||||
fail("hook lookup must remain after invalid-path early return")
|
||||
print("fileobject open-code hook C89 declaration and validation order: PASS")
|
||||
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Guard C89 local ordering in the float32 packing fallback."""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import NoReturn
|
||||
|
||||
|
||||
def fail(message: str) -> NoReturn:
|
||||
print(message, file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
def extract_function(source: str, signature: str) -> str:
|
||||
start = source.find(signature)
|
||||
if start < 0:
|
||||
fail(f"missing function signature: {signature}")
|
||||
brace = source.find("{", start + len(signature))
|
||||
if brace < 0:
|
||||
fail("missing function body")
|
||||
depth = 0
|
||||
for end in range(brace, len(source)):
|
||||
if source[end] == "{":
|
||||
depth += 1
|
||||
elif source[end] == "}":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
return source[brace + 1:end]
|
||||
fail("unterminated function body")
|
||||
|
||||
|
||||
source = Path(sys.argv[1]).read_text(encoding="utf-8")
|
||||
body = extract_function(source, "PyFloat_Pack4(double x, char *data, int le)")
|
||||
expected = """ else {
|
||||
unsigned char s[sizeof(float)];
|
||||
float y = (float)x;
|
||||
int i, incr = 1;"""
|
||||
if expected not in body:
|
||||
fail("float32 fallback locals must be declared at the start of its block")
|
||||
copy = body.find("memcpy(s, &y, sizeof(float));")
|
||||
infinity_check = body.find("if (Py_IS_INFINITY(y) && !Py_IS_INFINITY(x))")
|
||||
pack_loop = body.find("for (i = 0; i < 4; i++)")
|
||||
if min(copy, infinity_check, pack_loop) < 0 or not infinity_check < copy < pack_loop:
|
||||
fail("float32 fallback must preserve overflow-check/copy/packing order")
|
||||
|
||||
dealloc = extract_function(source, "_PyFloat_ExactDealloc(PyObject *obj)")
|
||||
if " PyFloatObject *op;" not in dealloc or " PyFloatObject *op =" in dealloc:
|
||||
fail("float exact deallocator op must be declared without initializer at entry")
|
||||
if " struct _Py_float_state *state;" not in dealloc or " struct _Py_float_state *state =" in dealloc:
|
||||
fail("float exact deallocator state must be declared without initializer at entry")
|
||||
if not dealloc.find("assert(PyFloat_CheckExact(obj));") < dealloc.find("op = (PyFloatObject *)obj;") < dealloc.find("state = get_float_state();"):
|
||||
fail("float exact deallocator must preserve assert/op/state initialization order")
|
||||
|
||||
as_double = extract_function(source, "PyFloat_AsDouble(PyObject *op)")
|
||||
if " PyObject *res;" not in as_double or " double val;" not in as_double:
|
||||
fail("PyFloat_AsDouble temporaries must be declared at function entry")
|
||||
if "PyObject *res = _PyNumber_Index(op);" in as_double or "double val = PyLong_AsDouble(res);" in as_double:
|
||||
fail("PyFloat_AsDouble must not redeclare its entry temporaries")
|
||||
if not as_double.find("res = _PyNumber_Index(op);") < as_double.find("val = PyLong_AsDouble(res);") < as_double.find("Py_DECREF(res);"):
|
||||
fail("PyFloat_AsDouble must preserve index-convert/decref order")
|
||||
|
||||
vectorcall = extract_function(source, "float_vectorcall(PyObject *type, PyObject * const*args,")
|
||||
for declaration in (" Py_ssize_t nargs;", " PyObject *x;"):
|
||||
if declaration not in vectorcall:
|
||||
fail("float_vectorcall locals must be declared at function entry")
|
||||
if "Py_ssize_t nargs =" in vectorcall or "PyObject *x =" in vectorcall:
|
||||
fail("float_vectorcall locals must not be initialized at declaration")
|
||||
if not vectorcall.find("nargs = PyVectorcall_NARGS(nargsf);") < vectorcall.find("x = nargs >= 1 ? args[0] : NULL;"):
|
||||
fail("float_vectorcall must preserve nargs-before-argument selection order")
|
||||
|
||||
type_init = extract_function(source, "PyTypeObject PyFloat_Type =")
|
||||
expected_slots = """ float_new, /* tp_new */
|
||||
0, /* tp_free */
|
||||
0, /* tp_is_gc */
|
||||
0, /* tp_bases */
|
||||
0, /* tp_mro */
|
||||
0, /* tp_cache */
|
||||
0, /* tp_subclasses */
|
||||
0, /* tp_weaklist */
|
||||
0, /* tp_del */
|
||||
0, /* tp_version_tag */
|
||||
0, /* tp_finalize */
|
||||
(vectorcallfunc)float_vectorcall, /* tp_vectorcall */"""
|
||||
if expected_slots not in type_init or ".tp_vectorcall =" in type_init:
|
||||
fail("PyFloat_Type vectorcall must use C89 positional trailing slots")
|
||||
|
||||
state_init = extract_function(source, "_PyFloat_InitState(PyInterpreterState *interp)")
|
||||
format_declaration = " float_format_type detected_double_format, detected_float_format;"
|
||||
if format_declaration not in state_init:
|
||||
fail("float format detection locals must be declared at function entry")
|
||||
if format_declaration in state_init[state_init.find("if (!_Py_IsMainInterpreter(interp))"):]:
|
||||
fail("float format detection locals must not be declared after a statement")
|
||||
|
||||
clinic = Path(sys.argv[2]).read_text(encoding="utf-8")
|
||||
wrapper = extract_function(clinic, "float___getformat__(PyTypeObject *type, PyObject *arg)")
|
||||
declaration = " Py_ssize_t typestr_length;"
|
||||
if declaration not in wrapper:
|
||||
fail("float.__getformat__ typestr_length must be declared at wrapper entry")
|
||||
validation = wrapper.find("if (!PyUnicode_Check(arg))")
|
||||
assignment = wrapper.find("typestr = PyUnicode_AsUTF8AndSize(arg, &typestr_length);")
|
||||
if validation < 0 or assignment < validation or "Py_ssize_t typestr_length;" in wrapper[validation:]:
|
||||
fail("Clinic wrapper must preserve type validation before string conversion")
|
||||
print("floatobject C89 declarations and generated Clinic validation order: PASS")
|
||||
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Guard C89 local ordering in frame_getlocals."""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import NoReturn
|
||||
|
||||
|
||||
def fail(message: str) -> NoReturn:
|
||||
print(message, file=sys.stderr)
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
def extract_function(source: str, signature: str) -> str:
|
||||
start = source.find(signature)
|
||||
if start < 0:
|
||||
fail(f"missing function signature: {signature}")
|
||||
brace = source.find("{", start + len(signature))
|
||||
if brace < 0:
|
||||
fail("missing function body")
|
||||
depth = 0
|
||||
for end in range(brace, len(source)):
|
||||
if source[end] == "{":
|
||||
depth += 1
|
||||
elif source[end] == "}":
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
return source[brace + 1:end]
|
||||
fail("unterminated function body")
|
||||
|
||||
|
||||
source = Path(sys.argv[1]).read_text(encoding="utf-8")
|
||||
if "#define WILL_OVERFLOW (PY_ULL(1)<<((MAX_STACK_ENTRIES-1)*BITS_PER_BLOCK))" not in source:
|
||||
fail("frame stack overflow threshold must use Python's portable unsigned-long-long macro")
|
||||
if "#define WILL_OVERFLOW (1ULL<<" in source:
|
||||
fail("frame stack overflow threshold must not use a compiler-specific ULL literal")
|
||||
body = extract_function(source, "frame_getlocals(PyFrameObject *f, void *closure)")
|
||||
declaration = " PyObject *locals;"
|
||||
if declaration not in body or "PyObject *locals =" in body:
|
||||
fail("frame_getlocals locals must be declared without initializer at entry")
|
||||
if not body.find("if (PyFrame_FastToLocalsWithError(f) < 0)") < body.find("locals = f->f_frame->f_locals;") < body.find("Py_INCREF(locals);") < body.find("return locals;"):
|
||||
fail("frame_getlocals must preserve conversion, lookup, incref, and return order")
|
||||
|
||||
swap = extract_function(source, "stack_swap(int64_t stack, int n)")
|
||||
for declaration in (" Kind to_swap, top;", " int shift;", " int64_t replaced_low, replaced_top;"):
|
||||
if declaration not in swap:
|
||||
fail("stack_swap locals must be declared before its assertion")
|
||||
if "Kind to_swap =" in swap or "Kind top =" in swap or "int shift =" in swap or "int64_t replaced_low =" in swap or "int64_t replaced_top =" in swap:
|
||||
fail("stack_swap temporaries must not be initialized after statements")
|
||||
if not swap.find("assert(n >= 1);") < swap.find("to_swap = peek(stack, n);") < swap.find("top = top_of_stack(stack);") < swap.find("shift = BITS_PER_BLOCK*(n-1);") < swap.find("replaced_low =") < swap.find("replaced_top ="):
|
||||
fail("stack_swap must preserve peek, top, shift, and replacement order")
|
||||
|
||||
pop_level = extract_function(source, "pop_to_level(int64_t stack, int level)")
|
||||
if " int64_t max_item, level_max_stack;" not in pop_level:
|
||||
fail("pop_to_level locals must be declared at function entry")
|
||||
if "int64_t max_item =" in pop_level or "int64_t level_max_stack =" in pop_level:
|
||||
fail("pop_to_level locals must not be initialized after the early return")
|
||||
if not pop_level.find("if (level == 0)") < pop_level.find("max_item = (1<<BITS_PER_BLOCK) - 1;") < pop_level.find("level_max_stack = max_item <<") < pop_level.find("while (stack > level_max_stack)"):
|
||||
fail("pop_to_level must preserve level guard and stack reduction order")
|
||||
|
||||
mark = extract_function(source, "mark_stacks(PyCodeObject *code_obj, int len)")
|
||||
for declaration in (
|
||||
" PyObject *co_code;", " _Py_CODEUNIT *code;", " int64_t *stacks;",
|
||||
" int i, j, opcode, todo;", " int64_t next_stack, target_stack;",
|
||||
" int n, delta;", " unsigned char *start, *end, *scan;",
|
||||
" int start_offset, size, handler, depth_and_lasti, level, lasti;",
|
||||
" uint64_t exception_target_stack;",
|
||||
):
|
||||
if declaration not in mark:
|
||||
fail("mark_stacks locals must be declared at function entry")
|
||||
if "for (int " in mark or "int64_t target_stack =" in mark or "uint64_t target_stack =" in mark or "int64_t next_stack =" in mark:
|
||||
fail("mark_stacks must not introduce declarations after statements")
|
||||
if not mark.find("co_code = _PyCode_GetCode(code_obj);") < mark.find("code = (_Py_CODEUNIT *)PyBytes_AS_STRING(co_code);") < mark.find("stacks = PyMem_New(int64_t, len+1);"):
|
||||
fail("mark_stacks must preserve code lookup and stack allocation order")
|
||||
|
||||
explain = extract_function(source, "explain_incompatible_stack(int64_t to_stack)")
|
||||
if " Kind target_kind;" not in explain or "Kind target_kind =" in explain:
|
||||
fail("explain_incompatible_stack target kind must be declared at function entry")
|
||||
if not explain.find("assert(to_stack != 0);") < explain.find("target_kind = top_of_stack(to_stack);") < explain.find("switch(target_kind)"):
|
||||
fail("explain_incompatible_stack must preserve assertion and dispatch order")
|
||||
|
||||
marklines = extract_function(source, "marklines(PyCodeObject *code, int len)")
|
||||
for declaration in (" PyCodeAddressRange bounds;", " int last_line;", " int *linestarts;", " int i;"):
|
||||
if declaration not in marklines:
|
||||
fail("marklines locals must be declared at function entry")
|
||||
if "int last_line =" in marklines or "int *linestarts =" in marklines or "for (int i =" in marklines:
|
||||
fail("marklines must not declare locals after statements")
|
||||
if not marklines.find("_PyCode_InitAddressRange(code, &bounds);") < marklines.find("last_line = -1;") < marklines.find("linestarts = PyMem_New(int, len);") < marklines.find("for (i = 0; i < len; i++)"):
|
||||
fail("marklines must preserve range-init/allocation/initialization order")
|
||||
|
||||
firstline = extract_function(source, "first_line_not_before(int *lines, int len, int line)")
|
||||
if " int result, i;" not in firstline or "for (int i =" in firstline:
|
||||
fail("first_line_not_before loop index must be declared at function entry")
|
||||
if not firstline.find("result = INT_MAX;") < firstline.find("for (i = 0; i < len; i++)"):
|
||||
fail("first_line_not_before must initialize its minimum before scanning")
|
||||
print("frameobject C89 declarations and frame locals ownership order: PASS")
|
||||
@@ -9927,6 +9927,24 @@ else
|
||||
bad "bytearray_join C89 declaration preserves export/join/unexport order"
|
||||
fi
|
||||
|
||||
if python3 "$REPO_ROOT/scripts/vc6-fileobject-opencode-c89.test.py" "$REPO_ROOT/cpython/Objects/fileobject.c"; then
|
||||
pass "fileobject open-code hook C89 declaration and validation order"
|
||||
else
|
||||
bad "fileobject open-code hook C89 declaration and validation order"
|
||||
fi
|
||||
|
||||
if python3 "$REPO_ROOT/scripts/vc6-floatobject-pack4-c89.test.py" "$REPO_ROOT/cpython/Objects/floatobject.c" "$REPO_ROOT/cpython/Objects/clinic/floatobject.c.h"; then
|
||||
pass "floatobject float32 fallback C89 declarations and order"
|
||||
else
|
||||
bad "floatobject float32 fallback C89 declarations and order"
|
||||
fi
|
||||
|
||||
if python3 "$REPO_ROOT/scripts/vc6-frameobject-c89.test.py" "$REPO_ROOT/cpython/Objects/frameobject.c"; then
|
||||
pass "frameobject frame_getlocals C89 declaration and ownership order"
|
||||
else
|
||||
bad "frameobject frame_getlocals C89 declaration and ownership order"
|
||||
fi
|
||||
|
||||
if [ "$fail" -ne 0 ]; then
|
||||
echo "FAILED"
|
||||
exit 1
|
||||
|
||||
Reference in New Issue
Block a user