Skip to content

Commit

Permalink
Merge 2b099bc into 7779c1a
Browse files Browse the repository at this point in the history
  • Loading branch information
raskad authored Feb 11, 2022
2 parents 7779c1a + 2b099bc commit 9b90817
Show file tree
Hide file tree
Showing 32 changed files with 2,590 additions and 2,604 deletions.
2 changes: 1 addition & 1 deletion boa/benches/full.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ macro_rules! full_benchmarks {
static CODE: &str = include_str!(concat!("bench_scripts/", stringify!($name), ".js"));
let mut context = Context::default();
let statement_list = context.parse(CODE).expect("parsing failed");
let code_block = context.compile(&statement_list);
let code_block = context.compile(&statement_list).unwrap();
c.bench_function(concat!($id, " (Execution)"), move |b| {
b.iter(|| {
context.execute(black_box(code_block.clone())).unwrap()
Expand Down
147 changes: 71 additions & 76 deletions boa/src/builtins/function/arguments.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
use crate::{
builtins::Array,
environment::lexical_environment::Environment,
environments::DeclarativeEnvironment,
gc::{Finalize, Trace},
object::{FunctionBuilder, JsObject, ObjectData},
property::PropertyDescriptor,
property::{PropertyDescriptor, PropertyKey},
symbol::{self, WellKnownSymbols},
syntax::ast::node::FormalParameter,
Context, JsValue,
};
use rustc_hash::FxHashSet;
use gc::Gc;
use rustc_hash::FxHashMap;

#[derive(Debug, Clone, Trace, Finalize)]
pub struct MappedArguments(JsObject);
Expand Down Expand Up @@ -111,7 +112,7 @@ impl Arguments {
func: &JsObject,
formals: &[FormalParameter],
arguments_list: &[JsValue],
env: &Environment,
env: &Gc<DeclarativeEnvironment>,
context: &mut Context,
) -> JsObject {
// 1. Assert: formals does not contain a rest parameter, any binding patterns, or any initializers.
Expand Down Expand Up @@ -160,87 +161,81 @@ impl Arguments {
.expect("DefinePropertyOrThrow must not fail per the spec");

// 17. Let mappedNames be a new empty List.
// using a set to optimize `contains`
let mut mapped_names = FxHashSet::default();

// 12. Let parameterNames be the BoundNames of formals.
// 13. Let numberOfParameters be the number of elements in parameterNames.
// 18. Set index to numberOfParameters - 1.
// 19. Repeat, while index ≥ 0,
// a. Let name be parameterNames[index].

for (index, parameter_name_vec) in
formals.iter().map(FormalParameter::names).enumerate().rev()
{
for parameter_name in parameter_name_vec.iter().copied() {
// b. If name is not an element of mappedNames, then
if !mapped_names.contains(&parameter_name) {
// i. Add name as an element of the list mappedNames.
mapped_names.insert(parameter_name);
// ii. If index < len, then
if index < len {
// 1. Let g be MakeArgGetter(name, env).
// https://tc39.es/ecma262/#sec-makearggetter
let g = {
// 2. Let getter be ! CreateBuiltinFunction(getterClosure, 0, "", « »).
// 3. NOTE: getter is never directly accessible to ECMAScript code.
// 4. Return getter.
FunctionBuilder::closure_with_captures(
context,
// 1. Let getterClosure be a new Abstract Closure with no parameters that captures
// name and env and performs the following steps when called:
|_, _, captures, context| {
captures.0.get_binding_value(captures.1, false, context)
},
(env.clone(), parameter_name),
)
.length(0)
.name("")
.build()
};
// 2. Let p be MakeArgSetter(name, env).
// https://tc39.es/ecma262/#sec-makeargsetter
let p = {
// 2. Let setter be ! CreateBuiltinFunction(setterClosure, 1, "", « »).
// 3. NOTE: setter is never directly accessible to ECMAScript code.
// 4. Return setter.
FunctionBuilder::closure_with_captures(
context,
// 1. Let setterClosure be a new Abstract Closure with parameters (value) that captures
// name and env and performs the following steps when called:
|_, args, captures, context| {
let value = args.get(0).cloned().unwrap_or_default();
// a. Return env.SetMutableBinding(name, value, false).
captures
.0
.set_mutable_binding(captures.1, value, false, context)
.map(|_| JsValue::Undefined)
// Ok(JsValue::Undefined)
},
(env.clone(), parameter_name),
)
.length(1)
.name("")
.build()
};

// 3. Perform map.[[DefineOwnProperty]](! ToString(𝔽(index)), PropertyDescriptor {
// [[Set]]: p, [[Get]]: g, [[Enumerable]]: false, [[Configurable]]: true }).
map.__define_own_property__(
index.into(),
PropertyDescriptor::builder()
.set(p)
.get(g)
.enumerable(false)
.configurable(true)
.build(),
context,
)
.expect("[[DefineOwnProperty]] must not fail per the spec");
}
// Get the mapping of the environment binding index to the index of the object property.
// Parameters can be defined multiple times, so the mapping is not one to one.
let mut bindings = FxHashMap::default();
let mut property_index = 0;
'outer: for formal in formals {
for name in formal.names() {
if property_index >= len {
break 'outer;
}
let binding_index = bindings.len() + 1;
let entry = bindings
.entry(name)
.or_insert((binding_index, property_index));
entry.1 = property_index;
property_index += 1;
}
}
for (binding_index, property_index) in bindings.values() {
// 1. Let g be MakeArgGetter(name, env).
// https://tc39.es/ecma262/#sec-makearggetter
let g = {
// 2. Let getter be ! CreateBuiltinFunction(getterClosure, 0, "", « »).
// 3. NOTE: getter is never directly accessible to ECMAScript code.
// 4. Return getter.
FunctionBuilder::closure_with_captures(
context,
// 1. Let getterClosure be a new Abstract Closure with no parameters that captures
// name and env and performs the following steps when called:
|_, _, captures, _| Ok(captures.0.get(captures.1)),
(env.clone(), *binding_index),
)
.length(0)
.build()
};
// 2. Let p be MakeArgSetter(name, env).
// https://tc39.es/ecma262/#sec-makeargsetter
let p = {
// 2. Let setter be ! CreateBuiltinFunction(setterClosure, 1, "", « »).
// 3. NOTE: setter is never directly accessible to ECMAScript code.
// 4. Return setter.
FunctionBuilder::closure_with_captures(
context,
// 1. Let setterClosure be a new Abstract Closure with parameters (value) that captures
// name and env and performs the following steps when called:
|_, args, captures, _| {
let value = args.get(0).cloned().unwrap_or_default();
captures.0.set(captures.1, value);
Ok(JsValue::undefined())
},
(env.clone(), *binding_index),
)
.length(1)
.build()
};

// 3. Perform map.[[DefineOwnProperty]](! ToString(𝔽(index)), PropertyDescriptor {
// [[Set]]: p, [[Get]]: g, [[Enumerable]]: false, [[Configurable]]: true }).
map.__define_own_property__(
PropertyKey::from(*property_index),
PropertyDescriptor::builder()
.set(p)
.get(g)
.enumerable(false)
.configurable(true)
.build(),
context,
)
.expect("[[DefineOwnProperty]] must not fail per the spec");
}

// 20. Perform ! DefinePropertyOrThrow(obj, @@iterator, PropertyDescriptor {
// [[Value]]: %Array.prototype.values%, [[Writable]]: true, [[Enumerable]]: false,
Expand Down
7 changes: 3 additions & 4 deletions boa/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@
//! [spec]: https://tc39.es/ecma262/#sec-function-objects
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
use super::JsArgs;
use crate::{
builtins::BuiltIn,
builtins::{BuiltIn, JsArgs},
context::StandardObjects,
environment::lexical_environment::Environment,
environments::DeclarativeEnvironmentStack,
gc::{self, Finalize, Gc, Trace},
object::{
internal_methods::get_prototype_from_constructor, JsObject, NativeObject, Object,
Expand Down Expand Up @@ -177,7 +176,7 @@ pub enum Function {
},
VmOrdinary {
code: Gc<crate::vm::CodeBlock>,
environment: Environment,
environments: DeclarativeEnvironmentStack,
},
}

Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/global_this/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ impl BuiltIn for GlobalThis {
fn init(context: &mut Context) -> JsValue {
let _timer = BoaProfiler::global().start_event(Self::NAME, "init");

context.global_object().into()
context.global_object().clone().into()
}
}
8 changes: 4 additions & 4 deletions boa/src/builtins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,11 +101,11 @@ fn init_builtin<B: BuiltIn>(context: &mut Context) {
.value(value)
.writable(B::ATTRIBUTE.writable())
.enumerable(B::ATTRIBUTE.enumerable())
.configurable(B::ATTRIBUTE.configurable());
.configurable(B::ATTRIBUTE.configurable())
.build();
context
.global_object()
.borrow_mut()
.insert(B::NAME, property);
.global_bindings_mut()
.insert(B::NAME.into(), property);
}

/// Initializes built-in objects and functions
Expand Down
38 changes: 9 additions & 29 deletions boa/src/builtins/number/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,12 @@
//! [spec]: https://tc39.es/ecma262/#sec-number-object
//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number
use super::string::is_trimmable_whitespace;
use super::JsArgs;
use crate::context::StandardObjects;
use crate::object::JsObject;
use crate::{
builtins::{function::make_builtin_fn, BuiltIn},
object::{internal_methods::get_prototype_from_constructor, ConstructorBuilder, ObjectData},
builtins::{string::is_trimmable_whitespace, BuiltIn, JsArgs},
context::StandardObjects,
object::{
internal_methods::get_prototype_from_constructor, ConstructorBuilder, JsObject, ObjectData,
},
property::Attribute,
value::{AbstractRelation, IntegerOrInfinity, JsValue},
BoaProfiler, Context, JsResult,
Expand All @@ -39,12 +38,6 @@ const BUF_SIZE: usize = 2200;
#[derive(Debug, Clone, Copy)]
pub(crate) struct Number;

/// Maximum number of arguments expected to the builtin parseInt() function.
const PARSE_INT_MAX_ARG_COUNT: usize = 2;

/// Maximum number of arguments expected to the builtin parseFloat() function.
const PARSE_FLOAT_MAX_ARG_COUNT: usize = 1;

impl BuiltIn for Number {
const NAME: &'static str = "Number";

Expand Down Expand Up @@ -83,23 +76,10 @@ impl BuiltIn for Number {
.static_method(Self::number_is_integer, "isInteger", 1)
.build();

let global = context.global_object();
make_builtin_fn(
Self::parse_int,
"parseInt",
&global,
PARSE_INT_MAX_ARG_COUNT,
context,
);
make_builtin_fn(
Self::parse_float,
"parseFloat",
&global,
PARSE_FLOAT_MAX_ARG_COUNT,
context,
);
make_builtin_fn(Self::global_is_finite, "isFinite", &global, 1, context);
make_builtin_fn(Self::global_is_nan, "isNaN", &global, 1, context);
context.register_global_builtin_function("parseInt", 2, Self::parse_int);
context.register_global_builtin_function("parseFloat", 1, Self::parse_float);
context.register_global_builtin_function("isFinite", 1, Self::global_is_finite);
context.register_global_builtin_function("isNaN", 1, Self::global_is_nan);

number_object.into()
}
Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/regexp/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ impl RegExp {
pub(crate) fn create(p: JsValue, f: JsValue, context: &mut Context) -> JsResult<JsValue> {
// 1. Let obj be ? RegExpAlloc(%RegExp%).
let obj = Self::alloc(
&context.global_object().get(Self::NAME, context)?,
&context.global_object().clone().get(Self::NAME, context)?,
&[],
context,
)?;
Expand Down
2 changes: 1 addition & 1 deletion boa/src/builtins/set/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ impl Set {
let this_arg = args.get_or_undefined(1);
// TODO: if condition should also check that we are not in strict mode
let this_arg = if this_arg.is_undefined() {
JsValue::Object(context.global_object())
context.global_object().clone().into()
} else {
this_arg.clone()
};
Expand Down
Loading

0 comments on commit 9b90817

Please sign in to comment.