Skip to content

Commit 79b29f3

Browse files
authored
feat(ecmascript): Fine-tune (Weak)Map/Set internal methods (#175)
* feat(ecmascript): Fine-tune (Weak)Map/Set internal methods * fix(heap): Fix heap test expecting to find non-empty elements when creating empty objects
1 parent dfed3a5 commit 79b29f3

21 files changed

Lines changed: 305 additions & 131 deletions

nova_vm/src/ecmascript/builtins/array.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ impl InternalMethods for Array {
172172
return Ok(true);
173173
} else {
174174
// TODO: Proper handling
175-
Some(agent.heap.create_object_with_prototype(v, vec![]))
175+
Some(agent.heap.create_object_with_prototype(v, &[]))
176176
}
177177
} else {
178178
Some(agent.heap.create_null_object(Default::default()))

nova_vm/src/ecmascript/builtins/array/abstract_operations.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub fn array_create(
4343
{
4444
None
4545
} else {
46-
Some(agent.heap.create_object_with_prototype(proto, vec![]))
46+
Some(agent.heap.create_object_with_prototype(proto, &[]))
4747
}
4848
} else {
4949
None

nova_vm/src/ecmascript/builtins/array_buffer.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ fn create_array_buffer_base_object(agent: &mut Agent, array_buffer: ArrayBuffer)
5656
let prototype = agent.current_realm().intrinsics().array_buffer_prototype();
5757
let object_index = agent
5858
.heap
59-
.create_object_with_prototype(prototype.into(), vec![]);
59+
.create_object_with_prototype(prototype.into(), &[]);
6060
agent.heap.get_mut(*array_buffer).object_index = Some(object_index);
6161
OrdinaryObject::from(object_index)
6262
}
@@ -104,9 +104,9 @@ impl OrdinaryObjectInternalSlots for ArrayBuffer {
104104
prototype,
105105
Some(self.into())
106106
));
107-
agent.heap.create_object_with_prototype(prototype, vec![])
107+
agent.heap.create_object_with_prototype(prototype, &[])
108108
} else {
109-
agent.heap.create_null_object(vec![])
109+
agent.heap.create_null_object(&[])
110110
};
111111
agent.heap.get_mut(*self).object_index = Some(object_index);
112112
}

nova_vm/src/ecmascript/builtins/builtin_function.rs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -290,10 +290,9 @@ impl InternalMethods for BuiltinFunction {
290290
configurable: true,
291291
},
292292
};
293-
let object_index = agent.heap.create_object_with_prototype(
294-
prototype.into_object(),
295-
vec![length_entry, name_entry],
296-
);
293+
let object_index = agent
294+
.heap
295+
.create_object_with_prototype(prototype.into_object(), &[length_entry, name_entry]);
297296
agent.heap.get_mut(self.0).object_index = Some(object_index);
298297
Ok(true)
299298
} else if property_key == PropertyKey::from(BUILTIN_STRING_MEMORY.name) {
@@ -311,10 +310,9 @@ impl InternalMethods for BuiltinFunction {
311310
key: property_key,
312311
value: ObjectEntryPropertyDescriptor::from(property_descriptor),
313312
};
314-
let object_index = agent.heap.create_object_with_prototype(
315-
prototype.into_object(),
316-
vec![length_entry, name_entry],
317-
);
313+
let object_index = agent
314+
.heap
315+
.create_object_with_prototype(prototype.into_object(), &[length_entry, name_entry]);
318316
agent.heap.get_mut(self.0).object_index = Some(object_index);
319317
Ok(true)
320318
} else {
@@ -343,7 +341,7 @@ impl InternalMethods for BuiltinFunction {
343341
};
344342
let object_index = agent.heap.create_object_with_prototype(
345343
prototype.into_object(),
346-
vec![length_entry, name_entry, other_entry],
344+
&[length_entry, name_entry, other_entry],
347345
);
348346
agent.heap.get_mut(self.0).object_index = Some(object_index);
349347
Ok(true)
@@ -435,7 +433,7 @@ impl InternalMethods for BuiltinFunction {
435433
};
436434
let object_index = agent
437435
.heap
438-
.create_object_with_prototype(prototype.into_object(), vec![entry]);
436+
.create_object_with_prototype(prototype.into_object(), &[entry]);
439437
agent.heap.get_mut(self.0).object_index = Some(object_index);
440438
Ok(true)
441439
} else {
@@ -645,7 +643,7 @@ pub fn create_builtin_function(
645643
Some(
646644
agent
647645
.heap
648-
.create_object_with_prototype(prototype, vec![length_entry, name_entry]),
646+
.create_object_with_prototype(prototype, &[length_entry, name_entry]),
649647
)
650648
}
651649
} else {

nova_vm/src/ecmascript/builtins/data_view.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ impl InternalMethods for DataView {
158158
};
159159
let object_index = agent
160160
.heap
161-
.create_object_with_prototype(prototype.into_object(), vec![new_entry]);
161+
.create_object_with_prototype(prototype.into_object(), &[new_entry]);
162162
agent.heap.get_mut(self.0).object_index = Some(object_index);
163163
Ok(true)
164164
}

