ladybird/Libraries/LibWeb/HTML/Location.h
Andreas Kling 183c847c80
Some checks are pending
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (arm64, macos-15, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (x86_64, ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
LibJS: Cache PutById to setters in the prototype chain
This is *extremely* common on the web, but barely shows up at all in
JavaScript benchmarks.

A typical example is setting Element.innerHTML on a HTMLDivElement.
HTMLDivElement doesn't have innerHTML, so it has to travel up the
prototype chain until it finds it.

Before this change, we didn't cache this at all, so we had to travel
the prototype chain every time a setter like this was used.

We now use the same mechanism we already had for GetBydId and cache
PutById setter accesses in the prototype chain as well.

1.74x speedup on MicroBench/setter-in-prototype-chain.js
2025-05-05 15:21:43 +02:00

93 lines
4 KiB
C++

/*
* Copyright (c) 2020, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibJS/Forward.h>
#include <LibJS/Runtime/Completion.h>
#include <LibURL/URL.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Forward.h>
#include <LibWeb/HTML/CrossOrigin/CrossOriginPropertyDescriptorMap.h>
#include <LibWeb/HTML/Navigable.h>
namespace Web::HTML {
class Location final : public Bindings::PlatformObject {
WEB_PLATFORM_OBJECT(Location, Bindings::PlatformObject);
GC_DECLARE_ALLOCATOR(Location);
public:
virtual ~Location() override;
WebIDL::ExceptionOr<String> href() const;
WebIDL::ExceptionOr<void> set_href(String const&);
WebIDL::ExceptionOr<String> origin() const;
WebIDL::ExceptionOr<String> protocol() const;
WebIDL::ExceptionOr<void> set_protocol(String const&);
WebIDL::ExceptionOr<String> host() const;
WebIDL::ExceptionOr<void> set_host(String const&);
WebIDL::ExceptionOr<String> hostname() const;
WebIDL::ExceptionOr<void> set_hostname(String const&);
WebIDL::ExceptionOr<String> port() const;
WebIDL::ExceptionOr<void> set_port(String const&);
WebIDL::ExceptionOr<String> pathname() const;
WebIDL::ExceptionOr<void> set_pathname(String const&);
WebIDL::ExceptionOr<String> search() const;
WebIDL::ExceptionOr<void> set_search(String const&);
WebIDL::ExceptionOr<String> hash() const;
WebIDL::ExceptionOr<void> set_hash(StringView);
WebIDL::ExceptionOr<void> replace(String const& url);
void reload() const;
WebIDL::ExceptionOr<void> assign(String const& url);
virtual JS::ThrowCompletionOr<JS::Object*> internal_get_prototype_of() const override;
virtual JS::ThrowCompletionOr<bool> internal_set_prototype_of(Object* prototype) override;
virtual JS::ThrowCompletionOr<bool> internal_is_extensible() const override;
virtual JS::ThrowCompletionOr<bool> internal_prevent_extensions() override;
virtual JS::ThrowCompletionOr<Optional<JS::PropertyDescriptor>> internal_get_own_property(JS::PropertyKey const&) const override;
virtual JS::ThrowCompletionOr<bool> internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&, Optional<JS::PropertyDescriptor>* precomputed_get_own_property = nullptr) override;
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) const override;
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata*, PropertyLookupPhase) override;
virtual JS::ThrowCompletionOr<bool> internal_delete(JS::PropertyKey const&) override;
virtual JS::ThrowCompletionOr<GC::RootVector<JS::Value>> internal_own_property_keys() const override;
HTML::CrossOriginPropertyDescriptorMap const& cross_origin_property_descriptor_map() const { return m_cross_origin_property_descriptor_map; }
HTML::CrossOriginPropertyDescriptorMap& cross_origin_property_descriptor_map() { return m_cross_origin_property_descriptor_map; }
private:
explicit Location(JS::Realm&);
virtual bool is_html_location() const override { return true; }
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;
GC::Ptr<DOM::Document> relevant_document() const;
URL::URL url() const;
WebIDL::ExceptionOr<void> navigate(URL::URL, Bindings::NavigationHistoryBehavior = Bindings::NavigationHistoryBehavior::Auto);
// [[CrossOriginPropertyDescriptorMap]], https://html.spec.whatwg.org/multipage/browsers.html#crossoriginpropertydescriptormap
HTML::CrossOriginPropertyDescriptorMap m_cross_origin_property_descriptor_map;
// [[DefaultProperties]], https://html.spec.whatwg.org/multipage/history.html#defaultproperties
Vector<JS::Value> m_default_properties;
};
}
template<>
inline bool JS::Object::fast_is<Web::HTML::Location>() const { return is_html_location(); }