mirror of https://github.com/boa-dev/boa.git
Jason Williams
5 years ago
committed by
GitHub
14 changed files with 468 additions and 180 deletions
@ -1,12 +1,23 @@
|
||||
#[macro_use] |
||||
extern crate criterion; |
||||
|
||||
use boa::exec; |
||||
use boa::realm::Realm; |
||||
use criterion::Criterion; |
||||
use criterion::{black_box, Criterion}; |
||||
|
||||
static SRC: &str = r#" |
||||
let a = Symbol(); |
||||
let b = Symbol(); |
||||
let c = Symbol(); |
||||
"#; |
||||
|
||||
fn symbol_creation(c: &mut Criterion) { |
||||
c.bench_function("Symbol Creation", move |b| b.iter(|| exec(black_box(SRC)))); |
||||
} |
||||
|
||||
fn create_realm(c: &mut Criterion) { |
||||
c.bench_function("Create Realm", move |b| b.iter(|| Realm::create())); |
||||
} |
||||
|
||||
criterion_group!(benches, create_realm); |
||||
criterion_group!(benches, create_realm, symbol_creation); |
||||
criterion_main!(benches); |
||||
|
@ -0,0 +1,113 @@
|
||||
use crate::{ |
||||
builtins::{ |
||||
object::{Object, ObjectKind, INSTANCE_PROTOTYPE, PROTOTYPE}, |
||||
value::{to_value, ResultValue, Value, ValueData}, |
||||
}, |
||||
exec::Interpreter, |
||||
}; |
||||
use gc::{Gc, GcCell}; |
||||
use rand::random; |
||||
|
||||
/// https://tc39.es/ecma262/#sec-symbol-description
|
||||
/// Creates Symbol instances.
|
||||
///
|
||||
/// Symbol instances are ordinary objects that inherit properties from the Symbol prototype object.
|
||||
/// Symbol instances have a [[SymbolData]] internal slot.
|
||||
/// The [[SymbolData]] internal slot is the Symbol value represented by this Symbol object.
|
||||
pub fn call_symbol(_: &Value, args: &[Value], ctx: &mut Interpreter) -> ResultValue { |
||||
// From an implementation and specificaition perspective Symbols are similar to Objects.
|
||||
// They have internal slots to hold the SymbolData and Description, they also have methods and a prototype.
|
||||
// So we start by creating an Object
|
||||
// TODO: Set prototype to Symbol.prototype (by changing to Object::create(), use interpreter to get Symbol.prototype)
|
||||
let mut sym_instance = Object::default(); |
||||
sym_instance.kind = ObjectKind::Symbol; |
||||
|
||||
// Set description which should either be undefined or a string
|
||||
let desc_string = match args.get(0) { |
||||
Some(value) => to_value(value.to_string()), |
||||
None => Gc::new(ValueData::Undefined), |
||||
}; |
||||
|
||||
sym_instance.set_internal_slot("Description", desc_string); |
||||
sym_instance.set_internal_slot("SymbolData", to_value(random::<i32>())); |
||||
|
||||
// Set __proto__ internal slot
|
||||
let proto = ctx |
||||
.realm |
||||
.global_obj |
||||
.get_field_slice("Symbol") |
||||
.get_field_slice(PROTOTYPE); |
||||
sym_instance.set_internal_slot(INSTANCE_PROTOTYPE, proto); |
||||
|
||||
Ok(Gc::new(ValueData::Symbol(GcCell::new(sym_instance)))) |
||||
} |
||||
|
||||
/// <https://tc39.es/ecma262/#sec-symbol.prototype.tostring>
|
||||
pub fn to_string(this: &Value, _: &[Value], _: &mut Interpreter) -> ResultValue { |
||||
let s: Value = this.get_internal_slot("Description"); |
||||
let full_string = format!(r#"Symbol({})"#, s.to_string()); |
||||
Ok(to_value(full_string)) |
||||
} |
||||
|
||||
/// <https://tc39.es/ecma262/#sec-symbol-constructor>
|
||||
pub fn create_constructor(global: &Value) -> Value { |
||||
// Create Symbol constructor (or function in Symbol's case)
|
||||
let mut symbol_constructor = Object::default(); |
||||
symbol_constructor.set_internal_method("call", call_symbol); |
||||
|
||||
// Create prototype
|
||||
let mut symbol_prototype = Object::default(); |
||||
|
||||
// Symbol.prototype[[Prototype]] points to Object.prototype
|
||||
// Symbol Constructor -> Symbol Prototype -> Object Prototype
|
||||
let object_prototype = global.get_field_slice("Object").get_field_slice(PROTOTYPE); |
||||
symbol_prototype.set_internal_slot(INSTANCE_PROTOTYPE, object_prototype.clone()); |
||||
symbol_prototype.set_method("toString", to_string); |
||||
|
||||
let symbol_prototype_val = to_value(symbol_prototype); |
||||
|
||||
let symbol_constructor_value = to_value(symbol_constructor); |
||||
symbol_prototype_val.set_field_slice("construcotor", symbol_constructor_value.clone()); |
||||
symbol_constructor_value.set_field_slice(PROTOTYPE, symbol_prototype_val.clone()); |
||||
|
||||
symbol_constructor_value |
||||
} |
||||
|
||||
#[cfg(test)] |
||||
mod tests { |
||||
use super::*; |
||||
use crate::exec::Executor; |
||||
use crate::realm::Realm; |
||||
use crate::{forward, forward_val}; |
||||
|
||||
#[test] |
||||
fn check_symbol_constructor_is_function() { |
||||
let global: Gc<ValueData> = ValueData::new_obj(None); |
||||
let symbol_constructor = create_constructor(&global); |
||||
assert_eq!(symbol_constructor.is_function(), true); |
||||
} |
||||
|
||||
#[test] |
||||
fn call_symbol_and_check_return_type() { |
||||
let realm = Realm::create(); |
||||
let mut engine = Executor::new(realm); |
||||
let init = r#" |
||||
var sym = Symbol(); |
||||
"#; |
||||
forward(&mut engine, init); |
||||
let sym = forward_val(&mut engine, "sym").unwrap(); |
||||
assert_eq!(sym.is_symbol(), true); |
||||
} |
||||
|
||||
#[test] |
||||
fn print_symbol_expect_description() { |
||||
let realm = Realm::create(); |
||||
let mut engine = Executor::new(realm); |
||||
let init = r#" |
||||
var sym = Symbol("Hello"); |
||||
"#; |
||||
forward(&mut engine, init); |
||||
let sym = forward_val(&mut engine, "sym.toString()").unwrap(); |
||||
assert_eq!(sym.to_string(), "Symbol(Hello)"); |
||||
} |
||||
} |
Loading…
Reference in new issue