Commit graph

667 commits

Author SHA1 Message Date
Andreas Kling
b81269e78b Libraries: Clean up UTF-16 source text paths
Store parser errors, source range filenames, source code filenames,
module source, and Rust parser errors as UTF-16 where they flow back
into JavaScript-visible strings. Keep byte-oriented source buffers
byte-backed.

Remove temporary PrimitiveString, ByteString, and UTF-8 detours from
JSON, RegExp, module debug logging, print formatting, and tests.
2026-06-22 19:51:25 +02:00
Andreas Kling
b6bef6b688 Libraries: Use UTF-16 for JS-visible runtime strings
Produce JS-visible string results as UTF-16 at their source, including
numeric formatting, BigInt and BigFraction formatting, URI encoding,
console formatting, parser errors, regular expression errors, Intl and
Temporal records, LibUnicode locale boundaries, and LibWeb bindings.

Handle fractional radix formatting through the UTF-16 builder view.
2026-06-22 19:51:25 +02:00
Andreas Kling
7025dd1fa7 Libraries: Parse JS strings from UTF-16
Thread UTF-16 string input through JSON, script parsing, Date parsing,
Intl option parsing, Temporal parsing, and the helper library boundaries
that feed those parsers. Preserve ASCII fast paths where the source data
is known to be ASCII.
2026-06-22 19:51:25 +02:00
Andreas Kling
503453eb9c AK: Remove UTF-16 mode from StringBuilder
Remove the UTF-16 storage mode and make StringBuilder solely build
UTF-8 strings again. The remaining UTF-16 adoption path now goes
through Utf16StringBuilder, keeping the direct-adoption optimization
with the type that owns UTF-16 construction.
2026-06-22 16:10:40 +02:00
Andreas Kling
a8193e7572 AK+UI: Stop using StringBuilder UTF-16 mode
Move the remaining call sites that constructed StringBuilder in UTF-16
mode over to Utf16StringBuilder or explicit UTF-8 to UTF-16 conversion.
Teach FormatBuilder to target Utf16StringBuilder directly so formatted
Utf16String construction no longer needs StringBuilder's UTF-16 mode.

Update the Utf16String tests to cover Utf16StringBuilder adoption and
clear behavior directly.
2026-06-22 16:10:40 +02:00
Andreas Kling
bf5f24ab36 AK: Add Utf16StringBuilder formatting helpers
Add vformat support for Utf16StringBuilder and expose appendff and
try_appendff helpers on the builder itself. This lets callers build a
Utf16String on the purpose-built UTF-16 path even when using formatting.

Use the new API for Utf16String::formatted and add AK coverage for
formatting directly into a Utf16StringBuilder.
2026-06-22 16:10:40 +02:00
Andreas Kling
488006d276 AK: Add Utf16StringBuilder
Add a purpose-built builder for constructing Utf16String values.
It keeps ASCII storage while possible, widens to UTF-16 when needed,
and can hand outline storage to Utf16StringData for direct adoption.

Add AK coverage for ASCII strings, UTF-16 widening, code points,
trimming, and long string construction.
2026-06-22 16:10:40 +02:00
Andreas Kling
079af3d120 AK: Remove custom deleters from OwnPtr
OwnPtr now always deletes the owned object directly from clear(). Remove
the unused deleter template parameter and the DefaultDelete helper that
only supported that parameter. Drop the dedicated custom deleter test.
2026-06-13 22:49:15 +02:00
Sam Atkins
071b4f7062 AK: Allow derived types to create base badges
Derived classes can now mint their own badge and pass it to APIs that
accept a badge for an authorized base class.
2026-06-11 21:55:56 +02:00
Sam Atkins
ad3d65b834 AK: Allow Badge to accept multiple types
This lets public APIs name several authorized classes. Callers no longer
need duplicate overloads for one badge.
2026-06-11 21:55:56 +02:00
Andreas Kling
fc02ab95fe AK: Allocate string data in a dedicated heap partition
Add a string heap partition and route long AK string backing
allocations through it.

