Add optimization for generator bodies that don't introduce new members (#1013)

If a generator object literal doesn't add any object members, we
can simply use the parent in its place.

Co-authored-by: Kushal Pisavadia <kushi.p@gmail.com>
This commit is contained in:
Daniel Chao
2025-03-05 10:25:54 -08:00
committed by GitHub
parent bf484b3431
commit 18e7a7e87e
4 changed files with 94 additions and 0 deletions

View File

@@ -73,6 +73,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode {
@Specialization(guards = "checkObjectCannotHaveParameters()")
protected VmDynamic evalDynamic(VirtualFrame frame, VmDynamic parent) {
var data = executeChildren(frame, parent, parent.getLength());
if (data.hasNoMembers()) {
return parent;
}
var result = new VmDynamic(frame.materialize(), parent, data.members(), data.length());
return data.storeGeneratorFrames(result);
}
@@ -81,6 +84,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode {
protected VmTyped evalTyped(VirtualFrame frame, VmTyped parent) {
VmUtils.checkIsInstantiable(parent.getVmClass(), getParentNode());
var data = executeChildren(frame, parent, 0);
if (data.hasNoMembers()) {
return parent;
}
assert data.hasNoGeneratorFrames();
return new VmTyped(frame.materialize(), parent, parent.getVmClass(), data.members());
}
@@ -88,6 +94,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode {
@Specialization(guards = "checkListingCannotHaveParameters()")
protected VmListing evalListing(VirtualFrame frame, VmListing parent) {
var data = executeChildren(frame, parent, parent.getLength());
if (data.hasNoMembers()) {
return parent;
}
var result = new VmListing(frame.materialize(), parent, data.members(), data.length());
return data.storeGeneratorFrames(result);
}
@@ -95,6 +104,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode {
@Specialization(guards = "checkMappingCannotHaveParameters()")
protected VmMapping evalMapping(VirtualFrame frame, VmMapping parent) {
var data = executeChildren(frame, parent, 0);
if (data.hasNoMembers()) {
return parent;
}
var result = new VmMapping(frame.materialize(), parent, data.members());
return data.storeGeneratorFrames(result);
}
@@ -118,6 +130,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode {
@Specialization(guards = {"parent == getDynamicClass()", "checkObjectCannotHaveParameters()"})
protected VmDynamic evalDynamicClass(VirtualFrame frame, VmClass parent) {
var data = executeChildren(frame, parent, 0);
if (data.hasNoMembers()) {
return VmDynamic.empty();
}
var result =
new VmDynamic(frame.materialize(), parent.getPrototype(), data.members(), data.length());
return data.storeGeneratorFrames(result);
@@ -126,6 +141,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode {
@Specialization(guards = {"parent == getMappingClass()", "checkMappingCannotHaveParameters()"})
protected VmMapping evalMappingClass(VirtualFrame frame, VmClass parent) {
var data = executeChildren(frame, parent, 0);
if (data.hasNoMembers()) {
return VmMapping.empty();
}
var result = new VmMapping(frame.materialize(), parent.getPrototype(), data.members());
return data.storeGeneratorFrames(result);
}
@@ -133,6 +151,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode {
@Specialization(guards = {"parent == getListingClass()", "checkListingCannotHaveParameters()"})
protected VmListing evalListingClass(VirtualFrame frame, VmClass parent) {
var data = executeChildren(frame, parent, 0);
if (data.hasNoMembers()) {
return VmListing.empty();
}
var result =
new VmListing(frame.materialize(), parent.getPrototype(), data.members(), data.length());
return data.storeGeneratorFrames(result);
@@ -142,6 +163,9 @@ public abstract class GeneratorObjectLiteralNode extends ObjectLiteralNode {
protected VmTyped evalTypedObjectClass(VirtualFrame frame, VmClass parent) {
VmUtils.checkIsInstantiable(parent, getParentNode());
var data = executeChildren(frame, parent, 0);
if (data.hasNoMembers()) {
return parent.getPrototype();
}
assert data.hasNoGeneratorFrames();
return new VmTyped(frame.materialize(), parent.getPrototype(), parent, data.members());
}

View File

@@ -55,6 +55,10 @@ public final class ObjectData {
return length;
}
boolean hasNoMembers() {
return members.isEmpty();
}
boolean hasNoGeneratorFrames() {
return generatorFrames.isEmpty();
}

View File

@@ -0,0 +1,46 @@
// should only result in one trace in the output; generator object literals that don't add any
// members should be optimized away.
res1 {
prop = trace("hello")
}
res2 = (res1) {
when (false) {
prop2 = 2
}
}
res3 = (res1) {
for (_ in List()) {
"hello"
}
}
res4 = (res1) {
...List()
}
res5 = (res1) {
when (true) {
} else {
prop3 = 3
}
}
res6 = (Dynamic) {
when (true) {}
}
res7 = (Mapping) {
when (true) {}
}
class Person {}
res8 = (Person) {
when (true) {}
}
res9 = (Listing) {
when (true) {}
}

View File

@@ -0,0 +1,20 @@
res1 {
prop = "hello"
}
res2 {
prop = "hello"
}
res3 {
prop = "hello"
}
res4 {
prop = "hello"
}
res5 {
prop = "hello"
}
res6 {}
res7 {}
res8 {}
res9 {}
pkl: TRACE: "hello" = "hello" (file:///$snippetsDir/input/generators/generatorNoMembers.pkl)