mirror of
https://github.com/facebookarchive/prepack.git
synced 2024-08-17 10:30:32 +03:00
Impure abstract getters on prototype chain (#2257)
Summary: This fixes an issue where get on abstract top val didn't consider Receiver. This also illustrates two common patterns of getters that are not pure. One is reading a mutable property known by Prepack and one is lazily initializing a shared mutable property. I believe we'll want to continue supporting these patterns since they almost always work anyway. Note that supporting these don't add much negative consequence. We can still eliminate unused getters. Most of the time these patterns doesn't happen where the prototype is unknown or havoced. Usually the getter is abstract because the Receiver itself is unknown or havoced (not its prototype). So havocing even more doesn't have any further negative downside. Pull Request resolved: https://github.com/facebook/prepack/pull/2257 Differential Revision: D8862827 Pulled By: sebmarkbage fbshipit-source-id: 7e6e98f8b85b6fceaa5131136cc6163d94f5d289
This commit is contained in:
parent
7c6dddf236
commit
51e495a4e2
@ -498,7 +498,7 @@ export default class AbstractObjectValue extends AbstractValue {
|
||||
|
||||
if (this.values.isTop()) {
|
||||
let generateAbstractGet = () => {
|
||||
let ob = this;
|
||||
let ob = Receiver;
|
||||
if (this.kind === "explicit conversion to object") ob = this.args[0];
|
||||
let type = Value;
|
||||
if (P === "length" && Value.isTypeCompatibleWith(this.getType(), ArrayValue)) type = NumberValue;
|
||||
@ -520,7 +520,7 @@ export default class AbstractObjectValue extends AbstractValue {
|
||||
return generateAbstractGet();
|
||||
} else if (this.$Realm.isInPureScope()) {
|
||||
// This object might have leaked to a getter.
|
||||
Havoc.value(this.$Realm, this);
|
||||
Havoc.value(this.$Realm, Receiver);
|
||||
// The getter might throw anything.
|
||||
return this.$Realm.evaluateWithPossibleThrowCompletion(
|
||||
generateAbstractGet,
|
||||
|
33
test/serializer/pure-functions/GetterOnAbstractPrototype.js
Normal file
33
test/serializer/pure-functions/GetterOnAbstractPrototype.js
Normal file
@ -0,0 +1,33 @@
|
||||
var FooPrototype = global.__abstract
|
||||
? __abstract("object", "({ get legacyCache() { return this._cache || (this._cache = {}); } })")
|
||||
: {
|
||||
get legacyCache() {
|
||||
return this._cache || (this._cache = {});
|
||||
},
|
||||
};
|
||||
function Foo() {}
|
||||
Foo.prototype = FooPrototype;
|
||||
|
||||
function fn() {
|
||||
var Bar = new Foo();
|
||||
Object.defineProperty(Bar, "_cache", {
|
||||
writable: true,
|
||||
value: undefined,
|
||||
});
|
||||
Object.defineProperty(Bar, "cache", {
|
||||
get() {
|
||||
return this._cache || (this._cache = {});
|
||||
},
|
||||
});
|
||||
return [Bar.legacyCache, Bar.cache];
|
||||
}
|
||||
|
||||
global.fn = fn;
|
||||
if (global.__optimize) {
|
||||
__optimize(fn);
|
||||
}
|
||||
|
||||
inspect = function() {
|
||||
let [cache1, cache2] = fn();
|
||||
return cache1 === cache2;
|
||||
};
|
36
test/serializer/pure-functions/GetterOnAbstractPrototype2.js
Normal file
36
test/serializer/pure-functions/GetterOnAbstractPrototype2.js
Normal file
@ -0,0 +1,36 @@
|
||||
var FooPrototype = global.__abstract
|
||||
? __abstract("object", "({ get name() { return this._name; } })")
|
||||
: {
|
||||
get name() {
|
||||
return this._name;
|
||||
},
|
||||
};
|
||||
function Foo(name) {
|
||||
// Field initializer
|
||||
Object.defineProperty(this, "_name", {
|
||||
writable: true,
|
||||
value: name,
|
||||
});
|
||||
}
|
||||
Foo.prototype = FooPrototype;
|
||||
|
||||
function fn() {
|
||||
var Bar = new Foo("Sebastian");
|
||||
Object.defineProperty(Bar, "setName", {
|
||||
value: function(name) {
|
||||
return (this._name = name);
|
||||
},
|
||||
});
|
||||
var name = Bar.name;
|
||||
Bar.setName("Nikolai");
|
||||
return name;
|
||||
}
|
||||
|
||||
global.fn = fn;
|
||||
if (global.__optimize) {
|
||||
__optimize(fn);
|
||||
}
|
||||
|
||||
inspect = function() {
|
||||
return fn();
|
||||
};
|
Loading…
Reference in New Issue
Block a user