Deduplicate object creation code in a non-branched setting (#2302)

Summary:
This pull request breaks out the first part of #2185, which deduplicates object creation when leaking is unconditional to begin with. No changes are made to how leaking works. Only to how leak information is used by the serializer and visitor.
Pull Request resolved: https://github.com/facebook/prepack/pull/2302

Differential Revision: D8997109

Pulled By: sb98052

fbshipit-source-id: e0ea2e7ea574a9f2be71b70be289831c7f797d9d
This commit is contained in:
Sapan Bhatia 2018-07-25 11:35:52 -07:00 committed by Facebook Github Bot
parent b0fe89e863
commit 3bcd3fb4ee
8 changed files with 135 additions and 0 deletions

View File

@ -324,11 +324,20 @@ export class ResidualHeapSerializer {
);
}
// TODO #2259: Make deduplication in the face of leaking work for custom accessors
let isCertainlyLeaked = !obj.mightNotBeHavocedObject();
let shouldDropAsAssignedProp = (descriptor: Descriptor | void) =>
isCertainlyLeaked && (descriptor !== undefined && (descriptor.get === undefined && descriptor.set === undefined));
// inject properties
for (let [key, propertyBinding] of properties) {
invariant(propertyBinding);
if (propertyBinding.pathNode !== undefined) continue; // Property is assigned to inside loop
let desc = propertyBinding.descriptor;
if (shouldDropAsAssignedProp(desc)) continue;
if (desc === undefined) continue; //deleted
if (this.residualHeapInspector.canIgnoreProperty(obj, key)) continue;
invariant(desc !== undefined);
@ -1694,13 +1703,25 @@ export class ResidualHeapSerializer {
let remainingProperties = new Map(val.properties);
const dummyProperties = new Set();
let props = [];
let isCertainlyLeaked = !val.mightNotBeHavocedObject();
// TODO #2259: Make deduplication in the face of leaking work for custom accessors
let shouldDropAsAssignedProp = (descriptor: Descriptor | void) =>
isCertainlyLeaked && (descriptor !== undefined && (descriptor.get === undefined && descriptor.set === undefined));
if (val.temporalAlias !== undefined) {
return t.objectExpression(props);
} else {
for (let [key, propertyBinding] of val.properties) {
if (propertyBinding.descriptor !== undefined && shouldDropAsAssignedProp(propertyBinding.descriptor)) {
remainingProperties.delete(key);
continue;
}
if (propertyBinding.pathNode !== undefined) continue; // written to inside loop
let descriptor = propertyBinding.descriptor;
if (descriptor === undefined || descriptor.value === undefined) continue; // deleted
let serializedKey = getAsPropertyNameExpression(key);
if (this._canEmbedProperty(val, key, descriptor)) {
let propValue = descriptor.value;
@ -1727,6 +1748,7 @@ export class ResidualHeapSerializer {
}
}
}
this._emitObjectProperties(
val,
remainingProperties,
@ -1734,6 +1756,7 @@ export class ResidualHeapSerializer {
dummyProperties,
skipPrototype
);
return t.objectExpression(props);
}

View File

@ -287,6 +287,7 @@ export class ResidualHeapVisitor {
}
visitObjectProperties(obj: ObjectValue, kind?: ObjectKind): void {
// In non-instant render mode, properties of leaked objects are generated via assignments
let { skipPrototype, constructor } = getObjectPrototypeMetadata(this.realm, obj);
if (obj.temporalAlias !== undefined) return;
@ -313,6 +314,15 @@ export class ResidualHeapVisitor {
continue;
}
if (propertyBindingValue.pathNode !== undefined) continue; // property is written to inside a loop
// Leaked object. Properties are set via assignments
// TODO #2259: Make deduplication in the face of leaking work for custom accessors
if (
!obj.mightNotBeHavocedObject() &&
(descriptor !== undefined && (descriptor.get === undefined && descriptor.set === undefined))
)
continue;
invariant(propertyBindingValue);
this.visitObjectProperty(propertyBindingValue);
}

View File

@ -0,0 +1,22 @@
(function() {
function f(c, g) {
let x = 23;
let y = 0;
if (c) {
x = Date.now();
function h() {
y = x;
x++;
}
g(h);
return x - y;
} else {
x = Date.now();
return x - y;
}
}
global.__optimize && __optimize(f);
global.inspect = function() {
return f(true, g => g());
};
})();

View File

@ -0,0 +1,17 @@
(function() {
function f(g, c) {
let o = { foo: 42 };
if (c) {
g(o);
} else {
o.foo = 2;
}
return o;
}
global.__optimize && __optimize(f);
inspect = function() {
return JSON.stringify(f(o => o, false));
};
})();

View File

@ -0,0 +1,17 @@
(function() {
function f(g, c) {
let o = { foo: 42 };
if (c) {
g(o);
} else {
o.x = 1;
}
return o;
}
global.__optimize && __optimize(f);
inspect = function() {
return JSON.stringify(f(o => o, false));
};
})();

View File

@ -0,0 +1,17 @@
(function() {
function f(g) {
let o = {
foo: 1,
set x(v) {
this.foo += 1;
},
};
g(o);
return o;
}
global.__optimize && __optimize(f);
inspect = () => {
JSON.stringify(f(o => o));
};
})();

View File

@ -0,0 +1,17 @@
function f(g, c) {
let o = { foo: {} };
o.__proto__ = {};
if (c) {
g(o);
} else {
o.foo = { bar: 5 };
g(o);
}
return o;
}
global.__optimize && __optimize(f);
inspect = function() {
return f(o => o);
};

View File

@ -0,0 +1,12 @@
// Copies of 42:1
function f(g) {
var o = {};
o.foo = 42;
g(o);
return o;
}
global.__optimize && __optimize(f);
inspect = function() {
return f(o => o);
};