PropertyDelete/ComputedDelete instructions

This commit is contained in:
Joe Savona
2023-03-08 12:04:27 -08:00
parent 0363648178
commit f985d6cdba
13 changed files with 233 additions and 30 deletions
+35 -6
View File
@@ -1560,12 +1560,41 @@ function lowerExpression(
}
case "UnaryExpression": {
let expr = exprPath as NodePath<t.UnaryExpression>;
return {
kind: "UnaryExpression",
operator: expr.node.operator,
value: lowerExpressionToTemporary(builder, expr.get("argument")),
loc: exprLoc,
};
if (expr.node.operator === "delete") {
const argument = expr.get("argument");
if (argument.isMemberExpression()) {
const { object, property } = lowerMemberExpression(builder, argument);
if (typeof property === "string") {
return {
kind: "PropertyDelete",
object,
property,
loc: exprLoc,
};
} else {
return {
kind: "ComputedDelete",
object,
property,
loc: exprLoc,
};
}
} else {
builder.errors.push({
reason: `(BuildHIR::lowerExpression) delete on a non-member expression has no semantic meaning`,
severity: ErrorSeverity.InvalidInput,
nodePath: expr,
});
return { kind: "UnsupportedNode", node: expr.node, loc: exprLoc };
}
} else {
return {
kind: "UnaryExpression",
operator: expr.node.operator,
value: lowerExpressionToTemporary(builder, expr.get("argument")),
loc: exprLoc,
};
}
}
case "TypeCastExpression": {
let expr = exprPath as NodePath<t.TypeCastExpression>;
+14
View File
@@ -544,6 +544,13 @@ export type InstructionValue =
optional: boolean;
loc: SourceLocation;
}
// `delete object.property`
| {
kind: "PropertyDelete";
object: Place;
property: string;
loc: SourceLocation;
}
// store `object[index] = value` - like PropertyStore but with a dynamic property
| {
@@ -560,6 +567,13 @@ export type InstructionValue =
property: Place;
loc: SourceLocation;
}
// `delete object[property]`
| {
kind: "ComputedDelete";
object: Place;
property: Place;
loc: SourceLocation;
}
| { kind: "LoadGlobal"; name: string; loc: SourceLocation }
| FunctionExpression
| {
+12
View File
@@ -351,6 +351,12 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
} = ${printPlace(instrValue.value)}`;
break;
}
case "PropertyDelete": {
value = `PropertyDelete ${printPlace(instrValue.object)}.${
instrValue.property
}`;
break;
}
case "ComputedLoad": {
value = `ComputedLoad ${printPlace(instrValue.object)}[${printPlace(
instrValue.property
@@ -363,6 +369,12 @@ export function printInstructionValue(instrValue: ReactiveValue): string {
)}] = ${printPlace(instrValue.value)}`;
break;
}
case "ComputedDelete": {
value = `ComputedDelete ${printPlace(instrValue.object)}[${printPlace(
instrValue.property
)}]`;
break;
}
case "FunctionExpression": {
const fn = printFunction(instrValue.loweredFunc)
.split("\n")
+18
View File
@@ -80,6 +80,10 @@ export function* eachInstructionValueOperand(
yield instrValue.object;
break;
}
case "PropertyDelete": {
yield instrValue.object;
break;
}
case "PropertyStore": {
yield instrValue.object;
yield instrValue.value;
@@ -90,6 +94,11 @@ export function* eachInstructionValueOperand(
yield instrValue.property;
break;
}
case "ComputedDelete": {
yield instrValue.object;
yield instrValue.property;
break;
}
case "ComputedStore": {
yield instrValue.object;
yield instrValue.property;
@@ -254,6 +263,10 @@ export function mapInstructionOperands(
instrValue.object = fn(instrValue.object);
break;
}
case "PropertyDelete": {
instrValue.object = fn(instrValue.object);
break;
}
case "PropertyStore": {
instrValue.object = fn(instrValue.object);
instrValue.value = fn(instrValue.value);
@@ -264,6 +277,11 @@ export function mapInstructionOperands(
instrValue.property = fn(instrValue.property);
break;
}
case "ComputedDelete": {
instrValue.object = fn(instrValue.object);
instrValue.property = fn(instrValue.property);
break;
}
case "ComputedStore": {
instrValue.object = fn(instrValue.object);
instrValue.property = fn(instrValue.property);
@@ -716,6 +716,12 @@ function inferBlock(
lvalue.effect = Effect.Store;
continue;
}
case "PropertyDelete": {
// `delete` returns a boolean (immutable) and modifies the object
valueKind = ValueKind.Immutable;
effectKind = Effect.Mutate;
break;
}
case "PropertyLoad": {
if (!state.isDefined(instrValue.object)) {
// TODO @josephsavona: improve handling of globals
@@ -749,6 +755,13 @@ function inferBlock(
lvalue.effect = Effect.Store;
continue;
}
case "ComputedDelete": {
state.reference(instrValue.object, Effect.Mutate);
state.reference(instrValue.property, Effect.Read);
state.initialize(instrValue, ValueKind.Immutable);
state.reference(instr.lvalue, Effect.Mutate);
continue;
}
case "ComputedLoad": {
if (!state.isDefined(instrValue.object)) {
// TODO @josephsavona: improve handling of globals
@@ -175,8 +175,10 @@ function pruneableValue(
return true;
}
case "CallExpression":
case "ComputedDelete":
case "ComputedCall":
case "ComputedStore":
case "PropertyDelete":
case "PropertyCall":
case "PropertyStore": {
// Mutating instructions are not safe to prune.
@@ -711,6 +711,16 @@ function codegenInstructionValue(
}
break;
}
case "PropertyDelete": {
value = t.unaryExpression(
"delete",
t.memberExpression(
codegenPlace(cx, instrValue.object),
t.identifier(instrValue.property)
)
);
break;
}
case "ComputedStore": {
value = t.assignmentExpression(
"=",
@@ -731,6 +741,17 @@ function codegenInstructionValue(
);
break;
}
case "ComputedDelete": {
value = t.unaryExpression(
"delete",
t.memberExpression(
codegenPlace(cx, instrValue.object),
codegenPlace(cx, instrValue.property),
true
)
);
break;
}
case "LoadLocal": {
value = codegenPlace(cx, instrValue.place);
break;
@@ -205,7 +205,9 @@ function mayAllocate(value: InstructionValue): boolean {
case "BinaryExpression":
case "LoadLocal":
case "PropertyLoad":
case "PropertyDelete":
case "ComputedLoad":
case "ComputedDelete":
case "JSXText":
case "UnaryExpression":
case "TemplateLiteral":
@@ -0,0 +1,35 @@
## Input
```javascript
function Component(props) {
const x = { a: props.a, b: props.b };
const key = "b";
delete x[key];
return x;
}
```
## Code
```javascript
function Component(props) {
const $ = React.unstable_useMemoCache(3);
const c_0 = $[0] !== props.a;
const c_1 = $[1] !== props.b;
let x;
if (c_0 || c_1) {
x = { a: props.a, b: props.b };
delete x["b"];
$[0] = props.a;
$[1] = props.b;
$[2] = x;
} else {
x = $[2];
}
return x;
}
```
@@ -0,0 +1,6 @@
function Component(props) {
const x = { a: props.a, b: props.b };
const key = "b";
delete x[key];
return x;
}
@@ -0,0 +1,34 @@
## Input
```javascript
function Component(props) {
const x = { a: props.a, b: props.b };
delete x.b;
return x;
}
```
## Code
```javascript
function Component(props) {
const $ = React.unstable_useMemoCache(3);
const c_0 = $[0] !== props.a;
const c_1 = $[1] !== props.b;
let x;
if (c_0 || c_1) {
x = { a: props.a, b: props.b };
delete x.b;
$[0] = props.a;
$[1] = props.b;
$[2] = x;
} else {
x = $[2];
}
return x;
}
```
@@ -0,0 +1,5 @@
function Component(props) {
const x = { a: props.a, b: props.b };
delete x.b;
return x;
}
@@ -20,44 +20,56 @@ function component(a) {
```javascript
function component(a) {
const $ = React.unstable_useMemoCache(10);
const $ = React.unstable_useMemoCache(14);
const c_0 = $[0] !== a;
let t0;
let t;
let z;
let p;
let q;
if (c_0) {
t0 = { t: a };
t = { t: a };
z = +t.t;
q = -t.t;
p = void t.t;
t0 = delete t.t;
$[0] = a;
$[1] = t0;
$[2] = t;
$[3] = z;
$[4] = p;
$[5] = q;
} else {
t0 = $[1];
t = $[2];
z = $[3];
p = $[4];
q = $[5];
}
const t = t0;
const z = +t.t;
const q = -t.t;
const p = void t.t;
const n = delete t.t;
const n = t0;
const m = !t.t;
const e = ~t.t;
const f = typeof t.t;
const c_2 = $[2] !== z;
const c_3 = $[3] !== p;
const c_4 = $[4] !== q;
const c_5 = $[5] !== n;
const c_6 = $[6] !== m;
const c_7 = $[7] !== e;
const c_8 = $[8] !== f;
const c_6 = $[6] !== z;
const c_7 = $[7] !== p;
const c_8 = $[8] !== q;
const c_9 = $[9] !== n;
const c_10 = $[10] !== m;
const c_11 = $[11] !== e;
const c_12 = $[12] !== f;
let t1;
if (c_2 || c_3 || c_4 || c_5 || c_6 || c_7 || c_8) {
if (c_6 || c_7 || c_8 || c_9 || c_10 || c_11 || c_12) {
t1 = { z, p, q, n, m, e, f };
$[2] = z;
$[3] = p;
$[4] = q;
$[5] = n;
$[6] = m;
$[7] = e;
$[8] = f;
$[9] = t1;
$[6] = z;
$[7] = p;
$[8] = q;
$[9] = n;
$[10] = m;
$[11] = e;
$[12] = f;
$[13] = t1;
} else {
t1 = $[9];
t1 = $[13];
}
return t1;
}