1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 18:37:35 +00:00

LibJS/Bytecode: Add support for direct eval()

This is implemented as a special mode of the Call opcode that invokes
the PerformEval AO (instead of the Call or Construct AO).
This commit is contained in:
Andreas Kling 2023-06-15 13:16:01 +02:00
parent 8a3e350321
commit 2ac8a4bbb7
3 changed files with 25 additions and 4 deletions

View file

@ -1379,6 +1379,8 @@ Bytecode::CodeGenerationErrorOr<void> CallExpression::generate_bytecode(Bytecode
Bytecode::Op::Call::CallType call_type;
if (is<NewExpression>(*this)) {
call_type = Bytecode::Op::Call::CallType::Construct;
} else if (m_callee->is_identifier() && static_cast<Identifier const&>(*m_callee).string() == "eval"sv) {
call_type = Bytecode::Op::Call::CallType::DirectEval;
} else {
call_type = Bytecode::Op::Call::CallType::Call;
}

View file

@ -661,7 +661,12 @@ ThrowCompletionOr<void> Call::execute_impl(Bytecode::Interpreter& interpreter) c
auto argument_values = argument_list_evaluation(interpreter);
Value return_value;
if (m_type == CallType::Call)
if (m_type == CallType::DirectEval) {
if (callee == interpreter.realm().intrinsics().eval_function())
return_value = TRY(perform_eval(vm, argument_values[0].value_or(JS::js_undefined()), vm.in_strict_mode() ? CallerMode::Strict : CallerMode::NonStrict, EvalMode::Direct));
else
return_value = TRY(call(vm, function, this_value, move(argument_values)));
} else if (m_type == CallType::Call)
return_value = TRY(call(vm, function, this_value, move(argument_values)));
else
return_value = TRY(construct(vm, function, move(argument_values)));
@ -1239,10 +1244,23 @@ DeprecatedString JumpUndefined::to_deprecated_string_impl(Bytecode::Executable c
DeprecatedString Call::to_deprecated_string_impl(Bytecode::Executable const& executable) const
{
if (m_expression_string.has_value())
return DeprecatedString::formatted("Call callee:{}, this:{}, arguments:[...acc] ({})", m_callee, m_this_value, executable.get_string(m_expression_string.value()));
StringView type;
switch (m_type) {
case Call::CallType::Call:
type = ""sv;
break;
case Call::CallType::Construct:
type = " (Construct)"sv;
break;
case Call::CallType::DirectEval:
type = " (DirectEval)"sv;
break;
}
return DeprecatedString::formatted("Call callee:{}, this:{}, arguments:[...acc]", m_callee, m_this_value);
if (m_expression_string.has_value())
return DeprecatedString::formatted("Call{} callee:{}, this:{}, arguments:[...acc] ({})", type, m_callee, m_this_value, executable.get_string(m_expression_string.value()));
return DeprecatedString::formatted("Call{} callee:{}, this:{}, arguments:[...acc]", type, m_callee, m_this_value);
}
DeprecatedString SuperCall::to_deprecated_string_impl(Bytecode::Executable const&) const

View file

@ -714,6 +714,7 @@ public:
enum class CallType {
Call,
Construct,
DirectEval,
};
Call(CallType type, Register callee, Register this_value, Optional<StringTableIndex> expression_string = {})