Skip to content

Commit a20783f

Browse files
committed
Fix some issues
`replace` didn't preserve relocation; root block should be at the start of the block list; fix the pc-relative addressing of branching between hot and cold sections
1 parent f56e969 commit a20783f

2 files changed

Lines changed: 74 additions & 13 deletions

File tree

Tools/jit/_optimizers.py

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,17 @@ def _make_cold_target(self, block: _Block) -> str:
383383
block.noninstructions.insert(0, f"{label}:")
384384
return label
385385

386+
def _make_cross_section_target(self, block: _Block) -> str:
387+
real_target = self._make_cold_target(block).removeprefix(
388+
self.symbol_prefix
389+
)
390+
return (
391+
f"{self.symbol_prefix}_JIT_CROSS_SECTION_"
392+
f"{real_target}_JIT_CROSS_SECTION"
393+
)
394+
386395
def _relocation_marker(self, reloc: str, block: _Block) -> Instruction:
387-
target = self._make_cold_target(block).removeprefix(
396+
target = self._make_cross_section_target(block).removeprefix(
388397
self.symbol_prefix
389398
)
390399
label = f"{self.symbol_prefix}{reloc}_JIT_RELOCATION_{target}:"
@@ -555,15 +564,25 @@ def _partition_hot_cold_blocks(self) -> None:
555564
cold_blocks = [
556565
block for layout_hot, unit in units if not layout_hot for block in unit
557566
]
558-
self._relink_blocks(
559-
[
560-
*hot_blocks,
561-
continuation,
562-
cold_start,
563-
*cold_blocks,
564-
*self._metadata_blocks(),
565-
]
566-
)
567+
blocks = [
568+
*hot_blocks,
569+
continuation,
570+
cold_start,
571+
*cold_blocks,
572+
*self._metadata_blocks(),
573+
]
574+
if self._root in blocks and blocks[0] is not self._root:
575+
assert self._root.label is None
576+
assert not self._root.instructions
577+
assert self._root.target is None
578+
assert self._root.fallthrough
579+
blocks.remove(self._root)
580+
blocks.insert(0, self._root)
581+
self._relink_blocks(blocks)
582+
linked_blocks = list(self._blocks())
583+
assert linked_blocks[0] is self._root
584+
assert continuation in linked_blocks
585+
assert cold_start in linked_blocks
567586

568587
def _blocks(self) -> typing.Generator[_Block, None, None]:
569588
block: _Block | None = self._root
@@ -798,7 +817,7 @@ def _fixup_cross_section_branches(self) -> None:
798817
continue
799818
assert inst.kind is not InstructionKind.SHORT_BRANCH
800819
block.instructions[-1] = inst.update_target(
801-
self._make_cold_target(target)
820+
self._make_cross_section_target(target)
802821
)
803822

804823
def _fixup_external_labels(self) -> None:

Tools/jit/_stencils.py

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""Core data structures for compiled code templates."""
22

3+
import copy
34
import dataclasses
45
import enum
56
import sys
@@ -148,6 +149,9 @@ class HoleValue(enum.Enum):
148149
"IMAGE_REL_AMD64_REL32",
149150
}
150151

152+
_CROSS_SECTION_PREFIX = "_JIT_CROSS_SECTION_"
153+
_CROSS_SECTION_SUFFIX = "_JIT_CROSS_SECTION"
154+
151155
@dataclasses.dataclass
152156
class Hole:
153157
"""
@@ -170,8 +174,16 @@ class Hole:
170174
func: str = dataclasses.field(init=False)
171175
offset2: int = -1
172176
void: bool = False
173-
# Convenience method:
174-
replace = dataclasses.replace
177+
178+
def replace(self, **changes: typing.Any) -> typing.Self:
179+
field_names = {field.name for field in dataclasses.fields(self)}
180+
for name in changes:
181+
if name not in field_names:
182+
raise TypeError(f"unexpected field name: {name!r}")
183+
result = copy.copy(self)
184+
for name, value in changes.items():
185+
setattr(result, name, value)
186+
return result
175187

176188
def __post_init__(self) -> None:
177189
self.func = _PATCH_FUNCS[self.kind]
@@ -295,6 +307,9 @@ def convert_labels_to_relocations(self) -> None:
295307
first = first_in_pair[index]
296308
hole.fold(first)
297309

310+
self.split_code_at_cold_start()
311+
312+
def split_code_at_cold_start(self) -> None:
298313
cold_start = self.symbols.get("_JIT_COLD_START")
299314
if cold_start is None:
300315
return
@@ -330,6 +345,8 @@ def process_relocations(self, known_symbols: dict[str, int]) -> None:
330345
"""Fix up all GOT and internal relocations for this stencil group."""
331346
for stencil in self._code_stencils():
332347
for hole in stencil.holes.copy():
348+
if self._resolve_cross_section_symbol(hole):
349+
continue
333350
if (
334351
hole.kind
335352
in {"R_AARCH64_CALL26", "R_AARCH64_JUMP26", "ARM64_RELOC_BRANCH26"}
@@ -379,6 +396,8 @@ def process_relocations(self, known_symbols: dict[str, int]) -> None:
379396
self.data.pad(8)
380397
for stencil in self._all_stencils():
381398
for hole in stencil.holes:
399+
if self._resolve_cross_section_symbol(hole):
400+
continue
382401
if hole.value is HoleValue.GOT:
383402
assert hole.symbol is not None
384403
if "_JIT_" in hole.symbol:
@@ -415,6 +434,29 @@ def process_relocations(self, known_symbols: dict[str, int]) -> None:
415434
self.cold_code.holes.sort(key=lambda hole: hole.offset)
416435
self.data.holes.sort(key=lambda hole: hole.offset)
417436

437+
def _resolve_cross_section_symbol(self, hole: Hole) -> bool:
438+
if hole.value is not HoleValue.ZERO or hole.symbol is None:
439+
return False
440+
symbol = hole.symbol
441+
if not (
442+
symbol.startswith(_CROSS_SECTION_PREFIX)
443+
and symbol.endswith(_CROSS_SECTION_SUFFIX)
444+
):
445+
return False
446+
target = symbol.removeprefix(_CROSS_SECTION_PREFIX).removesuffix(
447+
_CROSS_SECTION_SUFFIX
448+
)
449+
try:
450+
value, addend = self.symbols[target]
451+
except KeyError:
452+
raise ValueError(
453+
f"Missing cross-section relocation target {target}"
454+
) from None
455+
hole.value = value
456+
hole.addend += addend
457+
hole.symbol = None
458+
return True
459+
418460
def _jit_symbol_table_lookup(self, symbol: str) -> int:
419461
return len(self.data.body) + self._jit_symbol_table.setdefault(
420462
symbol, 8 * len(self._jit_symbol_table)

0 commit comments

Comments
 (0)