Skip to content

Commit

Permalink
js: Implement object creation in bytecode
Browse files Browse the repository at this point in the history
  • Loading branch information
simonwuelker committed Mar 28, 2024
1 parent 5e17327 commit c9014d2
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 5 deletions.
16 changes: 15 additions & 1 deletion crates/js/src/bytecode/builder.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::{BasicBlock, BasicBlockExit, Instruction, Program};
use crate::Value;
use crate::{value::object, Value};

#[derive(Clone, Copy, Debug)]
pub struct Register(usize);
Expand Down Expand Up @@ -296,4 +296,18 @@ impl<'a> BasicBlockBuilder<'a> {
if_false,
}
}

pub fn create_data_property_or_throw(
&mut self,
object: Register,
property_key: object::PropertyKey,
property_value: Register,
) {
let instruction = Instruction::CreateDataPropertyOrThrow {
object,
property_key,
property_value,
};
self.push_instruction(instruction);
}
}
7 changes: 6 additions & 1 deletion crates/js/src/bytecode/instruction.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::Register;
use crate::Value;
use crate::{value::object, Value};

#[derive(Clone, Copy, Debug)]
pub struct VariableHandle(usize);
Expand Down Expand Up @@ -141,4 +141,9 @@ pub enum Instruction {
Throw {
value: Register,
},
CreateDataPropertyOrThrow {
object: Register,
property_key: object::PropertyKey,
property_value: Register,
},
}
28 changes: 27 additions & 1 deletion crates/js/src/bytecode/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::HashMap;
use super::{
BasicBlock, BasicBlockExit, Exception, Instruction, Program, Register, ThrowCompletionOr,
};
use crate::Value;
use crate::{value::Object, Value};

#[derive(Clone, Debug, Default)]
pub struct Vm {
Expand Down Expand Up @@ -65,6 +65,11 @@ impl Vm {
&self.registers[register.index()]
}

#[must_use]
fn register_mut(&mut self, register: Register) -> &mut Value {
&mut self.registers[register.index()]
}

fn set_register(&mut self, register: Register, value: Value) {
self.registers[register.index()] = value;
}
Expand Down Expand Up @@ -115,6 +120,27 @@ impl Vm {
let value = self.register(*value).clone();
return Err(Exception::new(value));
},
Instruction::CreateDataPropertyOrThrow {
object,
property_key,
property_value,
} => {
// https://262.ecma-international.org/14.0/#sec-createdatapropertyorthrow
let property_value = self.register(*property_value).clone();

let Value::Object(object) = self.register_mut(*object) else {
panic!("Cannot create property on non-object");
};

// 1. Let success be ? CreateDataProperty(O, P, V).
let success = Object::create_data_property(object, property_key, property_value)?;

// 2. If success is false, throw a TypeError exception.
if !success {
// FIXME: This should be a TypeError
return Err(Exception::new(Value::Null));
}
},
other => todo!("Implement instruction {other:?}"),
}

Expand Down
43 changes: 41 additions & 2 deletions crates/js/src/parser/expressions/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::{
tokenization::{Punctuator, SkipLineTerminators, Token, Tokenizer},
SyntaxError,
},
value::{object::PropertyKey, Object},
};

/// <https://262.ecma-international.org/14.0/#prod-ObjectLiteral>
Expand Down Expand Up @@ -75,7 +76,45 @@ impl CompileToBytecode for ObjectLiteral {
type Result = bytecode::Register;

fn compile(&self, builder: &mut bytecode::ProgramBuilder) -> Self::Result {
_ = builder;
todo!()
let object = builder
.get_current_block()
.allocate_register_with_value(Object::default().into());

for property_definition in &self.property_definitions {
let property_register = property_definition.compile(builder);
builder.get_current_block().create_data_property_or_throw(
object,
PropertyKey::String(property_register.name),
property_register.value,
);
}

object
}
}

#[derive(Debug)]
struct PropertyToBeCreated {
name: String,
value: bytecode::Register,
}

impl CompileToBytecode for PropertyDefinition {
type Result = PropertyToBeCreated;

fn compile(&self, builder: &mut bytecode::ProgramBuilder) -> Self::Result {
let mut builder = builder.get_current_block();

match self {
Self::IdentifierRef(identifier_reference) => {
let expr_value = builder.allocate_register();
builder.load_variable(identifier_reference.clone(), expr_value);

PropertyToBeCreated {
name: identifier_reference.clone(),
value: expr_value,
}
},
}
}
}
12 changes: 12 additions & 0 deletions crates/js/src/value/object/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ mod vtable;

use crate::bytecode::{Exception, ThrowCompletionOr};

use self::vtable::ObjectMethods;

use super::Value;

use std::{collections::HashMap, fmt, ptr};
Expand Down Expand Up @@ -239,3 +241,13 @@ impl fmt::Debug for Object {
.finish()
}
}

impl Default for Object {
fn default() -> Self {
Self {
extensible: true,
properties: HashMap::default(),
methods: ObjectMethods::ORDINARY,
}
}
}

0 comments on commit c9014d2

Please sign in to comment.