mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
TryStatement: maybe-throw terminal for per-instruction throw points
Adds a "maybe-throw" terminal which represents the possibility that the block may or may not throw, and can either continue forward or exit to an exception handler (`catch`). Also updates HIRBuilder to track the current mode, and when inside a try block to wrap every instruction inside a basic block that ends in a maybe-throw. So far this code isn't used yet, so doesn't affect output.
This commit is contained in:
@@ -279,7 +279,8 @@ export type Terminal =
|
||||
| TernaryTerminal
|
||||
| OptionalTerminal
|
||||
| LabelTerminal
|
||||
| SequenceTerminal;
|
||||
| SequenceTerminal
|
||||
| MaybeThrowTerminal;
|
||||
|
||||
function _staticInvariantTerminalHasLocation(
|
||||
terminal: Terminal
|
||||
@@ -444,6 +445,14 @@ export type SequenceTerminal = {
|
||||
loc: SourceLocation;
|
||||
};
|
||||
|
||||
export type MaybeThrowTerminal = {
|
||||
kind: "maybe-throw";
|
||||
continuation: BlockId;
|
||||
handler: BlockId;
|
||||
id: InstructionId;
|
||||
loc: SourceLocation;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instructions generally represent expressions but with all nesting flattened away,
|
||||
* such that all operands to each instruction are either primitive values OR are
|
||||
|
||||
@@ -77,6 +77,17 @@ export type Bindings = Map<
|
||||
{ node: t.Identifier; identifier: Identifier }
|
||||
>;
|
||||
|
||||
// Determines how instructions should be constructed in order to preserve
|
||||
// exception semantics
|
||||
type ExceptionsMode =
|
||||
// Mode used for code not covered by explicit exception handling, any
|
||||
// errors are assumed to be thrown out of the function
|
||||
| { kind: "ThrowExceptions" }
|
||||
// Mode used for code that *is* covered by explicit exception handling
|
||||
// (ie try/catch), which requires modeling the possibility of control
|
||||
// flow to the exception handler.
|
||||
| { kind: "CatchExceptions"; handler: BlockId };
|
||||
|
||||
/**
|
||||
* Helper class for constructing a CFG
|
||||
*/
|
||||
@@ -88,6 +99,7 @@ export default class HIRBuilder {
|
||||
#context: t.Identifier[];
|
||||
#bindings: Bindings;
|
||||
#env: Environment;
|
||||
#mode: ExceptionsMode = { kind: "ThrowExceptions" };
|
||||
parentFunction: NodePath<t.Function>;
|
||||
errors: CompilerError = new CompilerError();
|
||||
|
||||
@@ -130,6 +142,20 @@ export default class HIRBuilder {
|
||||
*/
|
||||
push(instruction: Instruction): void {
|
||||
this.#current.instructions.push(instruction);
|
||||
if (this.#mode.kind === "CatchExceptions") {
|
||||
const handler = this.#mode.handler;
|
||||
const continuationBlock = this.reserve(this.currentBlockKind());
|
||||
this.terminateWithContinuation(
|
||||
{
|
||||
kind: "maybe-throw",
|
||||
continuation: continuationBlock.id,
|
||||
handler,
|
||||
id: makeInstructionId(0),
|
||||
loc: instruction.loc,
|
||||
},
|
||||
continuationBlock
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
makeTemporary(): Identifier {
|
||||
@@ -723,6 +749,11 @@ export function reversePostorderBlocks(func: HIR): void {
|
||||
visit(terminal.block);
|
||||
break;
|
||||
}
|
||||
case "maybe-throw": {
|
||||
visit(terminal.handler);
|
||||
visit(terminal.continuation);
|
||||
break;
|
||||
}
|
||||
case "unsupported": {
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -80,6 +80,7 @@ export function printMixedHIR(
|
||||
return printInstruction(value);
|
||||
}
|
||||
switch (value.kind) {
|
||||
case "maybe-throw":
|
||||
case "sequence":
|
||||
case "label":
|
||||
case "optional":
|
||||
@@ -230,6 +231,10 @@ export function printTerminal(terminal: Terminal): Array<string> | string {
|
||||
value = `Unsupported`;
|
||||
break;
|
||||
}
|
||||
case "maybe-throw": {
|
||||
value = `MaybeThrow continuation=bb${terminal.continuation} handler=bb${terminal.handler}`;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assertExhaustive(
|
||||
terminal,
|
||||
|
||||
@@ -731,6 +731,17 @@ export function mapTerminalSuccessors(
|
||||
loc: terminal.loc,
|
||||
};
|
||||
}
|
||||
case "maybe-throw": {
|
||||
const continuation = fn(terminal.continuation);
|
||||
const handler = fn(terminal.handler);
|
||||
return {
|
||||
kind: "maybe-throw",
|
||||
continuation,
|
||||
handler,
|
||||
id: makeInstructionId(0),
|
||||
loc: terminal.loc,
|
||||
};
|
||||
}
|
||||
case "unsupported": {
|
||||
return terminal;
|
||||
}
|
||||
@@ -750,6 +761,7 @@ export function mapTerminalSuccessors(
|
||||
*/
|
||||
export function terminalFallthrough(terminal: Terminal): BlockId | null {
|
||||
switch (terminal.kind) {
|
||||
case "maybe-throw":
|
||||
case "branch":
|
||||
case "goto":
|
||||
case "return":
|
||||
@@ -784,6 +796,7 @@ export function mapOptionalFallthroughs(
|
||||
fn: (block: BlockId) => BlockId | null
|
||||
): void {
|
||||
switch (terminal.kind) {
|
||||
case "maybe-throw":
|
||||
case "branch":
|
||||
case "goto":
|
||||
case "return":
|
||||
@@ -917,6 +930,11 @@ export function* eachTerminalSuccessor(terminal: Terminal): Iterable<BlockId> {
|
||||
yield terminal.block;
|
||||
break;
|
||||
}
|
||||
case "maybe-throw": {
|
||||
yield terminal.continuation;
|
||||
yield terminal.handler;
|
||||
break;
|
||||
}
|
||||
case "unsupported":
|
||||
break;
|
||||
default: {
|
||||
@@ -956,6 +974,7 @@ export function mapTerminalOperands(
|
||||
terminal.value = fn(terminal.value);
|
||||
break;
|
||||
}
|
||||
case "maybe-throw":
|
||||
case "sequence":
|
||||
case "label":
|
||||
case "optional":
|
||||
@@ -1004,6 +1023,7 @@ export function* eachTerminalOperand(terminal: Terminal): Iterable<Place> {
|
||||
yield terminal.value;
|
||||
break;
|
||||
}
|
||||
case "maybe-throw":
|
||||
case "sequence":
|
||||
case "label":
|
||||
case "optional":
|
||||
|
||||
+7
@@ -636,6 +636,13 @@ class Driver {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "maybe-throw": {
|
||||
this.visitBlock(
|
||||
this.cx.ir.blocks.get(terminal.continuation)!,
|
||||
blockValue
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "unsupported": {
|
||||
CompilerError.invariant(false, {
|
||||
reason: "Unexpected unsupported terminal",
|
||||
|
||||
@@ -139,6 +139,7 @@ function printTerminalLabel(terminal: Terminal): string {
|
||||
buffer.push("Sequence");
|
||||
break;
|
||||
}
|
||||
case "maybe-throw":
|
||||
case "unsupported": {
|
||||
break;
|
||||
}
|
||||
@@ -246,6 +247,7 @@ function printTerminalArrows(blockId: BlockId, terminal: Terminal): string {
|
||||
buffer.push(printJumpArrow(blockId, terminal.fallthrough, "fallthrough"));
|
||||
break;
|
||||
}
|
||||
case "maybe-throw":
|
||||
case "throw":
|
||||
case "return":
|
||||
case "unsupported": {
|
||||
|
||||
Reference in New Issue
Block a user