Give StringBuilder partition-aware outlined storage so adopted String
and Utf16String buffers are allocated from the string heap. Keep the
string heap thread-local because mimalloc heaps may only allocate from
their creating thread, while cross-thread frees are handled by mimalloc.
2026-06-10 20:38:18 +02:00
Timothy Flynn
d3d96ce399 AK: Remove Utf32View and surrounding support
It is now unused, so let's just remove it.
2026-06-06 18:42:18 +02:00
Rocco Corsi
e3e78f4372 AK: Verify datetime fetching results and initialize struct tm
Cppcheck 2.17 tool found issue with struct tm under Windows

Checking AK/Time.cpp ...
Checking AK/Time.cpp: AK_OS_WINDOWS...
AK/Time.cpp:488:15: error: Uninitialized variable: &tm [uninitvar]
        (void)localtime_r(&timestamp, &tm);
              ^
32/39 files checked 87% done

Also the gmtime_X` and localtime_X calls were not checked for failures,
so those are now checked too.
2026-06-04 17:32:49 +02:00
Shannon Booth
de4b665298 AK: Fix rvalue Variant downcast to variant aliases
Pass the required TypeWrapper through the rvalue downcast<Variant<...>>
path, matching the existing const& overload.
2026-05-30 11:22:08 +02:00
sideshowbarker
028eb0a966 AK: Don’t let float precision sneak past is_within_range bounds
Problem: is_within_range<I>(F value) — where I is an integer and F is a
floating-point type — is unexpectedly too permissive in some cases:

a. Values that are 1 past the integer range unexpectedly pass; e.g.,
   is_within_range<int>(2147483648.0f) returns true — even though
   2147483648 is INT_MAX + 1.

b. Fractional values whose magnitude exceeds the destination max
   unexpectedly pass; e.g., is_within_range<unsigned>(4294967295.5)
   returns true — even though 4294967295.5 > UINT_MAX.

c. Fractional values within the destination’s numeric range unexpectedly
   pass (e.g., is_within_range<int>(2.5) returns true) — even though
   they aren’t exactly representable as the destination type.

Cause: TypeBoundsChecker integer-bounds specializations compare against
NumericLimits<Destination>::max() and ::min() directly. When a caller’s
value is a float, the integer max/min get implicitly converted to a
float for the comparison. For Destination/Source pairs with the integer
extreme not exactly representable in the float, that conversion rounds
up to the next power-of-two boundary — so “value <= F(max)” accepts
values that are actually out of range by one (case a). And the
comparison itself doesn’t reject fractional values (cases b and c).

Fix: When Source is a floating-point type:

1. First gate (case a) — Compare against 2^digits; exactly representable
   in any IEEE float, and equals max + 1 for unsigned / -min for two’s-
   complement signed integers.

2. Second gate (cases b and c) – Round-trip check: cast value to
   Destination, then cast back — and require equality. Only integer-
   valued floats whose truncation matches the original pass.

Fixes https://github.com/LadybirdBrowser/ladybird/issues/6212
2026-05-27 19:05:56 +02:00
Pavel Shliak
1c20baf3f3 AK: Remove duplicate Time expectations 2026-05-23 09:16:27 +02:00
Pavel Shliak
94f02afc0f AK: Remove duplicate NumberFormat expectation 2026-05-23 09:16:27 +02:00
Pavel Shliak
a384e9b86e AK: Remove duplicate Format expectation 2026-05-23 09:16:27 +02:00
Pavel Shliak
c2d8779c51 AK: Remove duplicate Bitmap expectations 2026-05-23 09:16:27 +02:00
Pavel Shliak
89761127e0 AK: Remove unused Stack 2026-05-22 02:31:44 -05:00
Pavel Shliak
95af04b8d6 AK: Remove unused IntrusiveRedBlackTree 2026-05-22 09:31:37 +02:00
Pavel Shliak
99561b86c2 AK: Remove unused DisjointChunks 2026-05-22 09:31:25 +02:00
Pavel Shliak
9ebcc67144 AK: Remove unused FixedPoint 2026-05-22 02:30:45 -05:00
Zaggy1024
40d1957d6a AK+Tests: Add a Duration function to scale by a rational 2026-05-19 15:20:58 -05:00
Asish Kumar
5636efe14a Tests/AK: Validate ensure_capacity pre- and postconditions
With the switch to mimalloc, ensure_capacity() guarantees only a
minimum capacity rather than a specific value. Keep the postcondition
as a minimum check and add a precondition so the test verifies that
ensure_capacity() grows the array when called.

Fixes #8876.
2026-05-12 00:08:33 +02:00
Andreas Kling
1859ecbb24 AK: Add lower_bound_index to binary search helpers
Add a helper for finding the first position in a sorted container where
needle can be inserted while preserving sort order. This gives callers a
lower-bound insertion point.

Cover empty inputs, duplicate values, custom comparators, and constexpr
use in TestBinarySearch.
2026-05-11 11:01:46 +02:00
Kevin Bortis
ba26f8eee7 AK: Reset UTF-16 StringBuilder ascii flag on clear()
StringBuilder::clear() did not reset m_utf16_builder_is_ascii. When a
UTF-16 mode builder processed a non-ASCII character then was cleared
and reused, subsequent ASCII content was stored as char16_t. The
to_utf16_string() path then corrupted the first code unit to null via
placement-new overlap in Utf16StringData::from_string_builder().

This caused the HTML parser's shared m_character_insertion_builder to
produce corrupted script text nodes when a non-ASCII character (e.g.
&times;) appeared in an earlier element, breaking inline script
execution with "Unexpected token Invalid" at line 1 column 1.
2026-05-09 09:49:02 -04:00
Timothy Flynn
2bd28cc4c0 AK: Keep Utf16StringData trailing storage out of tail padding
GCC 16 can clobber the first bytes of Utf16StringData payload when a
StringBuilder buffer is reused for string construction. The trailing
ASCII/UTF-16 storage previously started before sizeof(Utf16StringData),
inside tail padding, so placement-new of the header could zero the first
code unit.

This patch aligns the trailing storage union so payload begins after the
full header.
2026-05-08 18:00:59 -04:00
Aliaksandr Kalenik
4bbfe7eedd AK: Remove unused SegmentedVector
Display lists were the last user of SegmentedVector before the flat
command buffer replaced that storage. With no remaining includes, remove
the container and its unit test.
2026-05-08 20:45:17 +02:00
Undefine
542f3e5cca AK+Meta: Make AK / ObjC interop MacOS only
This is entirely unused but still could be useful in the AppKit port.
Originally this was meant for Swift interop which is why it had support
for other platforms, but now it's causing issues on systems like
FreeBSD, so lets just gate it behind the only platform it's useful for.
We also assume that Objective C blocks and Arc are supported for the
AppKit port to build so no need to check for that in CMake.
2026-05-05 22:08:24 +02:00
Timothy Flynn
8664eac047 AK: Protect AK's JSON parser against invalid UTF-8
We were forming parsed JSON strings as a ByteString and converting this
to a String wrapped with a MUST. Let's instead create a String from the
get-go and let the encoding error propagate.
2026-04-28 22:54:47 +02:00
Andreas Kling
c66cab7e6b AK: Hide tentative HashTable bucket from iterators across ensure()
HashMap<_, GC::Ref<_>>::ensure() crashed under UBSan whenever the
initialization callback triggered a GC: lookup_for_writing() stamped
the target bucket as used and added it to the ordered list before the
callback ran, so the marking visitor walked the map, read the
uninitialized slot, and failed the returns_nonnull check in GC::Ref.

Split bucket reservation into two phases. lookup_for_writing() now
hands back the target in the Free state (not in the ordered list,
m_size unchanged); callers placement-new the value and then commit via
commit_inserted_bucket(). The Robin Hood displacement loop still
stamps the slot internally and un-stamps before returning, so probing
is unchanged and the whole operation remains a single hash and a
single probe.
2026-04-25 06:21:36 +02:00
Aliaksandr Kalenik
eb4038fa83 AK: Fix Utf16View::operator<=> code-unit ordering on little-endian
The !has_ascii_storage() && !other.has_ascii_storage() branch did a
byte-wise __builtin_memcmp over a char16_t array, which on little-endian
does not give code-unit order: the low byte is compared first, so
0xD83D (bytes [0x3D, 0xD8]) spuriously compared less than 0x2764
(bytes [0x64, 0x27]) even though the code unit 0xD83D is greater.

No in-tree caller currently uses operator<=> for Utf16View ordering,
so this bug is dormant; the follow-up LibJS change exposes it.

Replace the memcmp branch with a per-code-unit loop, which the compiler
can auto-vectorize and which mirrors what is_code_unit_less_than already
does.
2026-04-22 19:12:54 +02:00
Tim Ledbetter
df34c626d8 AK: Avoid UAF for consecutive SinglyLinkedList removals
The iterator returned by SinglyLinkedList::remove() left `m_prev`
default-initialized to `nullptr`. If the caller removed another element
without first advancing, the previous node's next pointer was left
dangling to the freed node.

This caused a UAF in FinalizationRegistry's `remove_by_token()` when
two consecutive records shared an unregister token.
2026-04-21 18:09:29 +02:00
Andreas Kling
0317007ee1 AK: Make short ASCII string literals compile-time constants
Make the _string, _fly_string, _utf16, and _utf16_fly_string UDL
operators constexpr, with a fast path for short (<= 7 byte) ASCII
literals that folds directly into an inline ShortString. Previously,
every "foo"_fly_string (and friends) involved an out-of-line call
into the string factory, even though the result is entirely known
at compile time.
2026-04-17 16:22:56 +02:00
Zaggy1024
3844edaaed AK: Avoid overflow in Duration::to_time_units() with fraction near 1
With numerators or denominators approaching NumericLimits<u32>::max(),
we could overflow in the sum of the remainder and the rounding
contribution. Instead, divide them separately and sum them afterward.
2026-04-16 15:08:27 -05:00
Zaggy1024
affbe61da0 AK: Simplify Duration::from_time_units and handle remainder overflow
Overflow could happen in the multiplication of the remainder seconds
back into time units. Instead, take a remainder of the time units from
the division and use that for the nanoseconds.
2026-04-16 15:08:27 -05:00
Shannon Booth
e47cdc6b63 AK: Remove public null state from StringView
Now that there are no callers of is_null left, Make default constructed
StringViews represent the empty string and disallow null pointers in the
public constructors, matching ByteString and String.

Keep a private null sentinel only for Optional<StringView>.
2026-03-31 13:48:50 +01:00
Shannon Booth
7ab9454f51 AK: Remove null state from Utf16View
The default constructor now initializes to an empty ASCII string rather
than a null pointer.

Also add a VERIFY in the utf16 constructor to assert the pointer is
non null, and remove the now unneeded is_null() method.
2026-03-31 13:48:50 +01:00
RubenKelevra
14a0f00400 AK: Guard JSON parser against deep nesting
Add a maximum nesting depth check in JsonParser so deeply nested
arrays/objects from untrusted input cannot blow the call stack.

Add regression tests for excessive nesting rejection and
reasonable nesting acceptance.
2026-03-27 14:29:43 +00:00
Andreas Kling
31f816a6d8 AK: Add SaturatingMath.h with branchless saturating arithmetic
Add standalone saturating_add(), saturating_sub(), and
saturating_mul() free functions for integral types.

The signed implementations are fully branchless, using
__builtin_add/sub/mul_overflow combined with bitmask selection.
2026-03-21 18:20:09 -05:00
Jelle Raaijmakers
e123d48043 AK: Add SentinelOptional
We specialize `Optional<T>` for value types that inherently support some
kind of "empty" value or whose value range allow for a unlikely to be
useful sentinel value that can mean "empty", instead of the boolean flag
a regular Optional<T> needs to store. Because of padding, this often
means saving 4 to 8 bytes per instance.

By extending the new `SentinelOptional<T, Traits>`, these
specializations are significantly simplified to just having to define
what the sentinel value is, and how to identify a sentinel value.
2026-03-20 12:03:36 +01:00
Tim Ledbetter
972bcdeebe AK: Use correct relocation for all HashTable entry types
Robin Hood displacement and `delete_bucket()` shift-up used BucketType's
implicit move operations, which bitwise-copy the `u8` storage array
instead of going through T's move constructor and destructor. This
change adds `relocate_bucket()` and `swap_buckets()` helpers that use a
fast path for trivially-relocatable types and move-construct + destroy
for others.
2026-03-19 14:21:44 +01:00
Tim Ledbetter
19a8c3dbd5 Tests/AK: Add some HashTable benchmarks 2026-03-19 14:21:44 +01:00
Tim Ledbetter
0eb7012b57 AK: Add TypedTransfer<T>::relocate()
This moves objects from source to destination destructively, ensuring
the destructors are called if necessary.
2026-03-19 14:21:44 +01:00
Tim Ledbetter
8dd3c20436 AK: Add IsTriviallyRelocatable type trait 2026-03-19 14:21:44 +01:00
Jelle Raaijmakers
2b78b84979 AK+Everywhere: Add and use weak_callback()
We have a common pattern of creating a `WeakPtr<T>` from a reference and
passing that into a lambda, to then take the strong ref when the lambda
is executed. Add `weak_callback(Weakable, lambda)` that returns a lambda
that only invokes the callback if a strong ref exists, and passes it as
the first argument.
2026-02-26 08:03:50 -05:00
Timothy Flynn
3355fb39ae AK+LibJS: Replace home-grown Ryu implementation with fmt's dragonbox
In the benchmark added here, fmt's dragonbox is ~3x faster than our own
Ryu implementation (1197ms for dragonbox vs. 3435ms for Ryu).

Daniel Lemire recently published an article about these algorithms:
https://lemire.me/blog/2026/02/01/converting-floats-to-strings-quickly/

In this article, fmt's dragonbox implementation is actually one of the
slower ones (with the caveat that some comments note that the article is
a bit out-of-date). I've gone with fmt here because:

1. It has a readily available recent version on vcpkg.
2. It provides the methods we need to actually convert a floating point
   to decimal exponential form.
3. There is an ongoing effort to replace dragonbox with a new algorithm,
   zmij, which promises to be faster.
4. It is one of the only users of AK/UFixedBigInt, so we can potentially
   remove that as well soon.
5. Bringing in fmt opens the door to replacing a bunch of AK::format
   facilities with fmt as well.
2026-02-23 18:30:40 +01:00
Jelle Raaijmakers
1745926fc6 AK+Everywhere: Use MurmurHash3 for int/u64 hashing
Rework our hash functions a bit for significant better performance:

* Rename int_hash to u32_hash to mirror u64_hash.
* Make pair_int_hash call u64_hash instead of multiple u32_hash()es.
* Implement MurmurHash3's fmix32 and fmix64 for u32_hash and u64_hash.

On my machine, this speeds up u32_hash by 20%, u64_hash by ~290%, and
pair_int_hash by ~260%.

We lose the property that an input of 0 results in something that is not
0. I've experimented with an offset to both hash functions, but it
resulted in a measurable performance degradation for u64_hash. If
there's a good use case for 0 not to result in 0, we can always add in
that offset as a countermeasure in the future.
2026-02-20 22:47:24 +01:00
Zaggy1024
d5bf929699 AK+Tests: Destroy moved-from CallableWrappers
We won't attempt to destroy this wrapper later because m_kind gets set
to NullPointer. If any fields of the CallableType are not movable, this
results in a leak.

A test replicating the issue before the fix is added to a new
TestFunction.cpp file.
2026-02-18 13:13:32 -06:00