feat: indie status page MVP -- FastAPI + SQLite
- 8 DB models (services, incidents, monitors, subscribers, etc.) - Full CRUD API for services, incidents, monitors - Public status page with live data - Incident detail page with timeline - API key authentication - Uptime monitoring scheduler - 13 tests passing - TECHNICAL_DESIGN.md with full spec
This commit is contained in:
commit
902133edd3
4655 changed files with 1342691 additions and 0 deletions
113
venv/lib/python3.11/site-packages/mypyc/transform/spill.py
Normal file
113
venv/lib/python3.11/site-packages/mypyc/transform/spill.py
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
"""Insert spills for values that are live across yields."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from mypyc.analysis.dataflow import AnalysisResult, analyze_live_regs, get_cfg
|
||||
from mypyc.common import TEMP_ATTR_NAME
|
||||
from mypyc.ir.class_ir import ClassIR
|
||||
from mypyc.ir.func_ir import FuncIR
|
||||
from mypyc.ir.ops import (
|
||||
BasicBlock,
|
||||
Branch,
|
||||
DecRef,
|
||||
GetAttr,
|
||||
IncRef,
|
||||
LoadErrorValue,
|
||||
Register,
|
||||
SetAttr,
|
||||
Value,
|
||||
)
|
||||
|
||||
|
||||
def insert_spills(ir: FuncIR, env: ClassIR) -> None:
|
||||
cfg = get_cfg(ir.blocks, use_yields=True)
|
||||
live = analyze_live_regs(ir.blocks, cfg)
|
||||
entry_live = live.before[ir.blocks[0], 0]
|
||||
|
||||
entry_live = {op for op in entry_live if not (isinstance(op, Register) and op.is_arg)}
|
||||
# TODO: Actually for now, no Registers at all -- we keep the manual spills
|
||||
entry_live = {op for op in entry_live if not isinstance(op, Register)}
|
||||
|
||||
ir.blocks = spill_regs(ir.blocks, env, entry_live, live, ir.arg_regs[0])
|
||||
|
||||
|
||||
def spill_regs(
|
||||
blocks: list[BasicBlock],
|
||||
env: ClassIR,
|
||||
to_spill: set[Value],
|
||||
live: AnalysisResult[Value],
|
||||
self_reg: Register,
|
||||
) -> list[BasicBlock]:
|
||||
env_reg: Value
|
||||
for op in blocks[0].ops:
|
||||
if isinstance(op, GetAttr) and op.attr == "__mypyc_env__":
|
||||
env_reg = op
|
||||
break
|
||||
else:
|
||||
# Environment has been merged into generator object
|
||||
env_reg = self_reg
|
||||
|
||||
spill_locs = {}
|
||||
for i, val in enumerate(to_spill):
|
||||
name = f"{TEMP_ATTR_NAME}2_{i}"
|
||||
env.attributes[name] = val.type
|
||||
if val.type.error_overlap:
|
||||
# We can safely treat as always initialized, since the type has no pointers.
|
||||
# This way we also don't need to manage the defined attribute bitfield.
|
||||
env._always_initialized_attrs.add(name)
|
||||
spill_locs[val] = name
|
||||
|
||||
for block in blocks:
|
||||
ops = block.ops
|
||||
block.ops = []
|
||||
|
||||
for i, op in enumerate(ops):
|
||||
to_decref = []
|
||||
|
||||
if isinstance(op, IncRef) and op.src in spill_locs:
|
||||
raise AssertionError("not sure what to do with an incref of a spill...")
|
||||
if isinstance(op, DecRef) and op.src in spill_locs:
|
||||
# When we decref a spilled value, we turn that into
|
||||
# NULLing out the attribute, but only if the spilled
|
||||
# value is not live *when we include yields in the
|
||||
# CFG*. (The original decrefs are computed without that.)
|
||||
#
|
||||
# We also skip a decref is the env register is not
|
||||
# live. That should only happen when an exception is
|
||||
# being raised, so everything should be handled there.
|
||||
if op.src not in live.after[block, i] and env_reg in live.after[block, i]:
|
||||
# Skip the DecRef but null out the spilled location
|
||||
null = LoadErrorValue(op.src.type)
|
||||
block.ops.extend([null, SetAttr(env_reg, spill_locs[op.src], null, op.line)])
|
||||
continue
|
||||
|
||||
if (
|
||||
any(src in spill_locs for src in op.sources())
|
||||
# N.B: IS_ERROR should be before a spill happens
|
||||
# XXX: but could we have a regular branch?
|
||||
and not (isinstance(op, Branch) and op.op == Branch.IS_ERROR)
|
||||
):
|
||||
new_sources: list[Value] = []
|
||||
stolen = op.stolen()
|
||||
for src in op.sources():
|
||||
if src in spill_locs:
|
||||
read = GetAttr(env_reg, spill_locs[src], op.line)
|
||||
block.ops.append(read)
|
||||
new_sources.append(read)
|
||||
if src.type.is_refcounted and src not in stolen:
|
||||
to_decref.append(read)
|
||||
else:
|
||||
new_sources.append(src)
|
||||
|
||||
op.set_sources(new_sources)
|
||||
|
||||
block.ops.append(op)
|
||||
|
||||
for dec in to_decref:
|
||||
block.ops.append(DecRef(dec))
|
||||
|
||||
if op in spill_locs:
|
||||
# XXX: could we set uninit?
|
||||
block.ops.append(SetAttr(env_reg, spill_locs[op], op, op.line))
|
||||
|
||||
return blocks
|
||||
Loading…
Add table
Add a link
Reference in a new issue