mirror of
https://github.com/bendtherules/ask262.git
synced 2026-08-19 00:31:06 +00:00
Merge commit '6e92d2345e8231a44556ce7d416451f5f3e6c398' as 'engine262'
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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';
|
||||
Reference in New Issue
Block a user