mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-02 15:46:33 +00:00
LibJS+LibWeb: Set [[CanBlock]] false to Agent for window agent
similar-origin window agents have the [[CanBlock]] flag set to false. Achieve this by hooking up JS's concept with an agent to HTML::Agent. For now, this is only hooked up to the similar-origin window agent case but should be extended to the other agent types in the future.
This commit is contained in:
parent
4cd186f3f5
commit
e124ef52ee
Notes:
github-actions[bot]
2025-04-22 15:52:53 +00:00
Author: https://github.com/shannonbooth
Commit: e124ef52ee
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4406
16 changed files with 106 additions and 44 deletions
|
@ -154,6 +154,7 @@ namespace JS {
|
|||
|
||||
class ASTNode;
|
||||
class Accessor;
|
||||
class Agent;
|
||||
struct AsyncGeneratorRequest;
|
||||
class BigInt;
|
||||
class BoundFunction;
|
||||
|
|
|
@ -1,19 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
||||
* Copyright (c) 2025, Shannon Booth <shannon@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibJS/Runtime/Agent.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
Agent::~Agent() = default;
|
||||
|
||||
// 9.7.2 AgentCanSuspend ( ), https://tc39.es/ecma262/#sec-agentcansuspend
|
||||
bool agent_can_suspend()
|
||||
bool agent_can_suspend(VM const& vm)
|
||||
{
|
||||
// FIXME: 1. Let AR be the Agent Record of the surrounding agent.
|
||||
// FIXME: 2. Return AR.[[CanBlock]].
|
||||
return true;
|
||||
// 1. Let AR be the Agent Record of the surrounding agent.
|
||||
auto const* agent = vm.agent();
|
||||
|
||||
// 2. Return AR.[[CanBlock]].
|
||||
// NOTE: We default to true if no agent has been provided (standalone LibJS with no embedder).
|
||||
if (!agent)
|
||||
return true;
|
||||
return agent->can_block();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,13 +1,29 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Tim Flynn <trflynn89@serenityos.org>
|
||||
* Copyright (c) 2025, Shannon Booth <shannon@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibGC/Function.h>
|
||||
#include <LibGC/Root.h>
|
||||
#include <LibJS/Forward.h>
|
||||
|
||||
namespace JS {
|
||||
|
||||
bool agent_can_suspend();
|
||||
// https://tc39.es/ecma262/#sec-agents
|
||||
class Agent {
|
||||
public:
|
||||
virtual ~Agent();
|
||||
|
||||
// [[CanBlock]]
|
||||
virtual bool can_block() const = 0;
|
||||
|
||||
virtual void spin_event_loop_until(GC::Root<GC::Function<bool()>> goal_condition) = 0;
|
||||
};
|
||||
|
||||
bool agent_can_suspend(VM const&);
|
||||
|
||||
}
|
||||
|
|
|
@ -186,7 +186,7 @@ static ThrowCompletionOr<Value> do_wait(VM& vm, WaitMode mode, TypedArrayBase& t
|
|||
timeout = max(timeout_number.as_double(), 0.0);
|
||||
|
||||
// 10. If mode is sync and AgentCanSuspend() is false, throw a TypeError exception.
|
||||
if (mode == WaitMode::Sync && !agent_can_suspend())
|
||||
if (mode == WaitMode::Sync && !agent_can_suspend(vm))
|
||||
return vm.throw_completion<TypeError>(ErrorType::AgentCannotSuspend);
|
||||
|
||||
// FIXME: Implement the remaining steps when we support SharedArrayBuffer.
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibJS/Runtime/Agent.h>
|
||||
#include <LibJS/Runtime/Completion.h>
|
||||
#include <LibJS/Runtime/NativeFunction.h>
|
||||
#include <LibJS/Runtime/Promise.h>
|
||||
|
@ -98,9 +99,9 @@ ThrowCompletionOr<Value> await(VM& vm, Value value)
|
|||
|
||||
// FIXME: Since we don't support context suspension, we attempt to "wait" for the promise to resolve
|
||||
// by syncronously running all queued promise jobs.
|
||||
if (auto* custom_data = vm.custom_data()) {
|
||||
if (auto* agent = vm.agent()) {
|
||||
// Embedder case (i.e. LibWeb). Runs all promise jobs by performing a microtask checkpoint.
|
||||
custom_data->spin_event_loop_until(GC::create_function(vm.heap(), [success] {
|
||||
agent->spin_event_loop_until(GC::create_function(vm.heap(), [success] {
|
||||
return success.has_value();
|
||||
}));
|
||||
} else {
|
||||
|
|
|
@ -37,12 +37,12 @@
|
|||
|
||||
namespace JS {
|
||||
|
||||
ErrorOr<NonnullRefPtr<VM>> VM::create(OwnPtr<CustomData> custom_data)
|
||||
ErrorOr<NonnullRefPtr<VM>> VM::create(OwnPtr<Agent> agent)
|
||||
{
|
||||
ErrorMessages error_messages {};
|
||||
error_messages[to_underlying(ErrorMessage::OutOfMemory)] = ErrorType::OutOfMemory.message();
|
||||
|
||||
auto vm = adopt_ref(*new VM(move(custom_data), move(error_messages)));
|
||||
auto vm = adopt_ref(*new VM(move(agent), move(error_messages)));
|
||||
|
||||
WellKnownSymbols well_known_symbols {
|
||||
#define __JS_ENUMERATE(SymbolName, snake_name) \
|
||||
|
@ -63,12 +63,12 @@ static constexpr auto make_single_ascii_character_strings(IndexSequence<code_poi
|
|||
|
||||
static constexpr auto single_ascii_character_strings = make_single_ascii_character_strings(MakeIndexSequence<128>());
|
||||
|
||||
VM::VM(OwnPtr<CustomData> custom_data, ErrorMessages error_messages)
|
||||
VM::VM(OwnPtr<Agent> agent, ErrorMessages error_messages)
|
||||
: m_heap(this, [this](HashMap<GC::Cell*, GC::HeapRoot>& roots) {
|
||||
gather_roots(roots);
|
||||
})
|
||||
, m_error_messages(move(error_messages))
|
||||
, m_custom_data(move(custom_data))
|
||||
, m_agent(move(agent))
|
||||
{
|
||||
m_bytecode_interpreter = make<Bytecode::Interpreter>(*this);
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <LibGC/RootVector.h>
|
||||
#include <LibJS/CyclicModule.h>
|
||||
#include <LibJS/ModuleLoading.h>
|
||||
#include <LibJS/Runtime/Agent.h>
|
||||
#include <LibJS/Runtime/CommonPropertyNames.h>
|
||||
#include <LibJS/Runtime/Completion.h>
|
||||
#include <LibJS/Runtime/Error.h>
|
||||
|
@ -46,13 +47,7 @@ enum class EvalMode {
|
|||
|
||||
class VM : public RefCounted<VM> {
|
||||
public:
|
||||
struct CustomData {
|
||||
virtual ~CustomData() = default;
|
||||
|
||||
virtual void spin_event_loop_until(GC::Root<GC::Function<bool()>> goal_condition) = 0;
|
||||
};
|
||||
|
||||
static ErrorOr<NonnullRefPtr<VM>> create(OwnPtr<CustomData> = {});
|
||||
static ErrorOr<NonnullRefPtr<VM>> create(OwnPtr<Agent> = {});
|
||||
~VM();
|
||||
|
||||
GC::Heap& heap() { return m_heap; }
|
||||
|
@ -245,7 +240,8 @@ public:
|
|||
Function<void(Promise&)> on_promise_rejection_handled;
|
||||
Function<void(Object const&, PropertyKey const&)> on_unimplemented_property_access;
|
||||
|
||||
CustomData* custom_data() { return m_custom_data; }
|
||||
Agent* agent() { return m_agent; }
|
||||
Agent const* agent() const { return m_agent; }
|
||||
|
||||
void save_execution_context_stack();
|
||||
void clear_execution_context_stack();
|
||||
|
@ -294,7 +290,7 @@ private:
|
|||
#undef __JS_ENUMERATE
|
||||
};
|
||||
|
||||
VM(OwnPtr<CustomData>, ErrorMessages);
|
||||
VM(OwnPtr<Agent>, ErrorMessages);
|
||||
|
||||
void load_imported_module(ImportedModuleReferrer, ModuleRequest const&, GC::Ptr<GraphLoadingState::HostDefined>, ImportedModulePayload);
|
||||
ThrowCompletionOr<void> link_and_eval_module(CyclicModule&);
|
||||
|
@ -339,7 +335,7 @@ private:
|
|||
|
||||
u32 m_execution_generation { 0 };
|
||||
|
||||
OwnPtr<CustomData> m_custom_data;
|
||||
OwnPtr<Agent> m_agent;
|
||||
|
||||
OwnPtr<Bytecode::Interpreter> m_bytecode_interpreter;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue