Skip to content

Commit 17ca6a1

Browse files
sunnylqmclaude
andcommitted
fix(hermes-base): treat operand-width opcode variants and switch jump-table offsets as equivalent in the verification
With a base whose string set differs from the new bundle (e.g. the newest legacy version of an app), the new code's hot strings get large ids and hermesc emits GetById/LoadConstStringLongIndex instead of the Short forms, and switch jump tables move with instruction widths. The disassembly compare reported those as non-equivalent and dropped a perfectly good delta build. Fold the Short/Long/LongIndex suffix (and hermesc's column padding) and the switch table offsets; unit-tested, and verified on a real production base (v98) and on the RN 0.77 (v96) chain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 2d6f597 commit 17ca6a1

2 files changed

Lines changed: 38 additions & 2 deletions

File tree

src/utils/hermes-base.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,19 @@ export function normalizeDisassemblyLine(
622622
m = /^(\s*J[A-Za-z]+?)(Long)?\s+(L\d+|\d+)(.*)$/.exec(line);
623623
if (m) return `${m[1]} <tgt>${m[4]}`;
624624
m = /^(\s*DefineOwnById\w*\s+r\d+, r\d+, \d+, )(\d+)$/.exec(line);
625-
if (m) return `${m[1]}"${strings.get(Number(m[2])) ?? `?${m[2]}`}"`;
625+
if (m) line = `${m[1]}"${strings.get(Number(m[2])) ?? `?${m[2]}`}"`;
626+
// Operand-width variants of one instruction (GetByIdShort/GetById/GetByIdLong,
627+
// LoadConstString/LoadConstStringLongIndex, ...) only differ by how wide a
628+
// string/function id or offset is encoded — a foreign base hands the new
629+
// code's hot strings large ids, so the delta build legitimately picks the
630+
// wider form. Fold the suffix and the column padding that follows it.
631+
m = /^(\s*)([A-Za-z]+?)(?:LongIndex|Long|Short)?(\s+.*|)$/.exec(line);
632+
if (m) line = `${m[1]}${m[2]}${m[3].replace(/\s+/g, ' ')}`;
633+
// switch jump tables sit after the instructions; their relative offset (and
634+
// the table header hermesc prints for them) moves with instruction widths
635+
m = /^(\s*(?:String|UInt)?SwitchImm r\d+, \d+, )\d+(, .*)$/.exec(line);
636+
if (m) line = `${m[1]}<jt>${m[2]}`;
637+
if (/^\s*offset \d+$/.test(line)) line = line.replace(/\d+$/, '<jt>');
626638
return line;
627639
}
628640

tests/hermes-base.test.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -415,9 +415,33 @@ describe('helpers', () => {
415415
expect(
416416
normalizeDisassemblyLine('Offset in debug table: source 0x0000', strings),
417417
).toBeNull();
418+
// operand-width variants and padding fold together (foreign base → wide ids)
419+
expect(
420+
normalizeDisassemblyLine(
421+
' GetByIdShort r1, r1, 4, "process"',
422+
strings,
423+
),
424+
).toBe(
425+
normalizeDisassemblyLine(
426+
' GetById r1, r1, 4, "process"',
427+
strings,
428+
),
429+
);
430+
expect(
431+
normalizeDisassemblyLine(' LoadConstStringLongIndex r0, "x"', strings),
432+
).toBe(' LoadConstString r0, "x"');
433+
expect(
434+
normalizeDisassemblyLine(
435+
' StringSwitchImm r13, 2, 4024, L146, 150',
436+
strings,
437+
),
438+
).toBe(' StringSwitchImm r13, 2, <jt>, L146, 150');
439+
expect(normalizeDisassemblyLine(' offset 4024', strings)).toBe(
440+
' offset <jt>',
441+
);
418442
expect(
419443
normalizeDisassemblyLine(' GetByIdShort r3, r0, 2, "s"', strings),
420-
).toBe(' GetByIdShort r3, r0, 2, "s"');
444+
).toBe(' GetById r3, r0, 2, "s"');
421445
});
422446
});
423447

0 commit comments

Comments
 (0)