diff --git a/Libraries/LibWeb/WebIDL/CachedAttribute.h b/Libraries/LibWeb/WebIDL/CachedAttribute.h new file mode 100644 index 00000000000..373f1a5d8be --- /dev/null +++ b/Libraries/LibWeb/WebIDL/CachedAttribute.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2025, Idan Horowitz + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#define DEFINE_CACHED_ATTRIBUTE(name) \ + GC::Ptr cached_##name() const { return m_cached_##name; } \ + void set_cached_##name(GC::Ptr cached_##name) { m_cached_##name = cached_##name; } \ + \ +private: \ + GC::Ptr m_cached_##name; \ + \ +public: + +#define VISIT_CACHED_ATTRIBUTE(name) visitor.visit(m_cached_##name) diff --git a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp index 93a97443ca8..58f102c4c49 100644 --- a/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp +++ b/Meta/Lagom/Tools/CodeGenerators/LibWeb/BindingsGenerator/IDLGenerators.cpp @@ -3924,6 +3924,17 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.getter_callback@) [[maybe_unused]] auto* impl = TRY(impl_from(vm)); )~~~"); + auto cache_result = false; + if (attribute.extended_attributes.contains("CachedAttribute")) { + VERIFY(attribute.readonly); + cache_result = true; + attribute_generator.append(R"~~~( + auto cached_@attribute.cpp_name@ = impl->cached_@attribute.cpp_name@(); + if (cached_@attribute.cpp_name@) + return cached_@attribute.cpp_name@; +)~~~"); + } + if (attribute.extended_attributes.contains("CEReactions")) { // 1. Push a new element queue onto this object's relevant agent's custom element reactions stack. attribute_generator.append(R"~~~( @@ -4268,7 +4279,15 @@ JS_DEFINE_NATIVE_FUNCTION(@class_name@::@attribute.getter_callback@) )~~~"); } - generate_return_statement(generator, *attribute.type, interface); + if (cache_result) { + generate_wrap_statement(generator, "retval", *attribute.type, interface, ByteString::formatted("cached_{} =", attribute_generator.get("attribute.cpp_name"))); + attribute_generator.append(R"~~~( + impl->set_cached_@attribute.cpp_name@(cached_@attribute.cpp_name@); + return cached_@attribute.cpp_name@; +)~~~"); + } else { + generate_return_statement(generator, *attribute.type, interface); + } if (generated_reflected_element_array) { // 3. Let elementsAsFrozenArray be elements, converted to a FrozenArray?.