mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 17:27:35 +00:00
LibJS/Bytecode: Extract accumulator value before incurring side effects
Many operations in JavaScript may incur side effects, including calling arbitrary user code. Since the user code will clobber the accumulator, we have to take care to extract anything we need from the accumulator before doing anything that may have side effects. Fixes 3 test262 tests. :^)
This commit is contained in:
parent
c30775522e
commit
82828ad936
1 changed files with 21 additions and 10 deletions
|
@ -48,10 +48,8 @@ DeprecatedString Instruction::to_deprecated_string(Bytecode::Executable const& e
|
|||
|
||||
namespace JS::Bytecode::Op {
|
||||
|
||||
static ThrowCompletionOr<void> put_by_property_key(Object* object, Value value, PropertyKey name, Bytecode::Interpreter& interpreter, PropertyKind kind)
|
||||
static ThrowCompletionOr<void> put_by_property_key(VM& vm, Object* object, Value value, PropertyKey name, PropertyKind kind)
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
|
||||
if (kind == PropertyKind::Getter || kind == PropertyKind::Setter) {
|
||||
// The generator should only pass us functions for getters and setters.
|
||||
VERIFY(value.is_function());
|
||||
|
@ -72,9 +70,9 @@ static ThrowCompletionOr<void> put_by_property_key(Object* object, Value value,
|
|||
break;
|
||||
}
|
||||
case PropertyKind::KeyValue: {
|
||||
bool succeeded = TRY(object->internal_set(name, interpreter.accumulator(), object));
|
||||
bool succeeded = TRY(object->internal_set(name, value, object));
|
||||
if (!succeeded && vm.in_strict_mode())
|
||||
return vm.throw_completion<TypeError>(ErrorType::ReferenceNullishSetProperty, name, TRY_OR_THROW_OOM(vm, interpreter.accumulator().to_string_without_side_effects()));
|
||||
return vm.throw_completion<TypeError>(ErrorType::ReferenceNullishSetProperty, name, TRY_OR_THROW_OOM(vm, value.to_string_without_side_effects()));
|
||||
break;
|
||||
}
|
||||
case PropertyKind::Spread:
|
||||
|
@ -517,10 +515,11 @@ ThrowCompletionOr<void> GetById::execute_impl(Bytecode::Interpreter& interpreter
|
|||
ThrowCompletionOr<void> PutById::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
// NOTE: Get the value from the accumulator before side effects have a chance to overwrite it.
|
||||
auto value = interpreter.accumulator();
|
||||
auto object = TRY(interpreter.reg(m_base).to_object(vm));
|
||||
PropertyKey name = interpreter.current_executable().get_identifier(m_property);
|
||||
auto value = interpreter.accumulator();
|
||||
return put_by_property_key(object, value, name, interpreter, m_kind);
|
||||
return put_by_property_key(vm, object, value, name, m_kind);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> DeleteById::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
|
@ -903,9 +902,13 @@ void Yield::replace_references_impl(BasicBlock const& from, BasicBlock const& to
|
|||
ThrowCompletionOr<void> GetByValue::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
|
||||
// NOTE: Get the property key from the accumulator before side effects have a chance to overwrite it.
|
||||
auto property_key_value = interpreter.accumulator();
|
||||
|
||||
auto object = TRY(interpreter.reg(m_base).to_object(vm));
|
||||
|
||||
auto property_key = TRY(interpreter.accumulator().to_property_key(vm));
|
||||
auto property_key = TRY(property_key_value.to_property_key(vm));
|
||||
|
||||
interpreter.accumulator() = TRY(object->get(property_key));
|
||||
return {};
|
||||
|
@ -914,17 +917,25 @@ ThrowCompletionOr<void> GetByValue::execute_impl(Bytecode::Interpreter& interpre
|
|||
ThrowCompletionOr<void> PutByValue::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
|
||||
// NOTE: Get the value from the accumulator before side effects have a chance to overwrite it.
|
||||
auto value = interpreter.accumulator();
|
||||
|
||||
auto object = TRY(interpreter.reg(m_base).to_object(vm));
|
||||
|
||||
auto property_key = TRY(interpreter.reg(m_property).to_property_key(vm));
|
||||
return put_by_property_key(object, interpreter.accumulator(), property_key, interpreter, m_kind);
|
||||
return put_by_property_key(vm, object, value, property_key, m_kind);
|
||||
}
|
||||
|
||||
ThrowCompletionOr<void> DeleteByValue::execute_impl(Bytecode::Interpreter& interpreter) const
|
||||
{
|
||||
auto& vm = interpreter.vm();
|
||||
|
||||
// NOTE: Get the property key from the accumulator before side effects have a chance to overwrite it.
|
||||
auto property_key_value = interpreter.accumulator();
|
||||
|
||||
auto object = TRY(interpreter.reg(m_base).to_object(vm));
|
||||
auto property_key = TRY(interpreter.accumulator().to_property_key(vm));
|
||||
auto property_key = TRY(property_key_value.to_property_key(vm));
|
||||
bool strict = vm.in_strict_mode();
|
||||
auto reference = Reference { object, property_key, {}, strict };
|
||||
interpreter.accumulator() = Value(TRY(reference.delete_(vm)));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue