From f32393e2d29b27aff86b540bffed25bb900a9fbb Mon Sep 17 00:00:00 2001 From: Aapo Alasuutari Date: Mon, 9 Feb 2026 15:40:35 +0200 Subject: [PATCH 1/2] fix: AwaitReaction self use-after-free --- .../async_function_objects/await_reaction.rs | 44 ++++++++++++++----- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/async_function_objects/await_reaction.rs b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/async_function_objects/await_reaction.rs index 7b6e8a8e9..7fef65f39 100644 --- a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/async_function_objects/await_reaction.rs +++ b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/async_function_objects/await_reaction.rs @@ -67,8 +67,15 @@ impl AwaitReaction<'_> { let reaction = unsafe { reaction.take(agent) }.bind(gc.nogc()); match execution_result { ExecutionResult::Return(result) => { + // SAFETY: reaction is not shared. + let reaction = unsafe { reaction.take(agent) }.bind(gc.nogc()); + // [27.7.5.2 AsyncBlockStart ( promiseCapability, asyncBody, asyncContext )](https://tc39.es/ecma262/#sec-asyncblockstart) - // 2. d. Remove acAsyncContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context. + // + // 2. d. Remove acAsyncContext from the execution context stack + // and restore the execution context that is at the top of + // the execution context stack as the running execution + // context. agent.pop_execution_context(); // 2. e. If result is a normal completion, then // i. Perform ! Call(promiseCapability.[[Resolve]], undefined, « undefined »). @@ -82,8 +89,15 @@ impl AwaitReaction<'_> { .resolve(agent, result.unbind(), gc); } ExecutionResult::Throw(err) => { + // SAFETY: reaction is not shared. + let reaction = unsafe { reaction.take(agent) }.bind(gc.nogc()); + // [27.7.5.2 AsyncBlockStart ( promiseCapability, asyncBody, asyncContext )](https://tc39.es/ecma262/#sec-asyncblockstart) - // 2. d. Remove acAsyncContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context. + // + // 2. d. Remove acAsyncContext from the execution context stack + // and restore the execution context that is at the top of + // the execution context stack as the running execution + // context. agent.pop_execution_context(); // 2. g. i. Assert: result is a throw completion. // ii. Perform ! Call(promiseCapability.[[Reject]], undefined, « result.[[Value]] »). @@ -95,21 +109,29 @@ impl AwaitReaction<'_> { } ExecutionResult::Await { vm, awaited_value } => { // [27.7.5.3 Await ( value )](https://tc39.es/ecma262/#await) - // 8. Remove asyncContext from the execution context stack and restore the execution context that is at the top of the execution context stack as the running execution context. + // 8. Remove asyncContext from the execution context stack and + // restore the execution context that is at the top of the + // execution context stack as the running execution context. let execution_context = agent.pop_execution_context().unwrap(); - let data = reaction.get_mut(agent); + let data = reaction.get(agent).bind(gc.nogc()).get_mut(agent); data.vm = Some(vm); data.execution_context = Some(execution_context); - // `handler` corresponds to the `fulfilledClosure` and `rejectedClosure` functions, - // which resume execution of the function. - let handler = PromiseReactionHandler::Await(self); // 2. Let promise be ? PromiseResolve(%Promise%, value). - let promise = Promise::resolve(agent, awaited_value.unbind(), gc.reborrow()) - .unbind() - .bind(gc.nogc()); + let promise = + Promise::resolve(agent, awaited_value.unbind(), gc.reborrow()).unbind(); + let gc = gc.into_nogc(); + let promise = promise.bind(gc); + + // SAFETY: not shared. + let reaction = unsafe { reaction.take(agent) }.bind(gc); + + // `handler` corresponds to the `fulfilledClosure` and + // `rejectedClosure` functions, which resume execution of the + // function. + let handler = PromiseReactionHandler::Await(reaction); // 7. Perform PerformPromiseThen(promise, onFulfilled, onRejected). - inner_promise_then(agent, promise, handler, handler, None, gc.nogc()); + inner_promise_then(agent, promise, handler, handler, None, gc); } ExecutionResult::Yield { .. } => unreachable!(), } From 7b697f5289c4b8a8dec6f9117b1394234720191a Mon Sep 17 00:00:00 2001 From: Aapo Alasuutari Date: Mon, 9 Feb 2026 15:41:02 +0200 Subject: [PATCH 2/2] chore: remove some manual get/get_mut APIs --- nova_vm/src/ecmascript/builtins/array.rs | 27 +----- .../async_function_objects/await_reaction.rs | 22 ++--- .../promise_finally_functions.rs | 20 +--- .../promise_group_record.rs | 93 +++++++++---------- .../promise_reaction_records.rs | 4 +- .../promise_objects/promise_constructor.rs | 5 +- .../array_objects/array_prototype.rs | 4 +- .../builtins/shared_array_buffer.rs | 20 +--- .../regexp_string_iterator_objects.rs | 20 +--- nova_vm/src/ecmascript/execution/agent.rs | 2 +- nova_vm/src/ecmascript/execution/realm.rs | 19 ++-- .../ecmascript/scripts_and_modules/script.rs | 19 ++-- .../src/ecmascript/types/language/number.rs | 22 ----- nova_vm/src/heap.rs | 24 +---- 14 files changed, 101 insertions(+), 200 deletions(-) diff --git a/nova_vm/src/ecmascript/builtins/array.rs b/nova_vm/src/ecmascript/builtins/array.rs index 00e7611fc..959977c9e 100644 --- a/nova_vm/src/ecmascript/builtins/array.rs +++ b/nova_vm/src/ecmascript/builtins/array.rs @@ -22,9 +22,10 @@ use crate::{ }, engine::{Bindable, GcScope, NoGcScope}, heap::{ - CompactionLists, CreateHeapData, Heap, HeapMarkAndSweep, HeapSweepWeakReference, - WorkQueues, arena_vec_access, {BaseIndex, HeapIndexHandle}, - {ElementArrays, ElementDescriptor, ElementStorageMut, ElementStorageRef, ElementsVector}, + ArenaAccessSoA, ArenaAccessSoAMut, BaseIndex, CompactionLists, CreateHeapData, + ElementArrays, ElementDescriptor, ElementStorageMut, ElementStorageRef, ElementsVector, + Heap, HeapIndexHandle, HeapMarkAndSweep, HeapSweepWeakReference, WorkQueues, + arena_vec_access, }, }; @@ -111,26 +112,6 @@ impl<'a> Array<'a> { elems.reserve(elements, elems.len().saturating_add(additional)) } - pub(crate) fn get<'agent>( - self, - agent: &'agent impl AsRef>>, - ) -> ArrayHeapDataRef<'agent, 'a> { - agent - .as_ref() - .get(self.0.get_index_u32()) - .expect("Invalid Array reference") - } - - pub(crate) fn get_mut<'agent>( - self, - agent: &'agent mut impl AsMut>>, - ) -> ArrayHeapDataMut<'agent, 'static> { - agent - .as_mut() - .get_mut(self.0.get_index_u32()) - .expect("Invalid Array reference") - } - pub(crate) fn get_elements( self, agent: &impl AsRef>>, diff --git a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/async_function_objects/await_reaction.rs b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/async_function_objects/await_reaction.rs index 7fef65f39..5bf9fc035 100644 --- a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/async_function_objects/await_reaction.rs +++ b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/async_function_objects/await_reaction.rs @@ -12,7 +12,7 @@ use crate::{ }, heap::{ ArenaAccess, ArenaAccessMut, CompactionLists, CreateHeapData, Heap, HeapMarkAndSweep, - WorkQueues, arena_vec_access, {BaseIndex, HeapIndexHandle, index_handle}, + WorkQueues, arena_vec_access, {BaseIndex, index_handle}, }, }; @@ -23,11 +23,6 @@ index_handle!(AwaitReaction); arena_vec_access!(AwaitReaction, 'a, AwaitReactionRecord, await_reactions); impl AwaitReaction<'_> { - pub(crate) fn last(scripts: &[AwaitReactionRecord]) -> Self { - let index = scripts.len() - 1; - Self::from_index(index) - } - pub(crate) fn resume( self, agent: &mut Agent, @@ -38,7 +33,8 @@ impl AwaitReaction<'_> { let reaction = self.bind(gc.nogc()); let value = value.bind(gc.nogc()); // [27.7.5.3 Await ( value )](https://tc39.es/ecma262/#await) - // 3. c. Push asyncContext onto the execution context stack; asyncContext is now the running execution context. + // 3. c. Push asyncContext onto the execution context stack; + // asyncContext is now the running execution context. let record = reaction.get_mut(agent); let execution_context = record.execution_context.take().unwrap(); let vm = record.vm.take().unwrap(); @@ -46,8 +42,12 @@ impl AwaitReaction<'_> { agent.push_execution_context(execution_context); let reaction = reaction.scope(agent, gc.nogc()); - // 3. d. Resume the suspended evaluation of asyncContext using NormalCompletion(v) as the result of the operation that suspended it. - // 5. d. Resume the suspended evaluation of asyncContext using ThrowCompletion(reason) as the result of the operation that suspended it. + // 3. d. Resume the suspended evaluation of asyncContext using + // NormalCompletion(v) as the result of the operation that + // suspended it. + // 5. d. Resume the suspended evaluation of asyncContext using + // ThrowCompletion(reason) as the result of the operation that + // suspended it. let execution_result = match reaction_type { PromiseReactionType::Fulfill => { let executable = async_function.get_executable(agent).scope(agent, gc.nogc()); @@ -63,8 +63,6 @@ impl AwaitReaction<'_> { } }; - // SAFETY: reaction is not shared. - let reaction = unsafe { reaction.take(agent) }.bind(gc.nogc()); match execution_result { ExecutionResult::Return(result) => { // SAFETY: reaction is not shared. @@ -189,7 +187,7 @@ impl<'a> CreateHeapData, AwaitReaction<'a>> for Heap { fn create(&mut self, data: AwaitReactionRecord<'a>) -> AwaitReaction<'a> { self.await_reactions.push(data.unbind()); self.alloc_counter += core::mem::size_of::>(); - AwaitReaction::last(&self.await_reactions) + AwaitReaction(BaseIndex::last(&self.await_reactions)) } } diff --git a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_finally_functions.rs b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_finally_functions.rs index e012df218..32cc55b47 100644 --- a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_finally_functions.rs +++ b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_finally_functions.rs @@ -9,8 +9,8 @@ use crate::{ }, engine::{Bindable, GcScope, Scopable, bindable_handle}, heap::{ - CompactionLists, CreateHeapData, Heap, HeapMarkAndSweep, HeapSweepWeakReference, - WorkQueues, arena_vec_access, {BaseIndex, HeapIndexHandle}, + ArenaAccess, ArenaAccessMut, BaseIndex, CompactionLists, CreateHeapData, Heap, + HeapMarkAndSweep, HeapSweepWeakReference, WorkQueues, arena_vec_access, }, }; @@ -69,22 +69,6 @@ impl<'f> BuiltinPromiseFinallyFunction<'f> { }); (then_finally_closure, catch_finally_closure) } - - fn get(self, agent: &Agent) -> &PromiseFinallyFunctionHeapData<'f> { - agent - .heap - .promise_finally_functions - .get(self.get_index()) - .expect("Promise.prototype.finally handler not found") - } - - fn get_mut(self, agent: &mut Agent) -> &mut PromiseFinallyFunctionHeapData<'static> { - agent - .heap - .promise_finally_functions - .get_mut(self.get_index()) - .expect("Promise.prototype.finally handler not found") - } } impl<'a> FunctionInternalProperties<'a> for BuiltinPromiseFinallyFunction<'a> { diff --git a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_group_record.rs b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_group_record.rs index 25287937d..9fc837fca 100644 --- a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_group_record.rs +++ b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_group_record.rs @@ -6,12 +6,12 @@ use crate::{ ecmascript::{ Agent, Array, BUILTIN_STRING_MEMORY, ErrorHeapData, ExceptionType, OrdinaryObject, Promise, PromiseCapability, PromiseReactionType, PropertyDescriptor, Value, - define_property_or_throw, + try_define_property_or_throw, unwrap_try, }, engine::{Bindable, GcScope, NoGcScope, bindable_handle}, heap::{ - CompactionLists, CreateHeapData, Heap, HeapMarkAndSweep, ObjectEntry, WorkQueues, - arena_vec_access, {BaseIndex, HeapIndexHandle, index_handle}, + ArenaAccess, ArenaAccessMut, BaseIndex, CompactionLists, CreateHeapData, Heap, + HeapMarkAndSweep, ObjectEntry, WorkQueues, arena_vec_access, index_handle, }, }; @@ -36,7 +36,7 @@ pub struct PromiseGroup<'a>(BaseIndex<'a, PromiseGroupRecord<'static>>); index_handle!(PromiseGroup); arena_vec_access!(PromiseGroup, 'a, PromiseGroupRecord, promise_group_records); -impl<'a> PromiseGroupRecord<'static> { +impl<'a> PromiseGroupRecord<'a> { fn take_result_and_promise(&mut self) -> (Array<'a>, Option>) { self.remaining_elements_count = self.remaining_elements_count.saturating_sub(1); @@ -57,56 +57,67 @@ impl<'a> PromiseGroup<'a> { value: Value<'a>, mut gc: GcScope<'a, '_>, ) { + let group = self.bind(gc.nogc()); let value = value.bind(gc.nogc()); - let record = self.get(agent); + let record = group.get(agent); match record.promise_group_type { PromiseGroupType::All => match reaction_type { PromiseReactionType::Fulfill => { - self.fulfill(agent, index, value.unbind(), gc.reborrow()); + group + .unbind() + .fulfill(agent, index, value.unbind(), gc.reborrow()); } PromiseReactionType::Reject => { - self.immediately_reject(agent, value.unbind(), gc.nogc()); + group + .unbind() + .immediately_reject(agent, value.unbind(), gc.nogc()); } }, PromiseGroupType::AllSettled => { - let obj = self - .to_all_settled_obj(agent, reaction_type, value.unbind(), gc.nogc()) - .bind(gc.nogc()); - self.fulfill(agent, index, obj.unbind(), gc.reborrow()); + let obj = PromiseGroup::to_all_settled_obj(agent, reaction_type, value, gc.nogc()); + group + .unbind() + .fulfill(agent, index, obj.unbind(), gc.reborrow()); } PromiseGroupType::Any => match reaction_type { PromiseReactionType::Fulfill => { - self.immediately_resolve(agent, value.unbind(), gc.reborrow()); + group + .unbind() + .immediately_resolve(agent, value.unbind(), gc.reborrow()); } PromiseReactionType::Reject => { - self.reject(agent, index, value.unbind(), gc.reborrow()); + group + .unbind() + .reject(agent, index, value.unbind(), gc.into_nogc()); } }, } } fn fulfill(self, agent: &mut Agent, index: u32, value: Value<'a>, mut gc: GcScope<'a, '_>) { - let promise_group = self.bind(gc.nogc()); + let group = self.bind(gc.nogc()); let value = value.bind(gc.nogc()); - let promise_group_record = promise_group.get_mut(agent); + let promise_group_record = group.get_mut(agent); let (result_array, promise_to_resolve) = promise_group_record.take_result_and_promise(); let elements = result_array.as_mut_slice(agent); elements[index as usize] = Some(value.unbind()); if let Some(promise_to_resolve) = promise_to_resolve { - promise_group.pop_empty_records(agent); + group.pop_empty_records(agent); let capability = PromiseCapability::from_promise(promise_to_resolve, true); - capability.resolve(agent, result_array.unbind().into(), gc.reborrow()); + capability + .unbind() + .resolve(agent, result_array.unbind().into(), gc.reborrow()); } } - fn reject(self, agent: &mut Agent, index: u32, error: Value<'a>, mut gc: GcScope<'a, '_>) { - let promise_group = self.bind(gc.nogc()); - let error = error.bind(gc.nogc()); + fn reject(self, agent: &mut Agent, index: u32, error: Value<'a>, gc: NoGcScope<'a, '_>) { + let promise_group = self.bind(gc); + let error = error.bind(gc); let promise_group_record = promise_group.get_mut(agent); let (result_array, promise_to_resolve) = promise_group_record.take_result_and_promise(); @@ -117,14 +128,17 @@ impl<'a> PromiseGroup<'a> { if let Some(promise_to_resolve) = promise_to_resolve { promise_group.pop_empty_records(agent); - let aggregate_error = agent.heap.create(ErrorHeapData::new( - ExceptionType::AggregateError, - None, - None, - )); + let aggregate_error = agent + .heap + .create(ErrorHeapData::new( + ExceptionType::AggregateError, + None, + None, + )) + .bind(gc); let capability = PromiseCapability::from_promise(promise_to_resolve, true); - define_property_or_throw( + unwrap_try(try_define_property_or_throw( agent, aggregate_error, BUILTIN_STRING_MEMORY.errors.into(), @@ -136,11 +150,11 @@ impl<'a> PromiseGroup<'a> { enumerable: Some(true), configurable: Some(true), }, - gc.reborrow(), - ) - .unwrap(); + None, + gc, + )); - capability.reject(agent, aggregate_error.into(), gc.nogc()); + capability.reject(agent, aggregate_error.into(), gc); } } @@ -152,7 +166,7 @@ impl<'a> PromiseGroup<'a> { let capability = PromiseCapability::from_promise(data.promise, true); promise_group.pop_empty_records(agent); - capability.resolve(agent, value.unbind(), gc); + capability.unbind().resolve(agent, value.unbind(), gc); } fn immediately_reject(self, agent: &mut Agent, value: Value<'a>, gc: NoGcScope<'a, '_>) { @@ -167,7 +181,6 @@ impl<'a> PromiseGroup<'a> { } fn to_all_settled_obj( - self, agent: &mut Agent, reaction_type: PromiseReactionType, value: Value<'a>, @@ -209,22 +222,6 @@ impl<'a> PromiseGroup<'a> { obj.unbind().into() } - pub(crate) fn get(self, agent: &Agent) -> &PromiseGroupRecord<'a> { - agent - .heap - .promise_group_records - .get(self.get_index()) - .expect("PromiseGroupRecord not found") - } - - pub(crate) fn get_mut(self, agent: &mut Agent) -> &mut PromiseGroupRecord<'static> { - agent - .heap - .promise_group_records - .get_mut(self.get_index()) - .expect("PromiseGroupRecord not found") - } - fn pop_empty_records(self, agent: &mut Agent) { while let Some(last) = agent.heap.promise_group_records.last() { if last.remaining_elements_count == 0 { diff --git a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_reaction_records.rs b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_reaction_records.rs index 0b78217e2..84e350e13 100644 --- a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_reaction_records.rs +++ b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_abstract_operations/promise_reaction_records.rs @@ -9,8 +9,8 @@ use crate::{ }, engine::{Bindable, bindable_handle}, heap::{ - CompactionLists, CreateHeapData, Heap, HeapMarkAndSweep, WorkQueues, arena_vec_access, - {BaseIndex, index_handle}, + BaseIndex, CompactionLists, CreateHeapData, Heap, HeapMarkAndSweep, WorkQueues, + arena_vec_access, index_handle, }, }; diff --git a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_constructor.rs b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_constructor.rs index 4e91f9093..cf5469684 100644 --- a/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_constructor.rs +++ b/nova_vm/src/ecmascript/builtins/control_abstraction_objects/promise_objects/promise_constructor.rs @@ -16,7 +16,10 @@ use crate::{ iterator_step_value, ordinary_create_from_constructor, }, engine::{Bindable, GcScope, NoGcScope, Scopable, Scoped, bindable_handle}, - heap::{CreateHeapData, IntrinsicConstructorIndexes, ObjectEntry, WellKnownSymbolIndexes}, + heap::{ + ArenaAccessMut, CreateHeapData, IntrinsicConstructorIndexes, ObjectEntry, + WellKnownSymbolIndexes, + }, }; pub(crate) struct PromiseConstructor; diff --git a/nova_vm/src/ecmascript/builtins/indexed_collections/array_objects/array_prototype.rs b/nova_vm/src/ecmascript/builtins/indexed_collections/array_objects/array_prototype.rs index 001d40888..aa62192b9 100644 --- a/nova_vm/src/ecmascript/builtins/indexed_collections/array_objects/array_prototype.rs +++ b/nova_vm/src/ecmascript/builtins/indexed_collections/array_objects/array_prototype.rs @@ -19,7 +19,9 @@ use crate::{ try_to_integer_or_infinity, try_to_string, unwrap_try, }, engine::{Bindable, GcScope, Rootable, Scopable, ScopableCollection, Scoped}, - heap::{Heap, HeapIndexHandle, IntrinsicFunctionIndexes, WellKnownSymbolIndexes}, + heap::{ + ArenaAccessSoAMut, Heap, HeapIndexHandle, IntrinsicFunctionIndexes, WellKnownSymbolIndexes, + }, }; pub(crate) struct ArrayPrototype; diff --git a/nova_vm/src/ecmascript/builtins/shared_array_buffer.rs b/nova_vm/src/ecmascript/builtins/shared_array_buffer.rs index 04ec0c827..1bae40de1 100644 --- a/nova_vm/src/ecmascript/builtins/shared_array_buffer.rs +++ b/nova_vm/src/ecmascript/builtins/shared_array_buffer.rs @@ -15,8 +15,8 @@ use crate::{ }, engine::{Bindable, NoGcScope}, heap::{ - CompactionLists, CreateHeapData, Heap, HeapMarkAndSweep, HeapSweepWeakReference, - WorkQueues, arena_vec_access, {BaseIndex, HeapIndexHandle}, + ArenaAccess, ArenaAccessMut, BaseIndex, CompactionLists, CreateHeapData, Heap, + HeapMarkAndSweep, HeapSweepWeakReference, WorkQueues, arena_vec_access, }, }; @@ -89,22 +89,6 @@ impl<'sab> SharedArrayBuffer<'sab> { .bind(gc) } - fn get(self, agent: &Agent) -> &SharedArrayBufferRecord<'sab> { - agent - .heap - .shared_array_buffers - .get(self.get_index()) - .expect("Invalid SharedArrayBuffer") - } - - fn get_mut(self, agent: &mut Agent) -> &mut SharedArrayBufferRecord<'static> { - agent - .heap - .shared_array_buffers - .get_mut(self.get_index()) - .expect("Invalid SharedArrayBuffer") - } - pub fn grow<'gc>( self, agent: &mut Agent, diff --git a/nova_vm/src/ecmascript/builtins/text_processing/regexp_objects/regexp_string_iterator_objects.rs b/nova_vm/src/ecmascript/builtins/text_processing/regexp_objects/regexp_string_iterator_objects.rs index 671d7d8ff..c53a1fd17 100644 --- a/nova_vm/src/ecmascript/builtins/text_processing/regexp_objects/regexp_string_iterator_objects.rs +++ b/nova_vm/src/ecmascript/builtins/text_processing/regexp_objects/regexp_string_iterator_objects.rs @@ -17,8 +17,8 @@ use crate::{ }, engine::{Bindable, NoGcScope, bindable_handle}, heap::{ - CompactionLists, CreateHeapData, Heap, HeapMarkAndSweep, HeapSweepWeakReference, - WorkQueues, arena_vec_access, {BaseIndex, HeapIndexHandle}, + ArenaAccess, ArenaAccessMut, BaseIndex, CompactionLists, CreateHeapData, Heap, + HeapMarkAndSweep, HeapSweepWeakReference, WorkQueues, arena_vec_access, }, }; @@ -95,22 +95,6 @@ impl<'r> RegExpStringIterator<'r> { pub(crate) fn set_done(self, agent: &mut Agent) { self.get_mut(agent).done = true; } - - fn get(self, agent: &Agent) -> &RegExpStringIteratorRecord<'r> { - agent - .heap - .regexp_string_iterators - .get(self.get_index()) - .expect("Couldn't find RegExp String Iterator") - } - - fn get_mut(self, agent: &mut Agent) -> &mut RegExpStringIteratorRecord<'static> { - agent - .heap - .regexp_string_iterators - .get_mut(self.get_index()) - .expect("Couldn't find RegExp String Iterator") - } } impl<'a> InternalSlots<'a> for RegExpStringIterator<'a> { diff --git a/nova_vm/src/ecmascript/execution/agent.rs b/nova_vm/src/ecmascript/execution/agent.rs index 1159186e5..336adfa19 100644 --- a/nova_vm/src/ecmascript/execution/agent.rs +++ b/nova_vm/src/ecmascript/execution/agent.rs @@ -1561,7 +1561,7 @@ impl HeapMarkAndSweep for Agent { if let Some(last_filled_global_value) = last_filled_global_value { heap.globals .borrow_mut() - .drain(last_filled_global_value + 1..); + .truncate(last_filled_global_value + 1); } } diff --git a/nova_vm/src/ecmascript/execution/realm.rs b/nova_vm/src/ecmascript/execution/realm.rs index c90b0a7f6..6e28a374d 100644 --- a/nova_vm/src/ecmascript/execution/realm.rs +++ b/nova_vm/src/ecmascript/execution/realm.rs @@ -16,8 +16,8 @@ use crate::{ }, engine::{Bindable, GcScope, NoGcScope, Scopable, bindable_handle}, heap::{ - ArenaAccess, ArenaAccessMut, CompactionLists, HeapMarkAndSweep, WorkQueues, - arena_vec_access, {BaseIndex, HeapIndexHandle, index_handle}, + ArenaAccess, ArenaAccessMut, BaseIndex, CompactionLists, CreateHeapData, Heap, + HeapIndexHandle, HeapMarkAndSweep, WorkQueues, arena_vec_access, index_handle, }, }; use core::marker::PhantomData; @@ -35,11 +35,6 @@ impl core::fmt::Debug for Realm<'_> { } impl<'r> Realm<'r> { - pub(crate) fn last(realms: &[RealmRecord]) -> Self { - let index = realms.len() - 1; - Self::from_index(index) - } - /// ### \[\[\HostDefined]] pub fn host_defined(self, agent: &Agent) -> Option { self.get(agent).host_defined.clone() @@ -95,6 +90,14 @@ impl HeapMarkAndSweep for Realm<'static> { } } +impl<'a> CreateHeapData, Realm<'a>> for Heap { + fn create(&mut self, data: RealmRecord<'a>) -> Realm<'a> { + self.realms.push(data.unbind()); + self.alloc_counter += core::mem::size_of::>(); + Realm(BaseIndex::last(&self.realms)) + } +} + /// ## [9.3 Realms](https://tc39.es/ecma262/#sec-code-realms) /// /// Before it is evaluated, all ECMAScript code must be associated with a @@ -220,7 +223,7 @@ pub(crate) fn create_realm<'gc>(agent: &mut Agent, gc: NoGcScope<'gc, '_>) -> Re }; // 7. Return realmRec. - let realm = agent.heap.add_realm(realm_rec, gc); + let realm = agent.heap.create(realm_rec).bind(gc); Intrinsics::create_intrinsics(agent, realm.unbind(), gc); realm } diff --git a/nova_vm/src/ecmascript/scripts_and_modules/script.rs b/nova_vm/src/ecmascript/scripts_and_modules/script.rs index 842620f0c..31e0375fd 100644 --- a/nova_vm/src/ecmascript/scripts_and_modules/script.rs +++ b/nova_vm/src/ecmascript/scripts_and_modules/script.rs @@ -15,8 +15,8 @@ use crate::{ }, engine::{Bindable, Executable, GcScope, NoGcScope, Scopable, Vm, bindable_handle}, heap::{ - ArenaAccess, ArenaAccessMut, CompactionLists, HeapMarkAndSweep, WorkQueues, - arena_vec_access, {BaseIndex, HeapIndexHandle, index_handle}, + ArenaAccess, ArenaAccessMut, BaseIndex, CompactionLists, CreateHeapData, Heap, + HeapIndexHandle, HeapMarkAndSweep, WorkQueues, arena_vec_access, index_handle, }, ndt, }; @@ -69,10 +69,6 @@ impl Script<'_> { self.get(agent).source_code.bind(gc) } - pub(crate) fn last(scripts: &[ScriptRecord]) -> Self { - Self::from_index(scripts.len() - 1) - } - /// ### \[\[Realm]] pub(crate) fn realm<'a>(self, agent: &Agent, gc: NoGcScope<'a, '_>) -> Realm<'a> { self.get(agent).realm.bind(gc) @@ -106,6 +102,14 @@ impl HeapMarkAndSweep for Script<'static> { } } +impl<'a> CreateHeapData, Script<'a>> for Heap { + fn create(&mut self, data: ScriptRecord<'a>) -> Script<'a> { + self.scripts.push(data.unbind()); + self.alloc_counter += core::mem::size_of::>(); + Script(BaseIndex::last(&self.scripts)) + } +} + /// ### [16.1.4 Script Records](https://tc39.es/ecma262/#sec-script-records) /// /// A Script Record encapsulates information about a script being evaluated. @@ -255,8 +259,7 @@ pub fn parse_script<'a>( source_code: source_code.unbind(), }; // } - let script = agent.heap.add_script(script_record, gc); - Ok(script) + Ok(agent.heap.create(script_record).bind(gc)) } /// ### [16.1.6 ScriptEvaluation ( scriptRecord )](https://tc39.es/ecma262/#sec-runtime-semantics-scriptevaluation) diff --git a/nova_vm/src/ecmascript/types/language/number.rs b/nova_vm/src/ecmascript/types/language/number.rs index e0badd2aa..354f16f64 100644 --- a/nova_vm/src/ecmascript/types/language/number.rs +++ b/nova_vm/src/ecmascript/types/language/number.rs @@ -1517,28 +1517,6 @@ impl_value_from_n!(i16); impl_value_from_n!(u32); impl_value_from_n!(i32); -// impl<'n> HeapAccess for Number<'n> { -// type OutputRef<'a> -// = &'a f64 -// where -// Self: 'a, -// Agent: 'a; - -// type OutputMut<'a> -// = &'a mut f64 -// where -// Self: 'a, -// Agent: 'a; - -// fn get<'a>(self, source: &'a Agent) -> Self::OutputRef<'a> { -// todo!() -// } - -// fn get_mut<'a>(self, source: &'a mut Agent) -> Self::OutputMut<'a> { -// todo!() -// } -// } - impl<'a> CreateHeapData> for Heap { fn create(&mut self, data: f64) -> Number<'a> { // NOTE: This function cannot currently be implemented diff --git a/nova_vm/src/heap.rs b/nova_vm/src/heap.rs index d56114a25..b019de58a 100644 --- a/nova_vm/src/heap.rs +++ b/nova_vm/src/heap.rs @@ -47,11 +47,11 @@ use crate::{ ModuleRequestRecord, NumberHeapData, ObjectRecord, ObjectShapeRecord, ObjectShapeTransitionMap, PrimitiveObjectRecord, PromiseFinallyFunctionHeapData, PromiseGroupRecord, PromiseHeapData, PromiseReactionRecord, - PromiseResolvingFunctionHeapData, PrototypeShapeTable, ProxyHeapData, Realm, RealmRecord, - Script, ScriptRecord, SourceCodeHeapData, SourceTextModuleHeap, String, - StringIteratorHeapData, StringRecord, SymbolHeapData, + PromiseResolvingFunctionHeapData, PrototypeShapeTable, ProxyHeapData, RealmRecord, + ScriptRecord, SourceCodeHeapData, SourceTextModuleHeap, String, StringIteratorHeapData, + StringRecord, SymbolHeapData, }, - engine::{Bindable, ExecutableHeapData, HeapRootData, NoGcScope}, + engine::{ExecutableHeapData, HeapRootData}, }; #[cfg(feature = "array-buffer")] use ahash::AHashMap; @@ -391,22 +391,6 @@ impl Heap { heap } - pub(crate) fn add_realm<'a>(&mut self, realm: RealmRecord, _: NoGcScope<'a, '_>) -> Realm<'a> { - self.realms.push(realm.unbind()); - self.alloc_counter += core::mem::size_of::>(); - Realm::last(&self.realms) - } - - pub(crate) fn add_script<'a>( - &mut self, - script: ScriptRecord, - _: NoGcScope<'a, '_>, - ) -> Script<'a> { - self.scripts.push(script.unbind()); - self.alloc_counter += core::mem::size_of::>(); - Script::last(&self.scripts) - } - /// Allocate a borrowed string onto the Agent heap /// /// This method will hash the input and look for a matching string on the