Skip to content

Commit

Permalink
Merge 7e1fcd3 into 42610ac
Browse files Browse the repository at this point in the history
  • Loading branch information
HalidOdat committed Aug 24, 2021
2 parents 42610ac + 7e1fcd3 commit 5d70616
Show file tree
Hide file tree
Showing 12 changed files with 992 additions and 350 deletions.
49 changes: 19 additions & 30 deletions boa/src/builtins/function/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@

use crate::object::PROTOTYPE;
use crate::{
builtins::{Array, BuiltIn},
builtins::BuiltIn,
environment::lexical_environment::Environment,
gc::{custom_trace, empty_trace, Finalize, Trace},
object::{ConstructorBuilder, FunctionBuilder, GcObject, Object, ObjectData},
property::{Attribute, PropertyDescriptor},
syntax::ast::node::{FormalParameter, RcStatementList},
BoaProfiler, Context, JsResult, JsValue,
};
use bitflags::bitflags;

use std::fmt::{self, Debug};
use std::rc::Rc;

Expand Down Expand Up @@ -53,30 +53,6 @@ impl Debug for BuiltInFunction {
}
}

bitflags! {
#[derive(Finalize, Default)]
pub struct FunctionFlags: u8 {
const CONSTRUCTABLE = 0b0000_0010;
const LEXICAL_THIS_MODE = 0b0000_0100;
}
}

impl FunctionFlags {
#[inline]
pub(crate) fn is_constructable(&self) -> bool {
self.contains(Self::CONSTRUCTABLE)
}

#[inline]
pub(crate) fn is_lexical_this_mode(&self) -> bool {
self.contains(Self::LEXICAL_THIS_MODE)
}
}

unsafe impl Trace for FunctionFlags {
empty_trace!();
}

/// Boa representation of a Function Object.
///
/// FunctionBody is specific to this interpreter, it will either be Rust code or JavaScript code (AST Node)
Expand All @@ -93,11 +69,17 @@ pub enum Function {
constructable: bool,
},
Ordinary {
flags: FunctionFlags,
constructable: bool,
lexical_this_mode: bool,
body: RcStatementList,
params: Box<[FormalParameter]>,
environment: Environment,
},
#[cfg(feature = "vm")]
VmOrdinary {
code: gc::Gc<crate::vm::CodeBlock>,
environment: Environment,
},
}

impl Debug for Function {
Expand All @@ -114,20 +96,26 @@ unsafe impl Trace for Function {
Function::Ordinary { environment, .. } => {
mark(environment);
}
#[cfg(feature = "vm")]
Function::VmOrdinary { code, environment } => {
mark(code);
mark(environment);
}
}
});
}

