Skip to content

Commit 84e0a7d

Browse files
authored
compiler: reorder CST header fields (#598)
1 parent 33f369e commit 84e0a7d

File tree

7 files changed

+60
-46
lines changed

7 files changed

+60
-46
lines changed

packages/compiler/runtime/ohmRuntime.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@
3030
*
3131
* Offset Field
3232
* ------ ----------------------------------
33-
* 0 count: i32 (number of children)
34-
* 4 matchLength: i32 (chars consumed)
35-
* 8 typeAndDetails: i32
33+
* 0 matchLength: i32 (chars consumed)
34+
* 4 typeAndDetails: i32
3635
* bits [1:0] = node type
3736
* 0=nonterminal, 2=iteration, 3=optional
3837
* bits [31:2] = ruleId (nonterminal) or arity (iter)
38+
* 8 count: i32 (number of children)
3939
* 12 failureOffset: i32 (relative to startIdx)
4040
* 16+ children: i32[] (pointers to child nodes, or tagged terminals)
4141
*
@@ -249,24 +249,24 @@ export function bindingsAdvanceChunk(): void {
249249
return cstGetFailureOffset(entry);
250250
}
251251

252-
@inline function cstGetCount(ptr: i32): i32 {
252+
@inline function cstGetMatchLength(ptr: i32): i32 {
253253
return load<i32>(<usize>ptr, 0);
254254
}
255255

256-
@inline function cstSetCount(ptr: i32, count: i32): void {
257-
store<i32>(<usize>ptr, count, 0);
256+
@inline function cstSetMatchLength(ptr: i32, len: i32): void {
257+
store<i32>(<usize>ptr, len, 0);
258258
}
259259

260-
@inline function cstGetMatchLength(ptr: i32): i32 {
261-
return load<i32>(<usize>ptr, 4);
260+
@inline function cstSetTypeAndDetails(ptr: i32, val: i32): void {
261+
store<i32>(<usize>ptr, val, 4);
262262
}
263263

264-
@inline function cstSetMatchLength(ptr: i32, len: i32): void {
265-
store<i32>(<usize>ptr, len, 4);
264+
@inline function cstGetCount(ptr: i32): i32 {
265+
return load<i32>(<usize>ptr, 8);
266266
}
267267

268-
@inline function cstSetTypeAndDetails(ptr: i32, val: i32): void {
269-
store<i32>(<usize>ptr, val, 8);
268+
@inline function cstSetCount(ptr: i32, count: i32): void {
269+
store<i32>(<usize>ptr, count, 8);
270270
}
271271

272272
@inline function cstGetFailureOffset(ptr: i32): i32 {

packages/compiler/test/snapshots/test-wasm.js.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ Generated by [AVA](https://avajs.dev).
88

99
> Snapshot 1
1010
11-
'0000020c 00000000 00000000 00000810 000007f0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000000c 00620061 00000000 00000000 0000000c 000007a0 00000000 00000000 0000002c 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000024c 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000004c 00000810 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000001c 00000001 00000001 00000008 ffffffff 00000003 00000000 00000000 0000001c 00000002 00000002 00000000 ffffffff 00000003 000007f0 00000000'
11+
'0000020c 00000000 00000000 00000810 000007f0 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000000c 00620061 00000000 00000000 0000000c 000007a0 00000000 00000000 0000002c 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000024c 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000004c 00000810 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 0000001c 00000001 00000008 00000001 ffffffff 00000003 00000000 00000000 0000001c 00000002 00000000 00000002 ffffffff 00000003 000007f0 00000000'
1 Byte
Binary file not shown.

packages/compiler/test/test-wasm.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1860,9 +1860,9 @@ test('bindings chunks contain valid CST nodes and tagged terminals', async t =>
18601860
// CST node pointer: must be 4-byte aligned.
18611861
if ((val & 3) !== 0) return false;
18621862
// Read the CST node header and sanity-check.
1863-
const count = view.getInt32(val, true);
1864-
const matchLength = view.getInt32(val + 4, true);
1865-
return count >= 0 && matchLength >= 0;
1863+
const matchLength = view.getInt32(val, true);
1864+
const count = view.getInt32(val + 8, true);
1865+
return matchLength >= 0 && count >= 0;
18661866
}
18671867

18681868
// Walk forward through all chunks. Every non-zero slot should be a valid

packages/runtime/src/cstReader.ts

Lines changed: 26 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
import {isTaggedTerminal, MATCH_RECORD_TYPE_MASK, MatchRecordType} from './miniohm.ts';
1+
import {
2+
CST_CHILD_COUNT_OFFSET,
3+
CST_CHILDREN_OFFSET,
4+
CST_MATCH_LENGTH_OFFSET,
5+
CST_TYPE_AND_DETAILS_OFFSET,
6+
isTaggedTerminal,
7+
MATCH_RECORD_TYPE_MASK,
8+
MatchRecordType,
9+
} from './miniohm.ts';
210

311
import type {MatchContext, SucceededMatchResult} from './miniohm.ts';
412

@@ -101,7 +109,7 @@ export class CstReader {
101109
if (isSpacesHandle(raw)) return false;
102110
if (isTaggedTerminal(raw)) return true;
103111
return (
104-
((this._ctx.view.getInt32(raw + 8, true) &
112+
((this._ctx.view.getInt32(raw + CST_TYPE_AND_DETAILS_OFFSET, true) &
105113
MATCH_RECORD_TYPE_MASK) as MatchRecordType) === MatchRecordType.TERMINAL
106114
);
107115
}
@@ -111,7 +119,7 @@ export class CstReader {
111119
if (isSpacesHandle(raw)) return true;
112120
if (isTaggedTerminal(raw)) return false;
113121
return (
114-
((this._ctx.view.getInt32(raw + 8, true) &
122+
((this._ctx.view.getInt32(raw + CST_TYPE_AND_DETAILS_OFFSET, true) &
115123
MATCH_RECORD_TYPE_MASK) as MatchRecordType) === MatchRecordType.NONTERMINAL
116124
);
117125
}
@@ -120,7 +128,7 @@ export class CstReader {
120128
const raw = handle & MASK;
121129
if (isSpacesHandle(raw) || isTaggedTerminal(raw)) return false;
122130
return (
123-
((this._ctx.view.getInt32(raw + 8, true) &
131+
((this._ctx.view.getInt32(raw + CST_TYPE_AND_DETAILS_OFFSET, true) &
124132
MATCH_RECORD_TYPE_MASK) as MatchRecordType) === MatchRecordType.ITER_FLAG
125133
);
126134
}
@@ -129,7 +137,7 @@ export class CstReader {
129137
const raw = handle & MASK;
130138
if (isSpacesHandle(raw) || isTaggedTerminal(raw)) return false;
131139
return (
132-
((this._ctx.view.getInt32(raw + 8, true) &
140+
((this._ctx.view.getInt32(raw + CST_TYPE_AND_DETAILS_OFFSET, true) &
133141
MATCH_RECORD_TYPE_MASK) as MatchRecordType) === MatchRecordType.OPTIONAL
134142
);
135143
}
@@ -138,15 +146,15 @@ export class CstReader {
138146
childCount(handle: number): number {
139147
const raw = handle & MASK;
140148
if (isSpacesHandle(raw) || isTaggedTerminal(raw)) return 0;
141-
return this._ctx.view.getUint32(raw, true);
149+
return this._ctx.view.getUint32(raw + CST_CHILD_COUNT_OFFSET, true);
142150
}
143151

144152
/** Length of matched input (in UTF-16 code units). */
145153
matchLength(handle: number): number {
146154
const raw = handle & MASK;
147155
if (isSpacesHandle(raw)) return raw >>> 2;
148156
if (isTaggedTerminal(raw)) return raw >>> 1;
149-
return this._ctx.view.getUint32(raw + 4, true);
157+
return this._ctx.view.getUint32(raw + CST_MATCH_LENGTH_OFFSET, true);
150158
}
151159

152160
/**
@@ -157,10 +165,10 @@ export class CstReader {
157165
const raw = handle & MASK;
158166
if (isSpacesHandle(raw)) return 'spaces';
159167
if (isTaggedTerminal(raw)) return '_terminal';
160-
const type = (this._ctx.view.getInt32(raw + 8, true) &
168+
const type = (this._ctx.view.getInt32(raw + CST_TYPE_AND_DETAILS_OFFSET, true) &
161169
MATCH_RECORD_TYPE_MASK) as MatchRecordType;
162170
if (type === MatchRecordType.NONTERMINAL) {
163-
const ruleId = this._ctx.view.getInt32(raw + 8, true) >>> 2;
171+
const ruleId = this._ctx.view.getInt32(raw + CST_TYPE_AND_DETAILS_OFFSET, true) >>> 2;
164172
return this._ctx.ruleNames[ruleId].split('<')[0];
165173
}
166174
if (type === MatchRecordType.TERMINAL) return '_terminal';
@@ -175,13 +183,13 @@ export class CstReader {
175183
details(handle: number): number {
176184
const raw = handle & MASK;
177185
if (isSpacesHandle(raw) || isTaggedTerminal(raw)) return 0;
178-
return this._ctx.view.getInt32(raw + 8, true) >>> 2;
186+
return this._ctx.view.getInt32(raw + CST_TYPE_AND_DETAILS_OFFSET, true) >>> 2;
179187
}
180188

181189
/** Handle (Wasm pointer) of the i-th raw child. */
182190
childAt(handle: number, i: number): number {
183191
const raw = handle & MASK;
184-
return this._ctx.view.getUint32(raw + 16 + i * 4, true);
192+
return this._ctx.view.getUint32(raw + CST_CHILDREN_OFFSET + i * 4, true);
185193
}
186194

187195
/** Source string for a node. If startIdx is omitted, it is extracted from the handle. */
@@ -227,7 +235,7 @@ export class CstReader {
227235
/** Check whether a raw child handle has parent-level space skipping. */
228236
private _hasParentSpaces(rawChild: number): boolean {
229237
if (isTaggedTerminal(rawChild)) return true;
230-
const type = (this._ctx.view.getInt32(rawChild + 8, true) &
238+
const type = (this._ctx.view.getInt32(rawChild + CST_TYPE_AND_DETAILS_OFFSET, true) &
231239
MATCH_RECORD_TYPE_MASK) as MatchRecordType;
232240
return type === MatchRecordType.NONTERMINAL || type === MatchRecordType.TERMINAL;
233241
}
@@ -238,11 +246,11 @@ export class CstReader {
238246
fn: (child: number, leadingSpaces: number, offset: number, index: number) => void
239247
): void {
240248
if (isTaggedTerminal(handle)) return;
241-
const count = this._ctx.view.getUint32(handle, true);
249+
const count = this._ctx.view.getUint32(handle + CST_CHILD_COUNT_OFFSET, true);
242250
const {getSpacesLenAt} = this._ctx;
243251
let offset = 0;
244252
for (let i = 0; i < count; i++) {
245-
const child = this._ctx.view.getUint32(handle + 16 + i * 4, true);
253+
const child = this._ctx.view.getUint32(handle + CST_CHILDREN_OFFSET + i * 4, true);
246254
const rawSpacesLen =
247255
getSpacesLenAt && this._hasParentSpaces(child)
248256
? Math.max(0, getSpacesLenAt(parentStartIdx + offset))
@@ -251,7 +259,7 @@ export class CstReader {
251259
offset += rawSpacesLen;
252260
const len = isTaggedTerminal(child)
253261
? child >>> 1
254-
: this._ctx.view.getUint32(child + 4, true);
262+
: this._ctx.view.getUint32(child + CST_MATCH_LENGTH_OFFSET, true);
255263
fn(child, leadingSpaces, offset, i);
256264
offset += len;
257265
}
@@ -263,11 +271,11 @@ export class CstReader {
263271
): void {
264272
const raw = handle & MASK;
265273
if (isTaggedTerminal(raw)) return;
266-
const count = this._ctx.view.getUint32(raw, true);
274+
const count = this._ctx.view.getUint32(raw + CST_CHILD_COUNT_OFFSET, true);
267275
let childStart = (handle - raw) / SHIFT;
268276
const {getSpacesLenAt} = this._ctx;
269277
for (let i = 0; i < count; i++) {
270-
const rawChild = this._ctx.view.getUint32(raw + 16 + i * 4, true);
278+
const rawChild = this._ctx.view.getUint32(raw + CST_CHILDREN_OFFSET + i * 4, true);
271279
const rawSpacesLen =
272280
getSpacesLenAt && this._hasParentSpaces(rawChild)
273281
? Math.max(0, getSpacesLenAt(childStart))
@@ -280,7 +288,7 @@ export class CstReader {
280288
const childHandle = childStart * SHIFT + rawChild;
281289
const len = isTaggedTerminal(rawChild)
282290
? rawChild >>> 1
283-
: this._ctx.view.getUint32(rawChild + 4, true);
291+
: this._ctx.view.getUint32(rawChild + CST_MATCH_LENGTH_OFFSET, true);
284292
fn(childHandle, leadingSpaces, childStart, i);
285293
childStart += len;
286294
}

packages/runtime/src/miniohm.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@ import {getLineAndColumn, getLineAndColumnMessage} from './extras.ts';
33

44
export const MATCH_RECORD_TYPE_MASK = 0b11;
55

6+
// Byte offsets for fields in a CST match record (Wasm linear memory layout).
7+
export const CST_MATCH_LENGTH_OFFSET = 0;
8+
export const CST_TYPE_AND_DETAILS_OFFSET = 4;
9+
export const CST_CHILD_COUNT_OFFSET = 8;
10+
export const CST_CHILDREN_OFFSET = 16;
11+
612
// Tagged terminal: (matchLength << 1) | 1. Bit 0 distinguishes from real pointers.
713
export function isTaggedTerminal(handle: number): boolean {
814
return (handle & 1) !== 0;
@@ -584,7 +590,7 @@ class CstNodeImpl implements CstNodeBase {
584590
switch (this.type) {
585591
case CstNodeType.NONTERMINAL: {
586592
const {ruleNames, view} = this._ctx;
587-
const ruleId = view.getInt32(this._base + 8, true) >>> 2;
593+
const ruleId = view.getInt32(this._base + CST_TYPE_AND_DETAILS_OFFSET, true) >>> 2;
588594
return ruleNames[ruleId].split('<')[0];
589595
}
590596
case CstNodeType.TERMINAL:
@@ -598,19 +604,19 @@ class CstNodeImpl implements CstNodeBase {
598604
}
599605
}
600606

601-
get count(): number {
602-
if (isTaggedTerminal(this._base)) return 0;
603-
return this._ctx.view.getUint32(this._base, true);
604-
}
605-
606607
get matchLength(): number {
607608
if (isTaggedTerminal(this._base)) return this._base >>> 1;
608-
return this._ctx.view.getUint32(this._base + 4, true);
609+
return this._ctx.view.getUint32(this._base + CST_MATCH_LENGTH_OFFSET, true);
609610
}
610611

611612
get _typeAndDetails(): number {
612613
if (isTaggedTerminal(this._base)) return MatchRecordType.TERMINAL;
613-
return this._ctx.view.getInt32(this._base + 8, true);
614+
return this._ctx.view.getInt32(this._base + CST_TYPE_AND_DETAILS_OFFSET, true);
615+
}
616+
617+
get count(): number {
618+
if (isTaggedTerminal(this._base)) return 0;
619+
return this._ctx.view.getUint32(this._base + CST_CHILD_COUNT_OFFSET, true);
614620
}
615621

616622
get arity(): number {
@@ -658,7 +664,7 @@ class CstNodeImpl implements CstNodeBase {
658664
let {startIdx} = this;
659665
const {getSpacesLenAt} = this._ctx;
660666
for (let i = 0; i < this.count; i++) {
661-
const slotOffset = this._base + 16 + i * 4;
667+
const slotOffset = this._base + CST_CHILDREN_OFFSET + i * 4;
662668
const ptr = this._ctx.view.getUint32(slotOffset, true);
663669

664670
if (isTaggedTerminal(ptr)) {
@@ -680,7 +686,7 @@ class CstNodeImpl implements CstNodeBase {
680686
// Only query spaces for terminals and nonterminals — not for
681687
// iteration (ITER_FLAG) or optional nodes, which handle space
682688
// skipping internally.
683-
const type = (this._ctx.view.getInt32(ptr + 8, true) &
689+
const type = (this._ctx.view.getInt32(ptr + CST_TYPE_AND_DETAILS_OFFSET, true) &
684690
MATCH_RECORD_TYPE_MASK) as MatchRecordType;
685691
let spacesLen = 0;
686692
if (

packages/runtime/src/unstableDebug.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,8 @@ function walkRecordTree(
7878
const ptr = stack.pop()!;
7979
stats.count++;
8080

81-
const count = view.getUint32(ptr, true);
82-
const typeAndDetails = view.getInt32(ptr + 8, true);
81+
const count = view.getUint32(ptr + 8, true);
82+
const typeAndDetails = view.getInt32(ptr + 4, true);
8383
const type = typeAndDetails & MATCH_RECORD_TYPE_MASK;
8484

8585
// Each match record: 16-byte header + count * 4 bytes of child pointers.

0 commit comments

Comments
 (0)