From d8a71bc78e3aef0d96ff8f7f8e4a02c403adc8b7 Mon Sep 17 00:00:00 2001 From: raskad <32105367+raskad@users.noreply.github.com> Date: Sat, 11 Dec 2021 22:11:39 +0000 Subject: [PATCH] Fix internal vm tests (#1718) This PR fixes some vm implementation code. All our internal tests should now pass with the vm enabled. There are only a few (~100) 262 tests left that currently break with the vm, that previously worked. --- boa/src/builtins/function/mod.rs | 13 +- boa/src/builtins/iterable/mod.rs | 45 +- boa/src/builtins/json/mod.rs | 2 + boa/src/builtins/regexp/mod.rs | 4 - boa/src/bytecompiler.rs | 501 +++++++++++++-------- boa/src/context.rs | 19 +- boa/src/environment/lexical_environment.rs | 5 + boa/src/exec/tests.rs | 23 +- boa/src/lib.rs | 30 +- boa/src/syntax/parser/expression/update.rs | 42 +- boa/src/vm/call_frame.rs | 25 +- boa/src/vm/code_block.rs | 157 ++++--- boa/src/vm/mod.rs | 489 +++++++++++++++----- boa/src/vm/opcode.rs | 246 ++++++++-- boa_tester/src/exec/js262.rs | 13 +- 15 files changed, 1149 insertions(+), 465 deletions(-) diff --git a/boa/src/builtins/function/mod.rs b/boa/src/builtins/function/mod.rs index fb18ebb4c3..3381f96b60 100644 --- a/boa/src/builtins/function/mod.rs +++ b/boa/src/builtins/function/mod.rs @@ -208,6 +208,7 @@ impl fmt::Debug for Function { impl Function { // Adds the final rest parameters to the Environment as an array + #[cfg(not(feature = "vm"))] pub(crate) fn add_rest_param( param: &FormalParameter, index: usize, @@ -240,6 +241,7 @@ impl Function { } // Adds an argument to the environment + #[cfg(not(feature = "vm"))] pub(crate) fn add_arguments_to_environment( param: &FormalParameter, value: JsValue, @@ -580,7 +582,16 @@ impl BuiltInFunctionObject { .into()) } } - + #[cfg(feature = "vm")] + (Function::VmOrdinary { .. }, Some(name)) if name.is_empty() => { + Ok("[Function (anonymous)]".into()) + } + #[cfg(feature = "vm")] + (Function::VmOrdinary { .. }, Some(name)) => { + Ok(format!("[Function: {}]", &name).into()) + } + #[cfg(feature = "vm")] + (Function::VmOrdinary { .. }, None) => Ok("[Function (anonymous)]".into()), _ => Ok("TODO".into()), } } diff --git a/boa/src/builtins/iterable/mod.rs b/boa/src/builtins/iterable/mod.rs index 84f54329e9..4df65edaa3 100644 --- a/boa/src/builtins/iterable/mod.rs +++ b/boa/src/builtins/iterable/mod.rs @@ -230,30 +230,43 @@ impl IteratorRecord { completion: JsResult, context: &mut Context, ) -> JsResult { - let mut inner_result = self.iterator_object.get_field("return", context); + // 1. Assert: Type(iteratorRecord.[[Iterator]]) is Object. + // 2. Let iterator be iteratorRecord.[[Iterator]]. + // 3. Let innerResult be GetMethod(iterator, "return"). + let inner_result = self.iterator_object.get_method("return", context); + //let mut inner_result = self.iterator_object.get_field("return", context); - // 5 + // 4. If innerResult.[[Type]] is normal, then if let Ok(inner_value) = inner_result { - // b - if inner_value.is_undefined() { - return completion; + // a. Let return be innerResult.[[Value]]. + match inner_value { + // b. If return is undefined, return Completion(completion). + None => return completion, + // c. Set innerResult to Call(return, iterator). + Some(value) => { + let inner_result = value.call(&self.iterator_object, &[], context); + + // 5. If completion.[[Type]] is throw, return Completion(completion). + let completion = completion?; + + // 6. If innerResult.[[Type]] is throw, return Completion(innerResult). + inner_result?; + + // 7. If Type(innerResult.[[Value]]) is not Object, throw a TypeError exception. + // 8. Return Completion(completion). + return Ok(completion); + } } - // c - inner_result = context.call(&inner_value, &self.iterator_object, &[]); } - // 6 + // 5. If completion.[[Type]] is throw, return Completion(completion). let completion = completion?; - // 7 - let inner_result = inner_result?; - - // 8 - if !inner_result.is_object() { - return context.throw_type_error("`return` method of iterator didn't return an Object"); - } + // 6. If innerResult.[[Type]] is throw, return Completion(innerResult). + inner_result?; - // 9 + // 7. If Type(innerResult.[[Value]]) is not Object, throw a TypeError exception. + // 8. Return Completion(completion). Ok(completion) } } diff --git a/boa/src/builtins/json/mod.rs b/boa/src/builtins/json/mod.rs index 0f3cbc42df..1c68e236fc 100644 --- a/boa/src/builtins/json/mod.rs +++ b/boa/src/builtins/json/mod.rs @@ -96,6 +96,8 @@ impl Json { // 9. Let unfiltered be completion.[[Value]]. // 10. Assert: unfiltered is either a String, Number, Boolean, Null, or an Object that is defined by either an ArrayLiteral or an ObjectLiteral. let unfiltered = context.eval(script_string.as_bytes())?; + #[cfg(feature = "vm")] + context.vm.pop_frame(); // 11. If IsCallable(reviver) is true, then if let Some(obj) = args.get_or_undefined(1).as_callable() { diff --git a/boa/src/builtins/regexp/mod.rs b/boa/src/builtins/regexp/mod.rs index 15bdf69c84..0b9c6043f4 100644 --- a/boa/src/builtins/regexp/mod.rs +++ b/boa/src/builtins/regexp/mod.rs @@ -38,9 +38,6 @@ pub struct RegExp { /// Regex matcher. matcher: Regex, - /// Update last_index, set if global or sticky flags are set. - use_last_index: bool, - /// Flag 's' - dot matches newline characters. dot_all: bool, @@ -340,7 +337,6 @@ impl RegExp { let regexp = RegExp { matcher, - use_last_index: global || sticky, dot_all, global, ignore_case, diff --git a/boa/src/bytecompiler.rs b/boa/src/bytecompiler.rs index fe5d83eb2e..1aa6e62dfe 100644 --- a/boa/src/bytecompiler.rs +++ b/boa/src/bytecompiler.rs @@ -16,7 +16,7 @@ use crate::{ vm::{CodeBlock, Opcode}, JsBigInt, JsString, JsValue, }; -use std::collections::HashMap; +use std::{collections::HashMap, mem::size_of}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] enum Literal { @@ -36,6 +36,8 @@ struct JumpControlInfo { start_address: u32, kind: JumpControlInfoKind, breaks: Vec