Skip to content

Commit 7b483f5

Browse files
committed
perf: bypass validation for trusted InstrLocation and Instr construction
Add two fast-path factory methods that skip validation by using object.__new__ + direct slot assignment, for call sites where the inputs are already known to be valid: **InstrLocation._from_tuple** — replaces InstrLocation(...) at four internal sites where positions come from trusted sources (existing InstrLocation.lineno, SetLineno.lineno, first_lineno): - ConcreteBytecode.to_bytecode (fallback lineno-only location) - ConcreteBytecode._pack_location (propagated from existing location) - _ConvertBytecodeToConcrete.concrete_instructions (first_lineno seed and SetLineno-derived locations) **BaseInstr._from_trusted** — replaces Instr(name, arg, location=loc) in ConcreteBytecode.to_bytecode, where name/opcode/arg/location are all derived from already-validated ConcreteInstr objects. CPU own-time profile data: | Hotspot | Before | After | |---|---|---| | `ConcreteBytecode.to_bytecode` | 5.98% | 5.07% | | `Instr._check_arg` | 2.87% | eliminated | | `BaseInstr._set` (via to_bytecode) | 1.48% | eliminated | | `BaseInstr._from_trusted` | — | <1% (not in top 20) | Throughput (Bytecode.from_code().to_code() on dis module's code object, 1 second timed window, 5 runs): | | r/s range | |---|---| | Before | 103–108 | | After | 109–114 |
1 parent 8bf35e4 commit 7b483f5

2 files changed

Lines changed: 45 additions & 5 deletions

File tree

src/bytecode/concrete.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,9 @@ def _assemble_locations(
575575

576576
_, size, lineno, old_location = next(iter_in)
577577
# Infer the line if location is None
578-
old_location = old_location or InstrLocation(lineno, None, None, None)
578+
old_location = old_location or InstrLocation._from_tuple(
579+
lineno, None, None, None
580+
)
579581
lineno = first_lineno
580582

581583
# We track the last set lineno to be able to compute deltas
@@ -930,14 +932,18 @@ def to_bytecode(
930932
else:
931933
arg = c_arg
932934

933-
location = c_instr.location or InstrLocation(lineno, None, None, None)
935+
location = c_instr.location or InstrLocation._from_tuple(
936+
lineno, None, None, None
937+
)
934938

935939
if jump_target is not None:
936940
arg = PLACEHOLDER_LABEL
937941
instr_index = len(instructions)
938942
jumps.append((instr_index, jump_target))
939943

940-
instructions.append(Instr(c_instr.name, arg, location=location))
944+
instructions.append(
945+
Instr._from_trusted(c_instr._name, c_instr._opcode, arg, location)
946+
)
941947

942948
# We now insert the TryEnd entries
943949
if current_instr_offset in ex_end:
@@ -1030,7 +1036,9 @@ def add(names: list[str], name: str) -> int:
10301036
return index
10311037

10321038
def concrete_instructions(self) -> None:
1033-
location = InstrLocation(self.bytecode.first_lineno, None, None, None)
1039+
location = InstrLocation._from_tuple(
1040+
self.bytecode.first_lineno, None, None, None
1041+
)
10341042
# Track instruction (index) using cell vars and free vars to be able to update
10351043
# the index used once all the names are known.
10361044
cell_instrs: list[int] = []
@@ -1086,7 +1094,7 @@ def concrete_instructions(self) -> None:
10861094
continue
10871095

10881096
if isinstance(instr, SetLineno):
1089-
location = InstrLocation(instr.lineno, None, None, None)
1097+
location = InstrLocation._from_tuple(instr.lineno, None, None, None)
10901098
continue
10911099

10921100
if isinstance(instr, TryBegin):

src/bytecode/instr.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,22 @@ def from_positions(cls, position: dis.Positions) -> InstrLocation: # type: igno
621621
position.end_col_offset,
622622
)
623623

624+
@classmethod
625+
def _from_tuple(
626+
cls,
627+
lineno: Optional[int],
628+
end_lineno: Optional[int],
629+
col_offset: Optional[int],
630+
end_col_offset: Optional[int],
631+
) -> InstrLocation:
632+
"""Fast path for trusted position data (e.g. from co_positions())."""
633+
new = object.__new__(cls)
634+
object.__setattr__(new, "lineno", lineno)
635+
object.__setattr__(new, "end_lineno", end_lineno)
636+
object.__setattr__(new, "col_offset", col_offset)
637+
object.__setattr__(new, "end_col_offset", end_col_offset)
638+
return new
639+
624640

625641
class SetLineno:
626642
__slots__ = ("_lineno",)
@@ -819,6 +835,22 @@ def copy(self: T) -> T:
819835
new._location = self._location
820836
return new
821837

838+
@classmethod
839+
def _from_trusted(
840+
cls: type[T],
841+
name: str,
842+
opcode: int,
843+
arg: A,
844+
location: Optional[InstrLocation],
845+
) -> T:
846+
"""Fast path for internal construction from already-validated data."""
847+
new = object.__new__(cls)
848+
new._name = name
849+
new._opcode = opcode
850+
new._arg = arg
851+
new._location = location
852+
return new
853+
822854
def has_jump(self) -> bool:
823855
return self._has_jump(self._opcode)
824856

0 commit comments

Comments
 (0)