Browse Source

Fix 2 bugs that stopped test262 (#812)

* Fix: Add check for length in Array.prototype.map

* Fix: Make Array.prototype.reduceRight work for length 1

* Refactor: Cleanup Array.prototype.map to use usize for length
pull/828/head
João Borges 4 years ago committed by GitHub
parent
commit
9d4c49c6dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      boa/src/builtins/array/mod.rs

19
boa/src/builtins/array/mod.rs

@ -581,7 +581,7 @@ impl Array {
/// ///
/// [spec]: https://tc39.es/ecma262/#sec-array.prototype.map /// [spec]: https://tc39.es/ecma262/#sec-array.prototype.map
/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map /// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
pub(crate) fn map(this: &Value, args: &[Value], interpreter: &mut Context) -> Result<Value> { pub(crate) fn map(this: &Value, args: &[Value], context: &mut Context) -> Result<Value> {
if args.is_empty() { if args.is_empty() {
return Err(Value::from( return Err(Value::from(
"missing argument 0 when calling function Array.prototype.map", "missing argument 0 when calling function Array.prototype.map",
@ -591,16 +591,20 @@ impl Array {
let callback = args.get(0).cloned().unwrap_or_else(Value::undefined); let callback = args.get(0).cloned().unwrap_or_else(Value::undefined);
let this_val = args.get(1).cloned().unwrap_or_else(Value::undefined); let this_val = args.get(1).cloned().unwrap_or_else(Value::undefined);
let length = this.get_field("length").as_number().unwrap() as i32; let length = this.get_field("length").to_length(context)?;
let new = Self::new_array(interpreter)?; if length > 2usize.pow(32) - 1 {
return context.throw_range_error("Invalid array length");
}
let new = Self::new_array(context)?;
let values: Vec<Value> = (0..length) let values: Vec<Value> = (0..length)
.map(|idx| { .map(|idx| {
let element = this.get_field(idx); let element = this.get_field(idx);
let args = [element, Value::from(idx), new.clone()]; let args = [element, Value::from(idx), new.clone()];
interpreter context
.call(&callback, &this_val, &args) .call(&callback, &this_val, &args)
.unwrap_or_else(|_| Value::undefined()) .unwrap_or_else(|_| Value::undefined())
}) })
@ -1113,12 +1117,13 @@ impl Array {
); );
} }
let result = this.get_field(k); let result = this.get_field(k);
k -= 1; k = k.overflowing_sub(1).0;
result result
} else { } else {
initial_value initial_value
}; };
loop { // usize::MAX is bigger than the maximum array size so we can use it check for integer undeflow
while k != usize::MAX {
if this.has_field(k) { if this.has_field(k) {
let arguments = [accumulator, this.get_field(k), Value::from(k), this.clone()]; let arguments = [accumulator, this.get_field(k), Value::from(k), this.clone()];
accumulator = interpreter.call(&callback, &Value::undefined(), &arguments)?; accumulator = interpreter.call(&callback, &Value::undefined(), &arguments)?;
@ -1140,7 +1145,7 @@ impl Array {
if k == 0 { if k == 0 {
break; break;
} }
k -= 1; k = k.overflowing_sub(1).0;
} }
Ok(accumulator) Ok(accumulator)
} }

Loading…
Cancel
Save