diff --git a/boa/src/vm/mod.rs b/boa/src/vm/mod.rs index da9a0876c80..a9f0d2d57c7 100644 --- a/boa/src/vm/mod.rs +++ b/boa/src/vm/mod.rs @@ -78,162 +78,93 @@ impl<'a> VM<'a> { let _timer = BoaProfiler::global().start_event(&self.instructions[self.idx].to_string(), "vm"); - match self.instructions[self.idx] { - Instruction::Undefined => self.push(Value::undefined()), - Instruction::Null => self.push(Value::null()), - Instruction::True => self.push(Value::boolean(true)), - Instruction::False => self.push(Value::boolean(false)), - Instruction::Zero => self.push(Value::integer(0)), - Instruction::One => self.push(Value::integer(1)), - Instruction::Int32(i) => self.push(Value::integer(i)), - Instruction::Rational(r) => self.push(Value::rational(r)), - Instruction::String(index) => { - let value = self.pool[index].clone(); - self.push(value) - } - Instruction::BigInt(index) => { - let value = self.pool[index].clone(); - self.push(value) - } - Instruction::Add => { + + macro_rules! binop { + ($e:ident) => {{ let r = self.pop(); let l = self.pop(); - let val = l.add(&r, self.ctx)?; - - self.push(val); + let val = l.$e(&r, self.ctx)?; + Some(val.into()) + }}; + } + let result = match self.instructions[self.idx] { + Instruction::Undefined => Some(Value::undefined()), + Instruction::Null => Some(Value::null()), + Instruction::True => Some(Value::boolean(true)), + Instruction::False => Some(Value::boolean(false)), + Instruction::Zero => Some(Value::integer(0)), + Instruction::One => Some(Value::integer(1)), + Instruction::Int32(i) => Some(Value::integer(i)), + Instruction::Rational(r) => Some(Value::rational(r)), + Instruction::String(index) => Some(self.pool[index].clone()), + Instruction::BigInt(index) => Some(self.pool[index].clone()), + Instruction::Add => { + binop!(add) } Instruction::Sub => { - let r = self.pop(); - let l = self.pop(); - let val = l.sub(&r, self.ctx)?; - - self.push(val); + binop!(sub) } Instruction::Mul => { - let r = self.pop(); - let l = self.pop(); - let val = l.mul(&r, self.ctx)?; - - self.push(val); + binop!(mul) } Instruction::Div => { - let r = self.pop(); - let l = self.pop(); - let val = l.div(&r, self.ctx)?; - - self.push(val); + binop!(div) } Instruction::Pow => { - let r = self.pop(); - let l = self.pop(); - let val = l.pow(&r, self.ctx)?; - - self.push(val); + binop!(pow) } Instruction::Mod => { - let r = self.pop(); - let l = self.pop(); - let val = l.rem(&r, self.ctx)?; - - self.push(val); + binop!(rem) } Instruction::BitAnd => { - let r = self.pop(); - let l = self.pop(); - let val = l.bitand(&r, self.ctx)?; - - self.push(val); + binop!(bitand) } Instruction::BitOr => { - let r = self.pop(); - let l = self.pop(); - let val = l.bitor(&r, self.ctx)?; - - self.push(val); + binop!(bitor) } Instruction::BitXor => { - let r = self.pop(); - let l = self.pop(); - let val = l.bitxor(&r, self.ctx)?; - - self.push(val); + binop!(bitxor) } Instruction::Shl => { - let r = self.pop(); - let l = self.pop(); - let val = l.shl(&r, self.ctx)?; - - self.push(val); + binop!(shl) } Instruction::Shr => { - let r = self.pop(); - let l = self.pop(); - let val = l.shr(&r, self.ctx)?; - - self.push(val); + binop!(shr) } Instruction::UShr => { - let r = self.pop(); - let l = self.pop(); - let val = l.ushr(&r, self.ctx)?; - - self.push(val); + binop!(ushr) } Instruction::Eq => { let r = self.pop(); let l = self.pop(); - let val = l.equals(&r, self.ctx)?; - - self.push(val.into()); + Some((l.equals(&r, self.ctx)?).into()) } Instruction::NotEq => { let r = self.pop(); let l = self.pop(); - let val = !l.equals(&r, self.ctx)?; - - self.push(val.into()); + Some((!l.equals(&r, self.ctx)?).into()) } Instruction::StrictEq => { let r = self.pop(); let l = self.pop(); - let val = l.strict_equals(&r); - - self.push(val.into()); + Some((l.strict_equals(&r)).into()) } Instruction::StrictNotEq => { let r = self.pop(); let l = self.pop(); - let val = !l.strict_equals(&r); - - self.push(val.into()); + Some((!l.strict_equals(&r)).into()) } Instruction::Gt => { - let r = self.pop(); - let l = self.pop(); - let val = l.ge(&r, self.ctx)?; - - self.push(val.into()); + binop!(gt) } Instruction::Ge => { - let r = self.pop(); - let l = self.pop(); - let val = l.ge(&r, self.ctx)?; - - self.push(val.into()); + binop!(ge) } Instruction::Lt => { - let r = self.pop(); - let l = self.pop(); - let val = l.lt(&r, self.ctx)?; - - self.push(val.into()); + binop!(lt) } Instruction::Le => { - let r = self.pop(); - let l = self.pop(); - let val = l.le(&r, self.ctx)?; - - self.push(val.into()); + binop!(le) } Instruction::In => { let r = self.pop(); @@ -246,9 +177,7 @@ impl<'a> VM<'a> { )); } let key = l.to_property_key(self.ctx)?; - let val = self.ctx.has_property(&r, &key); - - self.push(val.into()); + Some(self.ctx.has_property(&r, &key).into()) } Instruction::InstanceOf => { let r = self.pop(); @@ -265,24 +194,24 @@ impl<'a> VM<'a> { } Instruction::Void => { let _value = self.pop(); - self.push(Value::undefined()); + Some(Value::undefined()) } Instruction::TypeOf => { let value = self.pop(); - self.push(value.get_type().as_str().into()); + Some(value.get_type().as_str().into()) } Instruction::Pos => { let value = self.pop(); let value = value.to_number(self.ctx)?; - self.push(value.into()); + Some(value.into()) } Instruction::Neg => { let value = self.pop(); - self.push(Value::from(!value.to_boolean())); + Some(Value::from(!value.to_boolean())) } Instruction::Not => { let value = self.pop(); - self.push((!value.to_boolean()).into()); + Some((!value.to_boolean()).into()) } Instruction::BitNot => { let target = self.pop(); @@ -293,7 +222,7 @@ impl<'a> VM<'a> { // TODO: this is not spec compliant. !(num as i32) }; - self.push(value.into()); + Some(value.into()) } Instruction::DefVar(name_index) => { let name: String = self.pool[name_index].to_string(self.ctx)?.to_string(); @@ -303,6 +232,8 @@ impl<'a> VM<'a> { .environment .create_mutable_binding(name.to_string(), false, VariableScope::Function) .map_err(|e| e.to_error(self.ctx))?; + + None } Instruction::DefLet(name_index) => { let name = self.pool[name_index].to_string(self.ctx)?; @@ -312,6 +243,8 @@ impl<'a> VM<'a> { .environment .create_mutable_binding(name.to_string(), false, VariableScope::Block) .map_err(|e| e.to_error(self.ctx))?; + + None } Instruction::DefConst(name_index) => { let name = self.pool[name_index].to_string(self.ctx)?; @@ -321,6 +254,8 @@ impl<'a> VM<'a> { .environment .create_immutable_binding(name.to_string(), false, VariableScope::Block) .map_err(|e| e.to_error(self.ctx))?; + + None } Instruction::InitLexical(name_index) => { let name = self.pool[name_index].to_string(self.ctx)?; @@ -331,8 +266,11 @@ impl<'a> VM<'a> { .initialize_binding(&name, value.clone()) .map_err(|e| e.to_error(self.ctx))?; - self.push(value); + Some(value) } + }; + if let Some(value) = result { + self.push(value); } self.idx += 1;