Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions core/engine/src/object/builtins/jsdataview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
use crate::{
Context, JsExpect, JsNativeError, JsResult, JsValue,
builtins::{DataView, array_buffer::BufferObject},
error::PanicError,
object::{JsArrayBuffer, JsObject},
value::TryFromJs,
};
Expand Down Expand Up @@ -60,7 +61,9 @@ impl JsDataView {
let offset = offset.unwrap_or_default();

let (buf_byte_len, is_fixed_len) = {
let buffer = buffer.borrow();
let buffer = buffer
.try_borrow()
.map_err(|e| PanicError::new(e.to_string()))?;
let buffer = buffer.data();

// 4. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
Expand Down Expand Up @@ -110,7 +113,13 @@ impl JsDataView {

// 11. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
// 12. Set bufferByteLength to ArrayBufferByteLength(buffer, seq-cst).
let Some(buf_byte_len) = buffer.borrow().data().bytes().map(|s| s.len() as u64) else {
let Some(buf_byte_len) = buffer
.try_borrow()
.map_err(|e| PanicError::new(e.to_string()))?
.data()
.bytes()
.map(|s| s.len() as u64)
else {
return Err(JsNativeError::typ()
.with_message("ArrayBuffer is detached")
.into());
Expand Down
35 changes: 29 additions & 6 deletions core/engine/src/object/internal_methods/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use super::{
use crate::{
Context, JsNativeError, JsResult,
context::intrinsics::{StandardConstructor, StandardConstructors},
error::PanicError,
object::JsObject,
property::{DescriptorKind, PropertyDescriptor, PropertyKey},
value::JsValue,
Expand Down Expand Up @@ -588,7 +589,10 @@ pub(crate) fn ordinary_set_prototype_of(
#[allow(clippy::unnecessary_wraps)]
pub(crate) fn ordinary_is_extensible(obj: &JsObject, _context: &mut Context) -> JsResult<bool> {
// 1. Return O.[[Extensible]].
Ok(obj.borrow().extensible)
Ok(obj
.try_borrow()
.map_err(|e| PanicError::new(e.to_string()))?
.extensible)
}

/// Abstract operation `OrdinaryPreventExtensions`.
Expand All @@ -603,7 +607,9 @@ pub(crate) fn ordinary_prevent_extensions(
_context: &mut Context,
) -> JsResult<bool> {
// 1. Set O.[[Extensible]] to false.
obj.borrow_mut().extensible = false;
obj.try_borrow_mut()
.map_err(|e| PanicError::new(e.to_string()))?
.extensible = false;

// 2. Return true.
Ok(true)
Expand Down Expand Up @@ -635,7 +641,11 @@ pub(crate) fn ordinary_get_own_property(
// 7. Set D.[[Enumerable]] to the value of X's [[Enumerable]] attribute.
// 8. Set D.[[Configurable]] to the value of X's [[Configurable]] attribute.
// 9. Return D.
Ok(obj.borrow().properties.get_with_slot(key, context.slot()))
Ok(obj
.try_borrow()
.map_err(|e| PanicError::new(e.to_string()))?
.properties
.get_with_slot(key, context.slot()))
}

/// Abstract operation `OrdinaryDefineOwnProperty`.
Expand Down Expand Up @@ -945,7 +955,9 @@ pub(crate) fn ordinary_delete(
// 4. If desc.[[Configurable]] is true, then
Some(desc) if desc.expect_configurable() => {
// a. Remove the own property with name P from O.
obj.borrow_mut().remove(key);
obj.try_borrow_mut()
.map_err(|e| PanicError::new(e.to_string()))?
.remove(key);
// b. Return true.
true
}
Expand All @@ -972,7 +984,12 @@ pub(crate) fn ordinary_own_property_keys(
let mut keys = Vec::new();

let ordered_indexes = {
let mut indexes: Vec<_> = obj.borrow().properties.index_property_keys().collect();
let mut indexes: Vec<_> = obj
.try_borrow()
.map_err(|e| PanicError::new(e.to_string()))?
.properties
.index_property_keys()
.collect();
indexes.sort_unstable();
indexes
};
Expand All @@ -986,7 +1003,13 @@ pub(crate) fn ordinary_own_property_keys(
//
// 4. For each own property key P of O such that Type(P) is Symbol, in ascending chronological order of property creation, do
// a. Add P as the last element of keys.
keys.extend(obj.borrow().properties.shape.keys());
keys.extend(
obj.try_borrow()
.map_err(|e| PanicError::new(e.to_string()))?
.properties
.shape
.keys(),
);

// 5. Return keys.
Ok(keys)
Expand Down
39 changes: 28 additions & 11 deletions core/engine/src/object/internal_methods/string.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::{
Context, JsExpect, JsResult, JsString,
error::PanicError,
object::{JsData, JsObject},
property::{PropertyDescriptor, PropertyKey},
};
Expand Down Expand Up @@ -39,7 +40,7 @@ pub(crate) fn string_exotic_get_own_property(
Ok(desc)
} else {
// 4. Return ! StringGetOwnProperty(S, P).
Ok(string_get_own_property(obj, key))
string_get_own_property(obj, key)
}
}

Expand All @@ -57,12 +58,15 @@ pub(crate) fn string_exotic_define_own_property(
) -> JsResult<bool> {
// 1. Assert: IsPropertyKey(P) is true.
// 2. Let stringDesc be ! StringGetOwnProperty(S, P).
let string_desc = string_get_own_property(obj, key);
let string_desc = string_get_own_property(obj, key)?;

// 3. If stringDesc is not undefined, then
if let Some(string_desc) = string_desc {
// a. Let extensible be S.[[Extensible]].
let extensible = obj.borrow().extensible;
let extensible = obj
.try_borrow()
.map_err(|e| PanicError::new(e.to_string()))?
.extensible;
// b. Return ! IsCompatiblePropertyDescriptor(extensible, Desc, stringDesc).
Ok(super::is_compatible_property_descriptor(
extensible,
Expand Down Expand Up @@ -106,7 +110,8 @@ pub(crate) fn string_exotic_own_property_keys(
// and ! ToIntegerOrInfinity(P) ≥ len, in ascending numeric index order, do
// a. Add P as the last element of keys.
let mut remaining_indices: Vec<_> = obj
.borrow()
.try_borrow()
.map_err(|e| PanicError::new(e.to_string()))?
.properties
.index_property_keys()
.filter(|idx| (*idx as usize) >= len)
Expand All @@ -121,7 +126,13 @@ pub(crate) fn string_exotic_own_property_keys(
// 8. For each own property key P of O such that Type(P) is Symbol, in ascending
// chronological order of property creation, do
// a. Add P as the last element of keys.
keys.extend(obj.borrow().properties.shape.keys());
keys.extend(
obj.try_borrow()
.map_err(|e| PanicError::new(e.to_string()))?
.properties
.shape
.keys(),
);

// 9. Return keys.
Ok(keys)
Expand All @@ -133,7 +144,10 @@ pub(crate) fn string_exotic_own_property_keys(
/// - [ECMAScript reference][spec]
///
/// [spec]: https://tc39.es/ecma262/#sec-stringgetownproperty
fn string_get_own_property(obj: &JsObject, key: &PropertyKey) -> Option<PropertyDescriptor> {
fn string_get_own_property(
obj: &JsObject,
key: &PropertyKey,
) -> JsResult<Option<PropertyDescriptor>> {
// 1. Assert: S is an Object that has a [[StringData]] internal slot.
// 2. Assert: IsPropertyKey(P) is true.
// 3. If Type(P) is not String, return undefined.
Expand All @@ -143,20 +157,23 @@ fn string_get_own_property(obj: &JsObject, key: &PropertyKey) -> Option<Property
// 7. If index is -0𝔽, return undefined.
let pos = match key {
PropertyKey::Index(index) => index.get() as usize,
_ => return None,
_ => return Ok(None),
};

// 8. Let str be S.[[StringData]].
// 9. Assert: Type(str) is String.
let string = obj
.downcast_ref::<JsString>()
.expect("string exotic method should only be callable from string objects")
.js_expect("string exotic method should only be callable from string objects")?
.clone();

// 10. Let len be the length of str.
// 11. If ℝ(index) < 0 or len ≤ ℝ(index), return undefined.
// 12. Let resultStr be the String value of length 1, containing one code unit from str, specifically the code unit at index ℝ(index).
let result_str = string.get(pos..=pos)?;
// 12. Let resultStr be the String value of length 1, containing one code unit from str,
// specifically the code unit at index ℝ(index).
let Some(result_str) = string.get(pos..=pos) else {
return Ok(None);
};

// 13. Return the PropertyDescriptor { [[Value]]: resultStr, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }.
let desc = PropertyDescriptor::builder()
Expand All @@ -166,5 +183,5 @@ fn string_get_own_property(obj: &JsObject, key: &PropertyKey) -> Option<Property
.configurable(false)
.build();

Some(desc)
Ok(Some(desc))
}
22 changes: 15 additions & 7 deletions core/engine/src/object/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::{
function::{BoundFunction, ClassFieldDefinition, OrdinaryFunction, set_function_name},
},
context::intrinsics::{StandardConstructor, StandardConstructors},
error::JsNativeError,
error::{JsNativeError, PanicError},
native_function::NativeFunctionObject,
object::{CONSTRUCTOR, JsObject, PROTOTYPE, PrivateElement, PrivateName},
property::{PropertyDescriptor, PropertyDescriptorBuilder, PropertyKey, PropertyNameKind},
Expand Down Expand Up @@ -656,7 +656,9 @@ impl JsObject {
// NOTE: This is an optimization, most of the cases that `LengthOfArrayLike` will be called
// is for arrays. The "length" property of an array is stored in the first index.
if self.is_array() {
let borrowed_object = self.borrow();
let borrowed_object = self
.try_borrow()
.map_err(|e| PanicError::new(e.to_string()))?;
// NOTE: using `to_u32` instead of `to_length` is an optimization,
// since arrays are limited to [0, 2^32 - 1] range.
return borrowed_object.properties().storage[0]
Expand Down Expand Up @@ -906,7 +908,7 @@ impl JsObject {
// 4. Let from be ! ToObject(source).
let from = source
.to_object(context)
.expect("function ToObject should never complete abruptly here");
.js_expect("function ToObject should never complete abruptly here")?;

// 5. Let keys be ? from.[[OwnPropertyKeys]]().
// 6. For each element nextKey of keys, do
Expand Down Expand Up @@ -939,7 +941,9 @@ impl JsObject {

// 2. Perform ! CreateDataPropertyOrThrow(target, nextKey, propValue).
self.create_data_property_or_throw(key, prop_value, context)
.expect("CreateDataPropertyOrThrow should never complete abruptly here");
.js_expect(
"CreateDataPropertyOrThrow should never complete abruptly here",
)?;
}
}
}
Expand Down Expand Up @@ -1019,7 +1023,8 @@ impl JsObject {
}

// 5. Append PrivateElement { [[Key]]: P, [[Kind]]: field, [[Value]]: value } to O.[[PrivateElements]].
self.borrow_mut()
self.try_borrow_mut()
.map_err(|e| PanicError::new(e.to_string()))?
.private_elements
.push((name.clone(), PrivateElement::Field(value)));

Expand Down Expand Up @@ -1090,7 +1095,8 @@ impl JsObject {
}

// 5. Append method to O.[[PrivateElements]].
self.borrow_mut()
self.try_borrow_mut()
.map_err(|e| PanicError::new(e.to_string()))?
.append_private_element(name.clone(), method.clone());

// 6. Return unused.
Expand Down Expand Up @@ -1155,7 +1161,9 @@ impl JsObject {
) -> JsResult<()> {
// 1. Let entry be PrivateElementFind(O, P).
// Note: This function is inlined here for mutable access.
let mut object_mut = self.borrow_mut();
let mut object_mut = self
.try_borrow_mut()
.map_err(|e| PanicError::new(e.to_string()))?;
let entry = object_mut
.private_elements
.iter_mut()
Expand Down
Loading