UNPKG

prepack

Version:

Execute a JS bundle, serialize global state and side effects to a snapshot that can be quickly restored.

1,208 lines (985 loc) 59.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FunctionImplementation = undefined; var _errors = require("../errors.js"); var _completions = require("../completions.js"); var _realm = require("../realm.js"); var _environment = require("../environment.js"); var _index = require("../values/index.js"); var _call = require("./call.js"); var _abstract = require("../methods/abstract.js"); var _construct = require("../methods/construct.js"); var _index2 = require("../methods/index.js"); var _iterator = require("../methods/iterator.js"); var _ObjectExpression = require("../evaluators/ObjectExpression.js"); var _singletons = require("../singletons.js"); var _traverseFast = require("../utils/traverse-fast.js"); var _traverseFast2 = _interopRequireDefault(_traverseFast); var _invariant = require("../invariant.js"); var _invariant2 = _interopRequireDefault(_invariant); var _parse = require("../utils/parse.js"); var _parse2 = _interopRequireDefault(_parse); var _strict = require("../utils/strict.js"); var _strict2 = _interopRequireDefault(_strict); 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 InternalCall(realm, F, thisArgument, argsList, tracerIndex) { // 1. Assert: F is an ECMAScript function object. (0, _invariant2.default)(F instanceof _index.FunctionValue, "expected function value"); // Tracing: Give all registered tracers a chance to detour, wrapping around each other if needed. while (tracerIndex < realm.tracers.length) { let tracer = realm.tracers[tracerIndex]; let nextIndex = ++tracerIndex; let detourResult = tracer.detourCall(F, thisArgument, argsList, undefined, () => InternalCall(realm, F, thisArgument, argsList, nextIndex)); if (detourResult instanceof _index.Value) return detourResult; } // 2. If F's [[FunctionKind]] internal slot is "classConstructor", throw a TypeError exception. if (F.$FunctionKind === "classConstructor") throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "not callable"); // 3. Let callerContext be the running execution context. let callerContext = realm.getRunningContext(); // 4. Let calleeContext be PrepareForOrdinaryCall(F, undefined). let calleeContext = (0, _call.PrepareForOrdinaryCall)(realm, F, undefined); let calleeEnv = calleeContext.lexicalEnvironment; let result; try { for (let t1 of realm.tracers) t1.beforeCall(F, thisArgument, argsList, undefined); // 5. Assert: calleeContext is now the running execution context. (0, _invariant2.default)(realm.getRunningContext() === calleeContext, "calleeContext should be current execution context"); // 6. Perform OrdinaryCallBindThis(F, calleeContext, thisArgument). (0, _call.OrdinaryCallBindThis)(realm, F, calleeContext, thisArgument); // 7. Let result be OrdinaryCallEvaluateBody(F, argumentsList). result = (0, _call.OrdinaryCallEvaluateBody)(realm, F, argsList); } finally { // 8. Remove calleeContext from the execution context stack and restore callerContext as the running execution context. realm.popContext(calleeContext); realm.onDestroyScope(calleeContext.lexicalEnvironment); if (calleeContext.lexicalEnvironment !== calleeEnv) realm.onDestroyScope(calleeEnv); (0, _invariant2.default)(realm.getRunningContext() === callerContext); for (let t2 of realm.tracers) t2.afterCall(F, thisArgument, argsList, undefined, result); } // 9. If result.[[Type]] is return, return NormalCompletion(result.[[Value]]). if (result instanceof _completions.ReturnCompletion) { return result.value; } // 10. ReturnIfAbrupt(result). or if possibly abrupt if (result instanceof _completions.Completion) { throw result; } // 11. Return NormalCompletion(undefined). return realm.intrinsics.undefined; } // ECMA262 9.4.1.1 /** * 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. */ function $BoundCall(realm, F, thisArgument, argumentsList) { // 1. Let target be the value of F's [[BoundTargetFunction]] internal slot. let target = F.$BoundTargetFunction; // 2. Let boundThis be the value of F's [[BoundThis]] internal slot. let boundThis = F.$BoundThis; // 3. Let boundArgs be the value of F's [[BoundArguments]] internal slot. let boundArgs = F.$BoundArguments; // 4. Let args be a new list containing the same values as the list boundArgs in the same order followed // by the same values as the list argumentsList in the same order. let args = boundArgs.concat(argumentsList); // 5. Return ? Call(target, boundThis, args). return (0, _call.Call)(realm, target, boundThis, args); } // ECMA262 9.4.1.2 function $BoundConstruct(realm, F, argumentsList, newTarget) { // 1. Let target be the value of F's [[BoundTargetFunction]] internal slot. let target = F.$BoundTargetFunction; // 2. Assert: target has a [[Construct]] internal method. (0, _invariant2.default)(target.$Construct !== undefined, "doesn't have a construct internal method"); // 3. Let boundArgs be the value of F's [[BoundArguments]] internal slot. let boundArgs = F.$BoundArguments; // 4. Let args be a new list containing the same values as the list boundArgs in the same order followed // by the same values as the list argumentsList in the same order. let args = boundArgs.concat(argumentsList); // 5. If SameValue(F, newTarget) is true, let newTarget be target. if ((0, _abstract.SameValue)(realm, F, newTarget)) newTarget = target; // 6. Return ? Construct(target, args, newTarget). return (0, _construct.Construct)(realm, target, args, newTarget); } function InternalConstruct(realm, F, argumentsList, newTarget, thisArgument, tracerIndex) { // 1. Assert: F is an ECMAScript function object. (0, _invariant2.default)(F instanceof _index.FunctionValue, "expected function"); // 2. Assert: Type(newTarget) is Object. (0, _invariant2.default)(newTarget instanceof _index.ObjectValue, "expected object"); if (!realm.hasRunningContext()) { (0, _invariant2.default)(realm.useAbstractInterpretation); throw new _errors.FatalError("no running context"); } // 3. Let callerContext be the running execution context. let callerContext = realm.getRunningContext(); // 4. Let kind be F's [[ConstructorKind]] internal slot. let kind = F.$ConstructorKind; // 5. If kind is "base", then if (thisArgument === undefined && kind === "base") { // a. Let thisArgument be ? OrdinaryCreateFromConstructor(newTarget, "%ObjectPrototype%"). thisArgument = _singletons.Create.OrdinaryCreateFromConstructor(realm, newTarget, "ObjectPrototype"); } // Tracing: Give all registered tracers a chance to detour, wrapping around each other if needed. while (tracerIndex < realm.tracers.length) { let tracer = realm.tracers[tracerIndex]; let nextIndex = ++tracerIndex; let detourResult = tracer.detourCall(F, thisArgument, argumentsList, newTarget, () => InternalConstruct(realm, F, argumentsList, newTarget, thisArgument, nextIndex)); if (detourResult instanceof _index.ObjectValue) return detourResult; (0, _invariant2.default)(detourResult === undefined); } // 6. Let calleeContext be PrepareForOrdinaryCall(F, newTarget). let calleeContext = (0, _call.PrepareForOrdinaryCall)(realm, F, newTarget); let calleeEnv = calleeContext.lexicalEnvironment; // 7. Assert: calleeContext is now the running execution context. (0, _invariant2.default)(realm.getRunningContext() === calleeContext, "expected calleeContext to be running context"); let result, envRec; try { for (let t1 of realm.tracers) t1.beforeCall(F, thisArgument, argumentsList, newTarget); // 8. If kind is "base", perform OrdinaryCallBindThis(F, calleeContext, thisArgument). if (kind === "base") { (0, _invariant2.default)(thisArgument, "this wasn't initialized for some reason"); (0, _call.OrdinaryCallBindThis)(realm, F, calleeContext, thisArgument); } // 9. Let constructorEnv be the LexicalEnvironment of calleeContext. let constructorEnv = calleeContext.lexicalEnvironment; // 10. Let envRec be constructorEnv's EnvironmentRecord. envRec = constructorEnv.environmentRecord; // 11. Let result be OrdinaryCallEvaluateBody(F, argumentsList). result = (0, _call.OrdinaryCallEvaluateBody)(realm, F, argumentsList); } finally { // 12. Remove calleeContext from the execution context stack and restore callerContext as the running execution context. realm.popContext(calleeContext); realm.onDestroyScope(calleeContext.lexicalEnvironment); if (calleeContext.lexicalEnvironment !== calleeEnv) realm.onDestroyScope(calleeEnv); (0, _invariant2.default)(realm.getRunningContext() === callerContext); for (let t2 of realm.tracers) t2.afterCall(F, thisArgument, argumentsList, newTarget, result); } // 13. If result.[[Type]] is return, then if (result instanceof _completions.ReturnCompletion) { // a. If Type(result.[[Value]]) is Object, return NormalCompletion(result.[[Value]]). if (result.value.mightBeObject()) { return result.value.throwIfNotConcreteObject(); } // b. If kind is "base", return NormalCompletion(thisArgument). if (kind === "base") { (0, _invariant2.default)(thisArgument, "this wasn't initialized for some reason"); return thisArgument; } // c. If result.[[Value]] is not undefined, throw a TypeError exception. if (!result.value.mightBeUndefined()) throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "constructor must return Object"); result.value.throwIfNotConcrete(); } else if (result instanceof _completions.AbruptCompletion) { // 14. Else, ReturnIfAbrupt(result). throw result; } // 15. Return ? envRec.GetThisBinding(). let envRecThisBinding = envRec.GetThisBinding(); (0, _invariant2.default)(envRecThisBinding instanceof _index.ObjectValue); return envRecThisBinding; } class FunctionImplementation { FindVarScopedDeclarations(ast_node) { function FindVarScopedDeclarationsFor(ast, level) { let statements = []; switch (ast.type) { case "Program": statements = ast.body; break; case "BlockStatement": statements = ast.body; break; case "DoWhileStatement": statements = [ast.body]; break; case "WhileStatement": statements = [ast.body]; break; case "IfStatement": let astIfStatement = ast; statements = [astIfStatement.consequent, astIfStatement.alternate]; break; case "ForStatement": let astForStatement = ast; statements = [astForStatement.init, astForStatement.body]; break; case "ForInStatement": let astForInStatement = ast; statements = [astForInStatement.left, astForInStatement.body]; break; case "ForOfStatement": let astForOfStatement = ast; statements = [astForOfStatement.left, astForOfStatement.body]; break; case "LabeledStatement": statements = [ast.body]; break; case "WithStatement": statements = [ast.body]; break; case "SwitchStatement": for (let switchCase of ast.cases) { statements = statements.concat(switchCase.consequent); } break; case "TryStatement": let astTryStatement = ast; statements = [astTryStatement.block]; if (astTryStatement.finalizer) statements.push(astTryStatement.finalizer); if (astTryStatement.handler) statements.push(astTryStatement.handler.body); break; case "VariableDeclaration": return ast.kind === "var" ? [ast] : []; case "FunctionDeclaration": return level < 2 ? [ast] : []; default: return []; } let decls = []; for (let statement of statements) { if (statement) { decls = decls.concat(FindVarScopedDeclarationsFor(statement, level + 1)); } } return decls; } return FindVarScopedDeclarationsFor(ast_node, 0); } // ECMA262 9.2.12 FunctionDeclarationInstantiation(realm, func, argumentsList) { // 1. Let calleeContext be the running execution context. let calleeContext = realm.getRunningContext(); // 2. Let env be the LexicalEnvironment of calleeContext. let env = calleeContext.lexicalEnvironment; // 3. Let envRec be env's EnvironmentRecord. let envRec = env.environmentRecord; // 4. Let code be the value of the [[ECMAScriptCode]] internal slot of func. let code = func.$ECMAScriptCode; (0, _invariant2.default)(code !== undefined); // 5. Let strict be the value of the [[Strict]] internal slot of func. let strict = func.$Strict; // 6. Let formals be the value of the [[FormalParameters]] internal slot of func. let formals = func.$FormalParameters; (0, _invariant2.default)(formals !== undefined); // 7. Let parameterNames be the BoundNames of formals. let parameterNames = Object.create(null); for (let param of formals) { let paramBindings = t.getBindingIdentifiers(param, true); for (let name in paramBindings) { parameterNames[name] = (parameterNames[name] || []).concat(paramBindings[name]); } } // 8. If parameterNames has any duplicate entries, let hasDuplicates be true. Otherwise, let hasDuplicates be false. let hasDuplicates = false; for (let name in parameterNames) { let identifiers = parameterNames[name]; if (identifiers.length > 1) hasDuplicates = true; } parameterNames = Object.keys(parameterNames); // 9. Let simpleParameterList be IsSimpleParameterList of formals. let simpleParameterList = true; for (let param of formals) { if (param.type !== "Identifier") { simpleParameterList = false; break; } } // 10. Let hasParameterExpressions be ContainsExpression of formals. let hasParameterExpressions = false; (0, _invariant2.default)(formals !== undefined); for (let param of formals) { if (_singletons.Environment.ContainsExpression(realm, param)) { hasParameterExpressions = true; break; } } // 11. Let varNames be the VarDeclaredNames of code. let varNames = []; (0, _traverseFast2.default)(code, node => { if (node.type === "VariableDeclaration" && node.kind === "var") { varNames = varNames.concat(Object.keys(t.getBindingIdentifiers(node))); } if (node.type === "FunctionExpression" || node.type === "FunctionDeclaration") { return true; } return false; }); // 12. Let varDeclarations be the VarScopedDeclarations of code. let varDeclarations = this.FindVarScopedDeclarations(code); // 13. Let lexicalNames be the LexicallyDeclaredNames of code. let lexicalNames = []; // 14. Let functionNames be an empty List. let functionNames = []; // 15. Let functionsToInitialize be an empty List. let functionsToInitialize = []; // 16. For each d in varDeclarations, in reverse list order do for (let d of varDeclarations.reverse()) { // a. If d is neither a VariableDeclaration or a ForBinding, then if (d.type !== "VariableDeclaration") { // i. Assert: d is either a FunctionDeclaration or a GeneratorDeclaration. (0, _invariant2.default)(d.type === "FunctionDeclaration" || d.type === "GeneratorDeclaration"); // ii. Let fn be the sole element of the BoundNames of d. let fn = _singletons.Environment.BoundNames(realm, d)[0]; // iii. If fn is not an element of functionNames, then if (functionNames.indexOf(fn) < 0) { // 1. Insert fn as the first element of functionNames. functionNames.unshift(fn); // 2. NOTE If there are multiple FunctionDeclarations or GeneratorDeclarations for the same name, the last declaration is used. // 3. Insert d as the first element of functionsToInitialize. functionsToInitialize.unshift(d); } } } // 17. Let argumentsObjectNeeded be true. let argumentsObjectNeeded = true; // 18. If the value of the [[realmMode]] internal slot of func is lexical, then if (func.$ThisMode === "lexical") { // a. NOTE Arrow functions never have an arguments objects. // b. Let argumentsObjectNeeded be false. argumentsObjectNeeded = false; } else if (parameterNames.indexOf("arguments") >= 0) { // 19. Else if "arguments" is an element of parameterNames, then // a. Let argumentsObjectNeeded be false. argumentsObjectNeeded = false; } else if (hasParameterExpressions === false) { // 20. Else if hasParameterExpressions is false, then // a. If "arguments" is an element of functionNames or if "arguments" is an element of lexicalNames, then if (functionNames.indexOf("arguments") >= 0 || lexicalNames.indexOf("arguments") >= 0) { // i. Let argumentsObjectNeeded be false. argumentsObjectNeeded = true; } } // 21. For each String paramName in parameterNames, do for (let paramName of parameterNames) { // a. Let alreadyDeclared be envRec.HasBinding(paramName). let alreadyDeclared = envRec.HasBinding(paramName); // b. NOTE Early errors ensure that duplicate parameter names can only occur in non-strict functions that do not have parameter default values or rest parameters. // c. If alreadyDeclared is false, then if (alreadyDeclared === false) { // i. Perform ! envRec.CreateMutableBinding(paramName, false). envRec.CreateMutableBinding(paramName, false); // ii. If hasDuplicates is true, then if (hasDuplicates === true) { // 1. Perform ! envRec.InitializeBinding(paramName, undefined). envRec.InitializeBinding(paramName, realm.intrinsics.undefined); } } } // 22. If argumentsObjectNeeded is true, then if (argumentsObjectNeeded === true) { let ao; // a. If strict is true or if simpleParameterList is false, then if (strict === true || simpleParameterList === false) { // i. Let ao be CreateUnmappedArgumentsObject(argumentsList). ao = _singletons.Create.CreateUnmappedArgumentsObject(realm, argumentsList); } else { // b. Else, // i. NOTE mapped argument object is only provided for non-strict functions that don't have a rest parameter, any parameter default value initializers, or any destructured parameters. // ii. Let ao be CreateMappedArgumentsObject(func, formals, argumentsList, envRec). (0, _invariant2.default)(formals !== undefined); ao = _singletons.Create.CreateMappedArgumentsObject(realm, func, formals, argumentsList, envRec); } // c. If strict is true, then if (strict === true) { // i. Perform ! envRec.CreateImmutableBinding("arguments", false). envRec.CreateImmutableBinding("arguments", false); } else { // d. Else, // i. Perform ! envRec.CreateMutableBinding("arguments", false). envRec.CreateMutableBinding("arguments", false); } // e. Call envRec.InitializeBinding("arguments", ao). envRec.InitializeBinding("arguments", ao); // f. Append "arguments" to parameterNames. parameterNames.push("arguments"); } // 23. Let iteratorRecord be Record {[[Iterator]]: CreateListIterator(argumentsList), [[Done]]: false}. let iteratorRecord = { $Iterator: (0, _iterator.CreateListIterator)(realm, argumentsList), $Done: false }; // 24. If hasDuplicates is true, then if (hasDuplicates === true) { // a. Perform ? IteratorBindingInitialization for formals with iteratorRecord and undefined as arguments. (0, _invariant2.default)(formals !== undefined); _singletons.Environment.IteratorBindingInitialization(realm, formals, iteratorRecord, strict); } else { // 25. Else, // a. Perform ? IteratorBindingInitialization for formals with iteratorRecord and env as arguments. (0, _invariant2.default)(formals !== undefined); _singletons.Environment.IteratorBindingInitialization(realm, formals, iteratorRecord, strict, env); } // 26. If hasParameterExpressions is false, then let varEnv, varEnvRec; if (hasParameterExpressions === false) { // a. NOTE Only a single lexical environment is needed for the parameters and top-level vars. // b. Let instantiatedVarNames be a copy of the List parameterNames. let instantiatedVarNames = parameterNames.slice(); // c. For each n in varNames, do for (let n of varNames) { // i. If n is not an element of instantiatedVarNames, then if (instantiatedVarNames.indexOf(n) < 0) { // 1. Append n to instantiatedVarNames. instantiatedVarNames.push(n); // 2. Perform ! envRec.CreateMutableBinding(n, false). envRec.CreateMutableBinding(n, false); // 3. Call envRec.InitializeBinding(n, undefined). envRec.InitializeBinding(n, realm.intrinsics.undefined); } } // e. Let varEnv be env. varEnv = env; // f. Let varEnvRec be envRec. varEnvRec = envRec; } else { // 27. Else, // a. NOTE A separate Environment Record is needed to ensure that closures created by expressions in the formal parameter list do not have visibility of declarations in the function body. // b. Let varEnv be NewDeclarativeEnvironment(env). varEnv = _singletons.Environment.NewDeclarativeEnvironment(realm, env); // At this point we haven't set any context's lexical environment to varEnv (and we might never do so), // so it shouldn't be active realm.activeLexicalEnvironments.delete(varEnv); // c. Let varEnvRec be varEnv's EnvironmentRecord. varEnvRec = varEnv.environmentRecord; // d. Set the VariableEnvironment of calleeContext to varEnv. calleeContext.variableEnvironment = varEnv; // e. Let instantiatedVarNames be a new empty List. let instantiatedVarNames = []; // f. For each n in varNames, do for (let n of varNames) { // i. If n is not an element of instantiatedVarNames, then if (instantiatedVarNames.indexOf(n) < 0) { // 1. Append n to instantiatedVarNames. instantiatedVarNames.push(n); // 2. Perform ! varEnvRec.CreateMutableBinding(n, false). varEnvRec.CreateMutableBinding(n, false); // 3. If n is not an element of parameterNames or if n is an element of functionNames, let initialValue be undefined. let initialValue; if (parameterNames.indexOf(n) < 0 || functionNames.indexOf(n) < 0) { initialValue = realm.intrinsics.undefined; } else { // 4. Else, // a. Let initialValue be ! envRec.GetBindingValue(n, false). initialValue = envRec.GetBindingValue(n, false); } // 5. Call varEnvRec.InitializeBinding(n, initialValue). varEnvRec.InitializeBinding(n, initialValue); // 6. NOTE vars whose names are the same as a formal parameter, initially have the same value as the corresponding initialized parameter. } } } // 28. NOTE: Annex B.3.3.1 adds additional steps at realm point. let lexEnv; // 29. If strict is false, then if (strict === false) { // a. Let lexEnv be NewDeclarativeEnvironment(varEnv). lexEnv = _singletons.Environment.NewDeclarativeEnvironment(realm, varEnv); // b. NOTE: Non-strict functions use a separate lexical Environment Record for top-level lexical declarations so that a direct eval (see 12.3.4.1) can determine whether any var scoped declarations introduced by the eval code conflict with pre-existing top-level lexically scoped declarations. realm is not needed for strict functions because a strict direct eval always places all declarations into a new Environment Record. } else { // 30. Else, let lexEnv be varEnv. lexEnv = varEnv; // Since we previously removed varEnv, make sure to re-add it when it's used. realm.activeLexicalEnvironments.add(varEnv); } // 31. Let lexEnvRec be lexEnv's EnvironmentRecord. let lexEnvRec = lexEnv.environmentRecord; // 32. Set the LexicalEnvironment of calleeContext to lexEnv. calleeContext.lexicalEnvironment = lexEnv; // 33. Let lexDeclarations be the LexicallyScopedDeclarations of code. let lexDeclarations = []; // 34. For each element d in lexDeclarations do for (let d of lexDeclarations) { // a. NOTE A lexically declared name cannot be the same as a function/generator declaration, formal parameter, or a var name. Lexically declared names are only instantiated here but not initialized. // b. For each element dn of the BoundNames of d do for (let dn of _singletons.Environment.BoundNames(realm, d)) { // i. If IsConstantDeclaration of d is true, then if (d.kind === "const") { // 1. Perform ! lexEnvRec.CreateImmutableBinding(dn, true). lexEnvRec.CreateImmutableBinding(dn, true); } else { // ii. Else, // 1. Perform ! lexEnvRec.CreateMutableBinding(dn, false). lexEnvRec.CreateMutableBinding(dn, false); } } } // 35. For each parsed grammar phrase f in functionsToInitialize, do for (let f of functionsToInitialize) { // a. Let fn be the sole element of the BoundNames of f. let fn = _singletons.Environment.BoundNames(realm, f)[0]; // b. Let fo be the result of performing InstantiateFunctionObject for f with argument lexEnv. let fo = lexEnv.evaluate(f, strict); (0, _invariant2.default)(fo instanceof _index.Value); // c. Perform ! varEnvRec.SetMutableBinding(fn, fo, false). varEnvRec.SetMutableBinding(fn, fo, false); } // 36. Return NormalCompletion(empty). return realm.intrinsics.empty; } // ECMA262 9.2.11 SetFunctionName(realm, F, name, prefix) { // 1. Assert: F is an extensible object that does not have a name own property. (0, _invariant2.default)(F.getExtensible(), "expected object to be extensible and not have a name property"); // 2. Assert: Type(name) is either Symbol or String. (0, _invariant2.default)(typeof name === "string" || name instanceof _index.StringValue || name instanceof _index.SymbolValue || name instanceof _index.AbstractValue, "expected name to be a string or symbol"); if (typeof name === "string") name = new _index.StringValue(realm, name); // 3. Assert: If prefix was passed, then Type(prefix) is String. (0, _invariant2.default)(prefix === undefined || typeof prefix === "string", "expected prefix to be a string if passed"); // 4. If Type(name) is Symbol, then if (name instanceof _index.SymbolValue) { // a. Let description be name's [[Description]] value. let description = name.$Description; // b. If description is undefined, let name be the empty String. if (description === undefined) { name = realm.intrinsics.emptyString; } else { // c. Else, let name be the concatenation of "[", description, and "]". (0, _invariant2.default)(description instanceof _index.Value); name = new _index.StringValue(realm, `[${description.throwIfNotConcreteString().value}]`); } } // 5. If prefix was passed, then if (prefix) { // a. Let name be the concatenation of prefix, code unit 0x0020 (SPACE), and name. if (name instanceof _index.AbstractValue) { let prefixVal = new _index.StringValue(realm, prefix + " "); name = _index.AbstractValue.createFromBinaryOp(realm, "+", prefixVal, name, name.expressionLocation); } else { name = new _index.StringValue(realm, `${prefix} ${name.value}`); } } // 6. Return ! DefinePropertyOrThrow(F, "name", PropertyDescriptor{[[Value]]: name, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true}). return _singletons.Properties.DefinePropertyOrThrow(realm, F, "name", { value: name, enumerable: false, writable: false, configurable: true }); } // ECMA262 9.2.3 FunctionInitialize(realm, F, kind, ParameterList, Body, Scope) { // Note that F is a new object, and we can thus write to internal slots (0, _invariant2.default)(realm.isNewObject(F)); // 1. Assert: F is an extensible object that does not have a length own property. (0, _invariant2.default)(F.getExtensible(), "expected to be extensible and no length property"); // 2. Let len be the ExpectedArgumentCount of ParameterList. let len = 0; for (let FormalParameter of ParameterList) { if (FormalParameter.type === "AssignmentPattern") { break; } len += 1; } // 3. Perform ! DefinePropertyOrThrow(F, "length", PropertyDescriptor{[[Value]]: len, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: true}). _singletons.Properties.DefinePropertyOrThrow(realm, F, "length", { value: new _index.NumberValue(realm, len), writable: false, enumerable: false, configurable: true }); // 4. Let Strict be the value of the [[Strict]] internal slot of F. let Strict = F.$Strict; if (!Strict) { _singletons.Properties.DefinePropertyOrThrow(realm, F, "caller", { value: new _index.UndefinedValue(realm), writable: true, enumerable: false, configurable: true }); } // 5. Set the [[Environment]] internal slot of F to the value of Scope. F.$Environment = Scope; // 6. Set the [[FormalParameters]] internal slot of F to ParameterList. F.$FormalParameters = ParameterList; // 7. Set the [[ECMAScriptCode]] internal slot of F to Body. Body.uniqueOrderedTag = realm.functionBodyUniqueTagSeed++; F.$ECMAScriptCode = Body; // 8. Set the [[ScriptOrModule]] internal slot of F to GetActiveScriptOrModule(). F.$ScriptOrModule = _singletons.Environment.GetActiveScriptOrModule(realm); // 9. If kind is Arrow, set the [[realmMode]] internal slot of F to lexical. if (kind === "arrow") { F.$ThisMode = "lexical"; } else if (Strict === true) { // 10. Else if Strict is true, set the [[realmMode]] internal slot of F to strict. F.$ThisMode = "strict"; } else { // 11. Else set the [[realmMode]] internal slot of F to global. F.$ThisMode = "global"; } // Return F. return F; } // ECMA262 9.2.6 GeneratorFunctionCreate(realm, kind, ParameterList, Body, Scope, Strict) { // 1. Let functionPrototype be the intrinsic object %Generator%. let functionPrototype = realm.intrinsics.Generator; // 2. Let F be FunctionAllocate(functionPrototype, Strict, "generator"). let F = this.FunctionAllocate(realm, functionPrototype, Strict, "generator"); // 3. Return FunctionInitialize(F, kind, ParameterList, Body, Scope). return this.FunctionInitialize(realm, F, kind, ParameterList, Body, Scope); } // ECMA262 9.2.7 AddRestrictedFunctionProperties(F, realm) { // 1. Assert: realm.[[Intrinsics]].[[%ThrowTypeError%]] exists and has been initialized. // 2. Let thrower be realm.[[Intrinsics]].[[%ThrowTypeError%]]. let thrower = realm.intrinsics.ThrowTypeError; (0, _invariant2.default)(thrower); let desc = { get: thrower, set: thrower, enumerable: false, configurable: true }; // 3. Perform ! DefinePropertyOrThrow(F, "caller", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: true}). _singletons.Properties.DefinePropertyOrThrow(realm, F, "caller", desc); // 4. Return ! DefinePropertyOrThrow(F, "arguments", PropertyDescriptor {[[Get]]: thrower, [[Set]]: thrower, [[Enumerable]]: false, [[Configurable]]: true}). return _singletons.Properties.DefinePropertyOrThrow(realm, F, "arguments", desc); } // ECMA262 9.2.1 $Call(realm, F, thisArgument, argsList) { return InternalCall(realm, F, thisArgument, argsList, 0); } // ECMA262 9.2.2 $Construct(realm, F, argumentsList, newTarget) { return InternalConstruct(realm, F, argumentsList, newTarget, undefined, 0); } // ECMA262 9.2.3 FunctionAllocate(realm, functionPrototype, strict, functionKind) { // 1. Assert: Type(functionPrototype) is Object. (0, _invariant2.default)(functionPrototype instanceof _index.ObjectValue, "expected functionPrototype to be an object"); // 2. Assert: functionKind is either "normal", "non-constructor" or "generator". (0, _invariant2.default)(functionKind === "normal" || functionKind === "non-constructor" || functionKind === "generator", "invalid functionKind"); // 3. If functionKind is "normal", let needsConstruct be true. let needsConstruct; if (functionKind === "normal") { needsConstruct = true; } else { // 4. Else, let needsConstruct be false. needsConstruct = false; } // 5. If functionKind is "non-constructor", let functionKind be "normal". if (functionKind === "non-constructor") { functionKind = "normal"; } // 6. Let F be a newly created ECMAScript function object with the internal slots listed in Table 27. All of those internal slots are initialized to undefined. let F = new _index.ECMAScriptSourceFunctionValue(realm); // 7. Set F's essential internal methods to the default ordinary object definitions specified in 9.1. // 8. Set F's [[Call]] internal method to the definition specified in 9.2.1. F.$Call = (thisArgument, argsList) => { return this.$Call(realm, F, thisArgument, argsList); }; // 9. If needsConstruct is true, then if (needsConstruct === true) { // a. Set F's [[Construct]] internal method to the definition specified in 9.2.2. F.$Construct = (argumentsList, newTarget) => { return this.$Construct(realm, F, argumentsList, newTarget); }; // b. Set the [[ConstructorKind]] internal slot of F to "base". F.$ConstructorKind = "base"; } // 10. Set the [[Strict]] internal slot of F to strict. F.$Strict = strict; // 11. Set the [[FunctionKind]] internal slot of F to functionKind. F.$FunctionKind = functionKind; // 12. Set the [[Prototype]] internal slot of F to functionPrototype. F.$Prototype = functionPrototype; // 13. Set the [[Extensible]] internal slot of F to true. F.setExtensible(true); // 14. Set the [[Realm]] internal slot of F to the current Realm Record. F.$Realm = realm; // 15. Return F. return F; } // ECMA262 9.4.1.3 BoundFunctionCreate(realm, targetFunction, boundThis, boundArgs) { // 1. Assert: Type(targetFunction) is Object. (0, _invariant2.default)(targetFunction instanceof _index.ObjectValue, "expected an object"); // 2. Let proto be ? targetFunction.[[GetPrototypeOf]](). let proto = targetFunction.$GetPrototypeOf(); // 3. Let obj be a newly created object. let obj = new _index.BoundFunctionValue(realm); // 4. Set obj's essential internal methods to the default ordinary object definitions specified in 9.1. // 5. Set the [[Call]] internal method of obj as described in 9.4.1.1. obj.$Call = (thisArgument, argsList) => { return $BoundCall(realm, obj, thisArgument, argsList); }; // 6. If targetFunction has a [[Construct]] internal method, then if (targetFunction.$Construct) { // a. Set the [[Construct]] internal method of obj as described in 9.4.1.2. obj.$Construct = (thisArgument, argsList) => { return $BoundConstruct(realm, obj, thisArgument, argsList); }; } // 7. Set the [[Prototype]] internal slot of obj to proto. obj.$Prototype = proto; // 8. Set the [[Extensible]] internal slot of obj to true. obj.setExtensible(true); // 9. Set the [[BoundTargetFunction]] internal slot of obj to targetFunction. obj.$BoundTargetFunction = targetFunction; // 10. Set the [[BoundThis]] internal slot of obj to the value of boundThis. obj.$BoundThis = boundThis; // 11. Set the [[BoundArguments]] internal slot of obj to boundArgs. obj.$BoundArguments = boundArgs; // 12. Return obj. return obj; } // ECMA262 18.2.1.1 PerformEval(realm, x, evalRealm, strictCaller, direct) { // 1. Assert: If direct is false, then strictCaller is also false. if (direct === false) (0, _invariant2.default)(strictCaller === false, "strictCaller is only allowed on direct eval"); // 2. If Type(x) is not String, return x. if (!(x instanceof _index.StringValue)) return x; // 3. Let script be the ECMAScript code that is the result of parsing x, interpreted as UTF-16 encoded Unicode text // as described in 6.1.4, for the goal symbol Script. If the parse fails, throw a SyntaxError exception. If any // early errors are detected, throw a SyntaxError or a ReferenceError exception, depending on the type of the // error (but see also clause 16). Parsing and early error detection may be interweaved in an implementation // dependent manner. let ast = (0, _parse2.default)(realm, x.value, "eval", "script"); let script = ast.program; // 4. If script Contains ScriptBody is false, return undefined. if (!script.body) return realm.intrinsics.undefined; // 5. Let body be the ScriptBody of script. let body = t.blockStatement(script.body, script.directives); // 6. If strictCaller is true, let strictEval be true. let strictEval; if (strictCaller) { strictEval = true; } else { // 7. Else, let strictEval be IsStrict of script. strictEval = (0, _strict2.default)(script); } // 8. Let ctx be the running execution context. If direct is true, ctx will be the execution context that // performed the direct eval. If direct is false, ctx will be the execution context for the invocation of // the eval function. let ctx = realm.getRunningContext(); // 9. If direct is true, then let lexEnv, varEnv; if (direct) { // a. Let lexEnv be NewDeclarativeEnvironment(ctx's LexicalEnvironment). lexEnv = _singletons.Environment.NewDeclarativeEnvironment(realm, ctx.lexicalEnvironment); // b. Let varEnv be ctx's VariableEnvironment. varEnv = ctx.variableEnvironment; } else { // 10. Else, // a. Let lexEnv be NewDeclarativeEnvironment(evalRealm.[[GlobalEnv]]). lexEnv = _singletons.Environment.NewDeclarativeEnvironment(realm, evalRealm.$GlobalEnv); // b. Let varEnv be evalRealm.[[GlobalEnv]]. varEnv = evalRealm.$GlobalEnv; } // 11. If strictEval is true, let varEnv be lexEnv. if (strictEval) varEnv = lexEnv; // 12. If ctx is not already suspended, suspend ctx. ctx.suspend(); // 13. Let evalCxt be a new ECMAScript code execution context. let evalCxt = new _realm.ExecutionContext(); evalCxt.isStrict = strictEval; // 14. Set the evalCxt's Function to null. evalCxt.setFunction(null); // 15. Set the evalCxt's Realm to evalRealm. evalCxt.setRealm(evalRealm); // 16. Set the evalCxt's ScriptOrModule to ctx's ScriptOrModule. evalCxt.ScriptOrModule = ctx.ScriptOrModule; // 17. Set the evalCxt's VariableEnvironment to varEnv. evalCxt.variableEnvironment = varEnv; // 18. Set the evalCxt's LexicalEnvironment to lexEnv. evalCxt.lexicalEnvironment = lexEnv; // 19. Push evalCxt on to the execution context stack; evalCxt is now the running execution context. realm.pushContext(evalCxt); let result; try { // 20. Let result be EvalDeclarationInstantiation(body, varEnv, lexEnv, strictEval). (0, _invariant2.default)(varEnv); try { result = this.EvalDeclarationInstantiation(realm, body, varEnv, lexEnv, strictEval); } catch (e) { if (e instanceof _completions.AbruptCompletion) { result = e; } else { throw e; } } (0, _invariant2.default)(result instanceof _index.Value || result instanceof _completions.AbruptCompletion); // 21. If result.[[Type]] is normal, then if (result instanceof _index.Value) { // Evaluate expressions that passed for directives. if (script.directives) { for (let directive of script.directives) { result = new _index.StringValue(realm, directive.value.value); } } // a. Let result be the result of evaluating body. result = this.EvaluateStatements(script.body, result, strictEval, lexEnv, realm); } // 22. If result.[[Type]] is normal and result.[[Value]] is empty, then if (result instanceof _index.EmptyValue) { // a. Let result be NormalCompletion(undefined). result = realm.intrinsics.undefined; } } finally { // 23. Suspend evalCxt and remove it from the execution context stack. evalCxt.suspend(); realm.popContext(evalCxt); realm.onDestroyScope(evalCxt.lexicalEnvironment); } // 24. Resume the context that is now on the top of the execution context stack as the running execution context. (0, _invariant2.default)(realm.getRunningContext() === ctx); ctx.resume(); // 25. Return Completion(result). if (result instanceof _index.Value) { return result; } else { (0, _invariant2.default)(result instanceof _completions.AbruptCompletion); throw result; } } // If c is an abrupt completion and realm.savedCompletion is defined, the result is an instance of // JoinedAbruptCompletions and the effects that have been captured since the PossiblyNormalCompletion instance // in realm.savedCompletion has been created, becomes the effects of the branch that terminates in c. // If c is a normal completion, the result is realm.savedCompletion, with its value updated to c. // If c is undefined, the result is just realm.savedCompletion. // Call this only when a join point has been reached. incorporateSavedCompletion(realm, c) { let savedCompletion = realm.savedCompletion; if (savedCompletion !== undefined) { if (savedCompletion.savedPathConditions) { // Since we are joining several control flow paths, we need the curent path conditions to reflect // only the refinements that applied at the corresponding fork point. realm.pathConditions = savedCompletion.savedPathConditions; savedCompletion.savedPathConditions = []; } realm.savedCompletion = undefined; if (c === undefined) return savedCompletion; if (c instanceof _index.Value) { _singletons.Join.updatePossiblyNormalCompletionWithValue(realm, savedCompletion, c); return savedCompletion; } else { let e = realm.getCapturedEffects(savedCompletion); (0, _invariant2.default)(e !== undefined); realm.stopEffectCaptureAndUndoEffects(savedCompletion); let joined_effects = _singletons.Join.joinPossiblyNormalCompletionWithAbruptCompletion(realm, savedCompletion, c, e); realm.applyEffects(joined_effects); let jc = joined_effects[0]; (0, _invariant2.default)(jc instanceof _completions.AbruptCompletion); return jc; } } return c; } EvaluateStatements(body, initialBlockValue, strictCode, blockEnv, realm) { let blockValue = initialBlockValue; for (let node of body) { if (node.type !== "FunctionDeclaration") { let res = blockEnv.evaluateCompletionDeref(node, strictCode); if (!(res instanceof _index.EmptyValue)) { if (res instanceof _completions.AbruptCompletion) throw (0, _index2.UpdateEmpty)(realm, res, blockValue || realm.intrinsics.empty); (0, _invariant2.default)(res instanceof _index.Value); blockValue = res; } } } // 7. Return blockValue. return blockValue || realm.intrinsics.empty; } PartiallyEvaluateStatements(body, blockValue, strictCode, blockEnv, realm) { let statementAsts = []; for (let node of body) { if (node.type !== "FunctionDeclaration") { let [res, nast, nio] = blockEnv.partiallyEvaluateCompletionDeref(node, strictCode); for (let ioAst of nio) statementAsts.push(ioAst); statementAsts.push(nast); if (!(res instanceof _index.EmptyValue)) { if (blockValue === undefined || blockValue instanceof _index.Value) { if (res instanceof _completions.AbruptCompletion) return [(0, _index2.UpdateEmpty)(realm, res, blockValue || realm.intrinsics.empty), statementAsts]; (0, _invariant2.default)(res instanceof _completions.NormalCompletion || res instanceof _index.Value); blockValue = res; } } } } // 7. Return blockValue. return [blockValue || realm.intrinsics.empty, statementAsts]; } // ECMA262 9.2.5 FunctionCreate(realm, kind, ParameterList, Body, Scope, Strict, prototype) { // 1. If the prototype argument was not passed, then if (!prototype) { // a. Let prototype be the intrinsic object %FunctionPrototype%. prototype = realm.intrinsics.FunctionPrototype; } // 2. If kind is not Normal, let allocKind be "non-constructor". let allocKind; if (kind !== "normal") { allocKind = "non-constructor"; } else { // 3. Else, let allocKind be "normal". allocKind = "normal"; } // 4. Let F be FunctionAllocate(prototype, Strict, allocKind). let F = this.FunctionAllocate(realm, prototype, Strict, allocKind); // ECMAScript 2016, section 17: // "Every other data property described in clauses 18 through 26 and in Annex B.2 has the attributes { [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: true } unless otherwise specified." // Because we call `AddRestrictedFunctionProperties` on `FunctionPrototype`, accessing property "arguments" will raise a `TypeError` by default. // However, in non-strict mode this behavior is not desired, so we will add them as own properties of each `FunctionValue`, in accordance with ECMA 17. // Note: "arguments" ***MUST NOT*** be set if the function is in strict mode or is an arrow, method, constructor, or generator function. // See 16.2 "Forbidden Extensions" if (!Strict && kind === "normal") { _singletons.Properties.DefinePropertyOrThrow(realm, F, "arguments", { value: realm.intrinsics.undefined, enumerable: false, writable: true, configurable: true }); } // 5. Return FunctionInitialize(F, kind, ParameterList, Body, Scope). return this.FunctionInitialize(realm, F, kind, ParameterList, Body, Scope); } // ECMA262 18.2.1.2 EvalDeclarationInstantiation(realm, body, varEnv, lexEnv, strict) { // 1. Let varNames be the VarDeclaredNames of body. let varNames = []; (0, _traverseFast2.default)(body, node => { if (node.type === "VariableDeclaration" && node.kind === "var") { varNames = varNames.concat(Object.keys(t.getBindingIdentifiers(node))); } if (node.type === "FunctionExpression" || node.type === "FunctionDeclaration") { return true; } return false; }); // 2. Let varDeclarations be the VarScopedDeclarations of body. let varDeclarations = this.FindVarScopedDeclarations(body); // 3. Let lexEnvRec be lexEnv's EnvironmentRecord. let lexEnvRec = lexEnv.environmentRecord; // 4. Let varEnvRec be varEnv's EnvironmentRecord. let varEnvRec = varEnv.environmentRecord; // 5. If strict is false, then if (!strict) { // a. If varEnvRec is a global Environment Record, then if (varEnvRec instanceof _environment.GlobalEnvironmentRecord) { // i. For each name in varNames, do for (let name of varNames) { // 1. If varEnvRec.HasLexicalDeclaration(name) is true, throw a SyntaxError exception. if (varEnvRec.HasLexicalDeclaration(name)) { throw realm.createErrorThrowCompletion(realm.intrinsics.SyntaxError, new _index.StringValue(realm, name + " global object is restricted")); } // 2. NOTE: eval will not create a global var declaration that would be shadowed by a global lexical declaration. } } // b. Let thisLex be lexEnv. let thisLex = lexEnv; // c. Assert: The following loop will terminate. // d. Repeat while thisLex is not the same as varEnv, while (thisLex !== varEnv) { // i. Let thisEnvRec be thisLex's EnvironmentRecord. let thisEnvRec = thisLex.environmentRecord; // ii. If thisEnvRec is not an object Environment Record, then if (!(thisEnvRec instanceof _environment.ObjectEnvironmentRecord)) { // 1. NOTE: The environment of with statements cannot contain any lexical declaration so it d