Files
asciidisco.com/build/node_modules/prepack/lib/realm.js
2023-08-01 13:49:46 +02:00

1363 lines
54 KiB
JavaScript

"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.Realm = exports.ExecutionContext = exports.Tracer = undefined;
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }();
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /**
* 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.
*/
exports.construct_empty_effects = construct_empty_effects;
var _errors = require("./errors.js");
var _index = require("./values/index.js");
var _environment = require("./environment.js");
var _index2 = require("./methods/index.js");
var _completions = require("./completions.js");
var _invariant = require("./invariant.js");
var _invariant2 = _interopRequireDefault(_invariant);
var _seedrandom = require("seedrandom");
var _seedrandom2 = _interopRequireDefault(_seedrandom);
var _generator = require("./utils/generator.js");
var _internalizer = require("./utils/internalizer.js");
var _singletons = require("./singletons.js");
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 }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Tracer = exports.Tracer = function () {
function Tracer() {
_classCallCheck(this, Tracer);
}
_createClass(Tracer, [{
key: "beginEvaluateForEffects",
value: function beginEvaluateForEffects(state) {}
}, {
key: "endEvaluateForEffects",
value: function endEvaluateForEffects(state, effects) {}
}, {
key: "detourCall",
value: function detourCall(F, thisArgument, argumentsList, newTarget, performCall) {}
}, {
key: "beforeCall",
value: function beforeCall(F, thisArgument, argumentsList, newTarget) {}
}, {
key: "afterCall",
value: function afterCall(F, thisArgument, argumentsList, newTarget, result) {}
}]);
return Tracer;
}();
var ExecutionContext = exports.ExecutionContext = function () {
function ExecutionContext() {
_classCallCheck(this, ExecutionContext);
}
_createClass(ExecutionContext, [{
key: "setCaller",
value: function setCaller(context) {
this.caller = context;
}
}, {
key: "setFunction",
value: function setFunction(F) {
if (F instanceof _index.ECMAScriptSourceFunctionValue) this.isStrict = F.$Strict;
this.function = F;
}
}, {
key: "setLocation",
value: function setLocation(loc) {
if (!loc) return;
this.loc = loc;
}
}, {
key: "setRealm",
value: function setRealm(realm) {
this.realm = realm;
}
/*
Read-only envs disallow:
- creating bindings in their scope
- creating or modifying objects when they are current running context
*/
}, {
key: "setReadOnly",
value: function setReadOnly(value) {
var oldReadOnly = this.isReadOnly;
if (this.variableEnvironment) this.variableEnvironment.environmentRecord.isReadOnly = value;
if (this.lexicalEnvironment) this.lexicalEnvironment.environmentRecord.isReadOnly = value;
this.isReadOnly = value;
return oldReadOnly;
}
}, {
key: "suspend",
value: function suspend() {
// TODO #712: suspend
}
}, {
key: "resume",
value: function resume() {
// TODO #712: resume
return this.realm.intrinsics.undefined;
}
}]);
return ExecutionContext;
}();
function construct_empty_effects(realm) {
return [realm.intrinsics.empty, new _generator.Generator(realm), new Map(), new Map(), new Set()];
}
var Realm = exports.Realm = function () {
function Realm(opts) {
_classCallCheck(this, Realm);
this.contextStack = [];
this.MOBILE_JSC_VERSION = "jsc-600-1-4-17";
this.objectCount = 0;
this.symbolCount = 867501803871088;
this.functionBodyUniqueTagSeed = 1;
this.nextGeneratorId = 0;
this.isReadOnly = false;
this.useAbstractInterpretation = !!opts.serialize || !!opts.residual;
this.trackLeaks = !!opts.abstractEffectsInAdditionalFunctions;
if (opts.mathRandomSeed !== undefined) {
this.mathRandomGenerator = (0, _seedrandom2.default)(opts.mathRandomSeed);
}
this.strictlyMonotonicDateNow = !!opts.strictlyMonotonicDateNow;
this.timeout = opts.timeout;
if (this.timeout) {
// We'll call Date.now for every this.timeoutCounterThreshold'th AST node.
// The threshold is there to reduce the cost of the surprisingly expensive Date.now call.
this.timeoutCounter = this.timeoutCounterThreshold = 1024;
}
this.start = Date.now();
this.compatibility = opts.compatibility || "browser";
this.maxStackDepth = opts.maxStackDepth || 225;
this.omitInvariants = !!opts.omitInvariants;
this.$TemplateMap = [];
if (this.useAbstractInterpretation) {
this.preludeGenerator = new _generator.PreludeGenerator(opts.debugNames, opts.uniqueSuffix);
this.pathConditions = [];
_index.ObjectValue.setupTrackedPropertyAccessors(_index.ObjectValue.trackedPropertyNames);
_index.ObjectValue.setupTrackedPropertyAccessors(_index.NativeFunctionValue.trackedPropertyNames);
_index.ObjectValue.setupTrackedPropertyAccessors(_index.ProxyValue.trackedPropertyNames);
}
this.tracers = [];
// These get initialized in construct_realm to avoid the dependency
this.intrinsics = {};
this.$GlobalObject = {};
this.evaluators = Object.create(null);
this.partialEvaluators = Object.create(null);
this.$GlobalEnv = undefined;
this.react = {
enabled: opts.reactEnabled || false,
output: opts.reactOutput || "create-element",
flowRequired: true,
symbols: new Map(),
currentOwner: undefined,
reactLibraryObject: undefined,
hoistableReactElements: new WeakMap(),
hoistableFunctions: new WeakMap()
};
this.errorHandler = opts.errorHandler;
this.globalSymbolRegistry = [];
this.activeLexicalEnvironments = new Set();
this._abstractValuesDefined = new Set(); // A set of nameStrings to ensure abstract values have unique names
this.debugNames = opts.debugNames;
}
// A list of abstract conditions that are known to be true in the current execution path.
// For example, the abstract condition of an if statement is known to be true inside its true branch.
// Unique tag for identifying function body ast node. It is neeeded
// instead of ast node itself because we may perform ast tree deep clone
// during serialization which changes the ast identity.
_createClass(Realm, [{
key: "isCompatibleWith",
// to force flow to type the annotations
value: function isCompatibleWith(compatibility) {
return compatibility === this.compatibility;
}
// Checks if there is a let binding at global scope with the given name
// returning it if so
}, {
key: "getGlobalLetBinding",
value: function getGlobalLetBinding(key) {
var globrec = this.$GlobalEnv.environmentRecord;
// GlobalEnv should have a GlobalEnvironmentRecord
(0, _invariant2.default)(globrec instanceof _environment.GlobalEnvironmentRecord);
var dclrec = globrec.$DeclarativeRecord;
try {
return dclrec.HasBinding(key) ? dclrec.GetBindingValue(key, false) : undefined;
} catch (e) {
if (e instanceof _errors.FatalError) return undefined;
throw e;
}
}
/*
Read only realms disallow:
- using console.log
- creating bindings in any existing scopes
- modifying object properties in any existing scopes
Setting a realm read-only sets all contained environments to read-only, but
all new environments (e.g. new ExecutionContexts) will be writeable.
*/
}, {
key: "setReadOnly",
value: function setReadOnly(readOnlyValue) {
this.isReadOnly = readOnlyValue;
this.$GlobalEnv.environmentRecord.isReadOnly = readOnlyValue;
this.contextStack.forEach(function (ctx) {
ctx.setReadOnly(readOnlyValue);
});
}
}, {
key: "testTimeout",
value: function testTimeout() {
var timeout = this.timeout;
if (timeout && ! --this.timeoutCounter) {
this.timeoutCounter = this.timeoutCounterThreshold;
var total = Date.now() - this.start;
if (total > timeout) {
throw new _errors.FatalError("Timed out");
}
}
}
}, {
key: "hasRunningContext",
value: function hasRunningContext() {
return this.contextStack.length !== 0;
}
}, {
key: "getRunningContext",
value: function getRunningContext() {
var context = this.contextStack[this.contextStack.length - 1];
(0, _invariant2.default)(context, "There's no running execution context");
return context;
}
// Call when a scope falls out of scope and should be destroyed.
// Clears the Bindings corresponding to the disappearing Scope from ModifiedBindings
}, {
key: "onDestroyScope",
value: function onDestroyScope(lexicalEnvironment) {
(0, _invariant2.default)(this.activeLexicalEnvironments.has(lexicalEnvironment));
var modifiedBindings = this.modifiedBindings;
if (modifiedBindings) {
// Don't undo things to global scope because it's needed past its destruction point (for serialization)
var environmentRecord = lexicalEnvironment.environmentRecord;
if (environmentRecord instanceof _environment.DeclarativeEnvironmentRecord) {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = modifiedBindings.keys()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var b = _step.value;
if (environmentRecord.bindings[b.name] && environmentRecord.bindings[b.name] === b) modifiedBindings.delete(b);
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
}
// Ensures if we call onDestroyScope too early, there will be a failure.
this.activeLexicalEnvironments.delete(lexicalEnvironment);
lexicalEnvironment.destroy();
}
}, {
key: "pushContext",
value: function pushContext(context) {
if (this.contextStack.length >= this.maxStackDepth) {
throw new _errors.FatalError("Maximum stack depth exceeded");
}
this.contextStack.push(context);
}
}, {
key: "popContext",
value: function popContext(context) {
if (context.function !== undefined) {
var modifiedBindings = this.modifiedBindings;
if (modifiedBindings !== undefined) {
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
for (var _iterator2 = modifiedBindings.keys()[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
var b = _step2.value;
if (b.environment.$FunctionObject === context.function) modifiedBindings.delete(b);
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
}
}
var c = this.contextStack.pop();
(0, _invariant2.default)(c === context);
}
}, {
key: "wrapInGlobalEnv",
value: function wrapInGlobalEnv(callback) {
var context = new ExecutionContext();
context.isStrict = this.isStrict;
context.lexicalEnvironment = this.$GlobalEnv;
context.variableEnvironment = this.$GlobalEnv;
context.realm = this;
this.pushContext(context);
try {
return callback();
} finally {
this.popContext(context);
}
}
}, {
key: "assignToGlobal",
value: function assignToGlobal(name, value) {
var _this = this;
this.wrapInGlobalEnv(function () {
return _this.$GlobalEnv.assignToGlobal(name, value);
});
}
}, {
key: "deleteGlobalBinding",
value: function deleteGlobalBinding(name) {
this.$GlobalEnv.environmentRecord.DeleteBinding(name);
}
// Evaluate a context as if it won't have any side-effects outside of any objects
// that it created itself. This promises that any abstract functions inside of it
// also won't have effects on any objects or bindings that weren't created in this
// call.
}, {
key: "evaluatePure",
value: function evaluatePure(f) {
if (!this.trackLeaks) {
return f();
}
var saved_createdObjectsTrackedForLeaks = this.createdObjectsTrackedForLeaks;
// Track all objects (including function closures) created during
// this call. This will be used to make the assumption that every
// *other* object is unchanged (pure). These objects are marked
// as leaked if they're passed to abstract functions.
this.createdObjectsTrackedForLeaks = new Set();
try {
return f();
} finally {
this.createdObjectsTrackedForLeaks = saved_createdObjectsTrackedForLeaks;
}
}
// Evaluate the given ast in a sandbox and return the evaluation results
// in the form of a completion, a code generator, a map of changed variable
// bindings and a map of changed property bindings.
}, {
key: "evaluateNodeForEffects",
value: function evaluateNodeForEffects(ast, strictCode, env, state, generatorName) {
return this.evaluateForEffects(function () {
return env.evaluateCompletionDeref(ast, strictCode);
}, state, generatorName);
}
}, {
key: "evaluateAndRevertInGlobalEnv",
value: function evaluateAndRevertInGlobalEnv(func) {
var _this2 = this;
this.wrapInGlobalEnv(function () {
return _this2.evaluateForEffects(func);
});
}
}, {
key: "evaluateNodeForEffectsInGlobalEnv",
value: function evaluateNodeForEffectsInGlobalEnv(node, state, generatorName) {
var _this3 = this;
return this.wrapInGlobalEnv(function () {
return _this3.evaluateNodeForEffects(node, false, _this3.$GlobalEnv, state, generatorName);
});
}
}, {
key: "partiallyEvaluateNodeForEffects",
value: function partiallyEvaluateNodeForEffects(ast, strictCode, env) {
var nodeAst = void 0,
nodeIO = void 0;
function partialEval() {
var result = void 0;
var _env$partiallyEvaluat = env.partiallyEvaluateCompletionDeref(ast, strictCode);
var _env$partiallyEvaluat2 = _slicedToArray(_env$partiallyEvaluat, 3);
result = _env$partiallyEvaluat2[0];
nodeAst = _env$partiallyEvaluat2[1];
nodeIO = _env$partiallyEvaluat2[2];
return result;
}
var effects = this.evaluateForEffects(partialEval);
(0, _invariant2.default)(nodeAst !== undefined && nodeIO !== undefined);
return [effects, nodeAst, nodeIO];
}
}, {
key: "evaluateForEffects",
value: function evaluateForEffects(f, state, generatorName) {
// Save old state and set up empty state for ast
var _getAndResetModifiedM = this.getAndResetModifiedMaps(),
_getAndResetModifiedM2 = _slicedToArray(_getAndResetModifiedM, 2),
savedBindings = _getAndResetModifiedM2[0],
savedProperties = _getAndResetModifiedM2[1];
var saved_generator = this.generator;
var saved_createdObjects = this.createdObjects;
var saved_completion = this.savedCompletion;
this.generator = new _generator.Generator(this, generatorName);
this.createdObjects = new Set();
this.savedCompletion = undefined; // while in this call, we only explore the normal path.
var result = void 0;
try {
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = this.tracers[Symbol.iterator](), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var t1 = _step3.value;
t1.beginEvaluateForEffects(state);
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
var c = void 0;
try {
try {
c = f();
if (c instanceof _environment.Reference) c = _singletons.Environment.GetValue(this, c);
} catch (e) {
if (e instanceof _completions.AbruptCompletion) c = e;else throw e;
}
// This is a join point for the normal branch of a PossiblyNormalCompletion.
if (c instanceof _index.Value || c instanceof _completions.AbruptCompletion) c = _singletons.Functions.incorporateSavedCompletion(this, c);
(0, _invariant2.default)(c !== undefined);
if (c instanceof _completions.PossiblyNormalCompletion) {
// The current state may have advanced since the time control forked into the various paths recorded in c.
// Update the normal path and restore the global state to what it was at the time of the fork.
var subsequentEffects = this.getCapturedEffects(c, c.value);
(0, _invariant2.default)(subsequentEffects !== undefined);
this.stopEffectCaptureAndUndoEffects(c);
_singletons.Join.updatePossiblyNormalCompletionWithSubsequentEffects(this, c, subsequentEffects);
this.savedCompletion = undefined;
}
(0, _invariant2.default)(this.generator !== undefined);
(0, _invariant2.default)(this.modifiedBindings !== undefined);
(0, _invariant2.default)(this.modifiedProperties !== undefined);
(0, _invariant2.default)(this.createdObjects !== undefined);
var astGenerator = this.generator;
var astBindings = this.modifiedBindings;
var astProperties = this.modifiedProperties;
var astCreatedObjects = this.createdObjects;
// Return the captured state changes and evaluation result
result = [c, astGenerator, astBindings, astProperties, astCreatedObjects];
return result;
} finally {
// Roll back the state changes
if (this.savedCompletion !== undefined) this.stopEffectCaptureAndUndoEffects(this.savedCompletion);
if (result !== undefined) {
this.restoreBindings(result[2]);
this.restoreProperties(result[3]);
} else {
this.restoreBindings(this.modifiedBindings);
this.restoreProperties(this.modifiedProperties);
}
this.generator = saved_generator;
this.modifiedBindings = savedBindings;
this.modifiedProperties = savedProperties;
this.createdObjects = saved_createdObjects;
this.savedCompletion = saved_completion;
}
} finally {
var _iteratorNormalCompletion4 = true;
var _didIteratorError4 = false;
var _iteratorError4 = undefined;
try {
for (var _iterator4 = this.tracers[Symbol.iterator](), _step4; !(_iteratorNormalCompletion4 = (_step4 = _iterator4.next()).done); _iteratorNormalCompletion4 = true) {
var t2 = _step4.value;
t2.endEvaluateForEffects(state, result);
}
} catch (err) {
_didIteratorError4 = true;
_iteratorError4 = err;
} finally {
try {
if (!_iteratorNormalCompletion4 && _iterator4.return) {
_iterator4.return();
}
} finally {
if (_didIteratorError4) {
throw _iteratorError4;
}
}
}
}
}
}, {
key: "evaluateWithUndoForDiagnostic",
value: function evaluateWithUndoForDiagnostic(f) {
if (!this.useAbstractInterpretation) return f();
var savedHandler = this.errorHandler;
var diagnostic = void 0;
try {
this.errorHandler = function (d) {
diagnostic = d;
return "Fail";
};
var effects = this.evaluateForEffects(f);
this.applyEffects(effects);
var resultVal = effects[0];
if (resultVal instanceof _completions.AbruptCompletion) throw resultVal;
if (resultVal instanceof _completions.PossiblyNormalCompletion) {
// in this case one of the branches may complete abruptly, which means that
// not all control flow branches join into one flow at this point.
// Consequently we have to continue tracking changes until the point where
// all the branches come together into one.
resultVal = this.composeWithSavedCompletion(resultVal);
}
(0, _invariant2.default)(resultVal instanceof _index.Value);
return resultVal;
} catch (e) {
if (diagnostic !== undefined) return diagnostic;
throw e;
} finally {
this.errorHandler = savedHandler;
}
}
}, {
key: "evaluateForFixpointEffects",
value: function evaluateForFixpointEffects(loopContinueTest, loopBody) {
try {
var effects1 = this.evaluateForEffects(loopBody);
while (true) {
this.restoreBindings(effects1[2]);
this.restoreProperties(effects1[3]);
var effects2 = this.evaluateForEffects(function () {
var test = loopContinueTest();
if (!(test instanceof _index.AbstractValue)) throw new _errors.FatalError("loop terminates before fixed point");
return loopBody();
});
this.restoreBindings(effects1[2]);
this.restoreProperties(effects1[3]);
if (_singletons.Widen.containsEffects(effects1, effects2)) {
// effects1 includes every value present in effects2, so doing another iteration using effects2 will not
// result in any more values being added to abstract domains and hence a fixpoint has been reached.
var _effects = _slicedToArray(effects2, 4),
gen = _effects[1],
bindings2 = _effects[2],
pbindings2 = _effects[3];
this._emitPropertAssignments(gen, pbindings2);
this._emitLocalAssignments(gen, bindings2);
return [effects1, effects2];
}
effects1 = _singletons.Widen.widenEffects(this, effects1, effects2);
}
} catch (e) {
return undefined;
}
}
// populate the loop body generator with assignments that will update the phiNodes
}, {
key: "_emitLocalAssignments",
value: function _emitLocalAssignments(gen, bindings) {
var tvalFor = new Map();
bindings.forEach(function (binding, key, map) {
var val = binding.value;
if (val instanceof _index.AbstractValue) {
(0, _invariant2.default)(val._buildNode !== undefined);
var tval = gen.derive(val.types, val.values, [val], function (_ref) {
var _ref2 = _slicedToArray(_ref, 1),
n = _ref2[0];
return n;
}, {
skipInvariant: true
});
tvalFor.set(key, tval);
}
});
bindings.forEach(function (binding, key, map) {
var val = binding.value;
if (val instanceof _index.AbstractValue) {
var phiNode = key.phiNode;
var tval = tvalFor.get(key);
(0, _invariant2.default)(tval !== undefined);
gen.emitStatement([tval], function (_ref3) {
var _ref4 = _slicedToArray(_ref3, 1),
v = _ref4[0];
(0, _invariant2.default)(phiNode !== undefined);
var id = phiNode.buildNode([]);
return t.expressionStatement(t.assignmentExpression("=", id, v));
});
}
});
}
// populate the loop body generator with assignments that will update properties modified inside the loop
}, {
key: "_emitPropertAssignments",
value: function _emitPropertAssignments(gen, pbindings) {
var _this4 = this;
function isSelfReferential(value, pathNode) {
if (value === pathNode) return true;
if (value instanceof _index.AbstractValue && pathNode !== undefined) {
var _iteratorNormalCompletion5 = true;
var _didIteratorError5 = false;
var _iteratorError5 = undefined;
try {
for (var _iterator5 = value.args[Symbol.iterator](), _step5; !(_iteratorNormalCompletion5 = (_step5 = _iterator5.next()).done); _iteratorNormalCompletion5 = true) {
var v = _step5.value;
if (isSelfReferential(v, pathNode)) return true;
}
} catch (err) {
_didIteratorError5 = true;
_iteratorError5 = err;
} finally {
try {
if (!_iteratorNormalCompletion5 && _iterator5.return) {
_iterator5.return();
}
} finally {
if (_didIteratorError5) {
throw _iteratorError5;
}
}
}
}
return false;
}
var tvalFor = new Map();
pbindings.forEach(function (val, key, map) {
var value = val && val.value;
if (value instanceof _index.AbstractValue) {
(0, _invariant2.default)(value._buildNode !== undefined);
var tval = gen.derive(value.types, value.values, [key.object, value], function (_ref5) {
var _ref6 = _slicedToArray(_ref5, 2),
o = _ref6[0],
n = _ref6[1];
(0, _invariant2.default)(value instanceof _index.Value);
if (typeof key.key === "string" && value.mightHaveBeenDeleted() && isSelfReferential(value, key.pathNode)) {
var inTest = t.binaryExpression("in", t.stringLiteral(key.key), o);
var addEmpty = t.conditionalExpression(inTest, n, _internalizer.emptyExpression);
n = t.logicalExpression("||", n, addEmpty);
}
return n;
}, {
skipInvariant: true
});
tvalFor.set(key, tval);
}
});
pbindings.forEach(function (val, key, map) {
var path = key.pathNode;
var tval = tvalFor.get(key);
(0, _invariant2.default)(val !== undefined);
var value = val.value;
(0, _invariant2.default)(value instanceof _index.Value);
var mightHaveBeenDeleted = value.mightHaveBeenDeleted();
var mightBeUndefined = value.mightBeUndefined();
if (typeof key.key === "string") {
gen.emitStatement([key.object, tval || value, _this4.intrinsics.empty], function (_ref7) {
var _ref8 = _slicedToArray(_ref7, 3),
o = _ref8[0],
v = _ref8[1],
e = _ref8[2];
(0, _invariant2.default)(path !== undefined);
var lh = path.buildNode([o, t.identifier(key.key)]);
var r = t.expressionStatement(t.assignmentExpression("=", lh, v));
if (mightHaveBeenDeleted) {
// If v === __empty || (v === undefined && !(key.key in o)) then delete it
var emptyTest = t.binaryExpression("===", v, e);
var undefinedTest = t.binaryExpression("===", v, _internalizer.voidExpression);
var inTest = t.unaryExpression("!", t.binaryExpression("in", t.stringLiteral(key.key), o));
var guard = t.logicalExpression("||", emptyTest, t.logicalExpression("&&", undefinedTest, inTest));
var deleteIt = t.expressionStatement(t.unaryExpression("delete", lh));
return t.ifStatement(mightBeUndefined ? emptyTest : guard, deleteIt, r);
}
return r;
});
} else {
gen.emitStatement([key.object, key.key, tval || value, _this4.intrinsics.empty], function (_ref9) {
var _ref10 = _slicedToArray(_ref9, 4),
o = _ref10[0],
p = _ref10[1],
v = _ref10[2],
e = _ref10[3];
(0, _invariant2.default)(path !== undefined);
var lh = path.buildNode([o, p]);
return t.expressionStatement(t.assignmentExpression("=", lh, v));
});
}
});
}
}, {
key: "composeEffects",
value: function composeEffects(priorEffects, subsequentEffects) {
var _priorEffects = _slicedToArray(priorEffects, 5),
pg = _priorEffects[1],
pb = _priorEffects[2],
pp = _priorEffects[3],
po = _priorEffects[4];
var _subsequentEffects = _slicedToArray(subsequentEffects, 5),
sc = _subsequentEffects[0],
sg = _subsequentEffects[1],
sb = _subsequentEffects[2],
sp = _subsequentEffects[3],
so = _subsequentEffects[4];
var result = construct_empty_effects(this);
var _result = _slicedToArray(result, 5),
rb = _result[2],
rp = _result[3],
ro = _result[4];
result[0] = sc;
result[1] = _singletons.Join.composeGenerators(this, pg || result[1], sg);
if (pb) {
pb.forEach(function (val, key, m) {
return rb.set(key, val);
});
}
sb.forEach(function (val, key, m) {
return rb.set(key, val);
});
if (pp) {
pp.forEach(function (desc, propertyBinding, m) {
return rp.set(propertyBinding, desc);
});
}
sp.forEach(function (val, key, m) {
return rp.set(key, val);
});
if (po) {
po.forEach(function (ob, a) {
return ro.add(ob);
});
}
so.forEach(function (ob, a) {
return ro.add(ob);
});
return result;
}
}, {
key: "updateAbruptCompletions",
value: function updateAbruptCompletions(priorEffects, c) {
if (c.consequent instanceof _completions.AbruptCompletion) {
c.consequentEffects = this.composeEffects(priorEffects, c.consequentEffects);
var alternate = c.alternate;
if (alternate instanceof _completions.PossiblyNormalCompletion) this.updateAbruptCompletions(priorEffects, alternate);
} else {
(0, _invariant2.default)(c.alternate instanceof _completions.AbruptCompletion);
c.alternateEffects = this.composeEffects(priorEffects, c.alternateEffects);
var consequent = c.consequent;
if (consequent instanceof _completions.PossiblyNormalCompletion) this.updateAbruptCompletions(priorEffects, consequent);
}
}
}, {
key: "composeWithSavedCompletion",
value: function composeWithSavedCompletion(completion) {
if (this.savedCompletion === undefined) {
this.savedCompletion = completion;
this.savedCompletion.savedPathConditions = this.pathConditions;
this.captureEffects(completion);
} else {
this.savedCompletion = _singletons.Join.composePossiblyNormalCompletions(this, this.savedCompletion, completion);
}
if (completion.consequent instanceof _completions.AbruptCompletion) {
_singletons.Path.pushInverseAndRefine(completion.joinCondition);
if (completion.alternate instanceof _completions.PossiblyNormalCompletion) {
completion.alternate.pathConditions.forEach(_singletons.Path.pushAndRefine);
}
} else if (completion.alternate instanceof _completions.AbruptCompletion) {
_singletons.Path.pushAndRefine(completion.joinCondition);
if (completion.consequent instanceof _completions.PossiblyNormalCompletion) {
completion.consequent.pathConditions.forEach(_singletons.Path.pushAndRefine);
}
}
return completion.value;
}
}, {
key: "incorporatePriorSavedCompletion",
value: function incorporatePriorSavedCompletion(priorCompletion) {
if (priorCompletion === undefined) return;
if (this.savedCompletion === undefined) {
this.savedCompletion = priorCompletion;
this.captureEffects(priorCompletion);
} else {
this.savedCompletion = _singletons.Join.composePossiblyNormalCompletions(this, priorCompletion, this.savedCompletion);
}
}
}, {
key: "captureEffects",
value: function captureEffects(completion) {
if (completion.savedEffects !== undefined) {
// Already called captureEffects, just carry on
return;
}
completion.savedEffects = [this.intrinsics.undefined, this.generator, this.modifiedBindings, this.modifiedProperties, this.createdObjects];
this.generator = new _generator.Generator(this);
this.modifiedBindings = new Map();
this.modifiedProperties = new Map();
this.createdObjects = new Set();
}
}, {
key: "getCapturedEffects",
value: function getCapturedEffects(completion, v) {
if (completion.savedEffects === undefined) return undefined;
if (v === undefined) v = this.intrinsics.undefined;
(0, _invariant2.default)(this.generator !== undefined);
(0, _invariant2.default)(this.modifiedBindings !== undefined);
(0, _invariant2.default)(this.modifiedProperties !== undefined);
(0, _invariant2.default)(this.createdObjects !== undefined);
return [v, this.generator, this.modifiedBindings, this.modifiedProperties, this.createdObjects];
}
}, {
key: "stopEffectCapture",
value: function stopEffectCapture(completion) {
var e = this.getCapturedEffects(completion);
if (e !== undefined) {
this.stopEffectCaptureAndUndoEffects(completion);
this.applyEffects(e);
}
}
}, {
key: "stopEffectCaptureAndUndoEffects",
value: function stopEffectCaptureAndUndoEffects(completion) {
// Roll back the state changes
this.restoreBindings(this.modifiedBindings);
this.restoreProperties(this.modifiedProperties);
// Restore saved state
if (completion.savedEffects !== undefined) {
var _completion$savedEffe = _slicedToArray(completion.savedEffects, 5),
c = _completion$savedEffe[0],
g = _completion$savedEffe[1],
b = _completion$savedEffe[2],
p = _completion$savedEffe[3],
o = _completion$savedEffe[4];
c;
completion.savedEffects = undefined;
this.generator = g;
this.modifiedBindings = b;
this.modifiedProperties = p;
this.createdObjects = o;
} else {
(0, _invariant2.default)(false);
}
}
// Apply the given effects to the global state
}, {
key: "applyEffects",
value: function applyEffects(effects) {
var leadingComment = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
var _effects2 = _slicedToArray(effects, 5),
generator = _effects2[1],
bindings = _effects2[2],
properties = _effects2[3],
createdObjects = _effects2[4];
// Add generated code for property modifications
this.appendGenerator(generator, leadingComment);
// Restore bindings
this.restoreBindings(bindings);
this.restoreProperties(properties);
// track bindings
var realmModifiedBindings = this.modifiedBindings;
if (realmModifiedBindings !== undefined) {
bindings.forEach(function (val, key, m) {
(0, _invariant2.default)(realmModifiedBindings !== undefined);
if (!realmModifiedBindings.has(key)) {
realmModifiedBindings.set(key, val);
}
});
}
var realmModifiedProperties = this.modifiedProperties;
if (realmModifiedProperties !== undefined) {
properties.forEach(function (desc, propertyBinding, m) {
(0, _invariant2.default)(realmModifiedProperties !== undefined);
if (!realmModifiedProperties.has(propertyBinding)) {
realmModifiedProperties.set(propertyBinding, desc);
}
});
}
// add created objects
if (createdObjects.size > 0) {
var realmCreatedObjects = this.createdObjects;
if (realmCreatedObjects === undefined) this.createdObjects = new Set(createdObjects);else {
createdObjects.forEach(function (ob, a) {
(0, _invariant2.default)(realmCreatedObjects !== undefined);
realmCreatedObjects.add(ob);
});
}
}
}
}, {
key: "outputToConsole",
value: function outputToConsole(method, args) {
if (this.isReadOnly) {
// This only happens during speculative execution and is reported elsewhere
throw new _errors.FatalError("Trying to create console output in read-only realm");
}
if (this.useAbstractInterpretation) {
(0, _invariant2.default)(this.generator !== undefined);
this.generator.emitConsoleLog(method, args);
} else {
console[method](getString(this, args));
}
function getString(realm, values) {
var res = "";
while (values.length) {
var next = values.shift();
var nextString = _singletons.To.ToString(realm, next);
res += nextString;
}
return res;
}
}
// Record the current value of binding in this.modifiedBindings unless
// there is already an entry for binding.
}, {
key: "recordModifiedBinding",
value: function recordModifiedBinding(binding) {
if (binding.environment.isReadOnly) {
// This only happens during speculative execution and is reported elsewhere
throw new _errors.FatalError("Trying to modify a binding in read-only realm");
}
if (this.modifiedBindings !== undefined && !this.modifiedBindings.has(binding)) this.modifiedBindings.set(binding, {
hasLeaked: binding.hasLeaked,
value: binding.value
});
return binding;
}
}, {
key: "callReportObjectGetOwnProperties",
value: function callReportObjectGetOwnProperties(ob) {
if (this.reportObjectGetOwnProperties !== undefined) {
this.reportObjectGetOwnProperties(ob);
}
}
}, {
key: "callReportPropertyAccess",
value: function callReportPropertyAccess(binding) {
if (this.reportPropertyAccess !== undefined) {
this.reportPropertyAccess(binding);
}
}
// Record the current value of binding in this.modifiedProperties unless
// there is already an entry for binding.
}, {
key: "recordModifiedProperty",
value: function recordModifiedProperty(binding) {
if (binding === undefined) return;
if (this.isReadOnly && (this.getRunningContext().isReadOnly || !this.isNewObject(binding.object))) {
// This only happens during speculative execution and is reported elsewhere
throw new _errors.FatalError("Trying to modify a property in read-only realm");
}
this.callReportPropertyAccess(binding);
if (this.modifiedProperties !== undefined && !this.modifiedProperties.has(binding)) {
this.modifiedProperties.set(binding, (0, _index2.cloneDescriptor)(binding.descriptor));
}
}
}, {
key: "isNewObject",
value: function isNewObject(object) {
if (object instanceof _index.AbstractObjectValue) return false;
return this.createdObjects === undefined || this.createdObjects.has(object);
}
}, {
key: "recordNewObject",
value: function recordNewObject(object) {
if (this.createdObjects !== undefined) {
this.createdObjects.add(object);
}
if (this.createdObjectsTrackedForLeaks !== undefined) {
this.createdObjectsTrackedForLeaks.add(object);
}
}
// Returns the current values of modifiedBindings and modifiedProperties
// and then assigns new empty maps to them.
}, {
key: "getAndResetModifiedMaps",
value: function getAndResetModifiedMaps() {
var result = [this.modifiedBindings, this.modifiedProperties];
this.modifiedBindings = new Map();
this.modifiedProperties = new Map();
return result;
}
// Restores each Binding in the given map to the value it
// had when it was entered into the map and updates the map to record
// the value the Binding had just before the call to this method.
}, {
key: "restoreBindings",
value: function restoreBindings(modifiedBindings) {
if (modifiedBindings === undefined) return;
modifiedBindings.forEach(function (_ref11, binding, m) {
var hasLeaked = _ref11.hasLeaked,
value = _ref11.value;
var l = binding.hasLeaked;
var v = binding.value;
binding.hasLeaked = hasLeaked;
binding.value = value;
m.set(binding, {
hasLeaked: l,
value: v
});
});
}
// Restores each PropertyBinding in the given map to the value it
// had when it was entered into the map and updates the map to record
// the value the Binding had just before the call to this method.
}, {
key: "restoreProperties",
value: function restoreProperties(modifiedProperties) {
if (modifiedProperties === undefined) return;
modifiedProperties.forEach(function (desc, propertyBinding, m) {
var d = propertyBinding.descriptor;
propertyBinding.descriptor = desc;
m.set(propertyBinding, d);
});
}
// Provide the realm with maps in which to track modifications.
// A map can be set to undefined if no tracking is required.
}, {
key: "setModifiedMaps",
value: function setModifiedMaps(modifiedBindings, modifiedProperties) {
this.modifiedBindings = modifiedBindings;
this.modifiedProperties = modifiedProperties;
}
}, {
key: "rebuildObjectProperty",
value: function rebuildObjectProperty(object, key, propertyValue, path) {
if (!(propertyValue instanceof _index.AbstractValue)) return;
if (!propertyValue.isIntrinsic()) {
propertyValue.intrinsicName = path + "." + key;
propertyValue.kind = "rebuiltProperty";
propertyValue.args = [object];
propertyValue._buildNode = function (_ref12) {
var _ref13 = _slicedToArray(_ref12, 1),
node = _ref13[0];
return t.memberExpression(node, t.identifier(key));
};
this.rebuildNestedProperties(propertyValue, propertyValue.intrinsicName);
}
}
}, {
key: "rebuildNestedProperties",
value: function rebuildNestedProperties(abstractValue, path) {
if (!(abstractValue instanceof _index.AbstractObjectValue)) return;
if (abstractValue.values.isTop()) return;
var template = abstractValue.getTemplate();
(0, _invariant2.default)(!template.intrinsicName || template.intrinsicName === path);
// TODO #882: We are using the concept of "intrinsic values" to mark the template
// object as intrinsic, so that we'll never emit code that creates it, as it instead is used
// to refer to an unknown but existing object.
// However, it's not really an intrinsic object, and it might not exist ahead of time, but only starting
// from this point on, which might be tied to some nested generator.
// Which we currently don't track, and that needs to get fixed.
// For now, we use intrinsicNameGenerated to mark this case.
template.intrinsicName = path;
template.intrinsicNameGenerated = true;
var _iteratorNormalCompletion6 = true;
var _didIteratorError6 = false;
var _iteratorError6 = undefined;
try {
for (var _iterator6 = template.properties[Symbol.iterator](), _step6; !(_iteratorNormalCompletion6 = (_step6 = _iterator6.next()).done); _iteratorNormalCompletion6 = true) {
var _ref14 = _step6.value;
var _ref15 = _slicedToArray(_ref14, 2);
var _key = _ref15[0];
var binding = _ref15[1];
if (binding === undefined || binding.descriptor === undefined) continue; // deleted
(0, _invariant2.default)(binding.descriptor !== undefined);
var _value = binding.descriptor.value;
_singletons.Properties.ThrowIfMightHaveBeenDeleted(_value);
if (_value === undefined) {
_index.AbstractValue.reportIntrospectionError(abstractValue, _key);
throw new _errors.FatalError();
}
(0, _invariant2.default)(_value instanceof _index.Value);
this.rebuildObjectProperty(abstractValue, _key, _value, path);
}
} catch (err) {
_didIteratorError6 = true;
_iteratorError6 = err;
} finally {
try {
if (!_iteratorNormalCompletion6 && _iterator6.return) {
_iterator6.return();
}
} finally {
if (_didIteratorError6) {
throw _iteratorError6;
}
}
}
}
}, {
key: "createExecutionContext",
value: function createExecutionContext() {
var context = new ExecutionContext();
var loc = this.nextContextLocation;
if (loc) {
context.setLocation(loc);
this.nextContextLocation = null;
}
return context;
}
}, {
key: "setNextExecutionContextLocation",
value: function setNextExecutionContextLocation(loc) {
if (!loc) return;
//if (this.nextContextLocation) {
// throw new ThrowCompletion(
// Construct(this, this.intrinsics.TypeError, [new StringValue(this, "Already have a context location that we haven't used yet")])
// );
//} else {
this.nextContextLocation = loc;
//}
}
}, {
key: "reportIntrospectionError",
value: function reportIntrospectionError(message) {
if (message === undefined) message = "";
if (typeof message === "string") message = new _index.StringValue(this, message);
(0, _invariant2.default)(message instanceof _index.StringValue);
this.nextContextLocation = this.currentLocation;
var error = new _errors.CompilerDiagnostic(message.value, this.currentLocation, "PP0001", "FatalError");
this.handleError(error);
}
}, {
key: "createErrorThrowCompletion",
value: function createErrorThrowCompletion(type, message) {
(0, _invariant2.default)(type !== this.intrinsics.__IntrospectionError);
if (message === undefined) message = "";
if (typeof message === "string") message = new _index.StringValue(this, message);
(0, _invariant2.default)(message instanceof _index.StringValue);
this.nextContextLocation = this.currentLocation;
return new _completions.ThrowCompletion((0, _index2.Construct)(this, type, [message]), this.currentLocation);
}
}, {
key: "appendGenerator",
value: function appendGenerator(generator) {
var leadingComment = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : "";
var realmGenerator = this.generator;
if (realmGenerator === undefined) {
(0, _invariant2.default)(generator.empty());
return;
}
realmGenerator.appendGenerator(generator, leadingComment);
}
// Pass the error to the realm's error-handler
// Return value indicates whether the caller should try to recover from the
// error or not ('true' means recover if possible).
}, {
key: "handleError",
value: function handleError(diagnostic) {
if (!diagnostic.callStack && this.contextStack.length > 0) {
var error = (0, _index2.Construct)(this, this.intrinsics.Error);
var stack = error.$Get("stack", error);
if (stack instanceof _index.StringValue) diagnostic.callStack = stack.value;
}
// Default behaviour is to bail on the first error
var errorHandler = this.errorHandler;
if (!errorHandler) {
var msg = diagnostic.errorCode + ": " + diagnostic.message;
if (diagnostic.location) {
var loc_start = diagnostic.location.start;
var loc_end = diagnostic.location.end;
msg += " at " + loc_start.line + ":" + loc_start.column + " to " + loc_end.line + ":" + loc_end.column;
}
try {
switch (diagnostic.severity) {
case "Information":
console.log("Info: " + msg);
return "Recover";
case "Warning":
console.warn("Warn: " + msg);
return "Recover";
case "RecoverableError":
console.error("Error: " + msg);
return "Fail";
case "FatalError":
console.error("Fatal Error: " + msg);
return "Fail";
default:
(0, _invariant2.default)(false, "Unexpected error type");
}
} finally {
console.log(diagnostic.callStack);
}
}
return errorHandler(diagnostic);
}
}, {
key: "saveNameString",
value: function saveNameString(nameString) {
this._abstractValuesDefined.add(nameString);
}
}, {
key: "isNameStringUnique",
value: function isNameStringUnique(nameString) {
return !this._abstractValuesDefined.has(nameString);
}
}]);
return Realm;
}();
//# sourceMappingURL=realm.js.map