2020-04-15 16:58:22 -03:00
/*
2024-10-04 08:19:50 -03:00
* Copyright ( c ) 2020 - 2022 , Andreas Kling < andreas @ ladybird . org >
2020-04-15 16:58:22 -03:00
*
2021-04-22 05:24:48 -03:00
* SPDX - License - Identifier : BSD - 2 - Clause
2020-04-15 16:58:22 -03:00
*/
2026-05-15 03:23:39 -03:00
# include <AK/NeverDestroyed.h>
2022-12-20 18:09:57 -03:00
# include <LibJS/Runtime/AbstractOperations.h>
2021-07-01 07:24:46 -03:00
# include <LibJS/Runtime/DeclarativeEnvironment.h>
2020-06-08 15:31:21 -03:00
# include <LibJS/Runtime/Error.h>
2026-05-05 19:19:35 -03:00
# include <LibJS/Runtime/ExternalMemory.h>
2021-06-27 16:48:34 -03:00
# include <LibJS/Runtime/FunctionObject.h>
2020-09-27 10:18:55 -03:00
# include <LibJS/Runtime/GlobalObject.h>
2020-06-08 15:31:21 -03:00
# include <LibJS/Runtime/Value.h>
2020-04-15 16:58:22 -03:00
namespace JS {
2024-11-14 12:01:23 -03:00
GC_DEFINE_ALLOCATOR ( DeclarativeEnvironment ) ;
2023-11-19 05:45:05 -03:00
2021-07-01 07:24:46 -03:00
DeclarativeEnvironment : : DeclarativeEnvironment ( )
2024-05-11 08:31:33 -03:00
: Environment ( nullptr , IsDeclarative : : Yes )
2020-04-15 16:58:22 -03:00
{
}
2022-04-30 20:10:05 -03:00
DeclarativeEnvironment : : DeclarativeEnvironment ( Environment * parent_environment )
2024-05-11 08:31:33 -03:00
: Environment ( parent_environment , IsDeclarative : : Yes )
2021-06-21 19:56:14 -03:00
{
}
2023-02-05 16:02:54 -03:00
DeclarativeEnvironment : : DeclarativeEnvironment ( Environment * parent_environment , ReadonlySpan < Binding > bindings )
2024-05-11 08:31:33 -03:00
: Environment ( parent_environment , IsDeclarative : : Yes )
2022-03-09 17:37:10 -03:00
{
2026-05-14 18:56:48 -03:00
ensure_capacity ( bindings . size ( ) ) ;
for ( auto binding : bindings )
append_binding ( move ( binding ) ) ;
2022-03-09 17:37:10 -03:00
}
2026-05-15 03:23:39 -03:00
void DeclarativeEnvironment : : RareData : : visit_edges ( Visitor & visitor ) const
{
m_dispose_capability . visit_edges ( visitor ) ;
}
size_t DeclarativeEnvironment : : RareData : : external_memory_size ( ) const
{
auto size = sizeof ( RareData ) ;
size = saturating_add_external_memory_size ( size , vector_external_memory_size ( m_binding_names ) ) ;
size = saturating_add_external_memory_size ( size , vector_external_memory_size ( m_binding_flags ) ) ;
size = saturating_add_external_memory_size ( size , m_deleted_bindings . size_in_bytes ( ) ) ;
size = saturating_add_external_memory_size ( size , hash_map_external_memory_size ( m_bindings_assoc ) ) ;
if ( m_dispose_capability . disposable_resource_stack ) {
size = saturating_add_external_memory_size ( size , sizeof ( Vector < DisposableResource > ) ) ;
size = saturating_add_external_memory_size ( size , vector_external_memory_size ( * m_dispose_capability . disposable_resource_stack ) ) ;
}
return size ;
}
bool DeclarativeEnvironment : : RareData : : is_empty ( ) const
{
return m_binding_names . is_empty ( )
& & m_binding_flags . is_empty ( )
& & m_deleted_bindings . is_null ( )
& & m_bindings_assoc . is_empty ( )
& & ! m_dispose_capability . disposable_resource_stack
& & ! m_environment_shape_cache
2026-05-15 03:26:38 -03:00
& & m_expected_binding_count = = 0
& & m_environment_serial_number = = 0
& & ! m_is_catch_environment ;
2026-05-15 03:23:39 -03:00
}
DeclarativeEnvironment : : RareData & DeclarativeEnvironment : : ensure_rare_data ( )
{
if ( ! m_rare_data )
m_rare_data = make < RareData > ( ) ;
return * m_rare_data ;
}
void DeclarativeEnvironment : : drop_rare_data_if_empty ( )
{
if ( m_rare_data & & m_rare_data - > is_empty ( ) )
m_rare_data . clear ( ) ;
}
2026-05-15 03:26:38 -03:00
void DeclarativeEnvironment : : increment_environment_serial_number ( )
{
if ( m_shape )
return ;
if ( m_rare_data & & m_rare_data - > m_environment_shape_cache )
return ;
+ + ensure_rare_data ( ) . m_environment_serial_number ;
}
bool DeclarativeEnvironment : : is_catch_environment ( ) const
{
if ( ! m_rare_data )
return false ;
return m_rare_data - > m_is_catch_environment ;
}
void DeclarativeEnvironment : : set_is_catch_environment ( bool value )
{
if ( ! value & & ! m_rare_data )
return ;
ensure_rare_data ( ) . m_is_catch_environment = value ;
drop_rare_data_if_empty ( ) ;
}
2021-07-01 07:24:46 -03:00
void DeclarativeEnvironment : : visit_edges ( Visitor & visitor )
2020-04-15 16:58:22 -03:00
{
2021-01-28 06:13:47 -03:00
Base : : visit_edges ( visitor ) ;
2026-05-15 03:23:39 -03:00
if ( m_rare_data )
m_rare_data - > visit_edges ( visitor ) ;
2026-05-14 19:17:32 -03:00
visitor . visit ( m_shape ) ;
2025-01-16 18:51:26 -03:00
2026-05-14 18:56:48 -03:00
for ( auto & value : m_binding_values )
visitor . visit ( value ) ;
2020-04-15 16:58:22 -03:00
}
2026-05-05 19:19:35 -03:00
size_t DeclarativeEnvironment : : external_memory_size ( ) const
{
2026-05-15 03:23:39 -03:00
auto size = vector_external_memory_size ( m_binding_values ) ;
if ( m_rare_data )
size = saturating_add_external_memory_size ( size , m_rare_data - > external_memory_size ( ) ) ;
2026-05-05 19:19:35 -03:00
return size ;
}
2026-05-15 03:23:39 -03:00
DisposeCapability const & DeclarativeEnvironment : : dispose_capability ( ) const
{
static NeverDestroyed < DisposeCapability > empty_dispose_capability ;
if ( ! m_rare_data )
return * empty_dispose_capability ;
return m_rare_data - > m_dispose_capability ;
}
DisposeCapability & DeclarativeEnvironment : : dispose_capability ( )
{
return ensure_rare_data ( ) . m_dispose_capability ;
}
DisposeCapability * DeclarativeEnvironment : : dispose_capability_if_exists ( )
{
if ( ! m_rare_data | | ! m_rare_data - > m_dispose_capability . disposable_resource_stack )
return nullptr ;
return & m_rare_data - > m_dispose_capability ;
}
2026-05-15 03:26:38 -03:00
u64 DeclarativeEnvironment : : environment_serial_number ( ) const
{
if ( ! m_rare_data )
return 0 ;
return m_rare_data - > m_environment_serial_number ;
}
2026-05-14 18:56:48 -03:00
void DeclarativeEnvironment : : append_binding ( Binding binding )
{
auto index = m_binding_values . size ( ) ;
u8 flags = 0 ;
if ( binding . strict )
flags | = BindingFlagStrict ;
if ( binding . mutable_ )
flags | = BindingFlagMutable ;
if ( binding . can_be_deleted )
flags | = BindingFlagCanBeDeleted ;
2026-05-14 19:17:32 -03:00
if ( m_shape & & index < shape_binding_count ( ) ) {
VERIFY ( m_shape - > binding_name ( index ) = = binding . name ) ;
VERIFY ( m_shape - > binding_flags ( index ) = = flags ) ;
} else {
2026-05-15 03:23:39 -03:00
auto & rare_data = ensure_rare_data ( ) ;
rare_data . m_bindings_assoc . set ( binding . name , index ) ;
rare_data . m_binding_names . append ( move ( binding . name ) ) ;
rare_data . m_binding_flags . append ( flags ) ;
2026-05-14 19:17:32 -03:00
}
2026-05-14 19:43:44 -03:00
m_binding_values . append ( binding . initialized ? binding . value : js_special_empty_value ( ) ) ;
2026-05-14 18:56:48 -03:00
}
void DeclarativeEnvironment : : clear_binding ( Utf16FlyString const & name , size_t index )
{
2026-05-14 19:17:32 -03:00
if ( index < shape_binding_count ( ) ) {
ensure_deleted_bindings_capacity ( index + 1 ) ;
2026-05-15 03:23:39 -03:00
m_rare_data - > m_deleted_bindings . set ( index , true ) ;
2026-05-14 19:43:44 -03:00
m_binding_values [ index ] = js_special_empty_value ( ) ;
2026-05-14 19:17:32 -03:00
return ;
}
2026-05-15 03:23:39 -03:00
VERIFY ( m_rare_data ) ;
m_rare_data - > m_bindings_assoc . remove ( name ) ;
2026-05-14 19:17:32 -03:00
auto local_index = local_binding_index ( index ) ;
2026-05-15 03:23:39 -03:00
m_rare_data - > m_binding_names [ local_index ] = Utf16FlyString { } ;
2026-05-14 19:43:44 -03:00
m_binding_values [ index ] = js_special_empty_value ( ) ;
2026-05-15 03:23:39 -03:00
m_rare_data - > m_binding_flags [ local_index ] = 0 ;
2026-05-14 18:56:48 -03:00
}
DeclarativeEnvironment : : Binding DeclarativeEnvironment : : binding_at ( size_t index ) const
{
return Binding {
2026-05-14 19:17:32 -03:00
. name = binding_name ( index ) ,
2026-05-14 18:56:48 -03:00
. value = m_binding_values [ index ] ,
. strict = binding_is_strict ( index ) ,
. mutable_ = binding_is_mutable ( index ) ,
. can_be_deleted = binding_can_be_deleted ( index ) ,
. initialized = binding_is_initialized ( index ) ,
} ;
}
2026-05-14 19:17:32 -03:00
void DeclarativeEnvironment : : set_environment_shape_cache ( GC : : Ptr < EnvironmentShape > & cache , size_t expected_binding_count )
{
2026-05-15 03:23:39 -03:00
if ( expected_binding_count = = 0 )
2026-05-14 19:17:32 -03:00
return ;
2026-05-15 03:23:39 -03:00
if ( cache ) {
VERIFY ( cache - > size ( ) = = expected_binding_count ) ;
set_environment_shape ( GC : : Ref { * cache } ) ;
return ;
}
auto & rare_data = ensure_rare_data ( ) ;
rare_data . m_environment_shape_cache = & cache ;
rare_data . m_expected_binding_count = expected_binding_count ;
2026-05-14 19:17:32 -03:00
}
void DeclarativeEnvironment : : set_environment_shape ( GC : : Ref < EnvironmentShape > shape )
{
VERIFY ( ! m_shape ) ;
VERIFY ( m_binding_values . size ( ) < = shape - > size ( ) ) ;
m_shape = shape ;
2026-05-15 03:23:39 -03:00
if ( m_rare_data ) {
m_rare_data - > m_binding_names . clear ( ) ;
m_rare_data - > m_binding_flags . clear ( ) ;
m_rare_data - > m_bindings_assoc . clear ( ) ;
m_rare_data - > m_environment_shape_cache = nullptr ;
m_rare_data - > m_expected_binding_count = 0 ;
drop_rare_data_if_empty ( ) ;
}
2026-05-14 19:17:32 -03:00
}
void DeclarativeEnvironment : : maybe_finalize_environment_shape ( VM & vm )
{
2026-05-15 03:23:39 -03:00
if ( ! m_rare_data | | ! m_rare_data - > m_environment_shape_cache | | m_shape | | m_rare_data - > m_expected_binding_count = = 0 | | m_binding_values . size ( ) ! = m_rare_data - > m_expected_binding_count )
2026-05-14 19:17:32 -03:00
return ;
2026-05-15 03:23:39 -03:00
if ( * m_rare_data - > m_environment_shape_cache ) {
auto shape = GC : : Ref { * * m_rare_data - > m_environment_shape_cache } ;
2026-05-14 19:17:32 -03:00
VERIFY ( shape - > size ( ) = = m_binding_values . size ( ) ) ;
for ( size_t i = 0 ; i < m_binding_values . size ( ) ; + + i ) {
2026-05-15 03:23:39 -03:00
VERIFY ( shape - > binding_name ( i ) = = m_rare_data - > m_binding_names [ i ] ) ;
VERIFY ( shape - > binding_flags ( i ) = = m_rare_data - > m_binding_flags [ i ] ) ;
2026-05-14 19:17:32 -03:00
}
set_environment_shape ( shape ) ;
return ;
}
2026-05-15 03:23:39 -03:00
auto shape = EnvironmentShape : : create ( vm , m_rare_data - > m_binding_names , m_rare_data - > m_binding_flags ) ;
* m_rare_data - > m_environment_shape_cache = shape ;
2026-05-14 19:17:32 -03:00
set_environment_shape ( shape ) ;
}
2021-06-23 07:26:37 -03:00
// 9.1.1.1.1 HasBinding ( N ), https://tc39.es/ecma262/#sec-declarative-environment-records-hasbinding-n
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < bool > DeclarativeEnvironment : : has_binding ( Utf16FlyString const & name , Optional < size_t > * out_index ) const
2021-06-23 07:26:37 -03:00
{
2022-09-01 18:22:17 -03:00
auto binding_and_index = find_binding_and_index ( name ) ;
if ( ! binding_and_index . has_value ( ) )
2021-10-06 18:53:22 -03:00
return false ;
2022-09-01 18:22:17 -03:00
if ( ! is_permanently_screwed_by_eval ( ) & & out_index & & binding_and_index - > index ( ) . has_value ( ) )
* out_index = * ( binding_and_index - > index ( ) ) ;
2021-10-06 18:53:22 -03:00
return true ;
2021-06-23 07:26:37 -03:00
}
2021-06-23 08:25:57 -03:00
// 9.1.1.1.2 CreateMutableBinding ( N, D ), https://tc39.es/ecma262/#sec-declarative-environment-records-createmutablebinding-n-d
2026-05-14 19:17:32 -03:00
ThrowCompletionOr < void > DeclarativeEnvironment : : create_mutable_binding ( VM & vm , Utf16FlyString const & name , bool can_be_deleted )
2021-06-23 07:26:37 -03:00
{
2022-05-02 15:54:39 -03:00
// 1. Assert: envRec does not already have a binding for N.
2026-05-14 18:56:48 -03:00
// NOTE: We skip this to avoid O(n) traversal of m_binding_names.
2022-05-02 15:54:39 -03:00
2021-10-09 14:53:25 -03:00
// 2. 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.
2026-05-14 18:56:48 -03:00
append_binding ( Binding {
2022-03-08 13:56:42 -03:00
. name = name ,
2021-10-06 18:38:46 -03:00
. value = { } ,
. strict = false ,
. mutable_ = true ,
. can_be_deleted = can_be_deleted ,
. initialized = false ,
} ) ;
2026-05-14 19:17:32 -03:00
maybe_finalize_environment_shape ( vm ) ;
2021-10-09 14:53:25 -03:00
2026-05-15 03:26:38 -03:00
increment_environment_serial_number ( ) ;
2023-07-12 09:30:51 -03:00
2022-05-02 15:54:39 -03:00
// 3. Return unused.
2021-10-09 14:53:25 -03:00
return { } ;
2021-06-23 07:26:37 -03:00
}
2021-06-23 08:25:57 -03:00
// 9.1.1.1.3 CreateImmutableBinding ( N, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-createimmutablebinding-n-s
2026-05-14 19:17:32 -03:00
ThrowCompletionOr < void > DeclarativeEnvironment : : create_immutable_binding ( VM & vm , Utf16FlyString const & name , bool strict )
2021-06-23 07:26:37 -03:00
{
2022-05-02 15:54:39 -03:00
// 1. Assert: envRec does not already have a binding for N.
2026-05-14 18:56:48 -03:00
// NOTE: We skip this to avoid O(n) traversal of m_binding_names.
2022-05-02 15:54:39 -03:00
2021-10-09 15:00:06 -03:00
// 2. 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.
2026-05-14 18:56:48 -03:00
append_binding ( Binding {
2022-03-08 13:56:42 -03:00
. name = name ,
2021-10-06 18:38:46 -03:00
. value = { } ,
. strict = strict ,
. mutable_ = false ,
. can_be_deleted = false ,
. initialized = false ,
} ) ;
2026-05-14 19:17:32 -03:00
maybe_finalize_environment_shape ( vm ) ;
2021-10-09 15:00:06 -03:00
2026-05-15 03:26:38 -03:00
increment_environment_serial_number ( ) ;
2023-07-12 09:30:51 -03:00
2022-05-02 15:54:39 -03:00
// 3. Return unused.
2021-10-09 15:00:06 -03:00
return { } ;
2021-06-23 07:26:37 -03:00
}
2021-06-23 08:25:57 -03:00
// 9.1.1.1.4 InitializeBinding ( N, V ), https://tc39.es/ecma262/#sec-declarative-environment-records-initializebinding-n-v
2022-12-14 09:26:10 -03:00
// 4.1.1.1.1 InitializeBinding ( N, V, hint ), https://tc39.es/proposal-explicit-resource-management/#sec-declarative-environment-records
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < void > DeclarativeEnvironment : : initialize_binding ( VM & vm , Utf16FlyString const & name , Value value , Environment : : InitializeBindingHint hint )
2021-06-23 07:26:37 -03:00
{
2024-05-13 17:03:52 -03:00
return initialize_binding_direct ( vm , find_binding_and_index ( name ) - > index ( ) . value ( ) , value , hint ) ;
}
ThrowCompletionOr < void > DeclarativeEnvironment : : initialize_binding_direct ( VM & vm , size_t index , Value value , Environment : : InitializeBindingHint hint )
{
2021-10-09 15:16:24 -03:00
// 1. Assert: envRec must have an uninitialized binding for N.
2026-05-14 18:56:48 -03:00
VERIFY ( ! binding_is_initialized ( index ) ) ;
2026-05-14 19:43:44 -03:00
VERIFY ( ! value . is_special_empty_value ( ) ) ;
2021-10-09 15:16:24 -03:00
2025-01-16 18:51:26 -03:00
// 2. If hint is not normal, perform ? AddDisposableResource(envRec.[[DisposeCapability]], V, hint).
2022-12-20 18:09:57 -03:00
if ( hint ! = Environment : : InitializeBindingHint : : Normal )
2026-05-15 03:23:39 -03:00
TRY ( add_disposable_resource ( vm , ensure_rare_data ( ) . m_dispose_capability , value , hint ) ) ;
2022-12-14 09:26:10 -03:00
// 3. Set the bound value for N in envRec to V.
2026-05-14 18:56:48 -03:00
m_binding_values [ index ] = value ;
2021-10-09 15:16:24 -03:00
2022-12-14 09:26:10 -03:00
// 5. Return unused.
2021-10-09 15:16:24 -03:00
return { } ;
2021-06-23 07:26:37 -03:00
}
2021-06-23 08:25:57 -03:00
// 9.1.1.1.5 SetMutableBinding ( N, V, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-setmutablebinding-n-v-s
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < void > DeclarativeEnvironment : : set_mutable_binding ( VM & vm , Utf16FlyString const & name , Value value , bool strict )
2021-06-23 07:26:37 -03:00
{
2021-10-09 15:34:54 -03:00
// 1. If envRec does not have a binding for N, then
2022-09-01 18:22:17 -03:00
auto binding_and_index = find_binding_and_index ( name ) ;
if ( ! binding_and_index . has_value ( ) ) {
2021-10-09 15:34:54 -03:00
// a. If S is true, throw a ReferenceError exception.
if ( strict )
2022-08-21 11:12:43 -03:00
return vm . throw_completion < ReferenceError > ( ErrorType : : UnknownIdentifier , name ) ;
2021-10-09 15:34:54 -03:00
2022-05-24 14:19:49 -03:00
// b. Perform ! envRec.CreateMutableBinding(N, true).
2022-08-21 11:12:43 -03:00
MUST ( create_mutable_binding ( vm , name , true ) ) ;
2021-10-09 15:34:54 -03:00
2022-12-14 09:26:10 -03:00
// c. Perform ! envRec.InitializeBinding(N, V, normal).
MUST ( initialize_binding ( vm , name , value , Environment : : InitializeBindingHint : : Normal ) ) ;
2021-10-09 15:34:54 -03:00
2022-05-02 15:54:39 -03:00
// d. Return unused.
2021-10-09 15:34:54 -03:00
return { } ;
2021-06-23 07:26:37 -03:00
}
2021-10-09 15:34:54 -03:00
// 2-5. (extracted into a non-standard function below)
2026-05-14 18:56:48 -03:00
if ( binding_and_index - > index ( ) . has_value ( ) ) {
TRY ( set_mutable_binding_direct ( vm , * binding_and_index - > index ( ) , value , strict ) ) ;
} else {
auto binding = binding_and_index - > binding ( ) ;
TRY ( set_mutable_binding_direct ( vm , binding , value , strict ) ) ;
}
2021-10-09 15:34:54 -03:00
2022-05-02 15:54:39 -03:00
// 6. Return unused.
2021-10-09 15:34:54 -03:00
return { } ;
2021-10-06 19:10:00 -03:00
}
2022-08-21 11:12:43 -03:00
ThrowCompletionOr < void > DeclarativeEnvironment : : set_mutable_binding_direct ( VM & vm , size_t index , Value value , bool strict )
2021-10-06 19:10:00 -03:00
{
2026-05-14 18:56:48 -03:00
if ( binding_is_strict ( index ) )
strict = true ;
if ( ! binding_is_initialized ( index ) )
2026-05-14 19:17:32 -03:00
return vm . throw_completion < ReferenceError > ( ErrorType : : BindingNotInitialized , binding_name ( index ) ) ;
2026-05-14 18:56:48 -03:00
if ( binding_is_mutable ( index ) ) {
m_binding_values [ index ] = value ;
} else {
if ( strict )
return vm . throw_completion < TypeError > ( ErrorType : : InvalidAssignToConst ) ;
}
return { } ;
2022-09-01 18:22:17 -03:00
}
ThrowCompletionOr < void > DeclarativeEnvironment : : set_mutable_binding_direct ( VM & vm , Binding & binding , Value value , bool strict )
{
2021-10-06 18:38:46 -03:00
if ( binding . strict )
2021-06-23 07:26:37 -03:00
strict = true ;
2021-10-09 15:34:54 -03:00
if ( ! binding . initialized )
2022-08-21 11:12:43 -03:00
return vm . throw_completion < ReferenceError > ( ErrorType : : BindingNotInitialized , binding . name ) ;
2021-06-23 07:26:37 -03:00
2021-10-06 18:38:46 -03:00
if ( binding . mutable_ ) {
binding . value = value ;
2021-06-23 07:26:37 -03:00
} else {
2021-10-09 15:34:54 -03:00
if ( strict )
2022-08-21 11:12:43 -03:00
return vm . throw_completion < TypeError > ( ErrorType : : InvalidAssignToConst ) ;
2021-06-23 07:26:37 -03:00
}
2021-10-09 15:34:54 -03:00
return { } ;
2021-06-23 07:26:37 -03:00
}
2021-06-23 08:25:57 -03:00
// 9.1.1.1.6 GetBindingValue ( N, S ), https://tc39.es/ecma262/#sec-declarative-environment-records-getbindingvalue-n-s
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < Value > DeclarativeEnvironment : : get_binding_value ( VM & vm , Utf16FlyString const & name , [[maybe_unused]] bool strict )
2021-06-23 07:26:37 -03:00
{
2021-10-09 15:43:19 -03:00
// 1. Assert: envRec has a binding for N.
2022-09-01 18:22:17 -03:00
auto binding_and_index = find_binding_and_index ( name ) ;
VERIFY ( binding_and_index . has_value ( ) ) ;
2021-10-09 15:43:19 -03:00
// 2-3. (extracted into a non-standard function below)
2026-05-14 18:56:48 -03:00
if ( binding_and_index - > index ( ) . has_value ( ) )
return get_binding_value_direct ( vm , * binding_and_index - > index ( ) ) ;
auto binding = binding_and_index - > binding ( ) ;
return get_binding_value_direct ( vm , binding ) ;
2021-06-23 07:26:37 -03:00
}
2021-06-23 08:25:57 -03:00
// 9.1.1.1.7 DeleteBinding ( N ), https://tc39.es/ecma262/#sec-declarative-environment-records-deletebinding-n
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < bool > DeclarativeEnvironment : : delete_binding ( VM & , Utf16FlyString const & name )
2021-06-23 07:26:37 -03:00
{
2021-10-09 15:49:08 -03:00
// 1. Assert: envRec has a binding for the name that is the value of N.
2022-09-01 18:22:17 -03:00
auto binding_and_index = find_binding_and_index ( name ) ;
VERIFY ( binding_and_index . has_value ( ) ) ;
2021-10-09 15:49:08 -03:00
// 2. If the binding for N in envRec cannot be deleted, return false.
2026-05-14 18:56:48 -03:00
if ( ! binding_and_index - > index ( ) . has_value ( ) ) {
if ( ! binding_and_index - > binding ( ) . can_be_deleted )
return false ;
VERIFY_NOT_REACHED ( ) ;
}
auto index = * binding_and_index - > index ( ) ;
if ( ! binding_can_be_deleted ( index ) )
2021-06-23 07:26:37 -03:00
return false ;
2021-10-09 15:49:08 -03:00
// 3. Remove the binding for N from envRec.
2026-05-14 18:56:48 -03:00
// NOTE: We keep the entry in the parallel vectors to avoid disturbing indices.
clear_binding ( name , index ) ;
2021-10-09 15:49:08 -03:00
2026-05-15 03:26:38 -03:00
increment_environment_serial_number ( ) ;
2023-07-12 09:30:51 -03:00
2021-10-09 15:49:08 -03:00
// 4. Return true.
2021-06-23 07:26:37 -03:00
return true ;
}
2025-08-02 20:27:29 -03:00
ThrowCompletionOr < void > DeclarativeEnvironment : : initialize_or_set_mutable_binding ( VM & vm , Utf16FlyString const & name , Value value )
2021-09-22 07:44:56 -03:00
{
2022-09-01 18:22:17 -03:00
auto binding_and_index = find_binding_and_index ( name ) ;
VERIFY ( binding_and_index . has_value ( ) ) ;
2026-05-14 18:56:48 -03:00
VERIFY ( binding_and_index - > index ( ) . has_value ( ) ) ;
auto index = * binding_and_index - > index ( ) ;
if ( ! binding_is_initialized ( index ) )
TRY ( initialize_binding_direct ( vm , index , value , Environment : : InitializeBindingHint : : Normal ) ) ;
2021-09-22 07:44:56 -03:00
else
2026-05-14 18:56:48 -03:00
TRY ( set_mutable_binding_direct ( vm , index , value , false ) ) ;
2022-02-12 13:18:45 -03:00
return { } ;
}
2022-11-26 16:33:52 -03:00
void DeclarativeEnvironment : : shrink_to_fit ( )
{
2026-05-14 18:56:48 -03:00
m_binding_values . shrink_to_fit ( ) ;
2026-05-15 03:23:39 -03:00
if ( ! m_rare_data )
2026-05-14 18:56:48 -03:00
return ;
2026-05-14 19:17:32 -03:00
2026-05-15 03:23:39 -03:00
m_rare_data - > m_binding_names . shrink_to_fit ( ) ;
m_rare_data - > m_binding_flags . shrink_to_fit ( ) ;
if ( m_binding_values . is_empty ( ) ) {
m_rare_data - > m_deleted_bindings = { } ;
drop_rare_data_if_empty ( ) ;
2026-05-14 19:17:32 -03:00
return ;
2026-05-15 03:23:39 -03:00
}
if ( m_rare_data - > m_deleted_bindings . is_null ( ) ) {
drop_rare_data_if_empty ( ) ;
return ;
}
2026-05-14 19:17:32 -03:00
auto deleted_bindings = MUST ( Bitmap : : create ( m_binding_values . size ( ) , false ) ) ;
for ( size_t i = 0 ; i < m_binding_values . size ( ) ; + + i )
deleted_bindings . set ( i , binding_is_deleted ( i ) ) ;
2026-05-15 03:23:39 -03:00
m_rare_data - > m_deleted_bindings = move ( deleted_bindings ) ;
drop_rare_data_if_empty ( ) ;
2022-11-26 16:33:52 -03:00
}
2020-04-15 16:58:22 -03:00
}