nova_vm/src/ecmascript/builtins/ecmascript_function.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ pub(crate) fn ordinary_function_create<'agent, 'program>(
549549
function.object_index = Some(
550550
agent
551551
.heap
552-
.create_object_with_prototype(function_prototype, vec![]),
552+
.create_object_with_prototype(function_prototype, &[]),
553553
);
554554
}
555555
}

nova_vm/src/ecmascript/builtins/finalization_registry.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ impl InternalMethods for FinalizationRegistry {
166166
};
167167
let object_index = agent
168168
.heap
169-
.create_object_with_prototype(prototype.into_object(), vec![new_entry]);
169+
.create_object_with_prototype(prototype.into_object(), &[new_entry]);
170170
agent.heap.get_mut(self.0).object_index = Some(object_index);
171171
Ok(true)
172172
}

nova_vm/src/ecmascript/builtins/fundamental_objects/object_objects/object_constructor.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,9 +288,9 @@ impl ObjectConstructor {
288288
fn create(agent: &mut Agent, _this_value: Value, arguments: ArgumentsList) -> JsResult<Value> {
289289
let o = arguments.get(0);
290290
let obj: OrdinaryObject = if o == Value::Null {
291-
agent.heap.create_null_object(vec![]).into()
291+
agent.heap.create_null_object(&[]).into()
292292
} else if let Ok(o) = Object::try_from(o) {
293-
agent.heap.create_object_with_prototype(o, vec![]).into()
293+
agent.heap.create_object_with_prototype(o, &[]).into()
294294
} else {
295295
return Err(agent.throw_exception(ExceptionType::TypeError, "fail"));
296296
};

nova_vm/src/ecmascript/builtins/map.rs

Lines changed: 52 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::ops::{Index, IndexMut};
2+
13
use crate::{
24
ecmascript::{
35
execution::{Agent, JsResult},
@@ -7,8 +9,11 @@ use crate::{
79
},
810
},
911
heap::{indexes::MapIndex, GetHeapData, ObjectEntry, ObjectEntryPropertyDescriptor},
12+
Heap,
1013
};
1114

15+
use self::data::MapHeapData;
16+
1217
use super::ordinary::ordinary_set_prototype_of_check_loop;
1318

1419
pub mod data;
@@ -52,6 +57,42 @@ impl From<Map> for Object {
5257
}
5358
}
5459

60+
impl Index<Map> for Heap {
61+
type Output = MapHeapData;
62+
63+
fn index(&self, index: Map) -> &Self::Output {
64+
self.maps
65+
.get(index.0.into_index())
66+
.expect("Map out of bounds")
67+
.as_ref()
68+
.expect("Map slot empty")
69+
}
70+
}
71+
72+
impl IndexMut<Map> for Heap {
73+
fn index_mut(&mut self, index: Map) -> &mut Self::Output {
74+
self.maps
75+
.get_mut(index.0.into_index())
76+
.expect("Map out of bounds")
77+
.as_mut()
78+
.expect("Map slot empty")
79+
}
80+
}
81+
82+
fn create_map_base_object(agent: &mut Agent, map: Map, entries: &[ObjectEntry]) -> OrdinaryObject {
83+
// TODO: An issue crops up if multiple realms are in play:
84+
// The prototype should not be dependent on the realm we're operating in
85+
// but should instead be bound to the realm the object was created in.
86+
// We'll have to cross this bridge at a later point, likely be designating
87+
// a "default realm" and making non-default realms always initialize ObjectHeapData.
88+
let prototype = agent.current_realm().intrinsics().map_prototype();
89+
let object_index = agent
90+
.heap
91+
.create_object_with_prototype(prototype.into(), entries);
92+
agent.heap[map].object_index = Some(object_index);
93+
OrdinaryObject::from(object_index)
94+
}
95+
5596
impl OrdinaryObjectInternalSlots for Map {
5697
fn internal_extensible(self, agent: &Agent) -> bool {
5798
if let Some(object_index) = agent.heap.get(self.0).object_index {
@@ -64,9 +105,10 @@ impl OrdinaryObjectInternalSlots for Map {
64105
fn internal_set_extensible(self, agent: &mut Agent, value: bool) {
65106
if let Some(object_index) = agent.heap.get(self.0).object_index {
66107
OrdinaryObject::from(object_index).internal_set_extensible(agent, value)
67-
} else {
108+
} else if !value {
68109
// Create base object and set inextensible
69-
todo!()
110+
let base = create_map_base_object(agent, self, &[]);
111+
base.internal_set_extensible(agent, value);
70112
}
71113
}
72114

@@ -88,8 +130,9 @@ impl OrdinaryObjectInternalSlots for Map {
88130
if let Some(object_index) = agent.heap.get(self.0).object_index {
89131
OrdinaryObject::from(object_index).internal_set_prototype(agent, prototype)
90132
} else {
91-
// Create base object and set inextensible
92-
todo!()
133+
// Create base object and set prototype
134+
let base = create_map_base_object(agent, self, &[]);
135+
base.internal_set_prototype(agent, prototype);
93136
}
94137
}
95138
}
@@ -151,15 +194,11 @@ impl InternalMethods for Map {
151194
if let Some(object_index) = agent.heap.get(self.0).object_index {
152195
OrdinaryObject::from(object_index).internal_has_property(agent, property_key)
153196
} else {
154-
let prototype = agent.current_realm().intrinsics().map_prototype();
155197
let new_entry = ObjectEntry {
156198
key: property_key,
157199
value: ObjectEntryPropertyDescriptor::from(property_descriptor),
158200
};
159-
let object_index = agent
160-
.heap
161-
.create_object_with_prototype(prototype.into_object(), vec![new_entry]);
162-
agent.heap.get_mut(self.0).object_index = Some(object_index);
201+
create_map_base_object(agent, self, &[new_entry]);
163202
Ok(true)
164203
}
165204
}
@@ -168,10 +207,8 @@ impl InternalMethods for Map {
168207
if let Some(object_index) = agent.heap.get(self.0).object_index {
169208
OrdinaryObject::from(object_index).internal_has_property(agent, property_key)
170209
} else {
171-
let parent = self.internal_get_prototype_of(agent)?;
172-
parent.map_or(Ok(false), |parent| {
173-
parent.internal_has_property(agent, property_key)
174-
})
210+
let parent = agent.current_realm().intrinsics().map_prototype();
211+
parent.internal_has_property(agent, property_key)
175212
}
176213
}
177214

@@ -184,10 +221,8 @@ impl InternalMethods for Map {
184221
if let Some(object_index) = agent.heap.get(self.0).object_index {
185222
OrdinaryObject::from(object_index).internal_get(agent, property_key, receiver)
186223
} else {
187-
let parent = self.internal_get_prototype_of(agent)?;
188-
parent.map_or(Ok(Value::Undefined), |parent| {
189-
parent.internal_get(agent, property_key, receiver)
190-
})
224+
let parent = agent.current_realm().intrinsics().map_prototype();
225+
parent.internal_get(agent, property_key, receiver)
191226
}
192227
}
193228

nova_vm/src/ecmascript/builtins/ordinary.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ pub(crate) fn ordinary_object_create_with_intrinsics(
786786
prototype: Option<ProtoIntrinsics>,
787787
) -> Object {
788788
let Some(prototype) = prototype else {
789-
return agent.heap.create_null_object(vec![]).into();
789+
return agent.heap.create_null_object(&[]).into();
790790
};
791791

792792
match prototype {
@@ -819,7 +819,7 @@ pub(crate) fn ordinary_object_create_with_intrinsics(
819819
.intrinsics()
820820
.object_prototype()
821821
.into_object(),
822-
vec![],
822+
&[],
823823
)
824824
.into(),
825825
ProtoIntrinsics::RangeError => agent

0 commit comments

Comments
 (0)