Browse Source

Fix `this` in function calls (#2153)

This Pull Request changes the following:

- Fix the `this` value that is passend to function calls to be `undefined` if the function is not a property reference
- Add special handling for setting the `this` value for function calls where the function is a private property reference or a super property reference
pull/2156/head
raskad 2 years ago
parent
commit
aaeee43c4f
  1. 27
      boa_engine/src/bytecompiler.rs
  2. 24
      boa_engine/src/vm/mod.rs

27
boa_engine/src/bytecompiler.rs

@ -2162,10 +2162,35 @@ impl<'b> ByteCompiler<'b> {
self.emit(Opcode::Swap, &[]);
self.emit(Opcode::GetPropertyByValue, &[]);
}
Node::GetSuperField(get_super_field) => {
if kind == CallKind::Call {
self.emit_opcode(Opcode::This);
}
self.emit_opcode(Opcode::Super);
match get_super_field {
GetSuperField::Const(field) => {
let index = self.get_or_insert_name(*field);
self.emit(Opcode::GetPropertyByName, &[index]);
}
GetSuperField::Expr(expr) => {
self.compile_expr(expr, true)?;
self.emit_opcode(Opcode::Swap);
self.emit_opcode(Opcode::GetPropertyByValue);
}
}
}
Node::GetPrivateField(get_private_field) => {
self.compile_expr(get_private_field.obj(), true)?;
if kind == CallKind::Call {
self.emit(Opcode::Dup, &[]);
}
let index = self.get_or_insert_name(get_private_field.field());
self.emit(Opcode::GetPrivateField, &[index]);
}
expr => {
self.compile_expr(expr, true)?;
if kind == CallKind::Call || kind == CallKind::CallEval {
self.emit_opcode(Opcode::This);
self.emit_opcode(Opcode::PushUndefined);
self.emit_opcode(Opcode::Swap);
}
}

24
boa_engine/src/vm/mod.rs

@ -1707,17 +1707,13 @@ impl Context {
arguments.reverse();
let func = self.vm.pop();
let mut this = self.vm.pop();
let this = self.vm.pop();
let object = match func {
JsValue::Object(ref object) if object.is_callable() => object.clone(),
_ => return self.throw_type_error("not a callable function"),
};
if this.is_null_or_undefined() {
this = self.global_object().clone().into();
}
// A native function with the name "eval" implies, that is this the built-in eval function.
let eval = matches!(object.borrow().as_function(), Some(Function::Native { .. }));
@ -1748,7 +1744,7 @@ impl Context {
}
arguments.reverse();
let func = self.vm.pop();
let mut this = self.vm.pop();
let this = self.vm.pop();
let iterator_record = rest_argument.get_iterator(self, None, None)?;
let mut rest_arguments = Vec::new();
@ -1762,10 +1758,6 @@ impl Context {
_ => return self.throw_type_error("not a callable function"),
};
if this.is_null_or_undefined() {
this = self.global_object().clone().into();
}
// A native function with the name "eval" implies, that is this the built-in eval function.
let eval = matches!(object.borrow().as_function(), Some(Function::Native { .. }));
@ -1796,17 +1788,13 @@ impl Context {
arguments.reverse();
let func = self.vm.pop();
let mut this = self.vm.pop();
let this = self.vm.pop();
let object = match func {
JsValue::Object(ref object) if object.is_callable() => object.clone(),
_ => return self.throw_type_error("not a callable function"),
};
if this.is_null_or_undefined() {
this = self.global_object().clone().into();
}
let result = object.__call__(&this, &arguments, self)?;
self.vm.push(result);
@ -1823,7 +1811,7 @@ impl Context {
}
arguments.reverse();
let func = self.vm.pop();
let mut this = self.vm.pop();
let this = self.vm.pop();
let iterator_record = rest_argument.get_iterator(self, None, None)?;
let mut rest_arguments = Vec::new();
@ -1837,10 +1825,6 @@ impl Context {
_ => return self.throw_type_error("not a callable function"),
};
if this.is_null_or_undefined() {
this = self.global_object().clone().into();
}
let result = object.__call__(&this, &arguments, self)?;
self.vm.push(result);

Loading…
Cancel
Save