Merge commit '6e92d2345e8231a44556ce7d416451f5f3e6c398' as 'engine262'

This commit is contained in:
2026-03-27 10:07:29 +05:30
433 changed files with 90478 additions and 0 deletions
+345
View File
@@ -0,0 +1,345 @@
import type { Protocol } from 'devtools-protocol';
import { shouldStepOnNode } from '../host-defined/debugger-util.mts';
import {
} from '../host-defined/engine.mts';
import * as messages from '../messages.mts';
import { isArray } from '../helpers.mts';
import {
ObjectValue, SymbolValue, type Job, type Intrinsics, type ErrorType, Value, ThrowCompletion, Throw, GetActiveScriptOrModule, type ValueEvaluator, NormalCompletion, EnsureCompletion, skipDebugger, type ValueCompletion, type ScriptRecord, SourceTextModuleRecord, Realm, X, Construct,
ExecutionContextStack,
type AgentHostDefined,
DynamicParsedCodeRecord,
surroundingAgent,
type Feature,
type GCMarker,
type ResumeEvaluateOptions,
type ParseNode,
getBreakpointCandidates,
} from '#self';
let agentSignifier = 0;
/** https://tc39.es/ecma262/#table-agent-record */
export interface AgentRecord {
readonly LittleEndian: boolean;
CanBlock: boolean;
readonly Signifier: number;
readonly IsLockFree1: boolean;
readonly IsLockFree2: boolean;
readonly IsLockFree8: boolean;
// unsupported
CandidateExecution: never;
KeptAlive: Set<ObjectValue | SymbolValue>;
ModuleAsyncEvaluationCount: number;
}
/** https://tc39.es/ecma262/#sec-agents */
export class Agent {
readonly AgentRecord: AgentRecord;
executionContextStack = new ExecutionContextStack();
// NON-SPEC
readonly jobQueue: Job[] = [];
scheduledForCleanup = new Set();
hostDefinedOptions: AgentHostDefined;
constructor(options: AgentHostDefined = {}) {
const Signifier = agentSignifier;
agentSignifier += 1;
this.AgentRecord = {
LittleEndian: true,
CanBlock: true,
Signifier,
IsLockFree1: true,
IsLockFree2: true,
IsLockFree8: true,
CandidateExecution: undefined!,
KeptAlive: new Set(),
ModuleAsyncEvaluationCount: 0,
};
this.hostDefinedOptions = {
...options,
features: options.features,
};
}
/** https://tc39.es/ecma262/#running-execution-context */
get runningExecutionContext() {
return this.executionContextStack[this.executionContextStack.length - 1];
}
/** https://tc39.es/ecma262/#current-realm */
get currentRealmRecord() {
return this.runningExecutionContext.Realm;
}
/** https://tc39.es/ecma262/#active-function-object */
get activeFunctionObject() {
return this.runningExecutionContext.Function;
}
intrinsic<const T extends keyof Intrinsics>(name: T): Intrinsics[T] {
return this.currentRealmRecord.Intrinsics[name];
}
// Generate a throw completion using message templates
/** @deprecated Use Throw */
Throw<K extends keyof typeof messages>(type: ErrorType | Value, template: K, ...templateArgs: Parameters<(typeof messages)[K]>): ThrowCompletion {
if (type instanceof Value) {
return ThrowCompletion(type);
}
return Throw(type, template, ...templateArgs);
}
queueJob(queueName: string, job: () => void) {
const callerContext = this.runningExecutionContext;
const callerRealm = callerContext.Realm;
const callerScriptOrModule = GetActiveScriptOrModule();
const pending: Job = {
queueName,
job,
callerRealm,
callerScriptOrModule,
};
this.jobQueue.push(pending);
}
// NON-SPEC: Check if a feature is enabled in this agent.
feature(name: Feature): boolean {
return !!this.hostDefinedOptions.features?.includes(name);
}
// NON-SPEC
mark(m: GCMarker) {
this.AgentRecord.KeptAlive.forEach(m);
this.executionContextStack.forEach(m);
this.jobQueue.forEach((j) => {
m(j.callerRealm);
m(j.callerScriptOrModule);
});
}
// NON-SPEC
// #region Step-by-step evaluation
#pausedEvaluator?: ValueEvaluator;
#onEvaluatorFin?: (completion: NormalCompletion<Value> | ThrowCompletion) => void;
// NON-SPEC
/** This function will synchronously return a completion if this is a nested evaluation and debugger cannot be triggered. */
evaluate<T extends Value>(evaluator: ValueEvaluator<T>, onFinished: (completion: NormalCompletion<T> | ThrowCompletion) => void) {
if (this.#pausedEvaluator) {
const result = EnsureCompletion(skipDebugger(evaluator));
// only the top evaluator can be evaluted step by step.
onFinished(result);
return result;
}
this.#pausedEvaluator = evaluator;
this.#onEvaluatorFin = onFinished as (completion: NormalCompletion<Value> | ThrowCompletion) => void;
return undefined;
}
resumeEvaluate(options?: ResumeEvaluateOptions): IteratorResult<void, ValueCompletion> {
const { noBreakpoint } = options || {};
if (!this.#pausedEvaluator) {
throw new Error('No paused evaluator');
}
let nextLocation;
if (options?.pauseAt === 'step-over') {
nextLocation = this.runningExecutionContext.callSite.nextNode;
} else if (options?.pauseAt === 'step-out') {
nextLocation = this.executionContextStack[this.executionContextStack.length - 2].callSite.lastCallNode;
}
let debuggerStatementCompletion = options?.debuggerStatementCompletion;
while (true) {
const state = this.#pausedEvaluator.next({ type: 'debugger-resume', value: debuggerStatementCompletion });
debuggerStatementCompletion = undefined;
if (!noBreakpoint && this.hostDefinedOptions.onDebugger && !this.debugger_isPreviewing && !state.done) {
if (state.value.type === 'debugger') {
this.hostDefinedOptions.onDebugger();
return { done: false, value: undefined };
} else if (state.value.type === 'potential-debugger') {
if (options?.pauseAt === 'step-in' && shouldStepOnNode()) {
this.hostDefinedOptions.onDebugger();
return { done: false, value: undefined };
}
const callSite = surroundingAgent.runningExecutionContext.callSite;
if (nextLocation && (callSite.lastNode === nextLocation || callSite.lastCallNode === nextLocation)) {
this.hostDefinedOptions.onDebugger();
return { done: false, value: undefined };
}
}
}
if (state.done) {
this.#pausedEvaluator = undefined;
this.#onEvaluatorFin!(EnsureCompletion(state.value));
this.#onEvaluatorFin = undefined;
return state;
}
}
}
// #endregion
// NON-SPEC
// #region parsed scripts/modules
#script_id = 0;
parsedSources = new Map<string, ScriptRecord | SourceTextModuleRecord | DynamicParsedCodeRecord>();
addParsedSource(source: ScriptRecord | SourceTextModuleRecord) {
const id = `${this.#script_id}`;
if (source.HostDefined) {
source.HostDefined.scriptId = id;
}
this.hostDefinedOptions.onScriptParsed?.(source, id);
this.parsedSources.set(id, source);
this.#script_id += 1;
}
#dynamicParsedSourceIds = new Map<string, string>();
addDynamicParsedSource(realm: Realm, sourceText: string, ast?: unknown[] | ParseNode.Expression | ParseNode.Script): string | undefined {
if (this.debugger_isPreviewing) {
return undefined;
}
if (this.#dynamicParsedSourceIds.has(sourceText)) {
return this.#dynamicParsedSourceIds.get(sourceText);
}
const id = `${this.#script_id}`;
const source = new DynamicParsedCodeRecord(realm, !ast || isArray(ast) ? sourceText : ast);
source.HostDefined.scriptId = id;
this.hostDefinedOptions.onScriptParsed?.(source, id);
this.parsedSources.set(id, source);
this.#script_id += 1;
this.#dynamicParsedSourceIds.set(sourceText, id);
return id;
}
// #endregion
// #region breakpoint
breakpointsEnabled = false;
pauseOnExceptions: undefined | 'caught' | 'uncaught' | 'all';
#breakpointId = 0;
#breakpoints = new Map<string, Breakpoint>();
addBreakpointByUrl(breakpoint: Protocol.Debugger.SetBreakpointByUrlRequest): Protocol.Debugger.SetBreakpointByUrlResponse {
this.#breakpointId += 1;
let scriptId;
if (breakpoint.url) {
for (const [id, script] of this.parsedSources) {
if (script.HostDefined?.specifier === breakpoint.url) {
scriptId = id;
break;
}
}
}
if (!scriptId) {
return { breakpointId: this.#breakpointId.toString(), locations: [] };
}
return {
breakpointId: this.#breakpointId.toString(),
locations: [getBreakpointCandidates({ scriptId, lineNumber: breakpoint.lineNumber, columnNumber: breakpoint.columnNumber })[0]],
};
}
removeBreakpoint(breakpointId: string) {
this.#breakpoints.delete(breakpointId);
}
// #endregion
// #region side-effect free evaluator
#debugger_previewing = false;
#debugger_objectsCreatedDuringPreview = new Set<ObjectValue>();
get debugger_isPreviewing() {
return this.#debugger_previewing;
}
get debugger_cannotPreview() {
if (this.#debugger_previewing) {
return ThrowCompletion(X(Construct(this.currentRealmRecord.Intrinsics['%EvalError%'], [Value('Preview evaluator cannot evaluate side-effecting code')])));
}
return undefined;
}
debugger_tryTouchDuringPreview(object: ObjectValue) {
if (this.#debugger_previewing && !this.#debugger_objectsCreatedDuringPreview.has(object)) {
return this.debugger_cannotPreview;
}
return undefined;
}
debugger_markObjectCreated(object: ObjectValue) {
if (!this.#debugger_previewing) {
return;
}
this.#debugger_objectsCreatedDuringPreview.add(object);
}
debugger_scopePreview(): Disposable | null;
debugger_scopePreview<T>(cb: () => T): T;
debugger_scopePreview<T>(cb?: () => T): T | Disposable | null {
if (!cb) {
const old = this.#debugger_previewing;
this.#debugger_previewing = true;
return {
[Symbol.dispose]: () => {
this.#debugger_previewing = old;
this.#debugger_objectsCreatedDuringPreview.clear();
},
};
} else {
const old = this.#debugger_previewing;
this.#debugger_previewing = true;
try {
const res = cb();
return res;
} finally {
this.#debugger_previewing = old;
if (!old) {
this.#debugger_objectsCreatedDuringPreview.clear();
}
}
}
}
// #endregion
}
interface Breakpoint {
_: never;
}
/** https://tc39.es/ecma262/#sec-agentsignifier */
export function AgentSignifier() {
// 1. Let AR be the Agent Record of the surrounding agent.
const AR = surroundingAgent.AgentRecord;
// 2. Return AR.[[Signifier]].
return AR.Signifier;
}
/** https://tc39.es/ecma262/#sec-agentcansuspend */
export function AgentCanSuspend() {
const AR = surroundingAgent.AgentRecord;
return AR.CanBlock;
}
// https://tc39.es/ecma262/#sec-IncrementModuleAsyncEvaluationCount
export function IncrementModuleAsyncEvaluationCount() {
const AR = surroundingAgent.AgentRecord;
const count = AR.ModuleAsyncEvaluationCount;
AR.ModuleAsyncEvaluationCount = count + 1;
return count;
}
@@ -0,0 +1,956 @@
import { AbstractModuleRecord } from '../modules.mts';
import {
Descriptor,
ReferenceRecord,
UndefinedValue,
ObjectValue,
Value,
wellKnownSymbols,
BooleanValue,
JSStringValue,
NullValue,
} from '../value.mts';
import { surroundingAgent, type GCMarker } from '../host-defined/engine.mts';
import {
NormalCompletion, Q, X,
type ValueEvaluator,
} from '../completion.mts';
import { JSStringMap, skipDebugger } from '../helpers.mts';
import type { PlainEvaluator } from '../evaluator.mts';
import {
Assert,
DefinePropertyOrThrow,
Get,
HasOwnProperty,
HasProperty,
IsDataDescriptor,
IsExtensible,
IsPropertyKey,
Set,
ToBoolean,
isECMAScriptFunctionObject,
type ECMAScriptFunctionObject,
} from '#self';
/** https://tc39.es/ecma262/#sec-environment-records */
export abstract class EnvironmentRecord {
readonly OuterEnv: EnvironmentRecord | NullValue;
constructor(outerEnv: EnvironmentRecord | NullValue) {
this.OuterEnv = outerEnv;
}
abstract HasBinding(N: JSStringValue): ValueEvaluator<BooleanValue>;
abstract CreateMutableBinding(N: JSStringValue, D: BooleanValue): PlainEvaluator;
abstract CreateImmutableBinding(N: JSStringValue, S: BooleanValue): void;
abstract InitializeBinding(N: JSStringValue, V: Value): PlainEvaluator;
abstract SetMutableBinding(N: JSStringValue, V: Value, S: BooleanValue): PlainEvaluator;
abstract GetBindingValue(N: JSStringValue, S: BooleanValue): ValueEvaluator;
abstract DeleteBinding(N: JSStringValue): ValueEvaluator<BooleanValue>;
abstract HasThisBinding(): BooleanValue;
abstract HasSuperBinding(): BooleanValue;
abstract WithBaseObject(): ObjectValue | UndefinedValue;
// NON-SPEC
mark(m: GCMarker) {
m(this.OuterEnv);
}
}
interface DeclarativeEnvironmentBinding {
readonly indirect: boolean;
initialized: boolean;
readonly mutable?: boolean;
readonly strict?: boolean;
readonly deletable?: boolean;
value?: Value | undefined;
mark(m: GCMarker): void;
}
interface ModuleEnvironmentBinding extends DeclarativeEnvironmentBinding {
readonly target: [AbstractModuleRecord, JSStringValue];
}
/** https://tc39.es/ecma262/#sec-declarative-environment-records */
export class DeclarativeEnvironmentRecord extends EnvironmentRecord {
readonly bindings = new JSStringMap<DeclarativeEnvironmentBinding>();
/** https://tc39.es/ecma262/#sec-declarative-environment-records-hasbinding-n */
* HasBinding(N: JSStringValue) {
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
const envRec = this;
// 2. If envRec has a binding for the name that is the value of N, return true.
if (envRec.bindings.has(N)) {
return Value.true;
}
// 3. Return false.
return Value.false;
}
/** https://tc39.es/ecma262/#sec-declarative-environment-records-createmutablebinding-n-d */
* CreateMutableBinding(N: JSStringValue, D: BooleanValue) {
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
const envRec = this;
// 2. Assert: envRec does not already have a binding for N.
Assert(!envRec.bindings.has(N));
// 3. Create a mutable binding in envRec for N and record that it is uninitialized. If D
// is true, record that the newly created binding may be deleted by a subsequent
// DeleteBinding call.
this.bindings.set(N, {
indirect: false,
initialized: false,
mutable: true,
strict: undefined,
deletable: D === Value.true,
value: undefined,
mark(m: GCMarker) {
m(this.value);
},
});
// 4. Return NormalCompletion(empty).
return NormalCompletion(undefined);
}
/** https://tc39.es/ecma262/#sec-declarative-environment-records-createimmutablebinding-n-s */
CreateImmutableBinding(N: JSStringValue, S: BooleanValue) {
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
const envRec = this;
// 2. Assert: envRec does not already have a binding for N.
Assert(!envRec.bindings.has(N));
// 3. Create an immutable binding in envRec for N and record that it is uninitialized. If
// S is true, record that the newly created binding is a strict binding.
this.bindings.set(N, {
indirect: false,
initialized: false,
mutable: false,
strict: S === Value.true,
deletable: false,
value: undefined,
mark(m) {
m(this.value);
},
});
// 4. Return NormalCompletion(empty).
return NormalCompletion(undefined);
}
/** https://tc39.es/ecma262/#sec-declarative-environment-records-initializebinding-n-v */
* InitializeBinding(N: JSStringValue, V: Value) {
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
const envRec = this;
// 2. Assert: envRec must have an uninitialized binding for N.
const binding = envRec.bindings.get(N);
Assert(binding !== undefined && binding.initialized === false);
// 3. Set the bound value for N in envRec to V.
binding.value = V;
// 4. Record that the binding for N in envRec has been initialized.
binding.initialized = true;
// 5. Return NormalCompletion(empty).
return NormalCompletion(undefined);
}
/** https://tc39.es/ecma262/#sec-declarative-environment-records-setmutablebinding-n-v-s */
* SetMutableBinding(N: JSStringValue, V: Value, S: BooleanValue): PlainEvaluator {
Assert(IsPropertyKey(N));
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
const envRec = this;
// 2. If envRec does not have a binding for N, then
if (!envRec.bindings.has(N)) {
// a. If S is true, throw a ReferenceError exception.
if (S === Value.true) {
return surroundingAgent.Throw('ReferenceError', 'NotDefined', N);
}
// b. Perform envRec.CreateMutableBinding(N, true).
yield* envRec.CreateMutableBinding(N, Value.true);
// c. Perform envRec.InitializeBinding(N, V).
yield* envRec.InitializeBinding(N, V);
// d. Return NormalCompletion(empty).
return NormalCompletion(undefined);
}
const binding = this.bindings.get(N)!;
// 3. If the binding for N in envRec is a strict binding, set S to true.
if (binding.strict === true) {
S = Value.true;
}
// 4. If the binding for N in envRec has not yet been initialized, throw a ReferenceError exception.
if (binding.initialized === false) {
return surroundingAgent.Throw('ReferenceError', 'NotInitialized', N);
}
// 5. Else if the binding for N in envRec is a mutable binding, change its bound value to V.
if (binding.mutable === true) {
binding.value = V;
} else {
// a. Assert: This is an attempt to change the value of an immutable binding.
// b. If S is true, throw a TypeError exception.
if (S === Value.true) {
return surroundingAgent.Throw('TypeError', 'AssignmentToConstant', N);
}
}
// 7. Return NormalCompletion(empty).
return NormalCompletion(undefined);
}
/** https://tc39.es/ecma262/#sec-declarative-environment-records-getbindingvalue-n-s */
* GetBindingValue(N: JSStringValue, _S: BooleanValue): ValueEvaluator {
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
const envRec = this;
// 2. Assert: envRec has a binding for N.
const binding = envRec.bindings.get(N);
Assert(binding !== undefined);
// 3. If the binding for N in envRec is an uninitialized binding, throw a ReferenceError exception.
if (binding.initialized === false) {
return surroundingAgent.Throw('ReferenceError', 'NotInitialized', N);
}
// 4. Return the value currently bound to N in envRec.
return NormalCompletion(binding.value!);
}
/** https://tc39.es/ecma262/#sec-declarative-environment-records-deletebinding-n */
* DeleteBinding(N: JSStringValue) {
// 1. Let envRec be the declarative Environment Record for which the method was invoked.
const envRec = this;
// 2. Assert: envRec has a binding for the name that is the value of N.
const binding = envRec.bindings.get(N);
Assert(binding !== undefined);
// 3. If the binding for N in envRec cannot be deleted, return false.
if (binding.deletable === false) {
return Value.false;
}
// 4. Remove the binding for N from envRec.
envRec.bindings.delete(N);
// 5. Return true.
return Value.true;
}
/** https://tc39.es/ecma262/#sec-declarative-environment-records-hasthisbinding */
HasThisBinding(): BooleanValue {
// 1. Return false.
return Value.false;
}
/** https://tc39.es/ecma262/#sec-declarative-environment-records-hassuperbinding */
HasSuperBinding(): BooleanValue {
// 1. Return false.
return Value.false;
}
/** https://tc39.es/ecma262/#sec-declarative-environment-records-withbaseobject */
WithBaseObject() {
// 1. Return undefined.
return Value.undefined;
}
// NON-SPEC
override mark(m: GCMarker) {
// TODO(ts): this function does not call super.mark(). is it a mistake?
m(this.bindings);
}
}
/** https://tc39.es/ecma262/#sec-function-environment-records */
export class FunctionEnvironmentRecord extends DeclarativeEnvironmentRecord {
/** https://tc39.es/ecma262/#sec-newfunctionenvironment */
constructor(F: ECMAScriptFunctionObject, newTarget: UndefinedValue | ObjectValue) {
// 1. Assert: F is an ECMAScript function.
Assert(isECMAScriptFunctionObject(F));
// 2. Assert: Type(newTarget) is Undefined or Object.
Assert(newTarget instanceof UndefinedValue || newTarget instanceof ObjectValue);
// 3. Let env be a new function Environment Record containing no bindings.
super(F.Environment);
// 4. Set env.[[FunctionObject]] to F.
this.FunctionObject = F;
// 5. If F.[[ThisMode]] is lexical, set env.[[ThisBindingStatus]] to lexical.
if (F.ThisMode === 'lexical') {
this.ThisBindingStatus = 'lexical';
} else { // 6. Else, set env.[[ThisBindingStatus]] to uninitialized.
this.ThisBindingStatus = 'uninitialized';
}
// 7. Set env.[[NewTarget]] to newTarget.
this.NewTarget = newTarget;
// 8. Set env.[[OuterEnv]] to F.[[Environment]].
// 9. Return env.
}
protected ThisValue!: Value;
ThisBindingStatus: 'lexical' | 'uninitialized' | 'initialized';
readonly FunctionObject: ECMAScriptFunctionObject;
readonly NewTarget: UndefinedValue | ObjectValue;
/** https://tc39.es/ecma262/#sec-bindthisvalue */
BindThisValue(V: Value) {
// 1. Let envRec be the function Environment Record for which the method was invoked.
const envRec = this;
// 2. Assert: envRec.[[ThisBindingStatus]] is not lexical.
Assert(envRec.ThisBindingStatus !== 'lexical');
// 3. If envRec.[[ThisBindingStatus]] is initialized, throw a ReferenceError exception.
if (envRec.ThisBindingStatus === 'initialized') {
return surroundingAgent.Throw('ReferenceError', 'InvalidThis');
}
// 4. Set envRec.[[ThisValue]] to V.
envRec.ThisValue = V;
// 5. Set envRec.[[ThisBindingStatus]] to initialized.
envRec.ThisBindingStatus = 'initialized';
// 6. Return V.
return V;
}
/** https://tc39.es/ecma262/#sec-function-environment-records-hasthisbinding */
override HasThisBinding() {
// 1. Let envRec be the function Environment Record for which the method was invoked.
const envRec = this;
// 2. If envRec.[[ThisBindingStatus]] is lexical, return false; otherwise, return true.
if (envRec.ThisBindingStatus === 'lexical') {
return Value.false;
} else {
return Value.true;
}
}
/** https://tc39.es/ecma262/#sec-function-environment-records-hassuperbinding */
override HasSuperBinding() {
const envRec = this;
// 1. If envRec.[[ThisBindingStatus]] is lexical, return false.
if (envRec.ThisBindingStatus === 'lexical') {
return Value.false;
}
// 2. If envRec.[[FunctionObject]].[[HomeObject]] has the value undefined, return false; otherwise, return true.
if (envRec.FunctionObject.HomeObject === Value.undefined) {
return Value.false;
} else {
return Value.true;
}
}
/** https://tc39.es/ecma262/#sec-function-environment-records-getthisbinding */
GetThisBinding() {
// 1. Let envRec be the function Environment Record for which the method was invoked.
const envRec = this;
// 2. Assert: envRec.[[ThisBindingStatus]] is not lexical.
Assert(envRec.ThisBindingStatus !== 'lexical');
// 3. If envRec.[[ThisBindingStatus]] is uninitialized, throw a ReferenceError exception.
if (envRec.ThisBindingStatus === 'uninitialized') {
return surroundingAgent.Throw('ReferenceError', 'InvalidThis');
}
// 4. Return envRec.[[ThisValue]].
return envRec.ThisValue;
}
/** https://tc39.es/ecma262/#sec-getsuperbase */
GetSuperBase() {
const envRec = this;
// 1. Let home be envRec.[[FunctionObject]].[[HomeObject]].
const home = envRec.FunctionObject.HomeObject;
// 2. If home has the value undefined, return undefined.
if (home === Value.undefined) {
return Value.undefined;
}
// 3. Assert: Type(home) is Object.
Assert(home instanceof ObjectValue);
// 4. Return ! home.[[GetPrototypeOf]]().
return X(home.GetPrototypeOf());
}
override mark(m: GCMarker) {
super.mark(m);
m(this.ThisValue);
m(this.FunctionObject);
m(this.NewTarget);
}
}
/** https://tc39.es/ecma262/#sec-module-environment-records */
export class ModuleEnvironmentRecord extends DeclarativeEnvironmentRecord {
declare readonly bindings: JSStringMap<ModuleEnvironmentBinding>;
/** https://tc39.es/ecma262/#sec-module-environment-records-getbindingvalue-n-s */
override* GetBindingValue(N: JSStringValue, S: BooleanValue): ValueEvaluator {
// 1. Assert: S is true.
Assert(S === Value.true);
// 2. Let envRec be the module Environment Record for which the method was invoked.
const envRec = this;
// 3. Assert: envRec has a binding for N.
const binding = envRec.bindings.get(N);
Assert(binding !== undefined);
// 4. If the binding for N is an indirect binding, then
if (binding.indirect === true) {
// a. Let M and N2 be the indirection values provided when this binding for N was created.
const [M, N2] = binding.target;
// b.Let targetEnv be M.[[Environment]].
const targetEnv = M.Environment;
// c. If targetEnv is undefined, throw a ReferenceError exception.
if (!targetEnv) {
return surroundingAgent.Throw('ReferenceError', 'NotDefined', N);
}
// d. Return ? targetEnv.GetBindingValue(N2, true).
return yield* targetEnv.GetBindingValue(N2, Value.true);
}
// 5. If the binding for N in envRec is an uninitialized binding, throw a ReferenceError exception.
if (binding.initialized === false) {
return surroundingAgent.Throw('ReferenceError', 'NotInitialized', N);
}
// 6. Return the value currently bound to N in envRec.
return NormalCompletion(binding.value!);
}
/** https://tc39.es/ecma262/#sec-module-environment-records-deletebinding-n */
override DeleteBinding(): never {
Assert(false, 'This method is never invoked. See #sec-delete-operator-static-semantics-early-errors');
}
/** https://tc39.es/ecma262/#sec-module-environment-records-hasthisbinding */
override HasThisBinding() {
// Return true.
return Value.true;
}
/** https://tc39.es/ecma262/#sec-module-environment-records-getthisbinding */
GetThisBinding() {
// Return undefined.
return Value.undefined;
}
/** https://tc39.es/ecma262/#sec-createimportbinding */
CreateImportBinding(N: JSStringValue, M: AbstractModuleRecord, N2: JSStringValue) {
// 1. Let envRec be the module Environment Record for which the method was invoked.
const envRec = this;
// 2. Assert: envRec does not already have a binding for N.
Assert(skipDebugger(envRec.HasBinding(N)) === Value.false);
// 3. Assert: M is a Module Record.
Assert(M instanceof AbstractModuleRecord);
// 4. Assert: When M.[[Environment]] is instantiated it will have a direct binding for N2.
// 5. Create an immutable indirect binding in envRec for N that references M and N2 as its target binding and record that the binding is initialized.
envRec.bindings.set(N, {
indirect: true,
target: [M, N2],
initialized: true,
mark(m: GCMarker) {
m(this.target[0]);
m(this.target[1]);
},
});
// 6. Return NormalCompletion(empty).
return NormalCompletion(undefined);
}
}
/** https://tc39.es/ecma262/#sec-object-environment-records */
export class ObjectEnvironmentRecord extends EnvironmentRecord {
BindingObject: ObjectValue;
IsWithEnvironment: BooleanValue;
/** https://tc39.es/ecma262/#sec-newobjectenvironment */
constructor(O: ObjectValue, W: BooleanValue, E: EnvironmentRecord | NullValue) {
super(E);
this.BindingObject = O;
this.IsWithEnvironment = W;
}
/** https://tc39.es/ecma262/#sec-object-environment-records-hasbinding-n */
* HasBinding(N: JSStringValue): ValueEvaluator<BooleanValue> {
// 1. Let envRec be the object Environment Record for which the method was invoked.
const envRec = this;
// 2. Let bindings be the binding object for envRec.
const bindings = envRec.BindingObject;
// 3. Let foundBinding be ? HasProperty(bindings, N).
const foundBinding = Q(yield* HasProperty(bindings, N));
// 4. If foundBinding is false, return false.
if (foundBinding === Value.false) {
return Value.false;
}
// 5. If the IsWithEnvironment flag of envRec i s false, return true.
if (envRec.IsWithEnvironment === Value.false) {
return Value.true;
}
// 6. Let unscopables be ? Get(bindings, @@unscopables).
const unscopables = Q(yield* Get(bindings, wellKnownSymbols.unscopables));
// 7. If Type(unscopables) is Object, then
if (unscopables instanceof ObjectValue) {
// a. Let blocked be ! ToBoolean(? Get(unscopables, N)).
const blocked = X(ToBoolean(Q(yield* Get(unscopables, N))));
// b. If blocked is true, return false.
if (blocked === Value.true) {
return Value.false;
}
}
// 8. Return true.
return Value.true;
}
/** https://tc39.es/ecma262/#sec-object-environment-records-createmutablebinding-n-d */
* CreateMutableBinding(N: JSStringValue, D: BooleanValue): PlainEvaluator {
// 1. Let envRec be the object Environment Record for which the method was invoked.
const envRec = this;
// 2. Let envRec be the object Environment Record for which the method was invoked.
const bindings = envRec.BindingObject;
// 3. Return ? DefinePropertyOrThrow(bindings, N, PropertyDescriptor { [[Value]]: undefined, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: D }).
Q(yield* DefinePropertyOrThrow(bindings, N, Descriptor({
Value: Value.undefined,
Writable: Value.true,
Enumerable: Value.true,
Configurable: D,
})));
}
/** https://tc39.es/ecma262/#sec-object-environment-records-createimmutablebinding-n-s */
CreateImmutableBinding(_N: JSStringValue, _S: BooleanValue) {
Assert(false, 'CreateImmutableBinding called on an Object Environment Record');
}
/** https://tc39.es/ecma262/#sec-object-environment-records-initializebinding-n-v */
* InitializeBinding(N: JSStringValue, V: Value): PlainEvaluator {
// 1. Let envRec be the object Environment Record for which the method was invoked.
const envRec = this;
// 2. Assert: envRec must have an uninitialized binding for N.
// 3. Record that the binding for N in envRec has been initialized.
// 4. Return ? envRec.SetMutableBinding(N, V, false).
Q(yield* envRec.SetMutableBinding(N, V, Value.false));
}
/** https://tc39.es/ecma262/#sec-object-environment-records-setmutablebinding-n-v-s */
* SetMutableBinding(N: JSStringValue, V: Value, S: BooleanValue): PlainEvaluator {
// 1. Let envRec be the object Environment Record for which the method was invoked.
const envRec = this;
// 2. Let bindings be the binding object for envRec.
const bindings = envRec.BindingObject;
// 3. Let stillExists be ? HasProperty(bindings, N).
const stillExists = Q(yield* HasProperty(bindings, N));
// 4. If stillExists is false and S is true, throw a ReferenceError exception.
if (stillExists === Value.false && S === Value.true) {
return surroundingAgent.Throw('ReferenceError', 'NotDefined', N);
}
// 5. Return ? Set(bindings, N, V, S).
Q(yield* Set(bindings, N, V, S));
return undefined;
}
/** https://tc39.es/ecma262/#sec-object-environment-records-getbindingvalue-n-s */
* GetBindingValue(N: JSStringValue, S: BooleanValue): ValueEvaluator {
// 1. Let envRec be the object Environment Record for which the method was invoked.
const envRec = this;
// 2. Let bindings be the binding object for envRec.
const bindings = envRec.BindingObject;
// 3. Let value be ? HasProperty(bindings, N).
const value = Q(yield* HasProperty(bindings, N));
// 4. If value is false, then
if (value === Value.false) {
// a. If S is false, return the value undefined; otherwise throw a ReferenceError exception.
if (S === Value.false) {
return NormalCompletion(Value.undefined);
} else {
return surroundingAgent.Throw('ReferenceError', 'NotDefined', N);
}
}
// 5. Return Get(bindings, N).
return yield* Get(bindings, N);
}
/** https://tc39.es/ecma262/#sec-object-environment-records-deletebinding-n */
* DeleteBinding(N: JSStringValue): ValueEvaluator<BooleanValue> {
// 1. Let envRec be the object Environment Record for which the method was invoked.
const envRec = this;
// 2. Let bindings be the binding object for envRec.
const bindings = envRec.BindingObject;
// 3. Return ? bindings.[[Delete]](N).
return Q(yield* bindings.Delete(N));
}
/** https://tc39.es/ecma262/#sec-object-environment-records-hasthisbinding */
HasThisBinding() {
// 1. Return false.
return Value.false;
}
/** https://tc39.es/ecma262/#sec-object-environment-records-hassuperbinding */
HasSuperBinding() {
// 1. Return falase.
return Value.false;
}
/** https://tc39.es/ecma262/#sec-object-environment-records-withbaseobject */
WithBaseObject() {
// 1. Let envRec be the object Environment Record for which the method was invoked.
const envRec = this;
// 2. If the IsWithEnvironment flag of envRec is true, return the binding object for envRec.
if (envRec.IsWithEnvironment === Value.true) {
return envRec.BindingObject;
}
// 3. Otherwise, return undefined.
return Value.undefined;
}
// NON-SPEC
override mark(m: GCMarker) {
// TODO(ts): this function does not call super.mark(). is it a mistake?
m(this.BindingObject);
}
}
/** https://tc39.es/ecma262/#sec-global-environment-records */
export class GlobalEnvironmentRecord extends EnvironmentRecord {
readonly ObjectRecord: ObjectEnvironmentRecord;
readonly GlobalThisValue: ObjectValue;
readonly DeclarativeRecord: DeclarativeEnvironmentRecord;
/** https://tc39.es/ecma262/#sec-newglobalenvironment */
constructor(G: ObjectValue, thisValue: ObjectValue) {
// 1. Let objRec be NewObjectEnvironment(G, false, null).
const objRec = new ObjectEnvironmentRecord(G, Value.false, Value.null);
// 2. Let dclRec be a new declarative Environment Record containing no bindings.
const dclRec = new DeclarativeEnvironmentRecord(Value.null);
// 3. Let env be a new global Environment Record.
super(Value.null);
// 4. Set env.[[ObjectRecord]] to objRec.
this.ObjectRecord = objRec;
// 5. Set env.[[GlobalThisValue]] to thisValue.
this.GlobalThisValue = thisValue;
// 6. Set env.[[DeclarativeRecord]] to dclRec.
this.DeclarativeRecord = dclRec;
// 8. Set env.[[OuterEnv]] to null.
// 9. Return env.
}
/** https://tc39.es/ecma262/#sec-global-environment-records-hasbinding-n */
* HasBinding(N: JSStringValue) {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
const DclRec = envRec.DeclarativeRecord;
// 3. If DclRec.HasBinding(N) is true, return true.
if ((yield* DclRec.HasBinding(N)) === Value.true) {
return Value.true;
}
// 4. If DclRec.HasBinding(N) is true, return true.
const ObjRec = envRec.ObjectRecord;
// 5. Let ObjRec be envRec.[[ObjectRecord]].
return yield* ObjRec.HasBinding(N);
}
/** https://tc39.es/ecma262/#sec-global-environment-records-createmutablebinding-n-d */
* CreateMutableBinding(N: JSStringValue, D: BooleanValue) {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
const DclRec = envRec.DeclarativeRecord;
// 3. If DclRec.HasBinding(N) is true, throw a TypeError exception.
if ((yield* DclRec.HasBinding(N)) === Value.true) {
return surroundingAgent.Throw('TypeError', 'AlreadyDeclared', N);
}
// 4. Return DclRec.CreateMutableBinding(N, D).
return yield* DclRec.CreateMutableBinding(N, D);
}
/** https://tc39.es/ecma262/#sec-global-environment-records-createimmutablebinding-n-s */
CreateImmutableBinding(N: JSStringValue, S: BooleanValue) {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
const DclRec = envRec.DeclarativeRecord;
// 3. If DclRec.HasBinding(N) is true, throw a TypeError exception.
// TODO: remove skipDebugger
if (skipDebugger(DclRec.HasBinding(N)) === Value.true) {
return surroundingAgent.Throw('TypeError', 'AlreadyDeclared', N);
}
// Return DclRec.CreateImmutableBinding(N, S).
return DclRec.CreateImmutableBinding(N, S);
}
/** https://tc39.es/ecma262/#sec-global-environment-records-initializebinding-n-v */
* InitializeBinding(N: JSStringValue, V: Value) {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
const DclRec = envRec.DeclarativeRecord;
// 3. If DclRec.HasBinding(N) is true, then
// TODO: remove skipDebugger
if (skipDebugger(DclRec.HasBinding(N)) === Value.true) {
// a. Return DclRec.InitializeBinding(N, V).
return yield* DclRec.InitializeBinding(N, V);
}
// 4. Assert: If the binding exists, it must be in the object Environment Record.
// 5. Let ObjRec be envRec.[[ObjectRecord]].
const ObjRec = envRec.ObjectRecord;
// 6. Return ? ObjRec.InitializeBinding(N, V).
return yield* ObjRec.InitializeBinding(N, V);
}
/** https://tc39.es/ecma262/#sec-global-environment-records-setmutablebinding-n-v-s */
* SetMutableBinding(N: JSStringValue, V: Value, S: BooleanValue): PlainEvaluator {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
const DclRec = envRec.DeclarativeRecord;
// 3. If DclRec.HasBinding(N) is true, then
if ((yield* DclRec.HasBinding(N)) === Value.true) {
// a. Return DclRec.SetMutableBinding(N, V, S).
return yield* DclRec.SetMutableBinding(N, V, S);
}
// 4. Let ObjRec be envRec.[[ObjectRecord]].
const ObjRec = envRec.ObjectRecord;
// 5. Return ? ObjRec.SetMutableBinding(N, V, S).
Q(yield* ObjRec.SetMutableBinding(N, V, S));
return undefined;
}
/** https://tc39.es/ecma262/#sec-global-environment-records-getbindingvalue-n-s */
* GetBindingValue(N: JSStringValue, S: BooleanValue): ValueEvaluator {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
const DclRec = envRec.DeclarativeRecord;
// 3. If DclRec.HasBinding(N) is true, then
if ((yield* DclRec.HasBinding(N)) === Value.true) {
// a. Return DclRec.GetBindingValue(N, S).
return yield* DclRec.GetBindingValue(N, S);
}
// 4. Let ObjRec be envRec.[[ObjectRecord]].
const ObjRec = envRec.ObjectRecord;
// 5. Return ObjRec.GetBindingValue(N, S).
return yield* ObjRec.GetBindingValue(N, S);
}
/** https://tc39.es/ecma262/#sec-global-environment-records-deletebinding-n */
* DeleteBinding(N: JSStringValue): PlainEvaluator<BooleanValue> {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Let DclRec be envRec.[[DeclarativeRecord]].
const DclRec = this.DeclarativeRecord;
// 3. Let DclRec be envRec.[[DeclarativeRecord]].
if ((yield* DclRec.HasBinding(N)) === Value.true) {
// a. Return DclRec.DeleteBinding(N).
return Q(yield* DclRec.DeleteBinding(N));
}
// 4. Let ObjRec be envRec.[[ObjectRecord]].
const ObjRec = envRec.ObjectRecord;
// 5. Let globalObject be the binding object for ObjRec.
const globalObject = ObjRec.BindingObject;
// 6. Let existingProp be ? HasOwnProperty(globalObject, N).
const existingProp = Q(yield* HasOwnProperty(globalObject, N));
// 7. If existingProp is true, then
if (existingProp === Value.true) {
// a. Return ? ObjRec.DeleteBinding(N).
return Q(yield* ObjRec.DeleteBinding(N));
}
// 8. Return true.
return Value.true;
}
/** https://tc39.es/ecma262/#sec-global-environment-records-hasthisbinding */
HasThisBinding() {
// Return true.
return Value.true;
}
/** https://tc39.es/ecma262/#sec-global-environment-records-hassuperbinding */
HasSuperBinding() {
// 1. Return false.
return Value.false;
}
/** https://tc39.es/ecma262/#sec-global-environment-records-withbaseobject */
WithBaseObject() {
// 1. Return undefined.
return Value.undefined;
}
/** https://tc39.es/ecma262/#sec-global-environment-records-getthisbinding */
GetThisBinding() {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Return envRec.[[GlobalThisValue]].
return envRec.GlobalThisValue;
}
/** https://tc39.es/ecma262/#sec-haslexicaldeclaration */
* HasLexicalDeclaration(N: JSStringValue) {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Let envRec be the global Environment Record for which the method was invoked.
const DclRec = envRec.DeclarativeRecord;
// 3. Let DclRec be envRec.[[DeclarativeRecord]].
return yield* DclRec.HasBinding(N);
}
/** https://tc39.es/ecma262/#sec-hasrestrictedglobalproperty */
* HasRestrictedGlobalProperty(N: JSStringValue): ValueEvaluator<BooleanValue> {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Let ObjRec be envRec.[[ObjectRecord]].
const ObjRec = envRec.ObjectRecord;
// 3. Let globalObject be the binding object for ObjRec.
const globalObject = ObjRec.BindingObject;
// 4. Let existingProp be ? globalObject.[[GetOwnProperty]](N).
const existingProp = Q(yield* globalObject.GetOwnProperty(N));
// 5. If existingProp is undefined, return false.
if (existingProp instanceof UndefinedValue) {
return Value.false;
}
// 6. If existingProp.[[Configurable]] is true, return false.
if (existingProp.Configurable === Value.true) {
return Value.false;
}
// Return true.
return Value.true;
}
/** https://tc39.es/ecma262/#sec-candeclareglobalvar */
* CanDeclareGlobalVar(N: JSStringValue): ValueEvaluator<BooleanValue> {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Let ObjRec be envRec.[[ObjectRecord]].
const ObjRec = envRec.ObjectRecord;
// 3. Let globalObject be the binding object for ObjRec.
const globalObject = ObjRec.BindingObject;
// 4. Let hasProperty be ? HasOwnProperty(globalObject, N).
const hasProperty = Q(yield* HasOwnProperty(globalObject, N));
// 5. If hasProperty is true, return true.
if (hasProperty === Value.true) {
return Value.true;
}
// 6. Return ? IsExtensible(globalObject).
return Q(yield* IsExtensible(globalObject));
}
/** https://tc39.es/ecma262/#sec-candeclareglobalfunction */
* CanDeclareGlobalFunction(N: JSStringValue): ValueEvaluator<BooleanValue> {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Let ObjRec be envRec.[[ObjectRecord]].
const ObjRec = envRec.ObjectRecord;
// 3. Let globalObject be the binding object for ObjRec.
const globalObject = ObjRec.BindingObject;
// 4. Let existingProp be ? globalObject.[[GetOwnProperty]](N).
const existingProp = Q(yield* globalObject.GetOwnProperty(N));
// 5. If existingProp is undefined, return ? IsExtensible(globalObject).
if (existingProp instanceof UndefinedValue) {
return Q(yield* IsExtensible(globalObject));
}
// 6. If existingProp.[[Configurable]] is true, return true.
if (existingProp.Configurable === Value.true) {
return Value.true;
}
// 7. If IsDataDescriptor(existingProp) is true and existingProp has attribute values
// { [[Writable]]: true, [[Enumerable]]: true }, return true.
if (IsDataDescriptor(existingProp) === true
&& existingProp.Writable === Value.true
&& existingProp.Enumerable === Value.true) {
return Value.true;
}
// 8. Return false.
return Value.false;
}
/** https://tc39.es/ecma262/#sec-createglobalvarbinding */
* CreateGlobalVarBinding(N: JSStringValue, D: BooleanValue): PlainEvaluator {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Let ObjRec be envRec.[[ObjectRecord]].
const ObjRec = envRec.ObjectRecord;
// 3. Let globalObject be the binding object for ObjRec.
const globalObject = ObjRec.BindingObject;
// 4. Let hasProperty be ? HasOwnProperty(globalObject, N).
const hasProperty = Q(yield* HasOwnProperty(globalObject, N));
// 5. Let extensible be ? IsExtensible(globalObject).
const extensible = Q(yield* IsExtensible(globalObject));
// 6. If hasProperty is false and extensible is true, then
if (hasProperty === Value.false && extensible === Value.true) {
// a. Perform ? ObjRec.CreateMutableBinding(N, D).
Q(yield* ObjRec.CreateMutableBinding(N, D));
// b. Perform ? ObjRec.InitializeBinding(N, undefined).
Q(yield* ObjRec.InitializeBinding(N, Value.undefined));
}
// return NormalCompletion(empty).
return NormalCompletion(undefined);
}
/** https://tc39.es/ecma262/#sec-createglobalfunctionbinding */
* CreateGlobalFunctionBinding(N: JSStringValue, V: Value, D: BooleanValue): PlainEvaluator {
// 1. Let envRec be the global Environment Record for which the method was invoked.
const envRec = this;
// 2. Let ObjRec be envRec.[[ObjectRecord]].
const ObjRec = envRec.ObjectRecord;
// 3. Let globalObject be the binding object for ObjRec.
const globalObject = ObjRec.BindingObject;
// 4. Let existingProp be ? globalObject.[[GetOwnProperty]](N).
const existingProp = Q(yield* globalObject.GetOwnProperty(N));
// 5. If existingProp is undefined or existingProp.[[Configurable]] is true, then
let desc;
if (existingProp instanceof UndefinedValue || existingProp.Configurable === Value.true) {
// a. Let desc be the PropertyDescriptor { [[Value]]: V, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: D }.
desc = Descriptor({
Value: V,
Writable: Value.true,
Enumerable: Value.true,
Configurable: D,
});
} else {
// a. Let desc be the PropertyDescriptor { [[Value]]: V }.
desc = Descriptor({
Value: V,
});
}
// 7. Perform ? DefinePropertyOrThrow(globalObject, N, desc).
Q(yield* DefinePropertyOrThrow(globalObject, N, desc));
// 8. Record that the binding for N in ObjRec has been initialized.
// 9. Perform ? Set(globalObject, N, V, false).
Q(yield* Set(globalObject, N, V, Value.false));
// 1. Return NormalCompletion(empty).
return NormalCompletion(undefined);
}
override mark(m: GCMarker) {
// TODO(ts): this function does not call super.mark(). is it a mistake?
m(this.ObjectRecord);
m(this.GlobalThisValue);
m(this.DeclarativeRecord);
}
}
export type EnvironmentRecordWithThisBinding = FunctionEnvironmentRecord | GlobalEnvironmentRecord | ModuleEnvironmentRecord;
/** https://tc39.es/ecma262/#sec-getidentifierreference */
export function* GetIdentifierReference(env: EnvironmentRecord | NullValue, name: JSStringValue, strict: BooleanValue): PlainEvaluator<ReferenceRecord> {
// 1. If lex is the value null, then
if (env instanceof NullValue) {
// a. Return the Reference Record { [[Base]]: unresolvable, [[ReferencedName]]: name, [[Strict]]: strict, [[ThisValue]]: empty }.
return NormalCompletion(new ReferenceRecord({
Base: 'unresolvable',
ReferencedName: name,
Strict: strict,
ThisValue: undefined,
}));
}
// 2. Let exists be ? envRec.HasBinding(name).
const exists = Q(yield* env.HasBinding(name));
// 3. If exists is true, then
if (exists === Value.true) {
// a. Return the Reference Record { [[Base]]: env, [[ReferencedName]]: name, [[Strict]]: strict, [[ThisValue]]: empty }.
return NormalCompletion(new ReferenceRecord({
Base: env,
ReferencedName: name,
Strict: strict,
ThisValue: undefined,
}));
} else {
// a. Let outer be env.[[OuterEnv]].
const outer = env.OuterEnv;
// b. Return ? GetIdentifierReference(outer, name, strict).
return yield* GetIdentifierReference(outer, name, strict);
}
}
@@ -0,0 +1,134 @@
import type { ExecutionContextHostDefined, GCMarker } from '../host-defined/engine.mts';
import { __ts_cast__ } from '../helpers.mts';
import {
type YieldEvaluator, NullValue, type FunctionObject, Value, type GeneratorObject, type AsyncGeneratorObject, AbstractModuleRecord, type ScriptRecord, EnvironmentRecord, PrivateEnvironmentRecord, CallSite, PromiseCapabilityRecord, Realm,
surroundingAgent,
Assert,
GetIdentifierReference,
JSStringValue,
UndefinedValue,
type EnvironmentRecordWithThisBinding,
ObjectValue,
} from '#self';
/** https://tc39.es/ecma262/#sec-execution-contexts */
export class ExecutionContext {
codeEvaluationState?: YieldEvaluator;
Function: NullValue | FunctionObject = Value.null;
Generator?: GeneratorObject | AsyncGeneratorObject;
ScriptOrModule: AbstractModuleRecord | ScriptRecord | NullValue = Value.null;
VariableEnvironment!: EnvironmentRecord;
LexicalEnvironment!: EnvironmentRecord;
PrivateEnvironment: PrivateEnvironmentRecord | NullValue = Value.null;
HostDefined?: ExecutionContextHostDefined;
// NON-SPEC
callSite = new CallSite(this);
promiseCapability?: PromiseCapabilityRecord;
poppedForTailCall = false;
Realm!: Realm;
copy() {
const e = new ExecutionContext();
e.codeEvaluationState = this.codeEvaluationState;
e.Function = this.Function;
e.Realm = this.Realm;
e.ScriptOrModule = this.ScriptOrModule;
e.VariableEnvironment = this.VariableEnvironment;
e.LexicalEnvironment = this.LexicalEnvironment;
e.PrivateEnvironment = this.PrivateEnvironment;
e.HostDefined = this.HostDefined;
e.callSite = this.callSite.clone(e);
e.promiseCapability = this.promiseCapability;
return e;
}
// NON-SPEC
mark(m: GCMarker) {
m(this.Function);
m(this.Realm);
m(this.ScriptOrModule);
m(this.VariableEnvironment);
m(this.LexicalEnvironment);
m(this.PrivateEnvironment);
m(this.promiseCapability);
}
}
/** https://tc39.es/ecma262/#sec-getactivescriptormodule */
export function GetActiveScriptOrModule() {
for (let i = surroundingAgent.executionContextStack.length - 1; i >= 0; i -= 1) {
const e = surroundingAgent.executionContextStack[i];
if (e.ScriptOrModule !== Value.null) {
return e.ScriptOrModule;
}
}
return Value.null;
}
/** https://tc39.es/ecma262/#sec-resolvebinding */
export function ResolveBinding(name: JSStringValue, env?: EnvironmentRecord | UndefinedValue | NullValue, strict?: boolean) {
// 1. If env is not present or if env is undefined, then
if (env === undefined || env === Value.undefined) {
// a. Set env to the running execution context's LexicalEnvironment.
env = surroundingAgent.runningExecutionContext.LexicalEnvironment;
}
// 2. Assert: env is an Environment Record.
Assert(env instanceof EnvironmentRecord);
// 3. If the code matching the syntactic production that is being evaluated is contained in strict mode code, let strict be true; else let strict be false.
// 4. Return ? GetIdentifierReference(env, name, strict).
return GetIdentifierReference(env, name, strict ? Value.true : Value.false);
}
/** https://tc39.es/ecma262/#sec-getthisenvironment */
export function GetThisEnvironment(): EnvironmentRecordWithThisBinding {
// 1. Let env be the running execution context's LexicalEnvironment.
let env = surroundingAgent.runningExecutionContext.LexicalEnvironment;
// 2. Repeat,
while (true) {
__ts_cast__<EnvironmentRecord>(env);
// a. Let exists be env.HasThisBinding().
const exists = env.HasThisBinding();
// b. If exists is true, return envRec.
if (exists === Value.true) {
return env as EnvironmentRecordWithThisBinding;
}
// c. Let outer be env.[[OuterEnv]].
const outer = env.OuterEnv;
// d. Assert: outer is not null.
Assert(!(outer instanceof NullValue));
// e. Set env to outer.
env = outer;
}
}
/** https://tc39.es/ecma262/#sec-resolvethisbinding */
export function ResolveThisBinding() {
const envRec = GetThisEnvironment();
return envRec.GetThisBinding();
}
/** https://tc39.es/ecma262/#sec-getnewtarget */
export function GetNewTarget(): ObjectValue | UndefinedValue {
const envRec = GetThisEnvironment();
Assert('NewTarget' in envRec);
return envRec.NewTarget;
}
/** https://tc39.es/ecma262/#sec-getglobalobject */
export function GetGlobalObject() {
const currentRealm = surroundingAgent.currentRealmRecord;
return currentRealm.GlobalObject;
}
+54
View File
@@ -0,0 +1,54 @@
import type { kAsyncContext } from '../helpers.mts';
import {
type Realm, type AbstractModuleRecord, type ScriptRecord, type NullValue, type ExecutionContext, type FunctionObject,
Assert,
Call,
IsCallable,
Q,
Value,
type Arguments,
type ValueEvaluator,
surroundingAgent,
} from '#self';
/** https://tc39.es/ecma262/#job */
export interface Job {
readonly queueName: string;
readonly job: () => void;
readonly callerRealm: Realm;
readonly callerScriptOrModule: AbstractModuleRecord | ScriptRecord | NullValue;
}
/** https://tc39.es/ecma262/#sec-jobcallback-records */
export interface JobCallbackRecord {
Callback: FunctionObject & { [kAsyncContext]?: ExecutionContext; };
HostDefined: undefined;
}
/** https://tc39.es/ecma262/#sec-hostmakejobcallback */
export function HostMakeJobCallback(callback: FunctionObject): JobCallbackRecord {
// 1. Assert: IsCallable(callback) is true.
Assert(IsCallable(callback));
// 2. Return the JobCallback Record { [[Callback]]: callback, [[HostDefined]]: empty }.
return { Callback: callback, HostDefined: undefined };
}
/** https://tc39.es/ecma262/#sec-hostcalljobcallback */
export function* HostCallJobCallback(jobCallback: JobCallbackRecord, V: Value, argumentsList: Arguments): ValueEvaluator {
// 1. Assert: IsCallable(jobCallback.[[Callback]]) is true.
Assert(IsCallable(jobCallback.Callback));
// 1. Return ? Call(jobCallback.[[Callback]], V, argumentsList).
return Q(yield* Call(jobCallback.Callback, V, argumentsList));
}
// Atomics: HostEnqueueGenericJob
/** https://tc39.es/ecma262/#sec-hostenqueuepromisejob */
export function HostEnqueuePromiseJob(job: () => void, _realm: Realm | NullValue) {
if (surroundingAgent.debugger_isPreviewing) {
return;
}
surroundingAgent.queueJob('PromiseJobs', job);
}
// Atomics: HostEnqueueTimeoutJob
@@ -0,0 +1,41 @@
import {
type PrivateName, type GCMarker, Assert, JSStringValue, NullValue,
} from '#self';
/** https://tc39.es/ecma262/#sec-privateenvironment-records */
export class PrivateEnvironmentRecord {
readonly OuterPrivateEnvironment: PrivateEnvironmentRecord | NullValue;
readonly Names: PrivateName[] = [];
/** https://tc39.es/ecma262/#sec-newprivateenvironment */
constructor(outerEnv: PrivateEnvironmentRecord | NullValue) {
this.OuterPrivateEnvironment = outerEnv;
}
mark(m: GCMarker) {
this.Names.forEach((name) => {
m(name);
});
}
}
/** https://tc39.es/ecma262/#sec-resolve-private-identifier */
export function ResolvePrivateIdentifier(privEnv: PrivateEnvironmentRecord, identifier: JSStringValue) {
// 1. Let names be privEnv.[[Names]].
const names = privEnv.Names;
// 2. If names contains a Private Name whose [[Description]] is identifier, then
const name = names.find((n) => n.Description.stringValue() === identifier.stringValue());
if (name) {
// a. Let name be that Private Name.
// b. Return name.
return name;
} else { // 3. Else,
// a. Let outerPrivEnv be privEnv.[[OuterPrivateEnvironment]].
const outerPrivEnv = privEnv.OuterPrivateEnvironment;
// b. Assert: outerPrivEnv is not null.
Assert(!(outerPrivEnv instanceof NullValue));
// c. Return ResolvePrivateIdentifier(outerPrivEnv, identifier).
return ResolvePrivateIdentifier(outerPrivEnv, identifier);
}
}
+363
View File
@@ -0,0 +1,363 @@
import { AddRestrictedFunctionProperties, type Intrinsics } from '../abstract-ops/realms.mts';
import { bootstrapAggregateError } from '../intrinsics/AggregateError.mts';
import { bootstrapAggregateErrorPrototype } from '../intrinsics/AggregateErrorPrototype.mts';
import { bootstrapArray } from '../intrinsics/Array.mts';
import { bootstrapArrayBuffer } from '../intrinsics/ArrayBuffer.mts';
import { bootstrapArrayBufferPrototype } from '../intrinsics/ArrayBufferPrototype.mts';
import { bootstrapArrayIteratorPrototype } from '../intrinsics/ArrayIteratorPrototype.mts';
import { bootstrapArrayPrototype } from '../intrinsics/ArrayPrototype.mts';
import { bootstrapAsyncFromSyncIteratorPrototype } from '../intrinsics/AsyncFromSyncIteratorPrototype.mts';
import { bootstrapAsyncFunction } from '../intrinsics/AsyncFunction.mts';
import { bootstrapAsyncFunctionPrototype } from '../intrinsics/AsyncFunctionPrototype.mts';
import { bootstrapAsyncGeneratorFunction } from '../intrinsics/AsyncGeneratorFunction.mts';
import { bootstrapAsyncGeneratorFunctionPrototype } from '../intrinsics/AsyncGeneratorFunctionPrototype.mts';
import { bootstrapAsyncGeneratorFunctionPrototypePrototype } from '../intrinsics/AsyncGeneratorFunctionPrototypePrototype.mts';
import { bootstrapAsyncIteratorPrototype } from '../intrinsics/AsyncIteratorPrototype.mts';
import { bootstrapBigInt } from '../intrinsics/BigInt.mts';
import { bootstrapBigIntPrototype } from '../intrinsics/BigIntPrototype.mts';
import { bootstrapBoolean } from '../intrinsics/Boolean.mts';
import { bootstrapBooleanPrototype } from '../intrinsics/BooleanPrototype.mts';
import { bootstrapDataView } from '../intrinsics/DataView.mts';
import { bootstrapDataViewPrototype } from '../intrinsics/DataViewPrototype.mts';
import { bootstrapDate } from '../intrinsics/Date.mts';
import { bootstrapDatePrototype } from '../intrinsics/DatePrototype.mts';
import { bootstrapError } from '../intrinsics/Error.mts';
import { bootstrapErrorPrototype } from '../intrinsics/ErrorPrototype.mts';
import { bootstrapEval } from '../intrinsics/eval.mts';
import { bootstrapFinalizationRegistry } from '../intrinsics/FinalizationRegistry.mts';
import { bootstrapFinalizationRegistryPrototype } from '../intrinsics/FinalizationRegistryPrototype.mts';
import { bootstrapForInIteratorPrototype } from '../intrinsics/ForInIteratorPrototype.mts';
import { bootstrapFunction } from '../intrinsics/Function.mts';
import { bootstrapFunctionPrototype } from '../intrinsics/FunctionPrototype.mts';
import { bootstrapGeneratorFunction } from '../intrinsics/GeneratorFunction.mts';
import { bootstrapGeneratorFunctionPrototype } from '../intrinsics/GeneratorFunctionPrototype.mts';
import { bootstrapGeneratorFunctionPrototypePrototype } from '../intrinsics/GeneratorFunctionPrototypePrototype.mts';
import { bootstrapIsFinite } from '../intrinsics/isFinite.mts';
import { bootstrapIsNaN } from '../intrinsics/isNaN.mts';
import { bootstrapIterator } from '../intrinsics/Iterator.mts';
import { bootstrapIteratorHelperPrototype } from '../intrinsics/IteratorHelperPrototype.mts';
import { bootstrapIteratorPrototype } from '../intrinsics/IteratorPrototype.mts';
import { bootstrapJSON } from '../intrinsics/JSON.mts';
import { bootstrapMap } from '../intrinsics/Map.mts';
import { bootstrapMapIteratorPrototype } from '../intrinsics/MapIteratorPrototype.mts';
import { bootstrapMapPrototype } from '../intrinsics/MapPrototype.mts';
import { bootstrapMath } from '../intrinsics/Math.mts';
import { bootstrapNativeError } from '../intrinsics/NativeError.mts';
import { bootstrapNumber } from '../intrinsics/Number.mts';
import { bootstrapNumberPrototype } from '../intrinsics/NumberPrototype.mts';
import { bootstrapObject } from '../intrinsics/Object.mts';
import { makeObjectPrototype, bootstrapObjectPrototype } from '../intrinsics/ObjectPrototype.mts';
import { bootstrapParseFloat } from '../intrinsics/parseFloat.mts';
import { bootstrapParseInt } from '../intrinsics/parseInt.mts';
import { bootstrapPromise } from '../intrinsics/Promise.mts';
import { bootstrapPromisePrototype } from '../intrinsics/PromisePrototype.mts';
import { bootstrapProxy } from '../intrinsics/Proxy.mts';
import { bootstrapReflect } from '../intrinsics/Reflect.mts';
import { bootstrapRegExp } from '../intrinsics/RegExp.mts';
import { bootstrapRegExpPrototype } from '../intrinsics/RegExpPrototype.mts';
import { bootstrapRegExpStringIteratorPrototype } from '../intrinsics/RegExpStringIteratorPrototype.mts';
import { bootstrapSet } from '../intrinsics/Set.mts';
import { bootstrapSetIteratorPrototype } from '../intrinsics/SetIteratorPrototype.mts';
import { bootstrapSetPrototype } from '../intrinsics/SetPrototype.mts';
import { bootstrapShadowRealm } from '../intrinsics/ShadowRealm.mts';
import { bootstrapShadowRealmPrototype } from '../intrinsics/ShadowRealmPrototype.mts';
import { bootstrapString } from '../intrinsics/String.mts';
import { bootstrapStringIteratorPrototype } from '../intrinsics/StringIteratorPrototype.mts';
import { bootstrapStringPrototype } from '../intrinsics/StringPrototype.mts';
import { bootstrapSymbol } from '../intrinsics/Symbol.mts';
import { bootstrapSymbolPrototype } from '../intrinsics/SymbolPrototype.mts';
import { bootstrapThrowTypeError } from '../intrinsics/ThrowTypeError.mts';
import { bootstrapTypedArray } from '../intrinsics/TypedArray.mts';
import { bootstrapUint8Array } from '../intrinsics/TypedArray_Uint8Array.mts';
import { bootstrapTypedArrayConstructors } from '../intrinsics/TypedArrayConstructors.mts';
import { bootstrapTypedArrayPrototype } from '../intrinsics/TypedArrayPrototype.mts';
import { bootstrapTypedArrayPrototypes } from '../intrinsics/TypedArrayPrototypes.mts';
import { bootstrapURIHandling } from '../intrinsics/URIHandling.mts';
import { bootstrapWeakMap } from '../intrinsics/WeakMap.mts';
import { bootstrapWeakMapPrototype } from '../intrinsics/WeakMapPrototype.mts';
import { bootstrapWeakRef } from '../intrinsics/WeakRef.mts';
import { bootstrapWeakRefPrototype } from '../intrinsics/WeakRefPrototype.mts';
import { bootstrapWeakSet } from '../intrinsics/WeakSet.mts';
import { bootstrapWeakSetPrototype } from '../intrinsics/WeakSetPrototype.mts';
import { bootstrapWrapForValidIteratorPrototype } from '../intrinsics/WrapForValidIteratorPrototype.mts';
import { bootstrapTemporal } from '../intrinsics/Temporal/Temporal.mts';
import {
type ObjectValue, type GlobalEnvironmentRecord, type ParseNode, type LoadedModuleRequestRecord, type ManagedRealmHostDefined, type GCMarker,
ManagedRealm,
type Mutable,
DefinePropertyOrThrow,
Descriptor,
F as toNumberValue,
Value,
X,
surroundingAgent,
} from '#self';
/** https://tc39.es/ecma262/#sec-code-realms */
export abstract class Realm {
abstract readonly AgentSignifier: unknown;
abstract readonly Intrinsics: Intrinsics;
abstract readonly GlobalObject: ObjectValue;
abstract readonly GlobalEnv: GlobalEnvironmentRecord;
abstract readonly TemplateMap: { Site: ParseNode.TemplateLiteral; Array: ObjectValue; }[];
readonly LoadedModules: LoadedModuleRequestRecord[] = [];
abstract readonly HostDefined: ManagedRealmHostDefined;
// NON-SPEC
abstract randomState: undefined | BigUint64Array;
mark(m: GCMarker) {
m(this.GlobalObject);
m(this.GlobalEnv);
for (const v of Object.values(this.Intrinsics)) {
m(v);
}
for (const v of Object.values(this.TemplateMap)) {
m(v);
}
for (const v of this.LoadedModules) {
m(v.Module);
}
}
}
/** https://tc39.es/ecma262/pr/3728/#sec-makerealm */
export function MakeRealm(...args: ConstructorParameters<typeof ManagedRealm>) {
return new ManagedRealm(...args);
}
/** https://tc39.es/ecma262/#sec-createintrinsics */
export function CreateIntrinsics(realmRec: Realm) {
const intrinsics = Object.create(null);
(realmRec as Mutable<Realm>).Intrinsics = intrinsics;
makeObjectPrototype(realmRec);
bootstrapFunctionPrototype(realmRec);
bootstrapObjectPrototype(realmRec);
bootstrapThrowTypeError(realmRec);
bootstrapEval(realmRec);
bootstrapIsFinite(realmRec);
bootstrapIsNaN(realmRec);
bootstrapParseFloat(realmRec);
bootstrapParseInt(realmRec);
bootstrapURIHandling(realmRec);
bootstrapObject(realmRec);
bootstrapErrorPrototype(realmRec);
bootstrapError(realmRec);
bootstrapNativeError(realmRec);
bootstrapAggregateErrorPrototype(realmRec);
bootstrapAggregateError(realmRec);
bootstrapFunction(realmRec);
bootstrapIteratorPrototype(realmRec);
bootstrapIterator(realmRec);
bootstrapIteratorHelperPrototype(realmRec);
bootstrapWrapForValidIteratorPrototype(realmRec);
bootstrapAsyncIteratorPrototype(realmRec);
bootstrapArrayIteratorPrototype(realmRec);
bootstrapMapIteratorPrototype(realmRec);
bootstrapSetIteratorPrototype(realmRec);
bootstrapStringIteratorPrototype(realmRec);
bootstrapRegExpStringIteratorPrototype(realmRec);
bootstrapForInIteratorPrototype(realmRec);
bootstrapStringPrototype(realmRec);
bootstrapString(realmRec);
bootstrapArrayPrototype(realmRec);
bootstrapArray(realmRec);
bootstrapBooleanPrototype(realmRec);
bootstrapBoolean(realmRec);
bootstrapNumberPrototype(realmRec);
bootstrapNumber(realmRec);
bootstrapBigIntPrototype(realmRec);
bootstrapBigInt(realmRec);
bootstrapSymbolPrototype(realmRec);
bootstrapSymbol(realmRec);
bootstrapPromisePrototype(realmRec);
bootstrapPromise(realmRec);
bootstrapProxy(realmRec);
bootstrapReflect(realmRec);
bootstrapMath(realmRec);
bootstrapDatePrototype(realmRec);
bootstrapDate(realmRec);
bootstrapRegExpPrototype(realmRec);
bootstrapRegExp(realmRec);
bootstrapSetPrototype(realmRec);
bootstrapSet(realmRec);
bootstrapMapPrototype(realmRec);
bootstrapMap(realmRec);
bootstrapGeneratorFunctionPrototypePrototype(realmRec);
bootstrapGeneratorFunctionPrototype(realmRec);
bootstrapGeneratorFunction(realmRec);
bootstrapAsyncFunctionPrototype(realmRec);
bootstrapAsyncFunction(realmRec);
bootstrapAsyncGeneratorFunctionPrototypePrototype(realmRec);
bootstrapAsyncGeneratorFunctionPrototype(realmRec);
bootstrapAsyncGeneratorFunction(realmRec);
bootstrapAsyncFromSyncIteratorPrototype(realmRec);
bootstrapArrayBufferPrototype(realmRec);
bootstrapArrayBuffer(realmRec);
bootstrapTypedArrayPrototype(realmRec);
bootstrapTypedArray(realmRec);
bootstrapTypedArrayPrototypes(realmRec);
bootstrapTypedArrayConstructors(realmRec);
bootstrapUint8Array(realmRec);
bootstrapDataViewPrototype(realmRec);
bootstrapDataView(realmRec);
bootstrapJSON(realmRec);
bootstrapWeakMapPrototype(realmRec);
bootstrapWeakMap(realmRec);
bootstrapWeakSetPrototype(realmRec);
bootstrapWeakSet(realmRec);
bootstrapWeakRefPrototype(realmRec);
bootstrapWeakRef(realmRec);
bootstrapFinalizationRegistryPrototype(realmRec);
bootstrapFinalizationRegistry(realmRec);
bootstrapShadowRealmPrototype(realmRec);
bootstrapShadowRealm(realmRec);
if (surroundingAgent.feature('temporal')) {
bootstrapTemporal(realmRec);
}
AddRestrictedFunctionProperties(intrinsics['%Function.prototype%'], realmRec);
return intrinsics;
}
/** https://tc39.es/ecma262/#sec-setdefaultglobalbindings */
export function SetDefaultGlobalBindings(realmRec: Realm) {
const global = realmRec.GlobalObject;
// Value Properties of the Global Object
for (const [name, value] of [
['Infinity', toNumberValue(Infinity)],
['NaN', toNumberValue(NaN)],
['undefined', Value.undefined],
] as const) {
X(DefinePropertyOrThrow(global, Value(name), Descriptor({
Value: value,
Writable: Value.false,
Enumerable: Value.false,
Configurable: Value.false,
})));
}
X(DefinePropertyOrThrow(global, Value('globalThis'), Descriptor({
Value: realmRec.GlobalEnv.GlobalThisValue,
Writable: Value.true,
Enumerable: Value.false,
Configurable: Value.true,
})));
for (const name of [
// Function Properties of the Global Object
'eval',
'isFinite',
'isNaN',
'parseFloat',
'parseInt',
'decodeURI',
'decodeURIComponent',
'encodeURI',
'encodeURIComponent',
// Constructor Properties of the Global Object
'AggregateError',
'Array',
'ArrayBuffer',
'Boolean',
'BigInt',
'BigInt64Array',
'BigUint64Array',
'DataView',
'Date',
'Error',
'EvalError',
'FinalizationRegistry',
'Float32Array',
'Float64Array',
'Function',
'Int8Array',
'Int16Array',
'Int32Array',
'Iterator',
'Map',
'Number',
'Object',
'Promise',
'Proxy',
'RangeError',
'ReferenceError',
'RegExp',
'Set',
'ShadowRealm',
// 'SharedArrayBuffer',
'String',
'Symbol',
'SyntaxError',
'Temporal',
'TypeError',
'Uint8Array',
'Uint8ClampedArray',
'Uint16Array',
'Uint32Array',
'URIError',
'WeakMap',
'WeakRef',
'WeakSet',
// Other Properties of the Global Object
// 'Atomics',
'JSON',
'Math',
'Reflect',
] as const) {
const value = realmRec.Intrinsics[`%${name}%`];
if (!value) {
continue;
}
X(DefinePropertyOrThrow(global, Value(name), Descriptor({
Value: value,
Writable: Value.true,
Enumerable: Value.false,
Configurable: Value.true,
})));
}
}
@@ -0,0 +1,77 @@
import { surroundingAgent } from '../host-defined/engine.mts';
import {
type FinalizationRegistryObject, type PlainCompletion, Q, skipDebugger, NormalCompletion, ObjectValue, SymbolValue, Assert, HostCallJobCallback, type JobCallbackRecord, UndefinedValue, Value, type ValueEvaluator, KeyForSymbol,
} from '#self';
/** https://tc39.es/ecma262/#sec-host-cleanup-finalization-registry */
export function HostEnqueueFinalizationRegistryCleanupJob(fg: FinalizationRegistryObject): PlainCompletion<void> {
if (surroundingAgent.hostDefinedOptions.cleanupFinalizationRegistry !== undefined) {
Q(surroundingAgent.hostDefinedOptions.cleanupFinalizationRegistry(fg));
} else {
if (!surroundingAgent.scheduledForCleanup.has(fg)) {
surroundingAgent.scheduledForCleanup.add(fg);
surroundingAgent.queueJob('FinalizationCleanup', () => {
surroundingAgent.scheduledForCleanup.delete(fg);
// TODO: remove skipDebugger
skipDebugger(CleanupFinalizationRegistry(fg));
});
}
}
return NormalCompletion(undefined);
}/** https://tc39.es/ecma262/#sec-clear-kept-objects */
export function ClearKeptObjects() {
// 1. Let agentRecord be the surrounding agent's Agent Record.
const agentRecord = surroundingAgent.AgentRecord;
// 2. Set agentRecord.[[KeptAlive]] to a new empty List.
agentRecord.KeptAlive = new Set();
}/** https://tc39.es/ecma262/#sec-addtokeptobjects */
export function AddToKeptObjects(object: ObjectValue | SymbolValue) {
// 1. Let agentRecord be the surrounding agent's Agent Record.
const agentRecord = surroundingAgent.AgentRecord;
// 2. Append object to agentRecord.[[KeptAlive]].
agentRecord.KeptAlive.add(object);
}/** https://tc39.es/ecma262/#sec-cleanup-finalization-registry */
export function* CleanupFinalizationRegistry(finalizationRegistry: FinalizationRegistryObject, callback?: JobCallbackRecord): ValueEvaluator<UndefinedValue> {
Q(surroundingAgent.debugger_tryTouchDuringPreview(finalizationRegistry));
// 1. Assert: finalizationRegistry has [[Cells]] and [[CleanupCallback]] internal slots.
Assert('Cells' in finalizationRegistry && 'CleanupCallback' in finalizationRegistry);
// 2. Set callback to finalizationRegistry.[[CleanupCallback]].
if (callback === undefined) {
callback = finalizationRegistry.CleanupCallback;
}
// 3. While finalizationRegistry.[[Cells]] contains a Record cell such that cell.[[WeakRefTarget]] is empty, an implementation may perform the following steps:
for (let i = 0; i < finalizationRegistry.Cells.length; i += 1) {
// a. Choose any such _cell_.
const cell = finalizationRegistry.Cells[i];
if (cell.WeakRefTarget !== undefined) {
continue;
}
// b. Remove cell from finalizationRegistry.[[Cells]].
finalizationRegistry.Cells.splice(i, 1);
i -= 1;
// c. Perform ? HostCallJobCallback(callback, undefined, « cell.[[HeldValue]] »).
Q(yield* HostCallJobCallback(callback, Value.undefined, [cell.HeldValue]));
}
// 4. Return NormalCompletion(undefined).
return NormalCompletion(Value.undefined);
}/** https://tc39.es/ecma262/#sec-canbeheldweakly */
export function CanBeHeldWeakly(v: Value): v is ObjectValue | SymbolValue {
// 1. If v is an Object, return true.
if (v instanceof ObjectValue) {
return true;
}
// 2. If v is a Symbol and KeyForSymbol(v) is undefined, return true.
if (v instanceof SymbolValue && KeyForSymbol(v) === Value.undefined) {
return true;
}
// 3. Return false.
return false;
}
+7
View File
@@ -0,0 +1,7 @@
export * from './Environment.mts';
export * from './PrivateEnvironment.mts';
export * from './Realm.mts';
export * from './ExecutionContext.mts';
export * from './Job.mts';
export * from './Agent.mts';
export * from './WeakReference.mts';