Environment Record는 ECMAScript 코드의 렉시컬 중첩 구조를 기반으로 Identifier를 특정 변수 및 함수와 연결하는 관계를 정의하는 데 사용하는 명세 타입입니다. 일반적으로 Environment Record는 FunctionDeclaration, BlockStatement 또는 TryStatement의 Catch 절과 같은 ECMAScript 코드의 특정 구문 구조와 연결됩니다. 이러한 코드가 평가될 때마다 해당 코드가 생성하는 식별자 바인딩을 기록하기 위해 새로운 Environment Record가 생성됩니다.
모든 Environment Record에는 [[OuterEnv]] 필드가 있으며, 이 필드는 null이거나 바깥쪽 Environment Record에 대한 참조입니다. 이는 Environment Record의 논리적 중첩을 모델링하는 데 사용됩니다. (안쪽) Environment Record의 바깥쪽 참조는 해당 안쪽 Environment Record를 논리적으로 둘러싸는 Environment Record에 대한 참조입니다. 물론 바깥쪽 Environment Record 자체도 자신의 바깥쪽 Environment Record를 가질 수 있습니다. 하나의 Environment Record는 여러 안쪽 Environment Record의 바깥쪽 환경으로 사용될 수 있습니다. 예를 들어 FunctionDeclaration에 두 개의 중첩된 FunctionDeclaration이 포함되어 있으면, 각 중첩 함수의 Environment Record는 둘러싸는 함수의 현재 평가에 대한 Environment Record를 바깥쪽 Environment Record로 갖습니다.
Environment Record는 순수하게 명세상의 메커니즘이며 ECMAScript 구현체의 특정 산출물과 대응할 필요는 없습니다. ECMAScript 프로그램에서 이러한 값에 직접 접근하거나 조작하는 것은 불가능합니다.
Function Environment Record는 ECMAScript 함수 객체의 호출에 대응하며, 해당 함수 내 최상위 선언에 대한 바인딩을 포함합니다. 새로운 this 바인딩을 설정할 수도 있습니다. 또한 super 메서드 호출을 지원하는 데 필요한 상태를 캡처합니다.
Global Environment Record는 Script의 전역 선언에 사용됩니다. 바깥쪽 환경은 없으며 [[OuterEnv]]는 null입니다. 미리 식별자 바인딩이 채워질 수 있으며, 프로퍼티가 전역 환경의 식별자 바인딩 일부를 제공하는 연결된 전역 객체를 포함합니다. ECMAScript 코드가 실행됨에 따라 전역 객체에 추가 프로퍼티가 추가될 수 있고 초기 프로퍼티가 수정될 수도 있습니다.
Environment Record 추상 클래스에는 표 15에 정의된 추상 명세 메서드가 포함됩니다. 이러한 추상 메서드는 각 구체적인 하위 클래스마다 서로 다른 구체적 알고리즘을 갖습니다.
추상 메서드 CreateImmutableBinding. 인수 name (String) 및 strict (Boolean). 반환값: (정상 완료 (값: unused) 또는 throw 완료).
Environment Record에 새롭지만 초기화되지 않은 변경 불가능한 바인딩을 생성합니다. name은 바인딩된 이름의 텍스트입니다. strict가 true이면 해당 바인딩이 초기화된 후 이를 설정하려는 시도는 해당 바인딩을 참조하는 연산의 엄격 모드 설정과 관계없이 항상 예외를 던집니다.
Environment Record에 이미 존재하는 바인딩의 값을 반환합니다. name은 바인딩된 이름의 텍스트입니다. strict는 엄격 모드 코드에서 시작된 참조 또는 그 밖에 엄격 모드 참조 의미론이 필요한 참조를 식별하는 데 사용됩니다. strict가 true이고 바인딩이 존재하지 않으면 ReferenceError 예외를 던집니다. 바인딩은 존재하지만 초기화되지 않았으면 strict 값과 관계없이 ReferenceError를 던집니다.
추상 메서드 DeleteBinding. 인수 name (String). 반환값: (정상 완료 (값: Boolean) 또는 throw 완료).
Environment Record에서 바인딩을 삭제합니다. name은 바인딩된 이름의 텍스트입니다. name에 대한 바인딩이 존재하면 해당 바인딩을 제거하고 true를 반환합니다. 바인딩이 존재하지만 제거할 수 없으면 false를 반환합니다. 바인딩이 존재하지 않으면 true를 반환합니다.
각 Declarative Environment Record는 변수, 상수, let, 클래스, 모듈, import 및/또는 함수 선언을 포함하는 ECMAScript 프로그램 스코프와 연결됩니다. Declarative Environment Record는 해당 스코프 안의 선언에서 정의한 식별자 집합을 바인딩합니다.
a Declarative Environment RecordenvRecord의 구체 메서드 CreateMutableBinding. 인수 name (String) 및 deletable (Boolean). 반환값: 정상 완료 (값: unused). 초기화되지 않은 이름 name에 대한 새로운 변경 가능한 바인딩을 생성합니다. 이 Environment Record에는 name에 대한 바인딩이 이미 존재해서는 안 됩니다. deletable이 true이면 새 바인딩을 삭제할 수 있는 것으로 표시합니다. 호출되면 다음 단계를 수행한다.
a Declarative Environment RecordenvRecord의 구체 메서드 SetMutableBinding. 인수 name (String), value (ECMAScript 언어 값) 및 strict (Boolean). 반환값: (정상 완료 (값: unused) 또는 throw 완료). 이름이 name인 식별자의 현재 바인딩 값을 value 값으로 변경하려고 시도합니다. 일반적으로 name에 대한 바인딩이 이미 존재하지만 드문 경우에는 존재하지 않을 수 있습니다. 바인딩이 변경 불가능한 바인딩이고 strict가 true이면 TypeError를 던집니다. 호출되면 다음 단계를 수행한다.
각 Object Environment Record는 바인딩 객체라고 하는 객체와 연결됩니다. Object Environment Record는 자신의 바인딩 객체의 프로퍼티 이름과 직접 대응하는 문자열 식별자 이름 집합을 바인딩합니다. IdentifierName 형태의 String이 아닌 프로퍼티 키는 바인딩된 식별자 집합에 포함되지 않습니다. [[Enumerable]] 속성의 설정과 관계없이 자체 프로퍼티와 상속된 프로퍼티를 모두 집합에 포함합니다. 객체에 프로퍼티를 동적으로 추가하거나 삭제할 수 있으므로 Object Environment Record가 바인딩하는 식별자 집합은 프로퍼티를 추가하거나 삭제하는 모든 연산의 부작용으로 변경될 수 있습니다. 이러한 부작용의 결과로 생성되는 모든 바인딩은 대응하는 프로퍼티의 Writable 속성이 false이더라도 변경 가능한 바인딩으로 간주합니다. Object Environment Record에는 변경 불가능한 바인딩이 존재하지 않습니다.
with 문(14.11)을 위해 생성된 Object Environment Record는 함수 호출에 사용할 암묵적인 this 값으로 자신의 바인딩 객체를 제공할 수 있습니다. 이 기능은 Boolean [[IsWithEnvironment]] 필드로 제어됩니다.
Object Environment Record에는 표 16에 나열된 추가 상태 필드가 있습니다.
an Object Environment RecordenvRecord의 구체 메서드 CreateMutableBinding. 인수 name (String) 및 deletable (Boolean). 반환값: (정상 완료 (값: unused) 또는 throw 완료). Environment Record와 연결된 바인딩 객체에 이름이 name인 프로퍼티를 생성하고 undefined 값으로 초기화합니다. deletable이 true이면 새 프로퍼티의 [[Configurable]] 속성을 true로 설정하고, 그렇지 않으면 false로 설정합니다. 호출되면 다음 단계를 수행한다.
추상 연산 GetSuperBase. 인수 envRecord (Function Environment 레코드). 반환값: (Object, null 또는 undefined). envRecord에 바인딩된 super 프로퍼티 접근의 기반이 되는 객체를 반환합니다. undefined 값은 이러한 접근이 런타임 오류를 생성함을 나타냅니다. 호출되면 다음 단계를 수행한다.
Global Environment Record는 공통 realm에서 처리되는 모든 ECMAScript Script 요소가 공유하는 가장 바깥쪽 스코프를 나타내는 데 사용됩니다. Global Environment Record는 내장 전역(절 19), 전역 객체의 프로퍼티 및 Script 내에서 발생하는 모든 최상위 선언(8.2.11, 8.2.13)에 대한 바인딩을 제공합니다.
a Global Environment RecordenvRecord의 구체 메서드 CreateMutableBinding. 인수 name (String) 및 deletable (Boolean). 반환값: (정상 완료 (값: unused) 또는 throw 완료). 초기화되지 않은 이름 name에 대한 새로운 변경 가능한 바인딩을 생성합니다. 바인딩은 연결된 DeclarativeRecord에 생성됩니다. DeclarativeRecord에는 name에 대한 바인딩이 이미 존재해서는 안 됩니다. deletable이 true이면 새 바인딩을 삭제 가능 대상으로 표시합니다. 호출되면 다음 단계를 수행한다.
a Global Environment RecordenvRecord의 구체 메서드 SetMutableBinding. 인수 name (String), value (ECMAScript 언어 값) 및 strict (Boolean). 반환값: (정상 완료 (값: unused) 또는 throw 완료). 이름이 name인 식별자의 현재 바인딩 값을 value 값으로 변경하려고 시도합니다. 바인딩이 변경 불가능한 바인딩이고 strict가 true이면 TypeError를 던집니다. 일반적으로 name이라는 바인딩이 이미 존재하지만, 존재하지 않거나 현재 쓰기 가능하지 않은 경우 오류 처리는 strict에 따라 결정됩니다. 호출되면 다음 단계를 수행한다.
a Global Environment RecordenvRecord의 구체 메서드 GetBindingValue. 인수 name (String) 및 strict (Boolean). 반환값: (정상 완료 (값: ECMAScript 언어 값) 또는 throw 완료). 이름이 name인 바인딩된 식별자의 값을 반환합니다. 바인딩이 초기화되지 않은 바인딩이면 ReferenceError 예외를 던집니다. 일반적으로 name이라는 바인딩이 이미 존재하지만, 존재하지 않거나 현재 쓰기 가능하지 않은 경우 오류 처리는 strict에 따라 결정됩니다. 호출되면 다음 단계를 수행한다.
9.1.1.4.13 HasRestrictedGlobalProperty ( envRecord, name )
추상 연산 HasRestrictedGlobalProperty. 인수 envRecord (Global Environment 레코드) 및 name (String). 반환값: (정상 완료 (값: Boolean) 또는 throw 완료). 인수 식별자가 전역 렉시컬 바인딩으로 가려져서는 안 되는 전역 객체 프로퍼티의 이름인지 결정합니다. 호출되면 다음 단계를 수행한다.
추상 연산 CreateGlobalFunctionBinding. 인수 envRecord (Global Environment 레코드), name (String), value (ECMAScript 함수 객체) 및 deletable (Boolean). 반환값: (정상 완료 (값: unused) 또는 throw 완료). 연결된 Object Environment Record에 변경 가능한 바인딩을 생성하고 초기화합니다. 바인딩이 이미 존재하면 이를 교체합니다. 호출되면 다음 단계를 수행한다.
전역 함수 선언은 항상 전역 객체의 자체 프로퍼티로 나타납니다. 가능한 경우 기존 자체 프로퍼티를 표준 속성 값 집합을 갖도록 재구성합니다. 7 단계는 InitializeBinding 구체 메서드를 호출하는 것과 동등하며, globalObj가 Proxy이면 동일한 Proxy 트랩 호출 시퀀스를 생성합니다.
9.1.1.5 Module Environment Record
Module Environment Record는 ECMAScript Module의 바깥쪽 스코프를 나타내는 데 사용하는 Declarative Environment Record입니다. 일반적인 변경 가능한 바인딩과 변경 불가능한 바인딩 외에도 Module Environment Record는 다른 Environment Record에 존재하는 대상 바인딩에 대한 간접 접근을 제공하는 변경 불가능한 import 바인딩도 제공합니다.
a Module Environment RecordenvRecord의 구체 메서드 GetBindingValue. 인수 name (String) 및 strict (Boolean). 반환값: (정상 완료 (값: ECMAScript 언어 값) 또는 throw 완료). 이름이 name인 바인딩된 식별자의 값을 반환합니다. 그러나 바인딩이 간접 바인딩이면 대상 바인딩의 값을 반환합니다. 바인딩은 존재하지만 초기화되지 않았으면 ReferenceError를 던집니다. 호출되면 다음 단계를 수행한다.
추상 연산 CreateImportBinding. 인수 envRecord (Module Environment 레코드), name (String), targetModule (Module 레코드) 및 targetName (String). 반환값: unused. 이름 name에 대해 초기화된 새로운 변경 불가능한 간접 바인딩을 생성합니다. envRecord에는 name에 대한 바인딩이 이미 존재해서는 안 됩니다. targetName은 targetModule의 Module Environment Record에 존재하는 바인딩의 이름입니다. 새 바인딩의 값에 접근하면 대상 바인딩의 바인딩된 값에 간접적으로 접근합니다. 호출되면 다음 단계를 수행한다.
템플릿 객체는 각 realm의 Realm Record[[TemplateMap]]을 사용하여 realm별로 별도로 정규화됩니다. 각 [[Site]] 값은 TemplateLiteral인 Parse Node입니다. 연결된 [[Array]] 값은 태그 함수에 전달되는 대응하는 템플릿 객체입니다.
참고 1
Parse Node에 더 이상 접근할 수 없게 되면 대응하는 [[Array]]에도 접근할 수 없게 되며, 구현체가 [[TemplateMap]] 목록에서 해당 쌍을 제거하더라도 관찰할 수 없습니다.
realmRecord.[[Intrinsics]]의 필드를 표 6에 나열된 값으로 설정합니다. 필드 이름은 표의 “Intrinsic Name” 열에 나열된 이름입니다. 각 필드의 값은 절 19부터 28까지 각 객체의 명세에 정의된 프로퍼티 값으로 완전히 재귀적으로 채워진 새로운 객체 값입니다. 모든 객체 프로퍼티 값은 새로 생성된 객체 값입니다. 내장 함수 객체인 모든 값은 CreateBuiltinFunction(steps, length, name, slots, realmRecord, proto, async)을 수행하여 생성합니다. 여기에서 steps는 이 명세가 제공하는 해당 함수의 정의이고, name은 함수의 "name" 프로퍼티 초기값이며, length는 함수의 "length" 프로퍼티 초기값이고, slots는 지정된 함수 내부 슬롯 이름의 목록이며(있는 경우), proto는 함수의 [[Prototype]] 내부 슬롯에 지정된 값이고, async는 함수가 “async”로 설명되면 true, 그렇지 않으면 false입니다. 내재 객체와 그 프로퍼티의 생성은 아직 생성되지 않은 객체에 대한 의존성이 발생하지 않도록 순서를 정해야 합니다.
propertyDesc를 해당 프로퍼티에 지정된 속성을 포함하는, 프로퍼티에 대해 모든 필드가 채워진 데이터 Property Descriptor로 둡니다. 19.2, 19.3 또는 19.4에 나열된 프로퍼티의 경우 [[Value]] 속성의 값은 realmRecord의 대응하는 내재 객체입니다.
실행 컨텍스트 스택은 실행 컨텍스트를 추적하는 데 사용됩니다. 실행 중인 실행 컨텍스트는 항상 이 스택의 최상위 요소입니다. 현재 실행 중인 실행 컨텍스트와 연결된 실행 가능 코드에서 해당 실행 컨텍스트와 연결되지 않은 실행 가능 코드로 제어가 이전될 때마다 새로운 실행 컨텍스트가 생성됩니다. 새로 생성된 실행 컨텍스트는 스택에 푸시되어 실행 중인 실행 컨텍스트가 됩니다.
실행 컨텍스트에는 연결된 코드의 실행 진행 상황을 추적하는 데 필요한 구현체별 상태가 포함됩니다. 각 실행 컨텍스트에는 최소한 표 21에 나열된 상태 구성 요소가 있습니다.
실행 중인 실행 컨텍스트에 의한 코드 평가는 이 명세에 정의된 여러 지점에서 일시 중단될 수 있습니다. 실행 중인 실행 컨텍스트가 일시 중단되면 다른 실행 컨텍스트가 실행 중인 실행 컨텍스트가 되어 자신의 코드를 평가하기 시작할 수 있습니다. 이후 어느 시점에 일시 중단된 실행 컨텍스트가 다시 실행 중인 실행 컨텍스트가 되어 이전에 일시 중단된 지점부터 코드 평가를 계속할 수 있습니다. 실행 중인 실행 컨텍스트 상태의 실행 컨텍스트 간 전환은 일반적으로 스택과 같은 후입선출 방식으로 이루어집니다. 그러나 일부 ECMAScript 기능에는 비LIFO 방식의 실행 컨텍스트 전환이 필요합니다.
대부분의 상황에서 이 명세의 알고리즘은 실행 중인 실행 컨텍스트(실행 컨텍스트 스택의 최상위)만 직접 조작합니다. 따라서 “LexicalEnvironment” 및 “VariableEnvironment”라는 용어를 별도의 한정 없이 사용하면 실행 중인 실행 컨텍스트의 해당 구성 요소를 가리킵니다.
실행 컨텍스트는 순수하게 명세상의 메커니즘이며 ECMAScript 구현체의 특정 산출물과 대응할 필요는 없습니다. ECMAScript 코드가 실행 컨텍스트에 직접 접근하거나 이를 관찰하는 것은 불가능합니다.
추상 연산 RunSuspendedContext. 인수 context (실행 컨텍스트) 및 completionRecord (완료 레코드). 반환값: (정상 완료 (값: (ECMAScript 언어 값 또는 unused)) 또는 중도 완료). context를 재개하고(completionRecord를 재개 값으로 전달합니다) 결과를 기다립니다. 호출되면 다음 단계를 수행한다.
호스트 환경은 예약과 관련하여 모든 Job을 동일하게 취급할 필요가 없습니다. 예를 들어 웹 브라우저와 Node.js는 Promise 처리 Job을 다른 작업보다 더 높은 우선순위로 취급합니다. 향후 기능에서는 이처럼 높은 우선순위로 처리되지 않는 Job이 추가될 수 있습니다.
scriptOrModule이 Script Record 또는 Module Record이면 executionContext를 실행 컨텍스트 스택에서 ScriptOrModule 구성 요소가 scriptOrModule인 가장 위쪽의 실행 컨텍스트로 둡니다. executionContext의 Realm 구성 요소는 scriptOrModule.[[Realm]]입니다.
특정 시점에 실행은 다음 조건이 모두 참이면 ECMAScript 코드를 평가할 준비가 된 상태입니다:
구체적으로 어떤 Realm을 선택할지는 호스트 환경이 결정합니다. 이 최초 실행 컨텍스트와 Realm은 콜백 함수가 호출되기 전까지만 사용됩니다. Promise 핸들러와 같이 Job과 관련된 콜백 함수가 호출되면 해당 호출은 자신의 실행 컨텍스트와 Realm을 푸시합니다.
JobCallback Record { [[Callback]]: callback, [[HostDefined]]: empty }를 반환합니다.
웹 브라우저가 아닌 ECMAScript 호스트는 HostMakeJobCallback의 기본 구현을 사용해야 합니다.
참고
이는 콜백이 나중에 예약되어 실행되도록 하는 함수에 전달되는 시점에 호출됩니다. 예를 들어 promise.then(thenAction)은 반응 Job을 예약하는 시점이 아니라 Promise.prototype.then을 호출하는 시점에 thenAction에 대해 MakeJobCallback을 호출합니다.
웹 브라우저가 아닌 ECMAScript 호스트는 HostCallJobCallback의 기본 구현을 사용해야 합니다.
9.5.4 HostEnqueueGenericJob ( job, realm )
호스트 정의 추상 연산 HostEnqueueGenericJob. 인수 job (a JobAbstract Closure) 및 realm (Realm 레코드). 반환값: unused. realm.[[AgentSignifier]]로 나타내는 에이전트에서 미래의 어느 시점에 수행되도록 realmrealm에 job을 예약합니다. 이 알고리즘과 함께 사용하는 Abstract Closure는 우선순위나 순서와 같은 추가 제약 조건 없이 예약되도록 의도되었습니다.
호스트 정의 추상 연산 HostEnqueuePromiseJob. 인수 job (a JobAbstract Closure) 및 realm ((Realm 레코드 또는 null)). 반환값: unused. 미래의 어느 시점에 수행되도록 job을 예약합니다. 이 알고리즘과 함께 사용하는 Abstract Closure는 Promise 처리와 관련되거나 그 밖에 Promise 처리 연산과 같은 우선순위로 예약되도록 의도되었습니다.
HostEnqueuePromiseJob의 구현은 9.5의 요구 사항뿐만 아니라 다음 사항도 준수해야 합니다:
realm이 null이 아니면 job이 호출될 때마다 구현체는 job 호출 시점에 실행이 ECMAScript 코드를 평가할 준비가 되도록 구현체 정의 단계를 수행해야 합니다.
HostEnqueuePromiseJob이 호출되는 시점의 GetActiveScriptOrModule()을 scriptOrModule로 둡니다. realm이 null이 아니면 job이 호출될 때마다 구현체는 job 호출 시점에 scriptOrModule이 활성 스크립트 또는 모듈이 되도록 구현체 정의 단계를 수행해야 합니다.
Job은 이를 예약한 HostEnqueuePromiseJob 호출과 동일한 순서로 실행되어야 합니다.
호스트 정의 추상 연산 HostEnqueueTimeoutJob. 인수 timeoutJob (a JobAbstract Closure), realm (Realm 레코드) 및 milliseconds (음이 아닌 유한한 Number). 반환값: unused. realm.[[AgentSignifier]]로 나타내는 에이전트에서 최소 milliseconds밀리초 후에 수행되도록 realmrealm에 timeoutJob을 예약합니다.
[[LittleEndian]], [[Signifier]], [[IsLockFree1]], [[IsLockFree2]] 및 [[IsLockFree8]]의 값은 변경될 수 없습니다.
[[GlobalSymbolRegistry]]List는 추가만 가능하며 다시 할당되지 않습니다.
참고 2
[[IsLockFree1]], [[IsLockFree2]] 및 [[IsLockFree8]]의 값은 반드시 하드웨어에 의해 결정되는 것은 아니며, 시간에 따라 또는 ECMAScript 구현체마다 달라질 수 있는 구현 선택을 반영할 수도 있습니다.
[[IsLockFree4]] 필드는 없습니다. 4바이트 원자적 연산은 항상 lock-free입니다.
실제로 어떤 형태의 락을 사용하여 원자적 연산을 구현하면 해당 연산은 lock-free가 아닙니다. lock-free가 wait-free를 의미하지는 않습니다. lock-free 원자적 연산을 완료하는 데 필요한 머신 단계 수에는 상한이 없습니다.
크기가 n인 원자적 접근이 lock-free라는 사실은 크기가 n인 비원자적 접근의 (인지되는) 원자성에 대해 아무것도 의미하지 않습니다. 특히 비원자적 접근은 여전히 여러 개의 별도 메모리 접근 시퀀스로 수행될 수 있습니다. 자세한 내용은 ReadSharedMemory 및 WriteSharedMemory를 참조하시기 바랍니다.
참고 3
에이전트는 명세상의 메커니즘이며 ECMAScript 구현체의 특정 산출물과 대응할 필요는 없습니다.
9.6.1 AgentSignifier ( )
추상 연산 AgentSignifier. 인수 없음. 반환값: an agent signifier. 호출되면 다음 단계를 수행한다.
일부 환경에서는 특정 에이전트가 일시 중단되는 것이 합리적이지 않을 수 있습니다. 예를 들어 웹 브라우저 환경에서는 문서의 주 이벤트 처리 스레드가 일시 중단되는 것은 허용하지 않으면서 worker의 이벤트 처리 스레드는 일시 중단할 수 있도록 하는 것이 합리적일 수 있습니다.
9.6.3 IncrementModuleAsyncEvaluationCount ( )
추상 연산 IncrementModuleAsyncEvaluationCount. 인수 없음. 반환값: 음이 아닌 정수. 호출되면 다음 단계를 수행한다.
클러스터의 모든 에이전트가 특정 시점에 동시에 생존해 있을 필요는 없습니다. 에이전트A가 다른 에이전트B를 생성한 뒤 A가 종료되고, B가 에이전트C를 생성하는 경우, A가 B와 일부 메모리를 공유할 수 있고 B가 C와 일부 메모리를 공유할 수 있었다면 세 에이전트는 같은 클러스터에 있습니다.
클러스터 내의 모든 에이전트는 각자의 Agent Record에 있는 [[LittleEndian]] 필드에 대해 동일한 값을 가져야 합니다.
참고 3
에이전트 클러스터 내의 서로 다른 에이전트가 서로 다른 [[LittleEndian]] 값을 가지면 다중 바이트 데이터에 공유 메모리를 사용하기 어려워집니다.
클러스터 내의 모든 에이전트는 각자의 Agent Record에 있는 [[IsLockFree1]] 필드에 대해 동일한 값을 가져야 하며, [[IsLockFree2]] 및 [[IsLockFree8]] 필드도 마찬가지입니다.
클러스터 내의 모든 에이전트는 각자의 Agent Record에 있는 [[Signifier]] 필드에 서로 다른 값을 가져야 합니다.
임베딩은 에이전트의 인지나 협조 없이 에이전트를 비활성화(전진 진행 중지)하거나 활성화(전진 진행 재개)할 수 있습니다. 임베딩이 이를 수행하는 경우 클러스터 내 일부 에이전트는 활성 상태로 둔 채 다른 에이전트를 무기한 비활성화 상태로 두어서는 안 됩니다.
참고 4
앞의 제한은 다른 에이전트가 비활성화되었기 때문에 어떤 에이전트가 교착되거나 기아 상태에 빠지는 상황을 방지하기 위한 것입니다. 예를 들어 어떤 창의 문서와 독립적인 수명을 갖는 HTML shared worker가 그러한 독립 문서의 dedicated worker와 메모리를 공유할 수 있고, dedicated worker가 락을 보유한 상태에서 문서와 해당 dedicated worker가 비활성화된 후(예: 문서가 창의 방문 기록에 들어간 경우) shared worker가 해당 락을 획득하려고 시도한다면, shared worker는 dedicated worker가 다시 활성화될 때까지, 어쩌면 영원히, 블로킹됩니다. 그동안 다른 창에서 shared worker에 접근하려는 다른 worker는 기아 상태에 빠집니다.
이 제한의 결과로 임베딩 내부에서 동일한 suspend/wake 집합에 속하지 않는 에이전트 사이에서는 메모리를 공유할 수 없습니다.
임베딩은 에이전트 클러스터의 다른 에이전트가 사전에 알거나 협조하지 않아도 에이전트를 종료할 수 있습니다. 에이전트가 자신 또는 클러스터 내 다른 에이전트의 프로그램적 동작이 아니라 클러스터 외부의 요인으로 종료되면, 임베딩은 두 전략 중 하나를 선택해야 합니다. 클러스터의 모든 에이전트를 종료하거나, 클러스터의 에이전트가 협력하여 최소 하나의 남은 구성원이 종료를 감지할 수 있도록 신뢰할 수 있는 API를 제공해야 하며, 종료 데이터에는 종료된 에이전트를 식별하기에 충분한 정보가 포함되어야 합니다.
참고 5
이러한 종료의 예로는 운영 체제나 사용자가 별도 프로세스에서 실행 중인 에이전트를 종료하는 경우, 또는 에이전트별 리소스 계측 결과 해당 에이전트가 폭주 중임을 나타내어 임베딩 자체가 다른 에이전트와 같은 프로세스에서 실행 중인 에이전트를 종료하는 경우가 있습니다.
다음의 각 명세 값과 그 값에서 전이적으로 도달 가능한 값은 정확히 하나의 에이전트 클러스터에 속합니다.
에이전트는 명시적으로 블로킹을 제공하는 API를 통하는 경우를 제외하고 다른 에이전트가 블로킹되도록 해서는 안 됩니다.
참고
이 요구 사항은 메모리 모델의 생존성 보장과 함께 모든 seq-cst 쓰기가 결국 모든 에이전트에서 관찰 가능해짐을 보장합니다.
9.9 WeakRef 및 FinalizationRegistry 대상의 처리 모델
9.9.1 목표
이 명세는 어떤 객체나 Symbol이 가비지 컬렉션될 것이라는 보장도 하지 않습니다. 생존하지 않는 객체나 Symbol도 오랜 시간이 지난 후 해제될 수도 있고, 전혀 해제되지 않을 수도 있습니다. 이러한 이유로 이 명세에서는 가비지 컬렉션에 의해 발생하는 동작을 설명할 때 “할 수 있습니다”라는 표현을 사용합니다.
WeakRef.prototype.deref가 호출되면, 참조 대상(undefined가 반환되지 않은 경우)은 이후의 동기적 접근에서도 동일한 값이 반환되도록 생존 상태로 유지됩니다. 이 목록은 ClearKeptObjects추상 연산을 사용하여 동기 작업이 완료될 때 재설정됩니다.
일부 ECMAScript 구현체에는 ECMAScript가 유휴 상태일 때를 포함하여 백그라운드에서 실행되는 가비지 컬렉터 구현이 있습니다. 호스트 환경이 CleanupFinalizationRegistry를 예약할 수 있게 하면 finalizer 작업을 실행하기 위해 ECMAScript 실행을 재개하고, 보유 중인 값을 해제하여 전체 메모리 사용량을 줄일 수 있습니다.
9.9.2 생존성
객체 및/또는 Symbol의 어떤 집합 objSet에 대해 objSet에 대한 가상의 WeakRef 비인식 실행은, 참조 대상이 objSet의 요소인 WeakRef에 대해 추상 연산WeakRefDeref가 항상 undefined를 반환하는 실행입니다.
참고 1
WeakRef 비인식성과 생존성은 함께 두 가지 개념을 포착합니다. 첫째, WeakRef 자체는 참조 대상을 생존 상태로 유지하지 않습니다. 둘째, 생존성의 순환이 값이 생존 상태임을 의미하지는 않습니다. 구체적으로 v의 생존성 결정이 WeakRef 참조 대상 r의 생존성 결정에 의존하는 경우, r의 생존성은 v의 생존성을 가정할 수 없습니다. 그렇게 하면 순환 추론이 됩니다.
참고 2
WeakRef 비인식성은 순환을 고려하기 위해 개별 값이 아니라 객체 또는 Symbol의 집합에 대해 정의됩니다. 개별 값에 대해 정의하면 순환 안의 WeakRef 참조 대상은 그 동일성이 순환 내 다른 WeakRef 참조 대상을 통해서만 관찰되더라도 생존 상태로 간주됩니다.
참고 3
비공식적으로 개별 객체 또는 Symbol을 포함하는 모든 집합이 생존 상태이면 해당 객체 또는 Symbol도 생존 상태라고 합니다.
평가 중 어느 시점이든 객체 및/또는 Symbol의 집합 objSet은 다음 조건 중 하나라도 충족하면 생존 상태로 간주합니다:
objSet의 어떤 요소가 임의의 에이전트의 [[KeptAlive]]List에 포함되어 있습니다.
objSet에 대해, objSet의 값 중 하나의 동일성을 관찰하는 유효한 미래의 가상 WeakRef 비인식 실행이 존재합니다.
참고 4
위의 두 번째 조건은 값의 동일성을 WeakRef가 아닌 수단으로 관찰할 수 있으면 해당 값이 생존 상태라는 직관을 포착하려는 것입니다. 값의 동일성은 엄격 동등성 비교 결과를 관찰하거나 해당 값이 Map의 키로 사용되는 것을 관찰하여 확인할 수 있습니다.
참고 5
객체 또는 Symbol이 필드, 내부 슬롯 또는 프로퍼티에 존재한다고 해서 해당 값이 생존 상태임을 의미하지는 않습니다. 예를 들어 문제의 값이 프로그램에 다시 전달되지 않는다면 관찰할 수 없습니다.
이는 WeakMap의 키, WeakSet의 구성원, 그리고 FinalizationRegistry Cell Record의 [[WeakRefTarget]] 및 [[UnregisterToken]] 필드에 해당합니다.
위 정의에 따르면 WeakMap의 키가 생존 상태가 아니라면 이에 대응하는 값도 반드시 생존 상태라고 할 수는 없습니다.
참고 6
생존성은 엔진이 어떤 WeakRef를 비워서는 안 되는지를 보장하기 위한 하한입니다. 여기에서 정의한 생존성은 결정 불가능합니다. 실제로 엔진은 도달 가능성과 같은 보수적인 근사를 사용합니다. 구현에는 상당한 재량이 있을 것으로 예상됩니다.
9.9.3 실행
어느 시점이든 객체 및/또는 Symbol의 집합 objSet이 생존 상태가 아니면 ECMAScript 구현체는 다음 단계를 원자적으로 수행할 수 있습니다:
objSet의 각 요소 value에 대해 다음을 수행합니다.
ref.[[WeakRefTarget]]이 value인 각 WeakRefref에 대해 다음을 수행합니다.
ref.[[WeakRefTarget]]을 empty로 설정합니다.
finalizationRegistry.[[Cells]]가 cell.[[WeakRefTarget]]이 value인 Recordcell을 포함하는 각 FinalizationRegistryfinalizationRegistry에 대해 다음을 수행합니다.
cell.[[WeakRefTarget]]을 empty로 설정합니다.
enqueueCleanup을 true 또는 false 중 하나를 선택하는 구현체 정의 선택으로 둡니다.
map.[[WeakMapData]]가 entry.[[Key]]가 value인 Recordentry를 포함하는 각 WeakMap map에 대해 다음을 수행합니다.
entry.[[Key]]를 empty로 설정합니다.
entry.[[Value]]를 empty로 설정합니다.
set.[[WeakSetData]]가 value를 포함하는 각 WeakSet set에 대해 다음을 수행합니다.
set.[[WeakSetData]]에서 값이 value인 요소를 값이 empty인 요소로 교체합니다.
참고 1
생존성의 정의와 함께 이 절은 구현체가 WeakRef에 적용할 수 있는 최적화를 규정합니다.
객체의 동일성을 관찰하지 않고도 객체에 접근할 수 있습니다. 동일성이 관찰되지 않는 탈출하지 않는 객체의 프로퍼티에 대해 죽은 변수 제거 및 스칼라 대체와 같은 최적화가 허용됩니다. 따라서 이러한 최적화로 해당 객체를 가리키는 WeakRef가 관찰 가능하게 비워지는 것도 허용됩니다.
반면 객체의 동일성을 관찰할 수 있고 해당 객체가 WeakRef의 [[WeakRefTarget]] 내부 슬롯에 있으면, WeakRef를 관찰 가능하게 비우는 재구체화와 같은 최적화는 금지됩니다.
구현체는 생존 상태가 아닌 객체 또는 Symbol의 최대 집합에 대해 WeakRef를 비울 의무가 없습니다.
구현체가 WeakRef를 비울 생존하지 않는 집합 objSet을 선택하면, 이 정의에 따라 objSet의 모든 값에 대한 WeakRef를 동시에 비워야 합니다. 다시 말해, 구현체가 값 v를 가리키는 WeakRef를 비우면서, 비우지 않을 경우 v의 값을 관찰하는 실행이 가능해지는 다른 WeakRef를 비우지 않는 것은 적합하지 않습니다.
추상 연산 CanBeHeldWeakly. 인수 arg (ECMAScript 언어 값). 반환값: Boolean. arg가 약한 참조로 사용하기에 적합한 경우에만 true를 반환합니다. 약한 참조로 사용하기에 적합한 값만 WeakMap의 키, WeakSet의 요소, WeakRef의 대상 또는 FinalizationRegistry의 대상 중 하나가 될 수 있습니다. 호출되면 다음 단계를 수행한다.
언어 동일성이 없는 언어 값은 사전 참조 없이 만들어질 수 있으므로 약한 참조로 사용하기에 적합하지 않습니다. Symbol.for가 생성한 Symbol 값은 다른 Symbol 값과 달리 언어 동일성이 없으므로 약한 참조로 사용하기에 적합하지 않습니다. 잘 알려진 Symbol은 가비지 컬렉션되지 않을 가능성이 높지만, 수가 제한되어 있어 다양한 구현 방식으로 관리할 수 있으므로 약한 참조로 사용하기에 적합한 것으로 취급됩니다. 그러나 생존 상태인 WeakMap에서 잘 알려진 Symbol에 연결된 모든 값은 가비지 컬렉션되지 않을 가능성이 높아 구현체에서 메모리 리소스를 “누수”할 수 있습니다.