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 eff12382e..625e92370 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 @@ -2088,8 +2088,77 @@ impl ArrayPrototype { Ok(accumulator) } - fn reverse(_agent: &mut Agent, _this_value: Value, _: ArgumentsList) -> JsResult { - todo!() + fn reverse(agent: &mut Agent, this_value: Value, _: ArgumentsList) -> JsResult { + if let Value::Array(array) = this_value { + // Fast path: Array is dense and contains no descriptors. No JS + // functions can thus be called by shift. + if array.is_trivial(agent) && array.is_dense(agent) { + array.as_mut_slice(agent).reverse(); + return Ok(array.into_value()); + } + } + + // 1. Let O be ? ToObject(this value). + let o = to_object(agent, this_value)?; + // 2. Let len be ? LengthOfArrayLike(O). + let len = length_of_array_like(agent, o)?; + // 3. Let middle be floor(len / 2). + let middle = len / 2; + // 4. Let lower be 0. + let mut lower: i64 = 0; + // 5. Repeat, while lower ≠ middle, + while lower != middle { + // a. Let upper be len - lower - 1. + let upper = len - lower - 1; + // b. Let upperP be ! ToString(𝔽(upper)). + let upper_p = PropertyKey::Integer(upper.try_into().unwrap()); + // c. Let lowerP be ! ToString(𝔽(lower)). + let lower_p = PropertyKey::Integer(lower.try_into().unwrap()); + // d. Let lowerExists be ? HasProperty(O, lowerP). + // e. If lowerExists is true, then + // i. Let lowerValue be ? Get(O, lowerP). + let lower_exists = has_property(agent, o, lower_p)?; + // f. Let upperExists be ? HasProperty(O, upperP). + // g. If upperExists is true, then + // i. Let upperValue be ? Get(O, upperP). + let upper_exists = has_property(agent, o, upper_p)?; + + // h. If lowerExists is true and upperExists is true, then + if lower_exists && upper_exists { + // i. Perform ? Set(O, lowerP, upperValue, true). + // ii. Perform ? Set(O, upperP, lowerValue, true). + let lower_value = get(agent, o, lower_p)?; + let upper_value = get(agent, o, upper_p)?; + set(agent, o, lower_p, upper_value, true)?; + set(agent, o, upper_p, lower_value, true)?; + } + // i. Else if lowerExists is false and upperExists is true, then + else if !lower_exists && upper_exists { + // i. Perform ? Set(O, lowerP, upperValue, true). + // ii. Perform ? DeletePropertyOrThrow(O, upperP). + let upper_value = get(agent, o, upper_p)?; + set(agent, o, lower_p, upper_value, true)?; + delete_property_or_throw(agent, o, upper_p)?; + } + // j. Else if lowerExists is true and upperExists is false, then + else if lower_exists && !upper_exists { + // i. Perform ? DeletePropertyOrThrow(O, lowerP). + // ii. Perform ? Set(O, upperP, lowerValue, true). + let lower_value = get(agent, o, lower_p)?; + delete_property_or_throw(agent, o, lower_p)?; + set(agent, o, upper_p, lower_value, true)?; + } + // k. Else, + else { + // i. Assert: lowerExists and upperExists are both false. + // ii. NOTE: No action is required. + assert!(!(lower_exists && upper_exists)); + } + // l. Set lower to lower + 1. + lower += 1; + } + // 6. Return O. + Ok(o.into_value()) } /// ### [23.1.3.27 Array.prototype.shift ( )](https://tc39.es/ecma262/#sec-array.prototype.shift) diff --git a/tests/expectations.json b/tests/expectations.json index 7eb1f5498..c46d3412d 100644 --- a/tests/expectations.json +++ b/tests/expectations.json @@ -357,18 +357,7 @@ "built-ins/Array/prototype/reduceRight/resizable-buffer-grow-mid-iteration.js": "CRASH", "built-ins/Array/prototype/reduceRight/resizable-buffer-shrink-mid-iteration.js": "CRASH", "built-ins/Array/prototype/reduceRight/resizable-buffer.js": "CRASH", - "built-ins/Array/prototype/reverse/S15.4.4.8_A1_T1.js": "CRASH", - "built-ins/Array/prototype/reverse/S15.4.4.8_A1_T2.js": "CRASH", - "built-ins/Array/prototype/reverse/S15.4.4.8_A2_T1.js": "CRASH", - "built-ins/Array/prototype/reverse/S15.4.4.8_A2_T2.js": "CRASH", - "built-ins/Array/prototype/reverse/S15.4.4.8_A2_T3.js": "CRASH", - "built-ins/Array/prototype/reverse/S15.4.4.8_A3_T3.js": "CRASH", - "built-ins/Array/prototype/reverse/S15.4.4.8_A4_T1.js": "CRASH", - "built-ins/Array/prototype/reverse/S15.4.4.8_A4_T2.js": "CRASH", - "built-ins/Array/prototype/reverse/array-has-one-entry.js": "CRASH", - "built-ins/Array/prototype/reverse/call-with-boolean.js": "CRASH", "built-ins/Array/prototype/reverse/get_if_present_with_delete.js": "CRASH", - "built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-object.js": "CRASH", "built-ins/Array/prototype/reverse/length-exceeding-integer-limit-with-proxy.js": "CRASH", "built-ins/Array/prototype/reverse/resizable-buffer.js": "CRASH", "built-ins/Array/prototype/slice/coerced-start-end-grow.js": "CRASH", diff --git a/tests/metrics.json b/tests/metrics.json index 19f5dd95d..be7aeed90 100644 --- a/tests/metrics.json +++ b/tests/metrics.json @@ -1,8 +1,8 @@ { "results": { - "crash": 16297, - "fail": 8261, - "pass": 20690, + "crash": 16285, + "fail": 8262, + "pass": 20701, "skip": 40, "timeout": 3, "unresolved": 0