prepack
Version:
Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.
579 lines (534 loc) • 22.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _errors = require("../errors.js");
var _index = require("./index.js");
var _index2 = require("../domains/index.js");
var _index3 = require("../methods/index.js");
var _singletons = require("../singletons.js");
var _invariant = require("../invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
var _babelTypes = require("babel-types");
var t = _interopRequireWildcard(_babelTypes);
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
class AbstractObjectValue extends _index.AbstractValue {
constructor(realm, types, values, hashValue, args, buildNode, optionalArgs) {
super(realm, types, values, hashValue, args, buildNode, optionalArgs);
if (!values.isTop()) {
for (let element of this.values.getElements()) (0, _invariant2.default)(element instanceof _index.ObjectValue);
}
}
getTemplate() {
for (let element of this.values.getElements()) {
(0, _invariant2.default)(element instanceof _index.ObjectValue);
if (element.isPartialObject()) {
return element;
} else {
break;
}
}
_index.AbstractValue.reportIntrospectionError(this);
throw new _errors.FatalError();
}
isPartialObject() {
// At the very least, the identity of the object is unknown
return true;
}
isSimpleObject() {
if (this.cachedIsSimpleObject === undefined) this.cachedIsSimpleObject = this._elementsAreSimpleObjects();
return this.cachedIsSimpleObject;
}
_elementsAreSimpleObjects() {
if (this.values.isTop()) return false;
let result;
for (let element of this.values.getElements()) {
(0, _invariant2.default)(element instanceof _index.ObjectValue);
if (result === undefined) {
result = element.isSimpleObject();
} else if (result !== element.isSimpleObject()) {
_index.AbstractValue.reportIntrospectionError(this);
throw new _errors.FatalError();
}
}
if (result === undefined) {
_index.AbstractValue.reportIntrospectionError(this);
throw new _errors.FatalError();
}
return result;
}
isFinalObject() {
if (this.values.isTop()) return false;
let result;
for (let element of this.values.getElements()) {
(0, _invariant2.default)(element instanceof _index.ObjectValue);
if (result === undefined) {
result = element.isFinalObject();
} else if (result !== element.isFinalObject()) {
_index.AbstractValue.reportIntrospectionError(this);
throw new _errors.FatalError();
}
}
if (result === undefined) {
_index.AbstractValue.reportIntrospectionError(this);
throw new _errors.FatalError();
}
return result;
}
mightBeFalse() {
return false;
}
mightNotBeFalse() {
return true;
}
makeNotPartial() {
if (this.values.isTop()) {
_index.AbstractValue.reportIntrospectionError(this);
throw new _errors.FatalError();
}
for (let element of this.values.getElements()) {
(0, _invariant2.default)(element instanceof _index.ObjectValue);
element.makeNotPartial();
}
}
makePartial() {
if (this.values.isTop()) {
_index.AbstractValue.reportIntrospectionError(this);
throw new _errors.FatalError();
}
for (let element of this.values.getElements()) {
(0, _invariant2.default)(element instanceof _index.ObjectValue);
element.makePartial();
}
}
makeSimple(option) {
if (this.values.isTop() && this.getType() === _index.ObjectValue) {
let obj = new _index.ObjectValue(this.$Realm, this.$Realm.intrinsics.ObjectPrototype);
obj.intrinsicName = this.intrinsicName;
obj.intrinsicNameGenerated = true;
obj.makePartial();
obj._templateFor = this;
this.values = new _index2.ValuesDomain(obj);
}
if (!this.values.isTop()) {
for (let element of this.values.getElements()) {
(0, _invariant2.default)(element instanceof _index.ObjectValue);
element.makeSimple(option);
}
}
this.cachedIsSimpleObject = true;
}
makeFinal() {
if (this.values.isTop()) {
_index.AbstractValue.reportIntrospectionError(this);
throw new _errors.FatalError();
}
for (let element of this.values.getElements()) {
(0, _invariant2.default)(element instanceof _index.ObjectValue);
element.makeFinal();
}
}
throwIfNotObject() {
return this;
}
// ECMA262 9.1.3
$IsExtensible() {
return false;
}
// ECMA262 9.1.5
$GetOwnProperty(P) {
if (P instanceof _index.StringValue) P = P.value;
if (this.values.isTop()) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
let elements = this.values.getElements();
if (elements.size === 1) {
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
return cv.$GetOwnProperty(P, cv);
}
(0, _invariant2.default)(false);
} else if (this.kind === "conditional") {
// this is the join of two concrete objects
let [cond, ob1, ob2] = this.args;
(0, _invariant2.default)(cond instanceof _index.AbstractValue);
(0, _invariant2.default)(ob1 instanceof _index.ObjectValue);
(0, _invariant2.default)(ob2 instanceof _index.ObjectValue);
let d1 = ob1.$GetOwnProperty(P);
let d2 = ob2.$GetOwnProperty(P);
if (d1 === undefined || d2 === undefined || !(0, _index3.equalDescriptors)(d1, d2)) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
let desc = (0, _index3.cloneDescriptor)(d1);
(0, _invariant2.default)(desc !== undefined);
if ((0, _index3.IsDataDescriptor)(this.$Realm, desc)) {
let d1Value = d1.value;
(0, _invariant2.default)(d1Value === undefined || d1Value instanceof _index.Value);
let d2Value = d2.value;
(0, _invariant2.default)(d2Value === undefined || d2Value instanceof _index.Value);
desc.value = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, d1Value, d2Value);
}
return desc;
} else if (this.kind === "widened") {
// This abstract object was created by repeated assignments of freshly allocated objects to the same binding inside a loop
let [ob1, ob2] = this.args; // ob1: summary of iterations 1...n, ob2: summary of iteration n+1
(0, _invariant2.default)(ob1 instanceof _index.ObjectValue);
(0, _invariant2.default)(ob2 instanceof _index.ObjectValue);
let d1 = ob1.$GetOwnProperty(P);
let d2 = ob2.$GetOwnProperty(P);
if (d1 === undefined || d2 === undefined || !(0, _index3.equalDescriptors)(d1, d2)) {
// We do not handle the case where different loop iterations result in different kinds of propperties
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
let desc = (0, _index3.cloneDescriptor)(d1);
(0, _invariant2.default)(desc !== undefined);
if ((0, _index3.IsDataDescriptor)(this.$Realm, desc)) {
// Values may be different, i.e. values may be loop variant, so the widened value summarizes the entire loop
let d1Value = d1.value;
(0, _invariant2.default)(d1Value === undefined || d1Value instanceof _index.Value);
let d2Value = d2.value;
(0, _invariant2.default)(d2Value === undefined || d2Value instanceof _index.Value);
desc.value = _singletons.Widen.widenValues(this.$Realm, d1Value, d2Value);
} else {
// In this case equalDescriptors guarantees exact equality betwee d1 and d2.
// Inlining the accessors will eventually bring in data properties if the accessors have loop variant behavior
}
return desc;
} else {
let hasProp = false;
let doesNotHaveProp = false;
let desc;
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
let d = cv.$GetOwnProperty(P);
if (d === undefined) doesNotHaveProp = true;else {
hasProp = true;
if (desc === undefined) {
desc = (0, _index3.cloneDescriptor)(d);
(0, _invariant2.default)(desc !== undefined);
if (!(0, _index3.IsDataDescriptor)(this.$Realm, d)) continue;
} else {
if (!(0, _index3.equalDescriptors)(d, desc)) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
if (!(0, _index3.IsDataDescriptor)(this.$Realm, desc)) continue;
// values may be different
let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
desc.value = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, d.value, desc.value);
}
}
}
if (hasProp && doesNotHaveProp) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
return desc;
}
}
// ECMA262 9.1.6
$DefineOwnProperty(P, Desc) {
if (P instanceof _index.StringValue) P = P.value;
if (this.values.isTop()) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
let elements = this.values.getElements();
if (elements.size === 1) {
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
return cv.$DefineOwnProperty(P, Desc);
}
(0, _invariant2.default)(false);
} else {
if (!(0, _index3.IsDataDescriptor)(this.$Realm, Desc)) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
let desc = {
value: "value" in Desc ? Desc.value : this.$Realm.intrinsics.undefined,
writable: "writable" in Desc ? Desc.writable : false,
enumerable: "enumerable" in Desc ? Desc.enumerable : false,
configurable: "configurable" in Desc ? Desc.configurable : false
};
let new_val = desc.value;
(0, _invariant2.default)(new_val instanceof _index.Value);
let sawTrue = false;
let sawFalse = false;
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
let d = cv.$GetOwnProperty(P);
if (d !== undefined && !(0, _index3.equalDescriptors)(d, desc)) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
let dval = d === undefined || d.vale === undefined ? this.$Realm.intrinsics.empty : d.value;
(0, _invariant2.default)(dval instanceof _index.Value);
let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
desc.value = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, new_val, dval);
if (cv.$DefineOwnProperty(P, desc)) {
sawTrue = true;
} else sawFalse = true;
}
if (sawTrue && sawFalse) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
return sawTrue;
}
}
// ECMA262 9.1.7
$HasProperty(P) {
if (P instanceof _index.StringValue) P = P.value;
if (this.values.isTop()) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
let elements = this.values.getElements();
if (elements.size === 1) {
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
return cv.$HasProperty(P, cv);
}
(0, _invariant2.default)(false);
} else {
let hasProp = false;
let doesNotHaveProp = false;
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
if (cv.$HasProperty(P)) hasProp = true;else doesNotHaveProp = true;
}
if (hasProp && doesNotHaveProp) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
return hasProp;
}
}
// ECMA262 9.1.8
$Get(P, Receiver) {
if (P instanceof _index.StringValue) P = P.value;
if (this.values.isTop()) {
let generateAbstractGet = () => {
let type = _index.Value;
if (P === "length" && _index.Value.isTypeCompatibleWith(this.getType(), _index.ArrayValue)) type = _index.NumberValue;
return _index.AbstractValue.createTemporalFromBuildFunction(this.$Realm, type, [this], ([o]) => {
(0, _invariant2.default)(typeof P === "string");
return t.isValidIdentifier(P) ? t.memberExpression(o, t.identifier(P), false) : t.memberExpression(o, t.stringLiteral(P), true);
}, {
skipInvariant: true
});
};
if (this.isSimpleObject() && this.isIntrinsic()) {
return generateAbstractGet();
} else if (this.$Realm.isInPureScope()) {
// This object might have leaked to a getter.
_singletons.Havoc.value(this.$Realm, this);
// The getter might throw anything.
return this.$Realm.evaluateWithPossibleThrowCompletion(generateAbstractGet, _index2.TypesDomain.topVal, _index2.ValuesDomain.topVal);
}
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
let elements = this.values.getElements();
if (elements.size === 1) {
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
return cv.$Get(P, Receiver);
}
(0, _invariant2.default)(false);
} else if (this.kind === "conditional") {
// this is the join of two concrete objects
let [cond, ob1, ob2] = this.args;
(0, _invariant2.default)(cond instanceof _index.AbstractValue);
(0, _invariant2.default)(ob1 instanceof _index.ObjectValue);
(0, _invariant2.default)(ob2 instanceof _index.ObjectValue);
let d1 = ob1.$GetOwnProperty(P);
let d1val = d1 === undefined ? this.$Realm.intrinsics.undefined : (0, _index3.IsDataDescriptor)(this.$Realm, d1) ? d1.value : undefined;
let d2 = ob2.$GetOwnProperty(P);
let d2val = d2 === undefined ? this.$Realm.intrinsics.undefined : (0, _index3.IsDataDescriptor)(this.$Realm, d2) ? d2.value : undefined;
if (d1val === undefined || d2val === undefined) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
(0, _invariant2.default)(d1val instanceof _index.Value);
(0, _invariant2.default)(d2val instanceof _index.Value);
return _singletons.Join.joinValuesAsConditional(this.$Realm, cond, d1val, d2val);
} else {
let result;
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
let d = cv.$GetOwnProperty(P);
// We do not currently join property getters
if (d !== undefined && !(0, _index3.IsDataDescriptor)(this.$Realm, d)) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
let cvVal = d === undefined ? this.$Realm.intrinsics.undefined : d.value;
if (result === undefined) result = cvVal;else {
let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
result = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, cvVal, result);
}
}
(0, _invariant2.default)(result !== undefined);
return result;
}
}
$GetPartial(P, Receiver) {
if (!(P instanceof _index.AbstractValue)) return this.$Get(P, Receiver);
(0, _invariant2.default)(this === Receiver, "TODO #1021");
if (this.values.isTop()) {
if (this.isSimpleObject() && this.isIntrinsic()) {
return _index.AbstractValue.createTemporalFromBuildFunction(this.$Realm, _index.Value, [this, P], ([o, p]) => t.memberExpression(o, p, true));
}
_index.AbstractValue.reportIntrospectionError(this);
throw new _errors.FatalError();
}
let elements = this.values.getElements();
if (elements.size === 1) {
for (let cv of elements) {
return cv.$GetPartial(P, cv);
}
(0, _invariant2.default)(false);
} else {
let result;
for (let cv of elements) {
let cvVal = cv.$GetPartial(P, cv);
if (result === undefined) result = cvVal;else {
let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
result = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, cvVal, result);
}
}
(0, _invariant2.default)(result !== undefined);
return result;
}
}
// ECMA262 9.1.9
$Set(P, V, Receiver) {
if (P instanceof _index.StringValue) P = P.value;
(0, _invariant2.default)(this === Receiver, "TODO #1021");
if (this.values.isTop()) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
let elements = this.values.getElements();
if (elements.size === 1) {
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
return cv.$Set(P, V, cv);
}
(0, _invariant2.default)(false);
} else {
let sawTrue = false;
let sawFalse = false;
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
let d = cv.$GetOwnProperty(P);
if (d !== undefined && !(0, _index3.IsDataDescriptor)(this.$Realm, d)) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
let oldVal = d === undefined ? this.$Realm.intrinsics.empty : d.value;
let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
let v = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, V, oldVal);
if (cv.$Set(P, v, cv)) sawTrue = true;else sawFalse = true;
}
if (sawTrue && sawFalse) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
return sawTrue;
}
}
$SetPartial(P, V, Receiver) {
if (!(P instanceof _index.AbstractValue)) return this.$Set(P, V, Receiver);
(0, _invariant2.default)(this === Receiver, "TODO #1021");
if (this.values.isTop()) {
_index.AbstractValue.reportIntrospectionError(this);
throw new _errors.FatalError();
}
let elements = this.values.getElements();
if (elements.size === 1) {
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
return cv.$SetPartial(P, V, cv);
}
(0, _invariant2.default)(false);
} else {
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
let oldVal = this.$GetPartial(P, Receiver);
let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
let v = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, V, oldVal);
cv.$SetPartial(P, v, cv);
}
return true;
}
}
// ECMA262 9.1.10
$Delete(P) {
if (P instanceof _index.StringValue) P = P.value;
if (this.values.isTop()) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
let elements = this.values.getElements();
if (elements.size === 1) {
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
return cv.$Delete(P);
}
(0, _invariant2.default)(false);
} else {
let sawTrue = false;
let sawFalse = false;
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
let d = cv.$GetOwnProperty(P);
if (d === undefined) continue;
if (!(0, _index3.IsDataDescriptor)(this.$Realm, d)) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
let cond = _index.AbstractValue.createFromBinaryOp(this.$Realm, "===", this, cv, this.expressionLocation);
let v = _singletons.Join.joinValuesAsConditional(this.$Realm, cond, this.$Realm.intrinsics.empty, d.value);
if (cv.$Set(P, v, cv)) sawTrue = true;else sawFalse = true;
}
if (sawTrue && sawFalse) {
_index.AbstractValue.reportIntrospectionError(this, P);
throw new _errors.FatalError();
}
return sawTrue;
}
}
$OwnPropertyKeys() {
if (this.values.isTop()) {
_index.AbstractValue.reportIntrospectionError(this);
throw new _errors.FatalError();
}
let elements = this.values.getElements();
if (elements.size === 1) {
for (let cv of elements) {
(0, _invariant2.default)(cv instanceof _index.ObjectValue);
return cv.$OwnPropertyKeys();
}
(0, _invariant2.default)(false);
} else {
_index.AbstractValue.reportIntrospectionError(this);
throw new _errors.FatalError();
}
}
}
exports.default = AbstractObjectValue; /**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
//# sourceMappingURL=AbstractObjectValue.js.map