impl Function {
// Adds the final rest parameters to the Environment as an array
#[cfg(not(feature = "vm"))]
pub(crate) fn add_rest_param(
&self,
param: &FormalParameter,
index: usize,
args_list: &[JsValue],
context: &mut Context,
local_env: &Environment,
) {
use crate::builtins::Array;
// Create array of values
let array = Array::new_array(context);
Array::add_to_array_object(&array, args_list.get(index..).unwrap_or_default(), context)
Expand All @@ -147,7 +135,6 @@ impl Function {

// Adds an argument to the environment
pub(crate) fn add_arguments_to_environment(
&self,
param: &FormalParameter,
value: JsValue,
local_env: &Environment,
Expand All @@ -169,7 +156,9 @@ impl Function {
match self {
Self::Native { constructable, .. } => *constructable,
Self::Closure { constructable, .. } => *constructable,
Self::Ordinary { flags, .. } => flags.is_constructable(),
Self::Ordinary { constructable, .. } => *constructable,
#[cfg(feature = "vm")]
Self::VmOrdinary { code, .. } => code.constructable,
}
}
}
Expand Down
169 changes: 149 additions & 20 deletions boa/src/bytecompiler.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
use gc::Gc;

use crate::{
syntax::ast::{
node::{Declaration, GetConstField, GetField, Identifier, StatementList},
node::{Declaration, GetConstField, GetField, StatementList},
op::{AssignOp, BinOp, BitOp, CompOp, LogOp, NumOp, UnaryOp},
Const, Node,
},
vm::{CodeBlock, Opcode},
vm::{CodeBlock, Opcode, ThisMode},
JsBigInt, JsString, JsValue,
};
use std::collections::HashMap;
Expand All @@ -31,7 +33,7 @@ struct JumpControlInfo {

#[derive(Debug, Clone, Copy)]
enum Access<'a> {
Variable { name: &'a Identifier },
Variable { index: u32 },
ByName { node: &'a GetConstField },
ByValue { node: &'a GetField },
This,
Expand All @@ -42,26 +44,24 @@ pub struct ByteCompiler {
code_block: CodeBlock,
literals_map: HashMap<Literal, u32>,
names_map: HashMap<JsString, u32>,
functions_map: HashMap<JsString, u32>,
jump_info: Vec<JumpControlInfo>,
}

impl Default for ByteCompiler {
fn default() -> Self {
Self::new()
}
top_level: bool,
}

impl ByteCompiler {
/// Represents a placeholder address that will be patched later.
const DUMMY_ADDRESS: u32 = u32::MAX;

#[inline]
pub fn new() -> Self {
pub fn new(name: JsString, strict: bool) -> Self {
Self {
code_block: CodeBlock::new(),
code_block: CodeBlock::new(name, 0, strict, false),
literals_map: HashMap::new(),
names_map: HashMap::new(),
functions_map: HashMap::new(),
jump_info: Vec::new(),
top_level: true,
}
}

Expand Down Expand Up @@ -89,8 +89,8 @@ impl ByteCompiler {
}

let name = JsString::new(name);
let index = self.code_block.names.len() as u32;
self.code_block.names.push(name.clone());
let index = self.code_block.variables.len() as u32;
self.code_block.variables.push(name.clone());
self.names_map.insert(name, index);
index
}
Expand Down Expand Up @@ -267,7 +267,10 @@ impl ByteCompiler {
#[inline]
fn compile_access<'a>(&mut self, node: &'a Node) -> Access<'a> {
match node {
Node::Identifier(name) => Access::Variable { name },
Node::Identifier(name) => {
let index = self.get_or_insert_name(name.as_ref());
Access::Variable { index }
}
Node::GetConstField(node) => Access::ByName { node },
Node::GetField(node) => Access::ByValue { node },
Node::This => Access::This,
Expand All @@ -278,9 +281,8 @@ impl ByteCompiler {
#[inline]
fn access_get(&mut self, access: Access<'_>, use_expr: bool) {
match access {
Access::Variable { name } => {
let index = self.get_or_insert_name(name.as_ref());
self.emit(Opcode::GetName, &[index]);
Access::Variable { index: name } => {
self.emit(Opcode::GetName, &[name]);
}
Access::ByName { node } => {
let index = self.get_or_insert_name(node.field());
Expand Down Expand Up @@ -313,8 +315,7 @@ impl ByteCompiler {
}

match access {
Access::Variable { name } => {
let index = self.get_or_insert_name(name.as_ref());
Access::Variable { index } => {
self.emit(Opcode::SetName, &[index]);
}
Access::ByName { node } => {
Expand Down Expand Up @@ -532,7 +533,8 @@ impl ByteCompiler {
}
}
Node::Identifier(name) => {
let access = Access::Variable { name };
let index = self.get_or_insert_name(name.as_ref());
let access = Access::Variable { index };
self.access_get(access, use_expr);
}
Node::Assign(assign) => {
Expand Down Expand Up @@ -579,6 +581,37 @@ impl ByteCompiler {
Node::This => {
self.access_get(Access::This, use_expr);
}
Node::FunctionExpr(_function) => self.function(expr, use_expr),
Node::ArrowFunctionDecl(_function) => self.function(expr, use_expr),
Node::Call(call) => {
for arg in call.args().iter().rev() {
self.compile_expr(arg, true);
}
match call.expr() {
Node::GetConstField(field) => {
self.compile_expr(field.obj(), true);
self.emit(Opcode::Dup, &[]);
let index = self.get_or_insert_name(field.field());
self.emit(Opcode::GetPropertyByName, &[index]);
}
Node::GetField(field) => {
self.compile_expr(field.obj(), true);
self.emit(Opcode::Dup, &[]);
self.compile_expr(field.field(), true);
self.emit(Opcode::Swap, &[]);
self.emit(Opcode::GetPropertyByValue, &[]);
}
expr => {
self.emit(Opcode::This, &[]);
self.compile_expr(expr, true);
}
}
self.emit(Opcode::Call, &[call.args().len() as u32]);

if !use_expr {
self.emit(Opcode::Pop, &[]);
}
}
expr => todo!("TODO compile: {}", expr),
}
}
Expand Down Expand Up @@ -767,11 +800,107 @@ impl ByteCompiler {

self.pop_switch_control_info();
}
Node::FunctionDecl(_function) => self.function(node, false),
Node::Return(ret) => {
if let Some(expr) = ret.expr() {
self.compile_expr(expr, true);
} else {
self.emit(Opcode::PushUndefined, &[]);
}
self.emit(Opcode::Return, &[]);
}
Node::Empty => {}
expr => self.compile_expr(expr, use_expr),
}
}

pub(crate) fn function(&mut self, function: &Node, use_expr: bool) {
#[derive(Debug, Clone, Copy, PartialEq)]
enum FunctionKind {
Declaration,
Expression,
Arrow,
}

let (kind, name, paramaters, body) = match function {
Node::FunctionDecl(function) => (
FunctionKind::Declaration,
Some(function.name()),
function.parameters(),
function.body(),
),
Node::FunctionExpr(function) => (
FunctionKind::Expression,
function.name(),
function.parameters(),
function.body(),
),
Node::ArrowFunctionDecl(function) => (
FunctionKind::Arrow,
None,
function.params(),
function.body(),
),
_ => unreachable!(),
};

let length = paramaters.len() as u32;
let mut code = CodeBlock::new(name.unwrap_or("").into(), length, false, true);

if let FunctionKind::Arrow = kind {
code.constructable = false;
code.this_mode = ThisMode::Lexical;
}

let mut compiler = ByteCompiler {
code_block: code,
literals_map: HashMap::new(),
names_map: HashMap::new(),
functions_map: HashMap::new(),
jump_info: Vec::new(),
top_level: false,
};

for node in body {
compiler.compile_stmt(node, false);
}

compiler.code_block.params = paramaters.to_owned().into_boxed_slice();

compiler.emit(Opcode::PushUndefined, &[]);
compiler.emit(Opcode::Return, &[]);

let code = Gc::new(compiler.finish());

let index = self.code_block.functions.len() as u32;
self.code_block.functions.push(code);

self.emit(Opcode::GetFunction, &[index]);

match kind {
FunctionKind::Declaration => {
let index = self.get_or_insert_name(name.unwrap());
let access = Access::Variable { index };
self.access_set(access, None, false);
}
FunctionKind::Expression => {
if use_expr && name.is_some() {
self.emit(Opcode::Dup, &[]);
}
if let Some(name) = name {
let index = self.get_or_insert_name(name);
let access = Access::Variable { index };
self.access_set(access, None, false);
}
}
FunctionKind::Arrow => {
if !use_expr {
self.emit(Opcode::Pop, &[]);
}
}
}
}

#[inline]
pub fn finish(self) -> CodeBlock {
self.code_block
Expand Down

0 comments on commit 5d70616

Please sign in to comment.