@samitouri / QOS-React / commits / 9948e389f1

Opaque InstructionId type

[ghstack-poisoned] closes #797

Joseph Savona committed Nov 21, 2022 at 11:47 UTC 9948e389f15596be642e006c92f1c4c35968082c
6 files changed +65 -32
compiler/forget/src/HIR/BuildHIR.ts
+14 -13
@@ -17,6 +17,7 @@ import {
17 IfTerminal,
18 InstructionKind,
19 InstructionValue,
20 + makeInstructionId,
21 Place,
22 ReturnTerminal,
23 SourceLocation,
@@ -606,7 +607,7 @@ function lowerStatement(
607 };
608 }
609 builder.push({
609 - id: 0,
610 + id: makeInstructionId(0),
611 lvalue: { place: id, kind },
612 value,
613 loc: declaration.node.loc ?? GeneratedSource,
@@ -623,7 +624,7 @@ function lowerStatement(
624 return;
625 }
626 builder.push({
626 - id: 0,
627 + id: makeInstructionId(0),
628 lvalue: null,
629 value,
630 loc: stmt.node.loc ?? GeneratedSource,
@@ -662,7 +663,7 @@ function lowerStatement(
663 case "TSTypeAliasDeclaration":
664 case "WithStatement": {
665 builder.push({
665 - id: 0,
666 + id: makeInstructionId(0),
667 lvalue: null,
668 loc: stmtPath.node.loc ?? GeneratedSource,
669 value: {
@@ -862,7 +863,7 @@ function lowerExpression(
863 loc: left.loc,
864 };
865 builder.push({
865 - id: 0,
866 + id: makeInstructionId(0),
867 value: {
868 kind: "Primitive",
869 value: null,
@@ -880,7 +881,7 @@ function lowerExpression(
881 loc: left.loc,
882 };
883 builder.push({
883 - id: 0,
884 + id: makeInstructionId(0),
885 lvalue: {
886 place: { ...condPlace },
887 kind: InstructionKind.Const,
@@ -918,7 +919,7 @@ function lowerExpression(
919 if (operator === "=") {
920 const right = lowerExpression(builder, expr.get("right"));
921 builder.push({
921 - id: 0,
922 + id: makeInstructionId(0),
923 lvalue: { place: left, kind: InstructionKind.Reassign },
924 value: right,
925 loc: exprLoc,
@@ -948,7 +949,7 @@ function lowerExpression(
949
950 const right = lowerExpressionToPlace(builder, expr.get("right"));
951 builder.push({
951 - id: 0,
952 + id: makeInstructionId(0),
953 lvalue: { place: left, kind: InstructionKind.Reassign },
954 value: {
955 kind: "BinaryExpression",
@@ -1059,7 +1060,7 @@ function lowerConditional(
1060 const consequentBlock = builder.enter((blockId) => {
1061 let value = consequent();
1062 builder.push({
1062 - id: 0,
1063 + id: makeInstructionId(0),
1064 value,
1065 lvalue: { place: { ...place }, kind: InstructionKind.Const },
1066 loc: value.loc,
@@ -1074,7 +1075,7 @@ function lowerConditional(
1075 const alternateBlock = builder.enter((blockId) => {
1076 let value = alternate();
1077 builder.push({
1077 - id: 0,
1078 + id: makeInstructionId(0),
1079 value,
1080 lvalue: { place: { ...place }, kind: InstructionKind.Const },
1081 loc: value.loc,
@@ -1131,7 +1132,7 @@ function lowerJsxElementName(
1132 loc: exprLoc,
1133 };
1134 builder.push({
1134 - id: 0,
1135 + id: makeInstructionId(0),
1136 value: {
1137 kind: "Primitive",
1138 value: tag,
@@ -1171,7 +1172,7 @@ function lowerJsxElement(
1172 loc: exprLoc,
1173 };
1174 builder.push({
1174 - id: 0,
1175 + id: makeInstructionId(0),
1176 value: {
1177 kind: "JSXText",
1178 value: exprPath.node.value,
@@ -1194,7 +1195,7 @@ function lowerJsxElement(
1195 loc: exprLoc,
1196 };
1197 builder.push({
1197 - id: 0,
1198 + id: makeInstructionId(0),
1199 value: {
1200 kind: "OtherStatement",
1201 node: exprNode,
@@ -1224,7 +1225,7 @@ function lowerExpressionToPlace(
1225 loc: exprLoc,
1226 };
1227 builder.push({
1227 - id: 0,
1228 + id: makeInstructionId(0),
1229 value: instr,
1230 loc: exprLoc,
1231 lvalue: { place: { ...place }, kind: InstructionKind.Const },
compiler/forget/src/HIR/EnterSSA.ts
+3 -2
@@ -4,6 +4,7 @@ import {
4 HIRFunction,
5 Identifier,
6 IdentifierId,
7 + makeInstructionId,
8 Phi,
9 Place,
10 } from "./HIR";
@@ -53,8 +54,8 @@ class SSABuilder {
54 preSsaId: oldId.id,
55 name: oldId.name,
56 mutableRange: {
56 - start: 0,
57 - end: 0,
57 + start: makeInstructionId(0),
58 + end: makeInstructionId(0),
59 },
60 scope: null, // reset along w the mutable range
61 };
compiler/forget/src/HIR/HIR.ts
+18 -3
@@ -170,7 +170,7 @@ export type WhileTerminal = {
170 * or may occur only for side-effects (many expression statements).
171 */
172 export type Instruction = {
173 - id: number;
173 + id: InstructionId;
174 lvalue: LValue | null;
175 value: InstructionValue;
176 loc: SourceLocation;
@@ -270,8 +270,8 @@ export type Primitive = {
270 * the value is not mutable).
271 */
272 export type MutableRange = {
273 - start: number;
274 - end: number;
273 + start: InstructionId;
274 + end: InstructionId;
275 };
276
277 /**
@@ -360,3 +360,18 @@ export function makeIdentifierId(id: number): IdentifierId {
360 );
361 return id as IdentifierId;
362 }
363 +
364 +/**
365 + * Simulated opaque type for InstructionId to prevent using normal numbers as ids
366 + * accidentally.
367 + */
368 +const opaqueInstructionId = Symbol();
369 +export type InstructionId = number & { [opaqueInstructionId]: "IdentifierId" };
370 +
371 +export function makeInstructionId(id: number): InstructionId {
372 + invariant(
373 + id >= 0 && Number.isInteger(id),
374 + "Expected instruction id to be a non-negative integer"
375 + );
376 + return id as InstructionId;
377 +}
compiler/forget/src/HIR/HIRBuilder.ts
+7 -3
@@ -18,6 +18,7 @@ import {
18 Instruction,
19 makeBlockId,
20 makeIdentifierId,
21 + makeInstructionId,
22 Terminal,
23 } from "./HIR";
24 import { printInstruction } from "./PrintHIR";
@@ -112,7 +113,7 @@ export default class HIRBuilder {
113 preSsaId: null,
114 id,
115 name: null,
115 - mutableRange: { start: 0, end: 0 },
116 + mutableRange: { start: makeInstructionId(0), end: makeInstructionId(0) },
117 scope: null,
118 };
119 }
@@ -125,7 +126,10 @@ export default class HIRBuilder {
126 preSsaId: null,
127 id,
128 name: node.name,
128 - mutableRange: { start: 0, end: 0 },
129 + mutableRange: {
130 + start: makeInstructionId(0),
131 + end: makeInstructionId(0),
132 + },
133 scope: null,
134 };
135 this.#bindings.set(node, identifier);
@@ -502,7 +506,7 @@ function markInstructionIds(func: HIR) {
506 for (const [_, block] of func.blocks) {
507 for (const instr of block.instructions) {
508 invariant(instr.id === 0, `${printInstruction(instr)} already visited!`);
505 - instr.id = ++id;
509 + instr.id = makeInstructionId(++id);
510 }
511 }
512 }
compiler/forget/src/HIR/InferMutableLifetimes.ts
+17 -7
@@ -8,7 +8,15 @@
8 import invariant from "invariant";
9 import { assertExhaustive } from "../Common/utils";
10 import DisjointSet from "./DisjointSet";
11 -import { Effect, HIRFunction, Identifier, Instruction, Place } from "./HIR";
11 +import {
12 + Effect,
13 + HIRFunction,
14 + Identifier,
15 + Instruction,
16 + InstructionId,
17 + makeInstructionId,
18 + Place,
19 +} from "./HIR";
20 import { printInstruction, printPlace } from "./PrintHIR";
21 import { eachInstructionOperand } from "./visitors";
22
@@ -68,7 +76,7 @@ function inferPlace(place: Place, instr: Instruction) {
76 case Effect.Freeze:
77 return;
78 case Effect.Mutate: {
71 - place.identifier.mutableRange.end = instr.id + 1;
79 + place.identifier.mutableRange.end = makeInstructionId(instr.id + 1);
80 return;
81 }
82 default:
@@ -92,8 +100,8 @@ export function inferMutableRanges(func: HIRFunction) {
100 "Expected phi to have set start/end range values"
101 );
102 phi.id.mutableRange = {
95 - start,
96 - end,
103 + start: makeInstructionId(start),
104 + end: makeInstructionId(end),
105 };
106 }
107
@@ -126,7 +134,7 @@ export function inferMutableRanges(func: HIRFunction) {
134
135 // Let's be optimistic and assume this lvalue is not mutable by
136 // default.
129 - lvalueId.mutableRange.end = instr.id + 1;
137 + lvalueId.mutableRange.end = makeInstructionId(instr.id + 1);
138 } else {
139 inferPlace(instr.lvalue.place, instr);
140 }
@@ -138,7 +146,7 @@ export function inferMutableRanges(func: HIRFunction) {
146 // Store the mutable range and set of identifiers for each scope
147 const aliasIndentifiers: Map<
148 number,
141 - { end: number; identifiers: Set<Identifier> }
149 + { end: InstructionId; identifiers: Set<Identifier> }
150 > = new Map();
151
152 aliases.forEach((identifier, groupIdentifier) => {
@@ -156,7 +164,9 @@ export function inferMutableRanges(func: HIRFunction) {
164 };
165 aliasIndentifiers.set(aliasId, alias);
166 } else {
159 - alias.end = Math.max(alias.end, identifier.mutableRange.end);
167 + alias.end = makeInstructionId(
168 + Math.max(alias.end, identifier.mutableRange.end)
169 + );
170 }
171 alias.identifiers.add(identifier);
172 });
compiler/forget/src/HIR/InferReactiveScopeVariables.ts
+6 -4
@@ -10,6 +10,7 @@ import {
10 HIRFunction,
11 Identifier,
12 Instruction,
13 + makeInstructionId,
14 makeScopeId,
15 MutableRange,
16 Place,
@@ -125,11 +126,12 @@ export function inferReactiveScopeVariables(fn: HIRFunction) {
126 };
127 scopeVariables.set(scopeId, scope);
128 } else {
128 - scope.range.start = Math.min(
129 - scope.range.start,
130 - identifier.mutableRange.start
129 + scope.range.start = makeInstructionId(
130 + Math.min(scope.range.start, identifier.mutableRange.start)
131 + );
132 + scope.range.end = makeInstructionId(
133 + Math.max(scope.range.end, identifier.mutableRange.end)
134 );
132 - scope.range.end = Math.max(scope.range.end, identifier.mutableRange.end);
135 }
136 scope.variables.add(identifier);
137 });