Meta: Enable exit-time destructor warnings for libraries
Enable -Wexit-time-destructors for all in-tree library targets and update process-lifetime library statics so they no longer register exit-time destructors. Long-lived caches, lookup tables, singleton registries, and generated constants now use NeverDestroyed or leaked references where the data is intended to live until process exit. Update LibWeb, LibLine, and the binding generators so regenerated sources follow the same rule instead of reintroducing destructed statics.
This commit is contained in:
parent
8c7b5b4de6
commit
164ed80244
217 changed files with 1739 additions and 1344 deletions
|
|
@ -7,6 +7,7 @@
|
|||
#include <AK/Assertions.h>
|
||||
#include <AK/Backtrace.h>
|
||||
#include <AK/Format.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/Platform.h>
|
||||
#include <AK/StringView.h>
|
||||
|
||||
|
|
@ -49,8 +50,8 @@ void dump_backtrace(unsigned frames_to_skip, unsigned max_depth)
|
|||
auto stacktrace = cpptrace::generate_trace(frames_to_skip, max_depth);
|
||||
auto* var = getenv("LADYBIRD_BACKTRACE_SNIPPETS");
|
||||
bool print_snippets = var && strnlen(var, 1) > 0;
|
||||
static auto formatter = cpptrace::formatter {}.snippets(print_snippets);
|
||||
auto string = formatter.format(stacktrace, true);
|
||||
static NeverDestroyed<cpptrace::formatter> formatter { cpptrace::formatter {}.snippets(print_snippets) };
|
||||
auto string = formatter->format(stacktrace, true);
|
||||
warnln("{}", StringView { string.c_str(), string.length() });
|
||||
}
|
||||
#elif defined(AK_HAS_BACKTRACE_HEADER)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/BinarySearch.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibCompress/Deflate.h>
|
||||
#include <LibCompress/DeflateTables.h>
|
||||
|
||||
|
|
@ -16,30 +17,14 @@ namespace Compress {
|
|||
|
||||
CanonicalCode const& CanonicalCode::fixed_literal_codes()
|
||||
{
|
||||
static CanonicalCode code;
|
||||
static bool initialized = false;
|
||||
|
||||
if (initialized)
|
||||
return code;
|
||||
|
||||
code = MUST(CanonicalCode::from_bytes(fixed_literal_bit_lengths));
|
||||
initialized = true;
|
||||
|
||||
return code;
|
||||
static NeverDestroyed<CanonicalCode> code { MUST(CanonicalCode::from_bytes(fixed_literal_bit_lengths)) };
|
||||
return *code;
|
||||
}
|
||||
|
||||
CanonicalCode const& CanonicalCode::fixed_distance_codes()
|
||||
{
|
||||
static CanonicalCode code;
|
||||
static bool initialized = false;
|
||||
|
||||
if (initialized)
|
||||
return code;
|
||||
|
||||
code = MUST(CanonicalCode::from_bytes(fixed_distance_bit_lengths));
|
||||
initialized = true;
|
||||
|
||||
return code;
|
||||
static NeverDestroyed<CanonicalCode> code { MUST(CanonicalCode::from_bytes(fixed_distance_bit_lengths)) };
|
||||
return *code;
|
||||
}
|
||||
|
||||
ErrorOr<CanonicalCode> CanonicalCode::from_bytes(ReadonlyBytes bytes)
|
||||
|
|
|
|||
|
|
@ -6,28 +6,58 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/Badge.h>
|
||||
#include <AK/Platform.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibCore/EventLoop.h>
|
||||
#include <LibCore/EventLoopImplementation.h>
|
||||
#include <LibCore/EventReceiver.h>
|
||||
#include <LibCore/Promise.h>
|
||||
#include <LibCore/ThreadEventQueue.h>
|
||||
#ifndef AK_OS_WINDOWS
|
||||
# include <pthread.h>
|
||||
#endif
|
||||
|
||||
namespace Core {
|
||||
|
||||
namespace {
|
||||
|
||||
OwnPtr<Vector<EventLoop&>>& event_loop_stack_uninitialized()
|
||||
#ifndef AK_OS_WINDOWS
|
||||
static pthread_key_t s_event_loop_stack_key;
|
||||
static pthread_once_t s_event_loop_stack_key_once = PTHREAD_ONCE_INIT;
|
||||
|
||||
static void destroy_event_loop_stack(void* value)
|
||||
{
|
||||
thread_local OwnPtr<Vector<EventLoop&>> s_event_loop_stack = nullptr;
|
||||
delete static_cast<Vector<EventLoop&>*>(value);
|
||||
}
|
||||
|
||||
static void initialize_event_loop_stack_key()
|
||||
{
|
||||
VERIFY(pthread_key_create(&s_event_loop_stack_key, destroy_event_loop_stack) == 0);
|
||||
}
|
||||
|
||||
static void ensure_event_loop_stack_key()
|
||||
{
|
||||
VERIFY(pthread_once(&s_event_loop_stack_key_once, initialize_event_loop_stack_key) == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
Vector<EventLoop&>*& event_loop_stack_uninitialized()
|
||||
{
|
||||
thread_local Vector<EventLoop&>* s_event_loop_stack = nullptr;
|
||||
return s_event_loop_stack;
|
||||
}
|
||||
Vector<EventLoop&>& event_loop_stack()
|
||||
{
|
||||
auto& the_stack = event_loop_stack_uninitialized();
|
||||
if (the_stack == nullptr)
|
||||
the_stack = make<Vector<EventLoop&>>();
|
||||
if (the_stack == nullptr) {
|
||||
the_stack = new Vector<EventLoop&>();
|
||||
#ifndef AK_OS_WINDOWS
|
||||
ensure_event_loop_stack_key();
|
||||
VERIFY(pthread_setspecific(s_event_loop_stack_key, the_stack) == 0);
|
||||
#endif
|
||||
}
|
||||
return *the_stack;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <AK/BinaryHeap.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/Singleton.h>
|
||||
#include <AK/TemporaryChange.h>
|
||||
#include <AK/Time.h>
|
||||
|
|
@ -18,6 +19,7 @@
|
|||
#include <LibCore/System.h>
|
||||
#include <LibCore/ThreadEventQueue.h>
|
||||
#include <LibSync/Mutex.h>
|
||||
#include <LibSync/Once.h>
|
||||
#include <LibSync/RWLock.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/select.h>
|
||||
|
|
@ -30,10 +32,35 @@ namespace {
|
|||
struct ThreadData;
|
||||
class TimeoutSet;
|
||||
|
||||
HashMap<pthread_t, ThreadData*> s_thread_data;
|
||||
Sync::RWLock s_thread_data_lock;
|
||||
thread_local pthread_t s_thread_id;
|
||||
thread_local OwnPtr<ThreadData> s_this_thread_data;
|
||||
thread_local ThreadData* s_this_thread_data;
|
||||
static pthread_key_t s_this_thread_data_key;
|
||||
|
||||
static void destroy_thread_data(void*);
|
||||
|
||||
static auto& thread_data()
|
||||
{
|
||||
static NeverDestroyed<HashMap<pthread_t, ThreadData*>> thread_data;
|
||||
return *thread_data;
|
||||
}
|
||||
|
||||
static auto& thread_data_lock()
|
||||
{
|
||||
static NeverDestroyed<Sync::RWLock> lock;
|
||||
return *lock;
|
||||
}
|
||||
|
||||
static auto& thread_data_key_once()
|
||||
{
|
||||
static NeverDestroyed<Sync::OnceFlag> once;
|
||||
return *once;
|
||||
}
|
||||
|
||||
static void ensure_thread_data_key()
|
||||
{
|
||||
Sync::call_once(thread_data_key_once(), [] {
|
||||
VERIFY(pthread_key_create(&s_this_thread_data_key, destroy_thread_data) == 0);
|
||||
});
|
||||
}
|
||||
|
||||
short notification_type_to_poll_events(NotificationType type)
|
||||
{
|
||||
|
|
@ -224,29 +251,30 @@ public:
|
|||
struct ThreadData {
|
||||
static ThreadData& the()
|
||||
{
|
||||
if (s_thread_id == 0)
|
||||
s_thread_id = pthread_self();
|
||||
ensure_thread_data_key();
|
||||
ThreadData* data = nullptr;
|
||||
if (!s_this_thread_data) {
|
||||
data = new ThreadData;
|
||||
s_this_thread_data = adopt_own(*data);
|
||||
s_this_thread_data = data;
|
||||
VERIFY(pthread_setspecific(s_this_thread_data_key, s_this_thread_data) == 0);
|
||||
|
||||
Sync::RWLockLocker<Sync::LockMode::Write> locker(s_thread_data_lock);
|
||||
s_thread_data.set(s_thread_id, s_this_thread_data.ptr());
|
||||
Sync::RWLockLocker<Sync::LockMode::Write> locker(thread_data_lock());
|
||||
thread_data().set(s_this_thread_data->thread_id, s_this_thread_data);
|
||||
} else {
|
||||
data = s_this_thread_data.ptr();
|
||||
data = s_this_thread_data;
|
||||
}
|
||||
return *data;
|
||||
}
|
||||
|
||||
static ThreadData* for_thread(pthread_t thread_id)
|
||||
{
|
||||
// NOTE: s_thread_data_lock is supposed to be held by the caller.
|
||||
return s_thread_data.get(thread_id).value_or(nullptr);
|
||||
// NOTE: thread_data_lock() is supposed to be held by the caller.
|
||||
return thread_data().get(thread_id).value_or(nullptr);
|
||||
}
|
||||
|
||||
ThreadData()
|
||||
{
|
||||
thread_id = pthread_self();
|
||||
pid = getpid();
|
||||
|
||||
auto result = Core::System::pipe2(O_CLOEXEC);
|
||||
|
|
@ -267,8 +295,8 @@ struct ThreadData {
|
|||
close(wake_pipe_fds[0]);
|
||||
close(wake_pipe_fds[1]);
|
||||
|
||||
Sync::RWLockLocker<Sync::LockMode::Write> locker(s_thread_data_lock);
|
||||
s_thread_data.remove(s_thread_id);
|
||||
Sync::RWLockLocker<Sync::LockMode::Write> locker(thread_data_lock());
|
||||
thread_data().remove(thread_id);
|
||||
}
|
||||
|
||||
Sync::RecursiveMutex mutex;
|
||||
|
|
@ -285,8 +313,15 @@ struct ThreadData {
|
|||
Array<int, 2> wake_pipe_fds { -1, -1 };
|
||||
|
||||
pid_t pid { 0 };
|
||||
pthread_t thread_id { 0 };
|
||||
};
|
||||
|
||||
static void destroy_thread_data(void* value)
|
||||
{
|
||||
s_this_thread_data = nullptr;
|
||||
delete static_cast<ThreadData*>(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EventLoopImplementationUnix::EventLoopImplementationUnix()
|
||||
|
|
@ -569,7 +604,7 @@ void EventLoopManagerUnix::handle_signal(int signal_number)
|
|||
VERIFY(signal_number != 0);
|
||||
|
||||
// Use the thread-local directly instead of ThreadData::the() to avoid
|
||||
// taking a write lock on s_thread_data_lock. Signal handlers must not
|
||||
// taking a write lock on thread_data_lock(). Signal handlers must not
|
||||
// acquire locks, as we may already be holding one on this thread.
|
||||
if (!s_this_thread_data)
|
||||
return;
|
||||
|
|
@ -628,7 +663,7 @@ intptr_t EventLoopManagerUnix::register_timer(EventReceiver& object, int millise
|
|||
auto& thread_data = ThreadData::the();
|
||||
Sync::MutexLocker locker(thread_data.mutex);
|
||||
auto timer = new EventLoopTimer;
|
||||
timer->owner_thread = s_thread_id;
|
||||
timer->owner_thread = thread_data.thread_id;
|
||||
timer->owner = object;
|
||||
timer->interval = AK::Duration::from_milliseconds(milliseconds);
|
||||
timer->reload(MonotonicTime::now_coarse());
|
||||
|
|
@ -640,7 +675,7 @@ intptr_t EventLoopManagerUnix::register_timer(EventReceiver& object, int millise
|
|||
void EventLoopManagerUnix::unregister_timer(intptr_t timer_id)
|
||||
{
|
||||
auto* timer = bit_cast<EventLoopTimer*>(timer_id);
|
||||
Sync::RWLockLocker<Sync::LockMode::Read> locker(s_thread_data_lock);
|
||||
Sync::RWLockLocker<Sync::LockMode::Read> locker(thread_data_lock());
|
||||
auto* thread_data_ptr = ThreadData::for_thread(timer->owner_thread);
|
||||
if (!thread_data_ptr)
|
||||
return;
|
||||
|
|
@ -665,12 +700,12 @@ void EventLoopManagerUnix::register_notifier(Notifier& notifier)
|
|||
auto events = notification_type_to_poll_events(notifier.type());
|
||||
thread_data.poll_fds.append({ .fd = notifier.fd(), .events = events, .revents = 0 });
|
||||
|
||||
notifier.set_owner_thread(s_thread_id);
|
||||
notifier.set_owner_thread(thread_data.thread_id);
|
||||
}
|
||||
|
||||
void EventLoopManagerUnix::unregister_notifier(Notifier& notifier)
|
||||
{
|
||||
Sync::RWLockLocker<Sync::LockMode::Read> locker(s_thread_data_lock);
|
||||
Sync::RWLockLocker<Sync::LockMode::Read> locker(thread_data_lock());
|
||||
auto* thread_data = ThreadData::for_thread(notifier.owner_thread());
|
||||
if (!thread_data)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibCore/MimeData.h>
|
||||
|
|
@ -65,91 +66,100 @@ static Array constexpr s_plaintext_suffixes = {
|
|||
|
||||
// See https://www.iana.org/assignments/media-types/<mime-type> for a list of registered MIME types.
|
||||
// For example, https://www.iana.org/assignments/media-types/application/gzip
|
||||
static Array const s_registered_mime_type = {
|
||||
MimeType { .name = "application/gzip"sv, .common_extensions = { ".gz"sv, ".gzip"sv }, .description = "GZIP compressed data"sv, .magic_bytes = Vector<u8> { 0x1F, 0x8B } },
|
||||
MimeType { .name = "application/javascript"sv, .common_extensions = { ".js"sv, ".mjs"sv }, .description = "JavaScript source"sv },
|
||||
MimeType { .name = "application/json"sv, .common_extensions = { ".json"sv }, .description = "JSON data"sv },
|
||||
MimeType { .name = "application/pdf"sv, .common_extensions = { ".pdf"sv }, .description = "PDF document"sv, .magic_bytes = Vector<u8> { 0x25, 'P', 'D', 'F', 0x2D } },
|
||||
MimeType { .name = "application/rtf"sv, .common_extensions = { ".rtf"sv }, .description = "Rich text file"sv, .magic_bytes = Vector<u8> { 0x7B, 0x5C, 0x72, 0x74, 0x66, 0x31 } },
|
||||
MimeType { .name = "application/tar"sv, .common_extensions = { ".tar"sv }, .description = "Tape archive"sv, .magic_bytes = Vector<u8> { 0x75, 0x73, 0x74, 0x61, 0x72 }, .offset = 0x101 },
|
||||
MimeType { .name = "application/vnd.iccprofile"sv, .common_extensions = { ".icc"sv }, .description = "ICC color profile"sv, .magic_bytes = Vector<u8> { 'a', 'c', 's', 'p' }, .offset = 36 },
|
||||
MimeType { .name = "application/vnd.sqlite3"sv, .common_extensions = { ".sqlite"sv }, .description = "SQLite database"sv, .magic_bytes = Vector<u8> { 'S', 'Q', 'L', 'i', 't', 'e', ' ', 'f', 'o', 'r', 'm', 'a', 't', ' ', '3', 0x00 } },
|
||||
MimeType { .name = "application/wasm"sv, .common_extensions = { ".wasm"sv }, .description = "WebAssembly bytecode"sv, .magic_bytes = Vector<u8> { 0x00, 'a', 's', 'm' } },
|
||||
MimeType { .name = "application/x-7z-compressed"sv, .common_extensions = { "7z"sv }, .description = "7-Zip archive"sv, .magic_bytes = Vector<u8> { 0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C } },
|
||||
MimeType { .name = "application/x-blender"sv, .common_extensions = { ".blend"sv, ".blended"sv }, .description = "Blender project file"sv, .magic_bytes = Vector<u8> { 'B', 'L', 'E', 'N', 'D', 'E', 'R' } },
|
||||
MimeType { .name = "application/x-bzip2"sv, .common_extensions = { ".bz2"sv }, .description = "BZIP2 compressed data"sv, .magic_bytes = Vector<u8> { 'B', 'Z', 'h' } },
|
||||
MimeType { .name = "application/x-sheets+json"sv, .common_extensions = { ".sheets"sv }, .description = "Serenity Spreadsheet document"sv },
|
||||
MimeType { .name = "application/xhtml+xml"sv, .common_extensions = { ".xhtml"sv, ".xht"sv }, .description = "XHTML document"sv },
|
||||
MimeType { .name = "application/zip"sv, .common_extensions = { ".zip"sv }, .description = "ZIP archive"sv, .magic_bytes = Vector<u8> { 0x50, 0x4B } },
|
||||
static auto make_registered_mime_types()
|
||||
{
|
||||
return Array {
|
||||
MimeType { .name = "application/gzip"sv, .common_extensions = { ".gz"sv, ".gzip"sv }, .description = "GZIP compressed data"sv, .magic_bytes = Vector<u8> { 0x1F, 0x8B } },
|
||||
MimeType { .name = "application/javascript"sv, .common_extensions = { ".js"sv, ".mjs"sv }, .description = "JavaScript source"sv },
|
||||
MimeType { .name = "application/json"sv, .common_extensions = { ".json"sv }, .description = "JSON data"sv },
|
||||
MimeType { .name = "application/pdf"sv, .common_extensions = { ".pdf"sv }, .description = "PDF document"sv, .magic_bytes = Vector<u8> { 0x25, 'P', 'D', 'F', 0x2D } },
|
||||
MimeType { .name = "application/rtf"sv, .common_extensions = { ".rtf"sv }, .description = "Rich text file"sv, .magic_bytes = Vector<u8> { 0x7B, 0x5C, 0x72, 0x74, 0x66, 0x31 } },
|
||||
MimeType { .name = "application/tar"sv, .common_extensions = { ".tar"sv }, .description = "Tape archive"sv, .magic_bytes = Vector<u8> { 0x75, 0x73, 0x74, 0x61, 0x72 }, .offset = 0x101 },
|
||||
MimeType { .name = "application/vnd.iccprofile"sv, .common_extensions = { ".icc"sv }, .description = "ICC color profile"sv, .magic_bytes = Vector<u8> { 'a', 'c', 's', 'p' }, .offset = 36 },
|
||||
MimeType { .name = "application/vnd.sqlite3"sv, .common_extensions = { ".sqlite"sv }, .description = "SQLite database"sv, .magic_bytes = Vector<u8> { 'S', 'Q', 'L', 'i', 't', 'e', ' ', 'f', 'o', 'r', 'm', 'a', 't', ' ', '3', 0x00 } },
|
||||
MimeType { .name = "application/wasm"sv, .common_extensions = { ".wasm"sv }, .description = "WebAssembly bytecode"sv, .magic_bytes = Vector<u8> { 0x00, 'a', 's', 'm' } },
|
||||
MimeType { .name = "application/x-7z-compressed"sv, .common_extensions = { "7z"sv }, .description = "7-Zip archive"sv, .magic_bytes = Vector<u8> { 0x37, 0x7A, 0xBC, 0xAF, 0x27, 0x1C } },
|
||||
MimeType { .name = "application/x-blender"sv, .common_extensions = { ".blend"sv, ".blended"sv }, .description = "Blender project file"sv, .magic_bytes = Vector<u8> { 'B', 'L', 'E', 'N', 'D', 'E', 'R' } },
|
||||
MimeType { .name = "application/x-bzip2"sv, .common_extensions = { ".bz2"sv }, .description = "BZIP2 compressed data"sv, .magic_bytes = Vector<u8> { 'B', 'Z', 'h' } },
|
||||
MimeType { .name = "application/x-sheets+json"sv, .common_extensions = { ".sheets"sv }, .description = "Serenity Spreadsheet document"sv },
|
||||
MimeType { .name = "application/xhtml+xml"sv, .common_extensions = { ".xhtml"sv, ".xht"sv }, .description = "XHTML document"sv },
|
||||
MimeType { .name = "application/zip"sv, .common_extensions = { ".zip"sv }, .description = "ZIP archive"sv, .magic_bytes = Vector<u8> { 0x50, 0x4B } },
|
||||
|
||||
MimeType { .name = "audio/flac"sv, .common_extensions = { ".flac"sv }, .description = "FLAC audio"sv, .magic_bytes = Vector<u8> { 'f', 'L', 'a', 'C' } },
|
||||
MimeType { .name = "audio/midi"sv, .common_extensions = { ".mid"sv }, .description = "MIDI notes"sv, .magic_bytes = Vector<u8> { 0x4D, 0x54, 0x68, 0x64 } },
|
||||
MimeType { .name = "audio/mpeg"sv, .common_extensions = { ".mp3"sv }, .description = "MP3 audio"sv, .magic_bytes = Vector<u8> { 0xFF, 0xFB } },
|
||||
MimeType { .name = "audio/qoa"sv, .common_extensions = { ".qoa"sv }, .description = "Quite OK Audio"sv, .magic_bytes = Vector<u8> { 'q', 'o', 'a', 'f' } },
|
||||
MimeType { .name = "audio/wav"sv, .common_extensions = { ".wav"sv }, .description = "WAVE audio"sv, .magic_bytes = Vector<u8> { 'W', 'A', 'V', 'E' }, .offset = 8 },
|
||||
MimeType { .name = "audio/flac"sv, .common_extensions = { ".flac"sv }, .description = "FLAC audio"sv, .magic_bytes = Vector<u8> { 'f', 'L', 'a', 'C' } },
|
||||
MimeType { .name = "audio/midi"sv, .common_extensions = { ".mid"sv }, .description = "MIDI notes"sv, .magic_bytes = Vector<u8> { 0x4D, 0x54, 0x68, 0x64 } },
|
||||
MimeType { .name = "audio/mpeg"sv, .common_extensions = { ".mp3"sv }, .description = "MP3 audio"sv, .magic_bytes = Vector<u8> { 0xFF, 0xFB } },
|
||||
MimeType { .name = "audio/qoa"sv, .common_extensions = { ".qoa"sv }, .description = "Quite OK Audio"sv, .magic_bytes = Vector<u8> { 'q', 'o', 'a', 'f' } },
|
||||
MimeType { .name = "audio/wav"sv, .common_extensions = { ".wav"sv }, .description = "WAVE audio"sv, .magic_bytes = Vector<u8> { 'W', 'A', 'V', 'E' }, .offset = 8 },
|
||||
|
||||
MimeType { .name = "extra/elf"sv, .common_extensions = { ".elf"sv }, .description = "ELF"sv, .magic_bytes = Vector<u8> { 0x7F, 'E', 'L', 'F' } },
|
||||
MimeType { .name = "extra/ext"sv, .description = "EXT filesystem"sv, .magic_bytes = Vector<u8> { 0x53, 0xEF }, .offset = 0x438 },
|
||||
MimeType { .name = "extra/iso-9660"sv, .common_extensions = { ".iso"sv }, .description = "ISO 9660 CD/DVD image"sv, .magic_bytes = Vector<u8> { 0x43, 0x44, 0x30, 0x30, 0x31 }, .offset = 0x8001 },
|
||||
MimeType { .name = "extra/iso-9660"sv, .common_extensions = { ".iso"sv }, .description = "ISO 9660 CD/DVD image"sv, .magic_bytes = Vector<u8> { 0x43, 0x44, 0x30, 0x30, 0x31 }, .offset = 0x8801 },
|
||||
MimeType { .name = "extra/iso-9660"sv, .common_extensions = { ".iso"sv }, .description = "ISO 9660 CD/DVD image"sv, .magic_bytes = Vector<u8> { 0x43, 0x44, 0x30, 0x30, 0x31 }, .offset = 0x9001 },
|
||||
MimeType { .name = "extra/isz"sv, .common_extensions = { ".isz"sv }, .description = "Compressed ISO image"sv, .magic_bytes = Vector<u8> { 'I', 's', 'Z', '!' } },
|
||||
MimeType { .name = "extra/lua-bytecode"sv, .description = "Lua bytecode"sv, .magic_bytes = Vector<u8> { 0x1B, 'L', 'u', 'a' } },
|
||||
MimeType { .name = "extra/nes-rom"sv, .common_extensions = { ".nes"sv }, .description = "Nintendo Entertainment System ROM"sv, .magic_bytes = Vector<u8> { 'N', 'E', 'S', 0x1A } },
|
||||
MimeType { .name = "extra/qcow"sv, .common_extensions = { ".qcow"sv, ".qcow2"sv, ".qcow3"sv }, .description = "QCOW file"sv, .magic_bytes = Vector<u8> { 'Q', 'F', 'I' } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0x01 } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0x5E } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0x9C } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0xDA } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0x20 } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0x7D } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0xBB } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0xF9 } },
|
||||
MimeType { .name = "extra/win-31x-compressed"sv, .description = "Windows 3.1X compressed file"sv, .magic_bytes = Vector<u8> { 'K', 'W', 'A', 'J' } },
|
||||
MimeType { .name = "extra/win-95-compressed"sv, .description = "Windows 95 compressed file"sv, .magic_bytes = Vector<u8> { 'S', 'Z', 'D', 'D' } },
|
||||
MimeType { .name = "extra/elf"sv, .common_extensions = { ".elf"sv }, .description = "ELF"sv, .magic_bytes = Vector<u8> { 0x7F, 'E', 'L', 'F' } },
|
||||
MimeType { .name = "extra/ext"sv, .description = "EXT filesystem"sv, .magic_bytes = Vector<u8> { 0x53, 0xEF }, .offset = 0x438 },
|
||||
MimeType { .name = "extra/iso-9660"sv, .common_extensions = { ".iso"sv }, .description = "ISO 9660 CD/DVD image"sv, .magic_bytes = Vector<u8> { 0x43, 0x44, 0x30, 0x30, 0x31 }, .offset = 0x8001 },
|
||||
MimeType { .name = "extra/iso-9660"sv, .common_extensions = { ".iso"sv }, .description = "ISO 9660 CD/DVD image"sv, .magic_bytes = Vector<u8> { 0x43, 0x44, 0x30, 0x30, 0x31 }, .offset = 0x8801 },
|
||||
MimeType { .name = "extra/iso-9660"sv, .common_extensions = { ".iso"sv }, .description = "ISO 9660 CD/DVD image"sv, .magic_bytes = Vector<u8> { 0x43, 0x44, 0x30, 0x30, 0x31 }, .offset = 0x9001 },
|
||||
MimeType { .name = "extra/isz"sv, .common_extensions = { ".isz"sv }, .description = "Compressed ISO image"sv, .magic_bytes = Vector<u8> { 'I', 's', 'Z', '!' } },
|
||||
MimeType { .name = "extra/lua-bytecode"sv, .description = "Lua bytecode"sv, .magic_bytes = Vector<u8> { 0x1B, 'L', 'u', 'a' } },
|
||||
MimeType { .name = "extra/nes-rom"sv, .common_extensions = { ".nes"sv }, .description = "Nintendo Entertainment System ROM"sv, .magic_bytes = Vector<u8> { 'N', 'E', 'S', 0x1A } },
|
||||
MimeType { .name = "extra/qcow"sv, .common_extensions = { ".qcow"sv, ".qcow2"sv, ".qcow3"sv }, .description = "QCOW file"sv, .magic_bytes = Vector<u8> { 'Q', 'F', 'I' } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0x01 } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0x5E } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0x9C } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0xDA } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0x20 } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0x7D } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0xBB } },
|
||||
MimeType { .name = "extra/raw-zlib"sv, .description = "Raw zlib stream"sv, .magic_bytes = Vector<u8> { 0x78, 0xF9 } },
|
||||
MimeType { .name = "extra/win-31x-compressed"sv, .description = "Windows 3.1X compressed file"sv, .magic_bytes = Vector<u8> { 'K', 'W', 'A', 'J' } },
|
||||
MimeType { .name = "extra/win-95-compressed"sv, .description = "Windows 95 compressed file"sv, .magic_bytes = Vector<u8> { 'S', 'Z', 'D', 'D' } },
|
||||
|
||||
MimeType { .name = "font/otf"sv, .common_extensions = { "otf"sv }, .description = "OpenType font"sv, .magic_bytes = Vector<u8> { 'O', 'T', 'T', 'F' } },
|
||||
MimeType { .name = "font/ttf"sv, .common_extensions = { "ttf"sv }, .description = "TrueType font"sv, .magic_bytes = Vector<u8> { 0x00, 0x01, 0x00, 0x00, 0x00 } },
|
||||
MimeType { .name = "font/woff"sv, .common_extensions = { "woff"sv }, .description = "WOFF font"sv, .magic_bytes = Vector<u8> { 'W', 'O', 'F', 'F' } },
|
||||
MimeType { .name = "font/woff2"sv, .common_extensions = { "woff2"sv }, .description = "WOFF2 font"sv, .magic_bytes = Vector<u8> { 'W', 'O', 'F', '2' } },
|
||||
MimeType { .name = "font/otf"sv, .common_extensions = { "otf"sv }, .description = "OpenType font"sv, .magic_bytes = Vector<u8> { 'O', 'T', 'T', 'F' } },
|
||||
MimeType { .name = "font/ttf"sv, .common_extensions = { "ttf"sv }, .description = "TrueType font"sv, .magic_bytes = Vector<u8> { 0x00, 0x01, 0x00, 0x00, 0x00 } },
|
||||
MimeType { .name = "font/woff"sv, .common_extensions = { "woff"sv }, .description = "WOFF font"sv, .magic_bytes = Vector<u8> { 'W', 'O', 'F', 'F' } },
|
||||
MimeType { .name = "font/woff2"sv, .common_extensions = { "woff2"sv }, .description = "WOFF2 font"sv, .magic_bytes = Vector<u8> { 'W', 'O', 'F', '2' } },
|
||||
|
||||
MimeType { .name = "image/avif"sv, .common_extensions = { ".avif"sv }, .description = "AVIF image data"sv },
|
||||
MimeType { .name = "image/bmp"sv, .common_extensions = { ".bmp"sv }, .description = "BMP image data"sv, .magic_bytes = Vector<u8> { 'B', 'M' } },
|
||||
MimeType { .name = "image/gif"sv, .common_extensions = { ".gif"sv }, .description = "GIF image data"sv, .magic_bytes = Vector<u8> { 'G', 'I', 'F', '8', '7', 'a' } },
|
||||
MimeType { .name = "image/gif"sv, .common_extensions = { ".gif"sv }, .description = "GIF image data"sv, .magic_bytes = Vector<u8> { 'G', 'I', 'F', '8', '9', 'a' } },
|
||||
MimeType { .name = "image/j2c"sv, .common_extensions = { ".j2c"sv, ".j2k"sv }, .description = "JPEG2000 image data codestream"sv, .magic_bytes = Vector<u8> { 0xFF, 0x4F, 0xFF, 0x51 } },
|
||||
MimeType { .name = "image/jp2"sv, .common_extensions = { ".jp2"sv, ".jpf"sv, ".jpx"sv }, .description = "JPEG2000 image data"sv, .magic_bytes = Vector<u8> { 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A } },
|
||||
MimeType { .name = "image/jpeg"sv, .common_extensions = { ".jpg"sv, ".jpeg"sv }, .description = "JPEG image data"sv, .magic_bytes = Vector<u8> { 0xFF, 0xD8, 0xFF } },
|
||||
MimeType { .name = "image/jxl"sv, .common_extensions = { ".jxl"sv }, .description = "JPEG XL image data"sv, .magic_bytes = Vector<u8> { 0xFF, 0x0A } },
|
||||
MimeType { .name = "image/png"sv, .common_extensions = { ".png"sv }, .description = "PNG image data"sv, .magic_bytes = Vector<u8> { 0x89, 'P', 'N', 'G', 0x0D, 0x0A, 0x1A, 0x0A } },
|
||||
MimeType { .name = "image/svg+xml"sv, .common_extensions = { ".svg"sv }, .description = "Scalable Vector Graphics image"sv },
|
||||
MimeType { .name = "image/tiff"sv, .common_extensions = { ".tiff"sv }, .description = "TIFF image data"sv, .magic_bytes = Vector<u8> { 'I', 'I', '*', 0x00 } },
|
||||
MimeType { .name = "image/tiff"sv, .common_extensions = { ".tiff"sv }, .description = "TIFF image data"sv, .magic_bytes = Vector<u8> { 'M', 'M', 0x00, '*' } },
|
||||
MimeType { .name = "image/webp"sv, .common_extensions = { ".webp"sv }, .description = "WebP image data"sv, .magic_bytes = Vector<u8> { 'W', 'E', 'B', 'P' }, .offset = 8 },
|
||||
MimeType { .name = "image/x-icon"sv, .common_extensions = { ".ico"sv }, .description = "ICO image data"sv },
|
||||
MimeType { .name = "image/x-ilbm"sv, .common_extensions = { ".iff"sv, ".lbm"sv }, .description = "Interleaved bitmap image data"sv, .magic_bytes = Vector<u8> { 0x46, 0x4F, 0x52, 0x4F } },
|
||||
MimeType { .name = "image/x-jbig2"sv, .common_extensions = { ".jbig2"sv, ".jb2"sv }, .description = "JBIG2 image data"sv, .magic_bytes = Vector<u8> { 0x97, 0x4A, 0x42, 0x32, 0x0D, 0x0A, 0x1A, 0x0A } },
|
||||
MimeType { .name = "image/x-portable-arbitrarymap"sv, .common_extensions = { ".pam"sv }, .description = "PAM image data"sv, .magic_bytes = Vector<u8> { 0x50, 0x37, 0x0A } },
|
||||
MimeType { .name = "image/x-portable-bitmap"sv, .common_extensions = { ".pbm"sv }, .description = "PBM image data"sv, .magic_bytes = Vector<u8> { 0x50, 0x31, 0x0A } },
|
||||
MimeType { .name = "image/x-portable-graymap"sv, .common_extensions = { ".pgm"sv }, .description = "PGM image data"sv, .magic_bytes = Vector<u8> { 0x50, 0x32, 0x0A } },
|
||||
MimeType { .name = "image/x-portable-pixmap"sv, .common_extensions = { ".ppm"sv }, .description = "PPM image data"sv, .magic_bytes = Vector<u8> { 0x50, 0x33, 0x0A } },
|
||||
MimeType { .name = "image/x-targa"sv, .common_extensions = { ".tga"sv }, .description = "Targa image data"sv },
|
||||
MimeType { .name = "image/avif"sv, .common_extensions = { ".avif"sv }, .description = "AVIF image data"sv },
|
||||
MimeType { .name = "image/bmp"sv, .common_extensions = { ".bmp"sv }, .description = "BMP image data"sv, .magic_bytes = Vector<u8> { 'B', 'M' } },
|
||||
MimeType { .name = "image/gif"sv, .common_extensions = { ".gif"sv }, .description = "GIF image data"sv, .magic_bytes = Vector<u8> { 'G', 'I', 'F', '8', '7', 'a' } },
|
||||
MimeType { .name = "image/gif"sv, .common_extensions = { ".gif"sv }, .description = "GIF image data"sv, .magic_bytes = Vector<u8> { 'G', 'I', 'F', '8', '9', 'a' } },
|
||||
MimeType { .name = "image/j2c"sv, .common_extensions = { ".j2c"sv, ".j2k"sv }, .description = "JPEG2000 image data codestream"sv, .magic_bytes = Vector<u8> { 0xFF, 0x4F, 0xFF, 0x51 } },
|
||||
MimeType { .name = "image/jp2"sv, .common_extensions = { ".jp2"sv, ".jpf"sv, ".jpx"sv }, .description = "JPEG2000 image data"sv, .magic_bytes = Vector<u8> { 0x00, 0x00, 0x00, 0x0C, 0x6A, 0x50, 0x20, 0x20, 0x0D, 0x0A, 0x87, 0x0A } },
|
||||
MimeType { .name = "image/jpeg"sv, .common_extensions = { ".jpg"sv, ".jpeg"sv }, .description = "JPEG image data"sv, .magic_bytes = Vector<u8> { 0xFF, 0xD8, 0xFF } },
|
||||
MimeType { .name = "image/jxl"sv, .common_extensions = { ".jxl"sv }, .description = "JPEG XL image data"sv, .magic_bytes = Vector<u8> { 0xFF, 0x0A } },
|
||||
MimeType { .name = "image/png"sv, .common_extensions = { ".png"sv }, .description = "PNG image data"sv, .magic_bytes = Vector<u8> { 0x89, 'P', 'N', 'G', 0x0D, 0x0A, 0x1A, 0x0A } },
|
||||
MimeType { .name = "image/svg+xml"sv, .common_extensions = { ".svg"sv }, .description = "Scalable Vector Graphics image"sv },
|
||||
MimeType { .name = "image/tiff"sv, .common_extensions = { ".tiff"sv }, .description = "TIFF image data"sv, .magic_bytes = Vector<u8> { 'I', 'I', '*', 0x00 } },
|
||||
MimeType { .name = "image/tiff"sv, .common_extensions = { ".tiff"sv }, .description = "TIFF image data"sv, .magic_bytes = Vector<u8> { 'M', 'M', 0x00, '*' } },
|
||||
MimeType { .name = "image/webp"sv, .common_extensions = { ".webp"sv }, .description = "WebP image data"sv, .magic_bytes = Vector<u8> { 'W', 'E', 'B', 'P' }, .offset = 8 },
|
||||
MimeType { .name = "image/x-icon"sv, .common_extensions = { ".ico"sv }, .description = "ICO image data"sv },
|
||||
MimeType { .name = "image/x-ilbm"sv, .common_extensions = { ".iff"sv, ".lbm"sv }, .description = "Interleaved bitmap image data"sv, .magic_bytes = Vector<u8> { 0x46, 0x4F, 0x52, 0x4F } },
|
||||
MimeType { .name = "image/x-jbig2"sv, .common_extensions = { ".jbig2"sv, ".jb2"sv }, .description = "JBIG2 image data"sv, .magic_bytes = Vector<u8> { 0x97, 0x4A, 0x42, 0x32, 0x0D, 0x0A, 0x1A, 0x0A } },
|
||||
MimeType { .name = "image/x-portable-arbitrarymap"sv, .common_extensions = { ".pam"sv }, .description = "PAM image data"sv, .magic_bytes = Vector<u8> { 0x50, 0x37, 0x0A } },
|
||||
MimeType { .name = "image/x-portable-bitmap"sv, .common_extensions = { ".pbm"sv }, .description = "PBM image data"sv, .magic_bytes = Vector<u8> { 0x50, 0x31, 0x0A } },
|
||||
MimeType { .name = "image/x-portable-graymap"sv, .common_extensions = { ".pgm"sv }, .description = "PGM image data"sv, .magic_bytes = Vector<u8> { 0x50, 0x32, 0x0A } },
|
||||
MimeType { .name = "image/x-portable-pixmap"sv, .common_extensions = { ".ppm"sv }, .description = "PPM image data"sv, .magic_bytes = Vector<u8> { 0x50, 0x33, 0x0A } },
|
||||
MimeType { .name = "image/x-targa"sv, .common_extensions = { ".tga"sv }, .description = "Targa image data"sv },
|
||||
|
||||
MimeType { .name = "text/css"sv, .common_extensions = { ".css"sv }, .description = "Cascading Style Sheet"sv },
|
||||
MimeType { .name = "text/csv"sv, .common_extensions = { ".csv"sv }, .description = "CSV text"sv },
|
||||
MimeType { .name = "text/html"sv, .common_extensions = { ".html"sv, ".htm"sv, "/"sv }, .description = "HTML document"sv }, // FIXME: The "/" seems dubious
|
||||
MimeType { .name = "text/xml"sv, .common_extensions = { ".xml"sv }, .description = "XML document"sv },
|
||||
MimeType { .name = "text/markdown"sv, .common_extensions = { ".md"sv }, .description = "Markdown document"sv },
|
||||
MimeType { .name = "text/plain"sv, .common_extensions = Vector(s_plaintext_suffixes.span()), .description = "plain text"sv },
|
||||
MimeType { .name = "text/x-shellscript"sv, .common_extensions = { ".sh"sv }, .description = "POSIX shell script text executable"sv, .magic_bytes = Vector<u8> { '#', '!', '/', 'b', 'i', 'n', '/', 's', 'h', '\n' } },
|
||||
MimeType { .name = "text/css"sv, .common_extensions = { ".css"sv }, .description = "Cascading Style Sheet"sv },
|
||||
MimeType { .name = "text/csv"sv, .common_extensions = { ".csv"sv }, .description = "CSV text"sv },
|
||||
MimeType { .name = "text/html"sv, .common_extensions = { ".html"sv, ".htm"sv, "/"sv }, .description = "HTML document"sv }, // FIXME: The "/" seems dubious
|
||||
MimeType { .name = "text/xml"sv, .common_extensions = { ".xml"sv }, .description = "XML document"sv },
|
||||
MimeType { .name = "text/markdown"sv, .common_extensions = { ".md"sv }, .description = "Markdown document"sv },
|
||||
MimeType { .name = "text/plain"sv, .common_extensions = Vector(s_plaintext_suffixes.span()), .description = "plain text"sv },
|
||||
MimeType { .name = "text/x-shellscript"sv, .common_extensions = { ".sh"sv }, .description = "POSIX shell script text executable"sv, .magic_bytes = Vector<u8> { '#', '!', '/', 'b', 'i', 'n', '/', 's', 'h', '\n' } },
|
||||
|
||||
MimeType { .name = "video/matroska"sv, .common_extensions = { ".mkv"sv }, .description = "Matroska container"sv, .magic_bytes = Vector<u8> { 0x1A, 0x45, 0xDF, 0xA3 } },
|
||||
MimeType { .name = "video/webm"sv, .common_extensions = { ".webm"sv }, .description = "WebM video"sv },
|
||||
};
|
||||
MimeType { .name = "video/matroska"sv, .common_extensions = { ".mkv"sv }, .description = "Matroska container"sv, .magic_bytes = Vector<u8> { 0x1A, 0x45, 0xDF, 0xA3 } },
|
||||
MimeType { .name = "video/webm"sv, .common_extensions = { ".webm"sv }, .description = "WebM video"sv },
|
||||
};
|
||||
}
|
||||
|
||||
static auto const& registered_mime_types()
|
||||
{
|
||||
static NeverDestroyed<decltype(make_registered_mime_types())> mime_types { make_registered_mime_types() };
|
||||
return *mime_types;
|
||||
}
|
||||
|
||||
StringView guess_mime_type_based_on_filename(StringView path)
|
||||
{
|
||||
for (auto const& mime_type : s_registered_mime_type) {
|
||||
for (auto const& mime_type : registered_mime_types()) {
|
||||
for (auto const possible_extension : mime_type.common_extensions) {
|
||||
if (path.ends_with(possible_extension))
|
||||
return mime_type.name;
|
||||
|
|
@ -161,7 +171,7 @@ StringView guess_mime_type_based_on_filename(StringView path)
|
|||
|
||||
Optional<StringView> guess_mime_type_based_on_sniffed_bytes(ReadonlyBytes bytes)
|
||||
{
|
||||
for (auto const& mime_type : s_registered_mime_type) {
|
||||
for (auto const& mime_type : registered_mime_types()) {
|
||||
if (mime_type.magic_bytes.has_value()
|
||||
&& bytes.size() >= mime_type.offset
|
||||
&& bytes.slice(mime_type.offset).starts_with(*mime_type.magic_bytes)) {
|
||||
|
|
@ -174,7 +184,7 @@ Optional<StringView> guess_mime_type_based_on_sniffed_bytes(ReadonlyBytes bytes)
|
|||
|
||||
Optional<MimeType const&> get_mime_type_data(StringView mime_name)
|
||||
{
|
||||
for (auto const& mime_type : s_registered_mime_type) {
|
||||
for (auto const& mime_type : registered_mime_types()) {
|
||||
if (mime_name == mime_type.name)
|
||||
return mime_type;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/String.h>
|
||||
#include <LibCore/File.h>
|
||||
#include <LibCore/Platform/ProcessStatistics.h>
|
||||
|
|
@ -20,12 +21,12 @@ ErrorOr<void> update_process_statistics(ProcessStatistics& statistics)
|
|||
// Read the total time scheduled from /proc/stat, and each process's usage from /proc/pid/stat
|
||||
// Calculate the CPU percentage for each process based on the total time scheduled and the time spent in the process
|
||||
|
||||
static auto proc_stat = TRY(Core::File::open("/proc/stat"sv, Core::File::OpenMode::Read));
|
||||
TRY(proc_stat->seek(0, SeekMode::SetPosition));
|
||||
static NeverDestroyed<NonnullOwnPtr<Core::File>> proc_stat { TRY(Core::File::open("/proc/stat"sv, Core::File::OpenMode::Read)) };
|
||||
TRY((*proc_stat)->seek(0, SeekMode::SetPosition));
|
||||
|
||||
char buf[1024] = {};
|
||||
auto buffer = Bytes { buf, sizeof(buf) };
|
||||
auto line = TRY(proc_stat->read_some(buffer));
|
||||
auto line = TRY((*proc_stat)->read_some(buffer));
|
||||
|
||||
int user_time = 0;
|
||||
int system_time = 0;
|
||||
|
|
|
|||
|
|
@ -8,15 +8,20 @@
|
|||
|
||||
#include <AK/Format.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/NumberFormat.h>
|
||||
|
||||
namespace Core {
|
||||
|
||||
static HashMap<ByteString, TimingInfo> g_timing_info_table;
|
||||
static auto& timing_info_table()
|
||||
{
|
||||
static NeverDestroyed<HashMap<ByteString, TimingInfo>> timing_info_table;
|
||||
return *timing_info_table;
|
||||
}
|
||||
|
||||
void log_timing_info(ByteString const& name, AK::Duration const& elapsed_time, u64 print_every_n_calls)
|
||||
{
|
||||
auto& timing_info = g_timing_info_table.ensure(name);
|
||||
auto& timing_info = timing_info_table().ensure(name);
|
||||
timing_info.call_count++;
|
||||
timing_info.cumulative_time_nanoseconds += elapsed_time.to_nanoseconds();
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibCore/DirIterator.h>
|
||||
#include <LibCore/ResourceImplementation.h>
|
||||
#include <LibCore/ResourceImplementationFile.h>
|
||||
|
|
@ -11,18 +12,23 @@
|
|||
|
||||
namespace Core {
|
||||
|
||||
static OwnPtr<ResourceImplementation> s_the;
|
||||
static auto& installed_resource_implementation()
|
||||
{
|
||||
static NeverDestroyed<OwnPtr<ResourceImplementation>> implementation;
|
||||
return *implementation;
|
||||
}
|
||||
|
||||
void ResourceImplementation::install(OwnPtr<ResourceImplementation> the)
|
||||
{
|
||||
s_the = move(the);
|
||||
installed_resource_implementation() = move(the);
|
||||
}
|
||||
|
||||
ResourceImplementation& ResourceImplementation::the()
|
||||
{
|
||||
if (!s_the)
|
||||
auto& implementation = installed_resource_implementation();
|
||||
if (!implementation)
|
||||
install(make<ResourceImplementationFile>("/res"_string));
|
||||
return *s_the;
|
||||
return *implementation;
|
||||
}
|
||||
|
||||
NonnullRefPtr<Resource> ResourceImplementation::make_resource(String full_path, NonnullOwnPtr<Core::MappedFile> file, time_t modified_time)
|
||||
|
|
|
|||
|
|
@ -6,15 +6,21 @@
|
|||
*/
|
||||
|
||||
#include "SystemServerTakeover.h"
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibCore/Environment.h>
|
||||
#include <LibCore/Socket.h>
|
||||
#include <LibCore/System.h>
|
||||
|
||||
namespace Core {
|
||||
|
||||
HashMap<ByteString, int> s_overtaken_sockets {};
|
||||
bool s_overtaken_sockets_parsed { false };
|
||||
|
||||
static auto& overtaken_sockets()
|
||||
{
|
||||
static NeverDestroyed<HashMap<ByteString, int>> sockets;
|
||||
return *sockets;
|
||||
}
|
||||
|
||||
static void parse_sockets_from_system_server()
|
||||
{
|
||||
VERIFY(!s_overtaken_sockets_parsed);
|
||||
|
|
@ -29,7 +35,7 @@ static void parse_sockets_from_system_server()
|
|||
for (auto socket : sockets->split_view(';')) {
|
||||
auto params = socket.split_view(':');
|
||||
VERIFY(params.size() == 2);
|
||||
s_overtaken_sockets.set(params[0].to_byte_string(), params[1].to_number<int>().value());
|
||||
overtaken_sockets().set(params[0].to_byte_string(), params[1].to_number<int>().value());
|
||||
}
|
||||
|
||||
s_overtaken_sockets_parsed = true;
|
||||
|
|
@ -46,11 +52,11 @@ ErrorOr<NonnullOwnPtr<Core::LocalSocket>> take_over_socket_from_system_server(By
|
|||
int fd;
|
||||
if (socket_path.is_empty()) {
|
||||
// We want the first (and only) socket.
|
||||
VERIFY(s_overtaken_sockets.size() == 1);
|
||||
fd = s_overtaken_sockets.begin()->value;
|
||||
VERIFY(overtaken_sockets().size() == 1);
|
||||
fd = overtaken_sockets().begin()->value;
|
||||
} else {
|
||||
auto it = s_overtaken_sockets.find(socket_path);
|
||||
if (it == s_overtaken_sockets.end())
|
||||
auto it = overtaken_sockets().find(socket_path);
|
||||
if (it == overtaken_sockets().end())
|
||||
return Error::from_string_literal("Non-existent socket requested");
|
||||
fd = it->value;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibCore/EventLoopImplementation.h>
|
||||
#include <LibCore/EventReceiver.h>
|
||||
|
|
@ -46,11 +47,16 @@ struct ThreadEventQueue::Private {
|
|||
};
|
||||
|
||||
static pthread_key_t s_current_thread_event_queue_key;
|
||||
static Sync::OnceFlag s_current_thread_event_queue_key_once {};
|
||||
|
||||
static auto& current_thread_event_queue_key_once()
|
||||
{
|
||||
static NeverDestroyed<Sync::OnceFlag> once;
|
||||
return *once;
|
||||
}
|
||||
|
||||
ThreadEventQueue* ThreadEventQueue::current_or_null()
|
||||
{
|
||||
Sync::call_once(s_current_thread_event_queue_key_once, [] {
|
||||
Sync::call_once(current_thread_event_queue_key_once(), [] {
|
||||
pthread_key_create(&s_current_thread_event_queue_key, [](void* value) {
|
||||
if (value)
|
||||
delete static_cast<ThreadEventQueue*>(value);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <AK/HashTable.h>
|
||||
#include <AK/MaybeOwned.h>
|
||||
#include <AK/MemoryStream.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <AK/Random.h>
|
||||
#include <AK/StringView.h>
|
||||
|
|
@ -41,22 +42,28 @@ namespace DNS {
|
|||
|
||||
// FIXME: Load these keys from a file (likely something trusted by the system, e.g. "whatever systemd does").
|
||||
// https://data.iana.org/root-anchors/root-anchors.xml
|
||||
static Vector<Messages::Records::DNSKEY> s_root_zone_dnskeys = {
|
||||
{
|
||||
.flags = 257,
|
||||
.protocol = 3,
|
||||
.algorithm = Messages::DNSSEC::Algorithm::RSASHA256,
|
||||
.public_key = decode_base64("AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU="sv).release_value(),
|
||||
.calculated_key_tag = 20326,
|
||||
},
|
||||
{
|
||||
.flags = 256,
|
||||
.protocol = 3,
|
||||
.algorithm = Messages::DNSSEC::Algorithm::RSASHA256,
|
||||
.public_key = decode_base64("AwEAAa96jeuknZlaeSrvyAJj6ZHv28hhOKkx3rLGXVaC6rXTsDc449/cidltpkyGwCJNnOAlFNKF2jBosZBU5eeHspaQWOmOElZsjICMQMC3aeHbGiShvZsx4wMYSjH8e7Vrhbu6irwCzVBApESjbUdpWWmEnhathWu1jo+siFUiRAAxm9qyJNg/wOZqqzL/dL/q8PkcRU5oUKEpUge71M3ej2/7CPqpdVwuMoTvoB+ZOT4YeGyxMvHmbrxlFzGOHOijtzN+u1TQNatX2XBuzZNQ1K+s2CXkPIZo7s6JgZyvaBevYtxPvYLw4z9mR7K2vaF18UYH9Z9GNUUeayffKC73PYc="sv).release_value(),
|
||||
.calculated_key_tag = 38696,
|
||||
},
|
||||
};
|
||||
static Vector<Messages::Records::DNSKEY> const& root_zone_dnskeys()
|
||||
{
|
||||
static NeverDestroyed<Vector<Messages::Records::DNSKEY>> root_zone_dnskeys {
|
||||
Vector<Messages::Records::DNSKEY> {
|
||||
{
|
||||
.flags = 257,
|
||||
.protocol = 3,
|
||||
.algorithm = Messages::DNSSEC::Algorithm::RSASHA256,
|
||||
.public_key = decode_base64("AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTOiW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLYA4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU="sv).release_value(),
|
||||
.calculated_key_tag = 20326,
|
||||
},
|
||||
{
|
||||
.flags = 256,
|
||||
.protocol = 3,
|
||||
.algorithm = Messages::DNSSEC::Algorithm::RSASHA256,
|
||||
.public_key = decode_base64("AwEAAa96jeuknZlaeSrvyAJj6ZHv28hhOKkx3rLGXVaC6rXTsDc449/cidltpkyGwCJNnOAlFNKF2jBosZBU5eeHspaQWOmOElZsjICMQMC3aeHbGiShvZsx4wMYSjH8e7Vrhbu6irwCzVBApESjbUdpWWmEnhathWu1jo+siFUiRAAxm9qyJNg/wOZqqzL/dL/q8PkcRU5oUKEpUge71M3ej2/7CPqpdVwuMoTvoB+ZOT4YeGyxMvHmbrxlFzGOHOijtzN+u1TQNatX2XBuzZNQ1K+s2CXkPIZo7s6JgZyvaBevYtxPvYLw4z9mR7K2vaF18UYH9Z9GNUUeayffKC73PYc="sv).release_value(),
|
||||
.calculated_key_tag = 38696,
|
||||
},
|
||||
}
|
||||
};
|
||||
return *root_zone_dnskeys;
|
||||
}
|
||||
|
||||
class Resolver;
|
||||
|
||||
|
|
@ -1134,7 +1141,7 @@ private:
|
|||
};
|
||||
|
||||
if (is_root_zone) {
|
||||
resolve_using_keys(s_root_zone_dnskeys);
|
||||
resolve_using_keys(root_zone_dnskeys());
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,10 +29,10 @@ void DeviceActor::handle_message(Message const& message)
|
|||
if (message.type == "getDescription"sv) {
|
||||
auto build_id = Core::Version::read_long_version_string();
|
||||
|
||||
static auto browser_name = String::from_utf8_without_validation({ BROWSER_NAME, __builtin_strlen(BROWSER_NAME) });
|
||||
static auto browser_version = String::from_utf8_without_validation({ BROWSER_VERSION, __builtin_strlen(BROWSER_VERSION) });
|
||||
static auto platform_name = String::from_utf8_without_validation({ OS_STRING, __builtin_strlen(OS_STRING) });
|
||||
static auto arch = String::from_utf8_without_validation({ CPU_STRING, __builtin_strlen(CPU_STRING) });
|
||||
static auto& browser_name = *new String(String::from_utf8_without_validation({ BROWSER_NAME, __builtin_strlen(BROWSER_NAME) }));
|
||||
static auto& browser_version = *new String(String::from_utf8_without_validation({ BROWSER_VERSION, __builtin_strlen(BROWSER_VERSION) }));
|
||||
static auto& platform_name = *new String(String::from_utf8_without_validation({ OS_STRING, __builtin_strlen(OS_STRING) }));
|
||||
static auto& arch = *new String(String::from_utf8_without_validation({ CPU_STRING, __builtin_strlen(CPU_STRING) }));
|
||||
|
||||
// https://github.com/mozilla/gecko-dev/blob/master/devtools/shared/system.js
|
||||
JsonObject value;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <AK/JsonArray.h>
|
||||
#include <AK/JsonObject.h>
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/NumberFormat.h>
|
||||
#include <AK/Platform.h>
|
||||
#include <AK/ScopeGuard.h>
|
||||
|
|
@ -139,7 +140,13 @@ struct IncrementalSweepStats {
|
|||
Vector<IncrementalSweepBatchStats> batches;
|
||||
Core::ElapsedTimer timer { Core::TimerType::Precise };
|
||||
};
|
||||
IncrementalSweepStats g_incremental_sweep_stats;
|
||||
|
||||
IncrementalSweepStats& incremental_sweep_stats()
|
||||
{
|
||||
static NeverDestroyed<IncrementalSweepStats> stats;
|
||||
return *stats;
|
||||
}
|
||||
|
||||
bool g_next_incremental_sweep_should_report { false };
|
||||
|
||||
// Set by collect_garbage() while a reported collection is in flight. Used by
|
||||
|
|
@ -196,9 +203,9 @@ void print_gc_report(i64 total_us, size_t live_block_count)
|
|||
|
||||
void record_incremental_sweep_batch(size_t blocks_swept, i64 elapsed_us, bool forced)
|
||||
{
|
||||
if (!g_incremental_sweep_stats.should_report || blocks_swept == 0)
|
||||
if (!incremental_sweep_stats().should_report || blocks_swept == 0)
|
||||
return;
|
||||
g_incremental_sweep_stats.batches.append({
|
||||
incremental_sweep_stats().batches.append({
|
||||
.blocks_swept = blocks_swept,
|
||||
.elapsed_us = elapsed_us,
|
||||
.forced = forced,
|
||||
|
|
@ -207,30 +214,30 @@ void record_incremental_sweep_batch(size_t blocks_swept, i64 elapsed_us, bool fo
|
|||
|
||||
void print_incremental_sweep_report(size_t live_cell_bytes, size_t live_external_bytes, size_t next_gc_bytes_threshold)
|
||||
{
|
||||
if (!g_incremental_sweep_stats.should_report)
|
||||
if (!incremental_sweep_stats().should_report)
|
||||
return;
|
||||
|
||||
size_t swept_blocks = 0;
|
||||
i64 batch_time_us = 0;
|
||||
i64 shortest_batch_us = NumericLimits<i64>::max();
|
||||
i64 longest_batch_us = 0;
|
||||
for (auto const& batch : g_incremental_sweep_stats.batches) {
|
||||
for (auto const& batch : incremental_sweep_stats().batches) {
|
||||
swept_blocks += batch.blocks_swept;
|
||||
batch_time_us += batch.elapsed_us;
|
||||
shortest_batch_us = min(shortest_batch_us, batch.elapsed_us);
|
||||
longest_batch_us = max(longest_batch_us, batch.elapsed_us);
|
||||
}
|
||||
|
||||
if (g_incremental_sweep_stats.batches.is_empty())
|
||||
if (incremental_sweep_stats().batches.is_empty())
|
||||
shortest_batch_us = 0;
|
||||
|
||||
dbgln("Incremental sweep report");
|
||||
dbgln("=================================================================");
|
||||
dbgln("Totals:");
|
||||
dbgln(" Wall time: {} us", g_incremental_sweep_stats.timer.elapsed_time().to_microseconds());
|
||||
dbgln(" Wall time: {} us", incremental_sweep_stats().timer.elapsed_time().to_microseconds());
|
||||
dbgln(" Batch time: {} us", batch_time_us);
|
||||
dbgln(" Batches: {}", g_incremental_sweep_stats.batches.size());
|
||||
dbgln(" Swept blocks: {} / {} ({})", swept_blocks, g_incremental_sweep_stats.total_blocks, human_readable_size(swept_blocks * HeapBlock::BLOCK_SIZE));
|
||||
dbgln(" Batches: {}", incremental_sweep_stats().batches.size());
|
||||
dbgln(" Swept blocks: {} / {} ({})", swept_blocks, incremental_sweep_stats().total_blocks, human_readable_size(swept_blocks * HeapBlock::BLOCK_SIZE));
|
||||
dbgln(" Live cells: {}", human_readable_size(live_cell_bytes));
|
||||
dbgln(" Live external: {}", human_readable_size(live_external_bytes));
|
||||
dbgln(" Next threshold: {}", human_readable_size(next_gc_bytes_threshold));
|
||||
|
|
@ -238,8 +245,8 @@ void print_incremental_sweep_report(size_t live_cell_bytes, size_t live_external
|
|||
dbgln("Batch timings:");
|
||||
dbgln(" Shortest batch: {} us", shortest_batch_us);
|
||||
dbgln(" Longest batch: {} us", longest_batch_us);
|
||||
for (size_t i = 0; i < g_incremental_sweep_stats.batches.size(); ++i) {
|
||||
auto const& batch = g_incremental_sweep_stats.batches[i];
|
||||
for (size_t i = 0; i < incremental_sweep_stats().batches.size(); ++i) {
|
||||
auto const& batch = incremental_sweep_stats().batches[i];
|
||||
dbgln(" #{:>3}: {:>5} blocks in {:>8} us{}", i + 1, batch.blocks_swept, batch.elapsed_us, batch.forced ? " (forced)"sv : ""sv);
|
||||
}
|
||||
dbgln("=================================================================");
|
||||
|
|
@ -1279,13 +1286,13 @@ void Heap::start_incremental_sweep()
|
|||
m_incremental_sweep_active = true;
|
||||
m_sweep_live_cell_bytes = 0;
|
||||
m_sweep_live_external_bytes = 0;
|
||||
g_incremental_sweep_stats.should_report = false;
|
||||
g_incremental_sweep_stats.total_blocks = 0;
|
||||
g_incremental_sweep_stats.batches.clear();
|
||||
g_incremental_sweep_stats.should_report = g_next_incremental_sweep_should_report;
|
||||
incremental_sweep_stats().should_report = false;
|
||||
incremental_sweep_stats().total_blocks = 0;
|
||||
incremental_sweep_stats().batches.clear();
|
||||
incremental_sweep_stats().should_report = g_next_incremental_sweep_should_report;
|
||||
g_next_incremental_sweep_should_report = false;
|
||||
if (g_incremental_sweep_stats.should_report)
|
||||
g_incremental_sweep_stats.timer.start();
|
||||
if (incremental_sweep_stats().should_report)
|
||||
incremental_sweep_stats().timer.start();
|
||||
|
||||
// Populate each allocator's pending sweep list with its current blocks.
|
||||
// Blocks allocated during incremental sweep won't be on these lists
|
||||
|
|
@ -1300,7 +1307,7 @@ void Heap::start_incremental_sweep()
|
|||
if (allocator.has_blocks_pending_sweep())
|
||||
m_allocators_to_sweep.append(allocator);
|
||||
}
|
||||
g_incremental_sweep_stats.total_blocks = total_blocks;
|
||||
incremental_sweep_stats().total_blocks = total_blocks;
|
||||
|
||||
dbgln_if(INCREMENTAL_SWEEP_DEBUG, "[sweep] {} blocks to sweep", total_blocks);
|
||||
|
||||
|
|
|
|||
|
|
@ -26,8 +26,8 @@ SystemFontProvider::~SystemFontProvider() = default;
|
|||
|
||||
FontDatabase& FontDatabase::the()
|
||||
{
|
||||
static FontDatabase s_the;
|
||||
return s_the;
|
||||
static FontDatabase& database = *new FontDatabase;
|
||||
return database;
|
||||
}
|
||||
|
||||
SystemFontProvider& FontDatabase::install_system_font_provider(NonnullOwnPtr<SystemFontProvider> provider)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/Assertions.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibGfx/Font/GlobalFontConfig.h>
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
|
|
@ -26,8 +27,8 @@ GlobalFontConfig::~GlobalFontConfig()
|
|||
|
||||
GlobalFontConfig& GlobalFontConfig::the()
|
||||
{
|
||||
static GlobalFontConfig s_the;
|
||||
return s_the;
|
||||
static NeverDestroyed<GlobalFontConfig> s_the;
|
||||
return *s_the;
|
||||
}
|
||||
|
||||
FcConfig* GlobalFontConfig::get()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,13 @@
|
|||
|
||||
#include <fontconfig/fontconfig.h>
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename T>
|
||||
class NeverDestroyed;
|
||||
|
||||
}
|
||||
|
||||
namespace Gfx {
|
||||
|
||||
class GlobalFontConfig {
|
||||
|
|
@ -16,6 +23,8 @@ public:
|
|||
FcConfig* get();
|
||||
|
||||
private:
|
||||
friend class AK::NeverDestroyed<GlobalFontConfig>;
|
||||
|
||||
GlobalFontConfig();
|
||||
~GlobalFontConfig();
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/LsanSuppressions.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibGfx/Font/FontDatabase.h>
|
||||
#include <LibGfx/Font/TypefaceSkia.h>
|
||||
#include <LibIPC/Encoder.h>
|
||||
|
|
@ -35,7 +36,11 @@
|
|||
|
||||
namespace Gfx {
|
||||
|
||||
static sk_sp<SkFontMgr> s_font_manager;
|
||||
static auto& skia_font_manager()
|
||||
{
|
||||
static NeverDestroyed<sk_sp<SkFontMgr>> font_manager;
|
||||
return *font_manager;
|
||||
}
|
||||
|
||||
struct TypefaceSkia::Impl {
|
||||
Impl(sk_sp<SkTypeface> skia_typeface, std::unique_ptr<SkStreamAsset> stream = {}, Optional<SystemUIFontKind> system_ui_font_kind = {}
|
||||
|
|
@ -74,24 +79,25 @@ struct TypefaceSkia::Impl {
|
|||
|
||||
static SkFontMgr& font_manager()
|
||||
{
|
||||
if (!s_font_manager) {
|
||||
auto& font_manager = skia_font_manager();
|
||||
if (!font_manager) {
|
||||
#ifdef AK_OS_MACOS
|
||||
if (Gfx::FontDatabase::the().system_font_provider_name() != "FontConfig"sv) {
|
||||
s_font_manager = SkFontMgr_New_CoreText(nullptr);
|
||||
font_manager = SkFontMgr_New_CoreText(nullptr);
|
||||
}
|
||||
#endif
|
||||
#if defined(AK_OS_ANDROID)
|
||||
s_font_manager = SkFontMgr_New_Android(nullptr);
|
||||
font_manager = SkFontMgr_New_Android(nullptr);
|
||||
#elif defined(AK_OS_WINDOWS)
|
||||
s_font_manager = SkFontMgr_New_DirectWrite();
|
||||
font_manager = SkFontMgr_New_DirectWrite();
|
||||
#else
|
||||
if (!s_font_manager) {
|
||||
s_font_manager = SkFontMgr_New_FontConfig(nullptr, SkFontScanner_Make_FreeType());
|
||||
if (!font_manager) {
|
||||
font_manager = SkFontMgr_New_FontConfig(nullptr, SkFontScanner_Make_FreeType());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
VERIFY(s_font_manager);
|
||||
return *s_font_manager;
|
||||
VERIFY(font_manager);
|
||||
return *font_manager;
|
||||
}
|
||||
|
||||
static std::unique_ptr<SkMemoryStream> copy_stream_to_memory_stream(SkStreamAsset& stream)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <AK/RefPtr.h>
|
||||
#include <AK/Time.h>
|
||||
|
|
@ -37,7 +38,11 @@ static constexpr auto skia_deferred_cleanup_resource_age = std::chrono::seconds(
|
|||
static constexpr auto skia_resource_cache_high_watermark = 384 * MiB;
|
||||
static constexpr auto skia_resource_cache_critical_watermark = 512 * MiB;
|
||||
|
||||
static RefPtr<SkiaBackendContext> s_main_thread_context;
|
||||
static auto& main_thread_context()
|
||||
{
|
||||
static NeverDestroyed<RefPtr<SkiaBackendContext>> context;
|
||||
return *context;
|
||||
}
|
||||
|
||||
#if defined(AK_OS_MACOS) || USE_VULKAN
|
||||
static void invoke_async_flush_callback(void* context)
|
||||
|
|
@ -110,9 +115,9 @@ void SkiaBackendContext::perform_post_flush_cleanup()
|
|||
|
||||
void SkiaBackendContext::initialize_gpu_backend()
|
||||
{
|
||||
VERIFY(!s_main_thread_context);
|
||||
VERIFY(!main_thread_context());
|
||||
|
||||
s_main_thread_context = create_independent_gpu_backend();
|
||||
main_thread_context() = create_independent_gpu_backend();
|
||||
}
|
||||
|
||||
RefPtr<SkiaBackendContext> SkiaBackendContext::create_independent_gpu_backend()
|
||||
|
|
@ -137,7 +142,7 @@ RefPtr<SkiaBackendContext> SkiaBackendContext::create_independent_gpu_backend()
|
|||
|
||||
RefPtr<SkiaBackendContext> SkiaBackendContext::the_main_thread_context()
|
||||
{
|
||||
return s_main_thread_context;
|
||||
return main_thread_context();
|
||||
}
|
||||
|
||||
#ifdef USE_VULKAN
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <LibCore/ConfigFile.h>
|
||||
#include <LibCore/DirIterator.h>
|
||||
|
|
@ -14,17 +15,21 @@
|
|||
|
||||
namespace Gfx {
|
||||
|
||||
static Core::AnonymousBuffer theme_buffer;
|
||||
static auto& theme_buffer()
|
||||
{
|
||||
static NeverDestroyed<Core::AnonymousBuffer> buffer;
|
||||
return *buffer;
|
||||
}
|
||||
|
||||
Core::AnonymousBuffer& current_system_theme_buffer()
|
||||
{
|
||||
VERIFY(theme_buffer.is_valid());
|
||||
return theme_buffer;
|
||||
VERIFY(theme_buffer().is_valid());
|
||||
return theme_buffer();
|
||||
}
|
||||
|
||||
void set_system_theme(Core::AnonymousBuffer buffer)
|
||||
{
|
||||
theme_buffer = move(buffer);
|
||||
theme_buffer() = move(buffer);
|
||||
}
|
||||
|
||||
ErrorOr<Core::AnonymousBuffer> load_system_theme(Core::ConfigFile const& file, Optional<ByteString> const& color_scheme)
|
||||
|
|
@ -39,7 +44,7 @@ ErrorOr<Core::AnonymousBuffer> load_system_theme(Core::ConfigFile const& file, O
|
|||
if (color_scheme.value() != "Custom"sv)
|
||||
memcpy(data->path[(int)PathRole::ColorScheme], color_scheme.value().characters(), color_scheme.value().length());
|
||||
else
|
||||
memcpy(buffer.data<SystemTheme>(), theme_buffer.data<SystemTheme>(), sizeof(SystemTheme));
|
||||
memcpy(buffer.data<SystemTheme>(), theme_buffer().data<SystemTheme>(), sizeof(SystemTheme));
|
||||
}
|
||||
|
||||
auto get_color = [&](auto& name) -> Optional<Color> {
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ ByteString normalize_method(StringView method)
|
|||
{
|
||||
// To normalize a method, if it is a byte-case-insensitive match for `DELETE`, `GET`, `HEAD`, `OPTIONS`, `POST`,
|
||||
// or `PUT`, byte-uppercase it.
|
||||
static auto NORMALIZED_METHODS = to_array<ByteString>({ "DELETE"sv, "GET"sv, "HEAD"sv, "OPTIONS"sv, "POST"sv, "PUT"sv });
|
||||
static constexpr auto normalized_methods = to_array<StringView>({ "DELETE"sv, "GET"sv, "HEAD"sv, "OPTIONS"sv, "POST"sv, "PUT"sv });
|
||||
|
||||
for (auto const& normalized_method : NORMALIZED_METHODS) {
|
||||
for (auto const& normalized_method : normalized_methods) {
|
||||
if (normalized_method.equals_ignoring_ascii_case(method))
|
||||
return normalized_method;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,10 +5,15 @@
|
|||
*/
|
||||
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibIDL/ExposedTo.h>
|
||||
|
||||
static ByteString s_error_string;
|
||||
static auto& error_string()
|
||||
{
|
||||
static NeverDestroyed<ByteString> string;
|
||||
return *string;
|
||||
}
|
||||
|
||||
namespace IDL {
|
||||
|
||||
|
|
@ -54,19 +59,19 @@ ErrorOr<ExposedTo> parse_exposure_set(StringView interface_name, StringView expo
|
|||
if (auto parsed_exposed = exposed_from_string(candidate); parsed_exposed.has_value()) {
|
||||
whom |= parsed_exposed.value();
|
||||
} else {
|
||||
s_error_string = ByteString::formatted("Unknown Exposed attribute candidate {} in {} in {}", candidate, exposed_trimmed, interface_name);
|
||||
return Error::from_string_view(s_error_string.view());
|
||||
error_string() = ByteString::formatted("Unknown Exposed attribute candidate {} in {} in {}", candidate, exposed_trimmed, interface_name);
|
||||
return Error::from_string_view(error_string().view());
|
||||
}
|
||||
}
|
||||
if (whom == ExposedTo::Nobody) {
|
||||
s_error_string = ByteString::formatted("Unknown Exposed attribute {} in {}", exposed_trimmed, interface_name);
|
||||
return Error::from_string_view(s_error_string.view());
|
||||
error_string() = ByteString::formatted("Unknown Exposed attribute {} in {}", exposed_trimmed, interface_name);
|
||||
return Error::from_string_view(error_string().view());
|
||||
}
|
||||
return whom;
|
||||
}
|
||||
|
||||
s_error_string = ByteString::formatted("Unknown Exposed attribute {} in {}", exposed_trimmed, interface_name);
|
||||
return Error::from_string_view(s_error_string.view());
|
||||
error_string() = ByteString::formatted("Unknown Exposed attribute {} in {}", exposed_trimmed, interface_name);
|
||||
return Error::from_string_view(error_string().view());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/BinarySearch.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/NumericLimits.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
|
|
@ -636,8 +637,8 @@ size_t Executable::external_memory_size() const
|
|||
|
||||
static Vector<PropertyLookupCache*>& static_property_lookup_caches()
|
||||
{
|
||||
static Vector<PropertyLookupCache*> caches;
|
||||
return caches;
|
||||
static NeverDestroyed<Vector<PropertyLookupCache*>> caches;
|
||||
return *caches;
|
||||
}
|
||||
|
||||
StaticPropertyLookupCache::StaticPropertyLookupCache()
|
||||
|
|
@ -732,8 +733,8 @@ SourceRange const& Executable::get_source_range(u32 program_counter)
|
|||
return m_source_range_cache.ensure(program_counter, [&] {
|
||||
if (auto source_range = source_range_at(program_counter); source_range.has_value())
|
||||
return *source_range;
|
||||
static SourceRange dummy { SourceCode::create({}, Utf16String {}), {} };
|
||||
return dummy;
|
||||
static NeverDestroyed<SourceRange> dummy { SourceRange { SourceCode::create({}, Utf16String {}), {} } };
|
||||
return *dummy;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ ThrowCompletionOr<size_t> length_of_array_like(VM& vm, Object const& object)
|
|||
return object.indexed_array_like_size();
|
||||
|
||||
// 1. Return ℝ(? ToLength(? Get(obj, "length"))).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
return TRY(object.get(vm.names.length, cache)).to_length(vm);
|
||||
}
|
||||
|
||||
|
|
@ -202,7 +202,7 @@ ThrowCompletionOr<GC::RootVector<Value>> create_list_from_array_like(VM& vm, Val
|
|||
ThrowCompletionOr<FunctionObject*> species_constructor(VM& vm, Object const& object, FunctionObject& default_constructor)
|
||||
{
|
||||
// 1. Let C be ? Get(O, "constructor").
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto constructor = TRY(object.get(vm.names.constructor, cache));
|
||||
|
||||
// 2. If C is undefined, return defaultConstructor.
|
||||
|
|
@ -214,7 +214,7 @@ ThrowCompletionOr<FunctionObject*> species_constructor(VM& vm, Object const& obj
|
|||
return vm.throw_completion<TypeError>(ErrorType::NotAConstructor, constructor);
|
||||
|
||||
// 4. Let S be ? Get(C, @@species).
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto species = TRY(constructor.as_object().get(vm.well_known_symbol_species(), cache2));
|
||||
|
||||
// 5. If S is either undefined or null, return defaultConstructor.
|
||||
|
|
@ -414,7 +414,7 @@ ThrowCompletionOr<Object*> get_prototype_from_constructor(VM& vm, FunctionObject
|
|||
// 1. Assert: intrinsicDefaultProto is this specification's name of an intrinsic object. The corresponding object must be an intrinsic that is intended to be used as the [[Prototype]] value of an object.
|
||||
|
||||
// 2. Let proto be ? Get(constructor, "prototype").
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto prototype = TRY(constructor.get(vm.names.prototype, cache));
|
||||
|
||||
// 3. If Type(proto) is not Object, then
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include <AK/Function.h>
|
||||
#include <AK/HashTable.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/ScopeGuard.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
|
|
@ -29,7 +30,11 @@ namespace JS {
|
|||
|
||||
GC_DEFINE_ALLOCATOR(ArrayPrototype);
|
||||
|
||||
static HashTable<GC::Ref<Object>> s_array_join_seen_objects;
|
||||
static auto& array_join_seen_objects()
|
||||
{
|
||||
static NeverDestroyed<HashTable<GC::Ref<Object>>> seen_objects;
|
||||
return *seen_objects;
|
||||
}
|
||||
|
||||
ArrayPrototype::ArrayPrototype(Realm& realm)
|
||||
: Array(realm, realm.intrinsics().object_prototype())
|
||||
|
|
@ -119,7 +124,7 @@ static ThrowCompletionOr<Object*> array_species_create(VM& vm, Object& original_
|
|||
if (!is_array)
|
||||
return TRY(Array::create(realm, length)).ptr();
|
||||
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto constructor = TRY(original_array.get(vm.names.constructor, cache));
|
||||
if (constructor.is_constructor()) {
|
||||
auto& constructor_function = constructor.as_function();
|
||||
|
|
@ -132,7 +137,7 @@ static ThrowCompletionOr<Object*> array_species_create(VM& vm, Object& original_
|
|||
}
|
||||
|
||||
if (constructor.is_object()) {
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
constructor = TRY(constructor.as_object().get(vm.well_known_symbol_species(), cache2));
|
||||
if (constructor.is_null())
|
||||
constructor = js_undefined();
|
||||
|
|
@ -918,11 +923,11 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::join)
|
|||
// This is not part of the spec, but all major engines do some kind of circular reference checks.
|
||||
// FWIW: engine262, a "100% spec compliant" ECMA-262 impl, aborts with "too much recursion".
|
||||
// Same applies to Array.prototype.toLocaleString().
|
||||
if (s_array_join_seen_objects.contains(this_object))
|
||||
if (array_join_seen_objects().contains(this_object))
|
||||
return PrimitiveString::create(vm, String {});
|
||||
s_array_join_seen_objects.set(this_object);
|
||||
array_join_seen_objects().set(this_object);
|
||||
ArmedScopeGuard unsee_object_guard = [&] {
|
||||
s_array_join_seen_objects.remove(this_object);
|
||||
array_join_seen_objects().remove(this_object);
|
||||
};
|
||||
|
||||
auto length = TRY(length_of_array_like(vm, this_object));
|
||||
|
|
@ -1803,11 +1808,11 @@ JS_DEFINE_NATIVE_FUNCTION(ArrayPrototype::to_locale_string)
|
|||
// 1. Let array be ? ToObject(this value).
|
||||
auto this_object = TRY(vm.this_value().to_object(vm));
|
||||
|
||||
if (s_array_join_seen_objects.contains(this_object))
|
||||
if (array_join_seen_objects().contains(this_object))
|
||||
return PrimitiveString::create(vm, String {});
|
||||
s_array_join_seen_objects.set(this_object);
|
||||
array_join_seen_objects().set(this_object);
|
||||
ArmedScopeGuard unsee_object_guard = [&] {
|
||||
s_array_join_seen_objects.remove(this_object);
|
||||
array_join_seen_objects().remove(this_object);
|
||||
};
|
||||
|
||||
// 2. Let len be ? ToLength(? Get(array, "length")).
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/NumericLimits.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/Time.h>
|
||||
|
|
@ -365,15 +366,15 @@ Crypto::SignedBigInteger get_utc_epoch_nanoseconds(Temporal::ISODateTime const&
|
|||
|
||||
i64 clip_bigint_to_sane_time(Crypto::SignedBigInteger const& value)
|
||||
{
|
||||
static Crypto::SignedBigInteger const min_bigint { NumericLimits<i64>::min() };
|
||||
static Crypto::SignedBigInteger const max_bigint { NumericLimits<i64>::max() };
|
||||
static NeverDestroyed<Crypto::SignedBigInteger> min_bigint { NumericLimits<i64>::min() };
|
||||
static NeverDestroyed<Crypto::SignedBigInteger> max_bigint { NumericLimits<i64>::max() };
|
||||
|
||||
// The provided epoch (nano)seconds value is potentially out of range for AK::Duration and subsequently
|
||||
// get_time_zone_offset(). We can safely assume that the TZDB has no useful information that far
|
||||
// into the past and future anyway, so clamp it to the i64 range.
|
||||
if (value < min_bigint)
|
||||
if (value < *min_bigint)
|
||||
return NumericLimits<i64>::min();
|
||||
if (value > max_bigint)
|
||||
if (value > *max_bigint)
|
||||
return NumericLimits<i64>::max();
|
||||
|
||||
return value.to_i64();
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/Runtime/ErrorData.h>
|
||||
#include <LibJS/Runtime/ExecutionContext.h>
|
||||
|
|
@ -15,12 +16,16 @@
|
|||
|
||||
namespace JS {
|
||||
|
||||
static SourceRange dummy_source_range { SourceCode::create({}, Utf16String {}), {} };
|
||||
static auto& dummy_source_range()
|
||||
{
|
||||
static NeverDestroyed<SourceRange> source_range { SourceRange { SourceCode::create({}, Utf16String {}), {} } };
|
||||
return *source_range;
|
||||
}
|
||||
|
||||
SourceRange const& TracebackFrame::source_range() const
|
||||
{
|
||||
if (!cached_source_range.has_value())
|
||||
return dummy_source_range;
|
||||
return dummy_source_range();
|
||||
return *cached_source_range;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
namespace JS {
|
||||
|
||||
#define __ENUMERATE_JS_ERROR(name, message) \
|
||||
const ErrorType ErrorType::name = ErrorType(message##sv);
|
||||
ErrorType const& ErrorType::name = *new ErrorType(message##sv);
|
||||
JS_ENUMERATE_ERROR_TYPES(__ENUMERATE_JS_ERROR)
|
||||
#undef __ENUMERATE_JS_ERROR
|
||||
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ namespace JS {
|
|||
class JS_API ErrorType {
|
||||
public:
|
||||
#define __ENUMERATE_JS_ERROR(name, message) \
|
||||
static const ErrorType name;
|
||||
static ErrorType const& name;
|
||||
JS_ENUMERATE_ERROR_TYPES(__ENUMERATE_JS_ERROR)
|
||||
#undef __ENUMERATE_JS_ERROR
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <AK/AllOf.h>
|
||||
#include <AK/CharacterTypes.h>
|
||||
#include <AK/Find.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
|
|
@ -134,7 +135,7 @@ bool is_well_formed_currency_code(StringView currency)
|
|||
Vector<TimeZoneIdentifier> const& available_named_time_zone_identifiers()
|
||||
{
|
||||
// It is recommended that the result of AvailableNamedTimeZoneIdentifiers remains the same for the lifetime of the surrounding agent.
|
||||
static auto named_time_zone_identifiers = []() {
|
||||
static NeverDestroyed<Vector<TimeZoneIdentifier>> named_time_zone_identifiers { []() {
|
||||
// 1. Let identifiers be a List containing the String value of each Zone or Link name in the IANA Time Zone Database.
|
||||
auto const& identifiers = Unicode::available_time_zones();
|
||||
|
||||
|
|
@ -184,9 +185,9 @@ Vector<TimeZoneIdentifier> const& available_named_time_zone_identifiers()
|
|||
|
||||
// 8. Return result.
|
||||
return result;
|
||||
}();
|
||||
}() };
|
||||
|
||||
return named_time_zone_identifiers;
|
||||
return *named_time_zone_identifiers;
|
||||
}
|
||||
|
||||
// 6.5.2 GetAvailableNamedTimeZoneIdentifier ( timeZoneIdentifier ), https://tc39.es/ecma402/#sec-getavailablenamedtimezoneidentifier
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibJS/Runtime/Intl/Collator.h>
|
||||
|
||||
namespace JS::Intl {
|
||||
|
|
@ -36,13 +37,16 @@ ReadonlySpan<ResolutionOptionDescriptor> Collator::resolution_option_descriptors
|
|||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "co", [[Property]]: "collation" }, { [[Key]]: "kn", [[Property]]: "numeric", [[Type]]: boolean }, { [[Key]]: "kf", [[Property]]: "caseFirst", [[Values]]: « "upper", "lower", "false" » } ».
|
||||
static constexpr AK::Array case_first_values { "upper"sv, "lower"sv, "false"sv };
|
||||
|
||||
static auto descriptors = to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "co"sv, .property = vm.names.collation },
|
||||
{ .key = "kn"sv, .property = vm.names.numeric, .type = OptionType::Boolean },
|
||||
{ .key = "kf"sv, .property = vm.names.caseFirst, .values = case_first_values },
|
||||
});
|
||||
auto make_descriptors = [&] {
|
||||
return to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "co"sv, .property = vm.names.collation },
|
||||
{ .key = "kn"sv, .property = vm.names.numeric, .type = OptionType::Boolean },
|
||||
{ .key = "kf"sv, .property = vm.names.caseFirst, .values = case_first_values },
|
||||
});
|
||||
};
|
||||
static NeverDestroyed<decltype(make_descriptors())> descriptors { make_descriptors() };
|
||||
|
||||
return descriptors;
|
||||
return *descriptors;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/Date.h>
|
||||
#include <LibJS/Runtime/Intl/DateTimeFormat.h>
|
||||
|
|
@ -48,14 +49,17 @@ ReadonlySpan<ResolutionOptionDescriptor> DateTimeFormat::resolution_option_descr
|
|||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "ca", [[Property]]: "calendar" }, { [[Key]]: "nu", [[Property]]: "numberingSystem" }, { [[Key]]: "hour12", [[Property]]: "hour12", [[Type]]: boolean }, { [[Key]]: "hc", [[Property]]: "hourCycle", [[Values]]: « "h11", "h12", "h23", "h24" » } ».
|
||||
static constexpr AK::Array hour_cycle_values { "h11"sv, "h12"sv, "h23"sv, "h24"sv };
|
||||
|
||||
static auto descriptors = to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "ca"sv, .property = vm.names.calendar },
|
||||
{ .key = "nu"sv, .property = vm.names.numberingSystem },
|
||||
{ .key = "hour12"sv, .property = vm.names.hour12, .type = OptionType::Boolean },
|
||||
{ .key = "hc"sv, .property = vm.names.hourCycle, .values = hour_cycle_values },
|
||||
});
|
||||
auto make_descriptors = [&] {
|
||||
return to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "ca"sv, .property = vm.names.calendar },
|
||||
{ .key = "nu"sv, .property = vm.names.numberingSystem },
|
||||
{ .key = "hour12"sv, .property = vm.names.hour12, .type = OptionType::Boolean },
|
||||
{ .key = "hc"sv, .property = vm.names.hourCycle, .values = hour_cycle_values },
|
||||
});
|
||||
};
|
||||
static NeverDestroyed<decltype(make_descriptors())> descriptors { make_descriptors() };
|
||||
|
||||
return descriptors;
|
||||
return *descriptors;
|
||||
}
|
||||
|
||||
static Optional<Unicode::DateTimeFormat const&> get_or_create_formatter(StringView locale, StringView time_zone, OwnPtr<Unicode::DateTimeFormat>& formatter, Optional<Unicode::CalendarPattern> const& format)
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/GenericShorthands.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Intl/DurationFormat.h>
|
||||
|
|
@ -38,11 +39,14 @@ ReadonlySpan<StringView> DurationFormat::relevant_extension_keys() const
|
|||
ReadonlySpan<ResolutionOptionDescriptor> DurationFormat::resolution_option_descriptors(VM& vm) const
|
||||
{
|
||||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "nu", [[Property]]: "numberingSystem" } ».
|
||||
static auto descriptors = to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "nu"sv, .property = vm.names.numberingSystem },
|
||||
});
|
||||
auto make_descriptors = [&] {
|
||||
return to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "nu"sv, .property = vm.names.numberingSystem },
|
||||
});
|
||||
};
|
||||
static NeverDestroyed<decltype(make_descriptors())> descriptors { make_descriptors() };
|
||||
|
||||
return descriptors;
|
||||
return *descriptors;
|
||||
}
|
||||
|
||||
DurationFormat::Style DurationFormat::style_from_string(StringView style)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/Date.h>
|
||||
|
|
@ -137,14 +138,14 @@ JS_DEFINE_NATIVE_FUNCTION(Intl::supported_values_of)
|
|||
// 6. Else if key is "timeZone", then
|
||||
else if (key == "timeZone"sv) {
|
||||
// a. Let list be ! AvailablePrimaryTimeZoneIdentifiers( ).
|
||||
static auto const time_zones = available_primary_time_zone_identifiers();
|
||||
list = time_zones.span();
|
||||
static NeverDestroyed<Vector<String>> time_zones { available_primary_time_zone_identifiers() };
|
||||
list = time_zones->span();
|
||||
}
|
||||
// 7. Else if key is "unit", then
|
||||
else if (key == "unit"sv) {
|
||||
// a. Let list be ! AvailableCanonicalUnits( ).
|
||||
static auto const units = sanctioned_single_unit_identifiers();
|
||||
list = units.span();
|
||||
static NeverDestroyed<Vector<StringView>> units { sanctioned_single_unit_identifiers() };
|
||||
list = units->span();
|
||||
}
|
||||
// 8. Else,
|
||||
else {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibCrypto/BigInt/SignedBigInteger.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/BigInt.h>
|
||||
|
|
@ -49,11 +50,14 @@ ReadonlySpan<StringView> NumberFormat::relevant_extension_keys() const
|
|||
ReadonlySpan<ResolutionOptionDescriptor> NumberFormat::resolution_option_descriptors(VM& vm) const
|
||||
{
|
||||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "nu", [[Property]]: "numberingSystem" } ».
|
||||
static auto descriptors = to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "nu"sv, .property = vm.names.numberingSystem },
|
||||
});
|
||||
auto make_descriptors = [&] {
|
||||
return to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "nu"sv, .property = vm.names.numberingSystem },
|
||||
});
|
||||
};
|
||||
static NeverDestroyed<decltype(make_descriptors())> descriptors { make_descriptors() };
|
||||
|
||||
return descriptors;
|
||||
return *descriptors;
|
||||
}
|
||||
|
||||
StringView NumberFormatBase::computed_rounding_priority_string() const
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/Enumerate.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibJS/Runtime/Array.h>
|
||||
#include <LibJS/Runtime/Intl/RelativeTimeFormat.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
|
|
@ -31,11 +32,14 @@ ReadonlySpan<StringView> RelativeTimeFormat::relevant_extension_keys() const
|
|||
ReadonlySpan<ResolutionOptionDescriptor> RelativeTimeFormat::resolution_option_descriptors(VM& vm) const
|
||||
{
|
||||
// The value of the [[ResolutionOptionDescriptors]] internal slot is « { [[Key]]: "nu", [[Property]]: "numberingSystem" } ».
|
||||
static auto descriptors = to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "nu"sv, .property = vm.names.numberingSystem },
|
||||
});
|
||||
auto make_descriptors = [&] {
|
||||
return to_array<ResolutionOptionDescriptor>({
|
||||
{ .key = "nu"sv, .property = vm.names.numberingSystem },
|
||||
});
|
||||
};
|
||||
static NeverDestroyed<decltype(make_descriptors())> descriptors { make_descriptors() };
|
||||
|
||||
return descriptors;
|
||||
return *descriptors;
|
||||
}
|
||||
|
||||
// 18.5.1 SingularRelativeTimeUnit ( unit ), https://tc39.es/ecma402/#sec-singularrelativetimeunit
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ void IteratorRecord::visit_edges(Cell::Visitor& visitor)
|
|||
ThrowCompletionOr<GC::Ref<IteratorRecord>> get_iterator_direct(VM& vm, Object& object)
|
||||
{
|
||||
// 1. Let nextMethod be ? Get(obj, "next").
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto next_method = TRY(object.get(vm.names.next, cache));
|
||||
|
||||
// 2. Let iteratorRecord be Record { [[Iterator]]: obj, [[NextMethod]]: nextMethod, [[Done]]: false }.
|
||||
|
|
@ -70,7 +70,7 @@ ThrowCompletionOr<IteratorRecordImpl> get_iterator_from_method_impl(VM& vm, Valu
|
|||
return vm.throw_completion<TypeError>(ErrorType::NotIterable, object);
|
||||
|
||||
// 3. Let nextMethod be ? Get(iterator, "next").
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto next_method = TRY(iterator.get(vm, vm.names.next, cache));
|
||||
|
||||
// 4. Let iteratorRecord be the Iterator Record { [[Iterator]]: iterator, [[NextMethod]]: nextMethod, [[Done]]: false }.
|
||||
|
|
@ -99,7 +99,7 @@ ThrowCompletionOr<IteratorRecordImpl> get_iterator_impl(VM& vm, Value object, It
|
|||
// b. If method is undefined, then
|
||||
if (!method) {
|
||||
// i. Let syncMethod be ? GetMethod(obj, @@iterator).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto sync_method = TRY(object.get_method(vm, vm.well_known_symbol_iterator(), cache));
|
||||
|
||||
// ii. If syncMethod is undefined, throw a TypeError exception.
|
||||
|
|
@ -116,7 +116,7 @@ ThrowCompletionOr<IteratorRecordImpl> get_iterator_impl(VM& vm, Value object, It
|
|||
// 2. Else,
|
||||
else {
|
||||
// a. Let method be ? GetMethod(obj, @@iterator).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
method = TRY(object.get_method(vm, vm.well_known_symbol_iterator(), cache));
|
||||
}
|
||||
|
||||
|
|
@ -152,7 +152,7 @@ ThrowCompletionOr<GC::Ref<IteratorRecord>> get_iterator_flattenable(VM& vm, Valu
|
|||
}
|
||||
|
||||
// 2. Let method be ? GetMethod(obj, %Symbol.iterator%).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto method = TRY(object.get_method(vm, vm.well_known_symbol_iterator(), cache));
|
||||
|
||||
Value iterator;
|
||||
|
|
@ -221,7 +221,7 @@ ThrowCompletionOr<GC::Ref<Object>> iterator_next(VM& vm, IteratorRecordImpl& ite
|
|||
ThrowCompletionOr<bool> iterator_complete(VM& vm, Object& iterator_result)
|
||||
{
|
||||
// 1. Return ToBoolean(? Get(iterResult, "done")).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
return TRY(iterator_result.get(vm.names.done, cache)).to_boolean();
|
||||
}
|
||||
|
||||
|
|
@ -229,7 +229,7 @@ ThrowCompletionOr<bool> iterator_complete(VM& vm, Object& iterator_result)
|
|||
ThrowCompletionOr<Value> iterator_value(VM& vm, Object& iterator_result)
|
||||
{
|
||||
// 1. Return ? Get(iterResult, "value").
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
return TRY(iterator_result.get(vm.names.value, cache));
|
||||
}
|
||||
|
||||
|
|
@ -251,7 +251,7 @@ ThrowCompletionOr<IterationResultOrDone> iterator_step(VM& vm, IteratorRecordImp
|
|||
auto result = TRY(iterator_next(vm, iterator_record));
|
||||
|
||||
// 2. Let done be Completion(IteratorComplete(result)).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto done = result->get(vm.names.done, cache);
|
||||
|
||||
// 3. If done is a throw completion, then
|
||||
|
|
@ -276,7 +276,7 @@ ThrowCompletionOr<IterationResultOrDone> iterator_step(VM& vm, IteratorRecordImp
|
|||
}
|
||||
|
||||
// 6. Return result.
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
return ThrowCompletionOr<IterationResultOrDone> { IterationResult { done_value, result->get(vm.names.value, cache2) } };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -170,7 +170,7 @@ GC_DEFINE_ALLOCATOR(ConcatIterator);
|
|||
// 27.1.3.2.1 Iterator.concat ( ...items ), https://tc39.es/ecma262/#sec-iterator.concat
|
||||
JS_DEFINE_NATIVE_FUNCTION(IteratorConstructor::concat)
|
||||
{
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
// 1. Let iterables be a new empty List.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <AK/Array.h>
|
||||
#include <AK/FloatingPoint.h>
|
||||
#include <AK/Function.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/StringConversions.h>
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||
|
|
@ -98,9 +99,9 @@ static SignificandAndExponent compute_significand_and_exponent_with_precision(do
|
|||
{
|
||||
using Extractor = AK::FloatExtractor<double>;
|
||||
|
||||
static auto ONE_BIGINT = 1_bigint;
|
||||
static auto TWO_BIGINT = 2_bigint;
|
||||
static auto TEN_BIGINT = 10_bigint;
|
||||
static NeverDestroyed<Crypto::UnsignedBigInteger> ONE_BIGINT { 1_bigint };
|
||||
static NeverDestroyed<Crypto::UnsignedBigInteger> TWO_BIGINT { 2_bigint };
|
||||
static NeverDestroyed<Crypto::UnsignedBigInteger> TEN_BIGINT { 10_bigint };
|
||||
|
||||
auto result = AK::convert_to_decimal_exponential_form(number);
|
||||
auto exponent = result.exponent + count_digits(result.fraction) - 1;
|
||||
|
|
@ -134,7 +135,7 @@ static SignificandAndExponent compute_significand_and_exponent_with_precision(do
|
|||
// involves only unsigned integers.
|
||||
auto compute_significand = [&](i32 exponent) {
|
||||
auto numerator = binary_significand;
|
||||
auto denominator = ONE_BIGINT;
|
||||
auto denominator = *ONE_BIGINT;
|
||||
|
||||
// 2 ^ binary_exponent
|
||||
if (binary_exponent > 0)
|
||||
|
|
@ -144,9 +145,9 @@ static SignificandAndExponent compute_significand_and_exponent_with_precision(do
|
|||
|
||||
// 10 ^ (precision - exponent - 1)
|
||||
if (auto scale = precision - exponent - 1; scale > 0)
|
||||
numerator = numerator.multiplied_by(TEN_BIGINT.pow(scale));
|
||||
numerator = numerator.multiplied_by(TEN_BIGINT->pow(scale));
|
||||
else if (scale < 0)
|
||||
denominator = denominator.multiplied_by(TEN_BIGINT.pow(-scale));
|
||||
denominator = denominator.multiplied_by(TEN_BIGINT->pow(-scale));
|
||||
|
||||
auto [quotient, remainder] = numerator.divided_by(denominator);
|
||||
|
||||
|
|
@ -191,18 +192,18 @@ static SignificandAndExponent compute_significand_and_exponent_with_precision(do
|
|||
//
|
||||
// Similar to `compute_significand` above, we take care to clear any negative exponents to ensure that the math
|
||||
// involves only unsigned integers.
|
||||
if (significand == TEN_BIGINT.pow(precision - 1)) {
|
||||
if (significand == TEN_BIGINT->pow(precision - 1)) {
|
||||
auto alternate = compute_significand(exponent - 1);
|
||||
|
||||
if (alternate.count_digits_in_base(10) == static_cast<size_t>(precision)) {
|
||||
auto lhs = significand.multiplied_by(TEN_BIGINT).plus(alternate);
|
||||
auto rhs = TWO_BIGINT.multiplied_by(binary_significand);
|
||||
auto lhs = significand.multiplied_by(*TEN_BIGINT).plus(alternate);
|
||||
auto rhs = TWO_BIGINT->multiplied_by(binary_significand);
|
||||
|
||||
// 10 ^ (exponent - precision)
|
||||
if (auto scale = exponent - precision; scale > 0)
|
||||
lhs = lhs.multiplied_by(TEN_BIGINT.pow(scale));
|
||||
lhs = lhs.multiplied_by(TEN_BIGINT->pow(scale));
|
||||
else if (scale < 0)
|
||||
rhs = rhs.multiplied_by(TEN_BIGINT.pow(-scale));
|
||||
rhs = rhs.multiplied_by(TEN_BIGINT->pow(-scale));
|
||||
|
||||
// 2 ^ binary_exponent
|
||||
if (binary_exponent > 0)
|
||||
|
|
@ -224,8 +225,8 @@ static Crypto::UnsignedBigInteger compute_to_fixed_scaled_integer(double number,
|
|||
{
|
||||
using Extractor = AK::FloatExtractor<double>;
|
||||
|
||||
static auto ONE_BIGINT = 1_bigint;
|
||||
static auto FIVE_BIGINT = 5_bigint;
|
||||
static NeverDestroyed<Crypto::UnsignedBigInteger> ONE_BIGINT { 1_bigint };
|
||||
static NeverDestroyed<Crypto::UnsignedBigInteger> FIVE_BIGINT { 5_bigint };
|
||||
|
||||
// Decompose the number into its exact binary representation. An IEEE-754 double is exactly equal to:
|
||||
//
|
||||
|
|
@ -244,12 +245,12 @@ static Crypto::UnsignedBigInteger compute_to_fixed_scaled_integer(double number,
|
|||
binary_exponent = extractor.exponent - Extractor::exponent_bias - Extractor::mantissa_bits;
|
||||
}
|
||||
|
||||
auto numerator = binary_significand.multiplied_by(FIVE_BIGINT.pow(fraction_digits));
|
||||
auto numerator = binary_significand.multiplied_by(FIVE_BIGINT->pow(fraction_digits));
|
||||
auto binary_scale = binary_exponent + static_cast<i32>(fraction_digits);
|
||||
if (binary_scale >= 0)
|
||||
return MUST(numerator.shift_left(static_cast<size_t>(binary_scale)));
|
||||
|
||||
auto denominator = MUST(ONE_BIGINT.shift_left(static_cast<size_t>(-binary_scale)));
|
||||
auto denominator = MUST(ONE_BIGINT->shift_left(static_cast<size_t>(-binary_scale)));
|
||||
auto [quotient, remainder] = numerator.divided_by(denominator);
|
||||
|
||||
// Pick the larger integer if x * 10^f is exactly between two candidates.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <AK/TypeCasts.h>
|
||||
#include <AK/kmalloc.h>
|
||||
|
|
@ -34,7 +35,11 @@ namespace JS {
|
|||
|
||||
GC_DEFINE_ALLOCATOR(Object);
|
||||
|
||||
static GC::WeakHashMap<GC::Ptr<Object const>, HashMap<Utf16FlyString, Object::IntrinsicAccessor>> s_intrinsics;
|
||||
static auto& intrinsic_accessor_map()
|
||||
{
|
||||
static NeverDestroyed<GC::WeakHashMap<GC::Ptr<Object const>, HashMap<Utf16FlyString, Object::IntrinsicAccessor>>> intrinsics;
|
||||
return *intrinsics;
|
||||
}
|
||||
|
||||
// Heap-allocated named property storage layout:
|
||||
// [u32 capacity] [u32 padding] [Value 0] [Value 1] ...
|
||||
|
|
@ -165,7 +170,7 @@ Object::~Object()
|
|||
{
|
||||
free_indexed_elements();
|
||||
if (has_intrinsic_accessors())
|
||||
s_intrinsics.remove(this);
|
||||
intrinsic_accessor_map().remove(this);
|
||||
if (!named_storage_is_inline())
|
||||
free_heap_named_storage(m_named_properties);
|
||||
}
|
||||
|
|
@ -1281,7 +1286,7 @@ static Optional<Object::IntrinsicAccessor> find_intrinsic_accessor(Object const*
|
|||
if (!property_key.is_string())
|
||||
return {};
|
||||
|
||||
auto intrinsics = s_intrinsics.get(object);
|
||||
auto intrinsics = intrinsic_accessor_map().get(object);
|
||||
if (!intrinsics.has_value())
|
||||
return {};
|
||||
|
||||
|
|
@ -1347,7 +1352,7 @@ Optional<u32> Object::storage_set(PropertyKey const& property_key, ValueAndAttri
|
|||
}
|
||||
|
||||
if (has_intrinsic_accessors() && property_key.is_string()) {
|
||||
if (auto intrinsics = s_intrinsics.get(this); intrinsics.has_value())
|
||||
if (auto intrinsics = intrinsic_accessor_map().get(this); intrinsics.has_value())
|
||||
intrinsics->remove(property_key.as_string());
|
||||
}
|
||||
|
||||
|
|
@ -1387,7 +1392,7 @@ void Object::storage_delete(PropertyKey const& property_key)
|
|||
return indexed_delete(property_key.as_number());
|
||||
|
||||
if (has_intrinsic_accessors() && property_key.is_string()) {
|
||||
if (auto intrinsics = s_intrinsics.get(this); intrinsics.has_value())
|
||||
if (auto intrinsics = intrinsic_accessor_map().get(this); intrinsics.has_value())
|
||||
intrinsics->remove(property_key.as_string());
|
||||
}
|
||||
|
||||
|
|
@ -1456,7 +1461,7 @@ void Object::define_intrinsic_accessor(PropertyKey const& property_key, Property
|
|||
(void)storage_set(property_key, { {}, attributes });
|
||||
|
||||
set_has_intrinsic_accessors();
|
||||
auto& intrinsics = s_intrinsics.ensure(this);
|
||||
auto& intrinsics = intrinsic_accessor_map().ensure(this);
|
||||
intrinsics.set(property_key.as_string(), move(accessor));
|
||||
}
|
||||
|
||||
|
|
@ -1697,11 +1702,11 @@ ThrowCompletionOr<Value> Object::ordinary_to_primitive(Value::PreferredType pref
|
|||
// a. Let method be ? Get(O, name).
|
||||
Value method;
|
||||
if (method_name == vm.names.toString) {
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
method = TRY(get(method_name, cache));
|
||||
} else {
|
||||
ASSERT(method_name == vm.names.valueOf);
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
method = TRY(get(method_name, cache));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ JS_DEFINE_NATIVE_FUNCTION(ObjectPrototype::to_string)
|
|||
builtin_tag = "Object"sv;
|
||||
|
||||
// 15. Let tag be ? Get(O, @@toStringTag).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto to_string_tag = TRY(object->get(vm.well_known_symbol_to_string_tag(), cache));
|
||||
|
||||
// Optimization: Instead of creating another PrimitiveString from builtin_tag, we separate tag and to_string_tag and add an additional branch to step 16.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include <AK/CharacterTypes.h>
|
||||
#include <AK/Function.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
|
|
@ -62,7 +63,7 @@ void RegExpPrototype::initialize(Realm& realm)
|
|||
static ThrowCompletionOr<void> increment_last_index(VM& vm, Object& regexp_object, Utf16View const& string, bool unicode)
|
||||
{
|
||||
// Let thisIndex be ℝ(? ToLength(? Get(rx, "lastIndex"))).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto last_index_value = TRY(regexp_object.get(vm.names.lastIndex, cache));
|
||||
auto last_index = TRY(last_index_value.to_length(vm));
|
||||
|
||||
|
|
@ -70,13 +71,17 @@ static ThrowCompletionOr<void> increment_last_index(VM& vm, Object& regexp_objec
|
|||
last_index = advance_string_index(string, last_index, unicode);
|
||||
|
||||
// Perform ? Set(rx, "lastIndex", 𝔽(nextIndex), true).
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
TRY(regexp_object.set(vm.names.lastIndex, Value(last_index), cache2));
|
||||
return {};
|
||||
}
|
||||
|
||||
// FIXME: Add an eviction policy to bound the size of this cache.
|
||||
static HashMap<String, NonnullOwnPtr<regex::ECMAScriptRegex>> s_regex_cache;
|
||||
static auto& regex_cache()
|
||||
{
|
||||
static NeverDestroyed<HashMap<String, NonnullOwnPtr<regex::ECMAScriptRegex>>> cache;
|
||||
return *cache;
|
||||
}
|
||||
|
||||
static regex::ECMAScriptRegex const* get_or_compile_regex(RegExpObject& regexp_object)
|
||||
{
|
||||
|
|
@ -95,7 +100,7 @@ static regex::ECMAScriptRegex const* get_or_compile_regex(RegExpObject& regexp_o
|
|||
key_builder.append_code_point(static_cast<u8>(flag_bits));
|
||||
auto cache_key = key_builder.to_string_without_validation();
|
||||
|
||||
if (auto it = s_regex_cache.find(cache_key); it != s_regex_cache.end()) {
|
||||
if (auto it = regex_cache().find(cache_key); it != regex_cache().end()) {
|
||||
auto* ptr = it->value.ptr();
|
||||
regexp_object.set_cached_regex(ptr);
|
||||
return ptr;
|
||||
|
|
@ -125,7 +130,7 @@ static regex::ECMAScriptRegex const* get_or_compile_regex(RegExpObject& regexp_o
|
|||
|
||||
auto owned = make<regex::ECMAScriptRegex>(compiled.release_value());
|
||||
auto* ptr = owned.ptr();
|
||||
s_regex_cache.set(cache_key, move(owned));
|
||||
regex_cache().set(cache_key, move(owned));
|
||||
regexp_object.set_cached_regex(ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
|
@ -189,7 +194,7 @@ static ThrowCompletionOr<Value> regexp_builtin_exec(VM& vm, RegExpObject& regexp
|
|||
{
|
||||
auto& realm = *vm.current_realm();
|
||||
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto last_index_value = TRY(regexp_object.get(vm.names.lastIndex, cache));
|
||||
auto last_index = TRY(last_index_value.to_length(vm));
|
||||
|
||||
|
|
@ -205,7 +210,7 @@ static ThrowCompletionOr<Value> regexp_builtin_exec(VM& vm, RegExpObject& regexp
|
|||
|
||||
if (last_index > string->length_in_utf16_code_units()) {
|
||||
if (sticky || global) {
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
TRY(regexp_object.set(vm.names.lastIndex, Value(0), cache2));
|
||||
}
|
||||
return js_null();
|
||||
|
|
@ -231,7 +236,7 @@ static ThrowCompletionOr<Value> regexp_builtin_exec(VM& vm, RegExpObject& regexp
|
|||
|
||||
if (!matched) {
|
||||
if (sticky || global) {
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
TRY(regexp_object.set(vm.names.lastIndex, Value(0), cache2));
|
||||
}
|
||||
return js_null();
|
||||
|
|
@ -244,7 +249,7 @@ static ThrowCompletionOr<Value> regexp_builtin_exec(VM& vm, RegExpObject& regexp
|
|||
// In Unicode mode, match_index and end_index are already in code unit indices from the VM.
|
||||
// Update lastIndex.
|
||||
if (global || sticky) {
|
||||
static Bytecode::StaticPropertyLookupCache cache3;
|
||||
static auto& cache3 = *new Bytecode::StaticPropertyLookupCache;
|
||||
TRY(regexp_object.set(vm.names.lastIndex, Value(end_index), cache3));
|
||||
}
|
||||
|
||||
|
|
@ -315,7 +320,7 @@ static ThrowCompletionOr<Value> regexp_builtin_exec(VM& vm, RegExpObject& regexp
|
|||
MUST(groups.as_object().create_data_property_or_throw(group_name, value));
|
||||
}
|
||||
|
||||
static Bytecode::StaticPropertyLookupCache cache4;
|
||||
static auto& cache4 = *new Bytecode::StaticPropertyLookupCache;
|
||||
MUST(array->set(vm.names.groups, groups, cache4));
|
||||
}
|
||||
|
||||
|
|
@ -391,7 +396,7 @@ static ThrowCompletionOr<Value> regexp_builtin_exec(VM& vm, RegExpObject& regexp
|
|||
ThrowCompletionOr<Value> regexp_exec(VM& vm, Object& regexp_object, GC::Ref<PrimitiveString> string)
|
||||
{
|
||||
// 1. Let exec be ? Get(R, "exec").
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto exec = TRY(regexp_object.get(vm.names.exec, cache));
|
||||
|
||||
auto* typed_regexp_object = as_if<RegExpObject>(regexp_object);
|
||||
|
|
@ -514,7 +519,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::flags)
|
|||
// 19. If sticky is true, append the code unit 0x0079 (LATIN SMALL LETTER Y) as the last code unit of result.
|
||||
#define __JS_ENUMERATE(FlagName, flagName, flag_name, flag_char) \
|
||||
{ \
|
||||
static Bytecode::StaticPropertyLookupCache cache; \
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache; \
|
||||
auto flag_##flag_name = TRY(regexp_object->get(vm.names.flagName, cache)); \
|
||||
if (flag_##flag_name.to_boolean()) \
|
||||
builder.append(#flag_char##sv); \
|
||||
|
|
@ -539,7 +544,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_match)
|
|||
auto string = TRY(vm.argument(0).to_primitive_string(vm));
|
||||
|
||||
// 4. Let flags be ? ToString(? Get(rx, "flags")).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto flags_value = TRY(regexp_object->get(vm.names.flags, cache));
|
||||
auto flags = TRY(flags_value.to_string(vm));
|
||||
|
||||
|
|
@ -554,7 +559,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_match)
|
|||
bool full_unicode = flags.contains('u') || flags.contains('v');
|
||||
|
||||
// b. Perform ? Set(rx, "lastIndex", +0𝔽, true).
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
TRY(regexp_object->set(vm.names.lastIndex, Value(0), cache2));
|
||||
|
||||
// c. Let A be ! ArrayCreate(0).
|
||||
|
|
@ -617,7 +622,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_match_all)
|
|||
auto* constructor = TRY(species_constructor(vm, regexp_object, realm.intrinsics().regexp_constructor()));
|
||||
|
||||
// 5. Let flags be ? ToString(? Get(R, "flags")).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto flags_value = TRY(regexp_object->get(vm.names.flags, cache));
|
||||
auto flags = TRY(flags_value.to_string(vm));
|
||||
|
||||
|
|
@ -635,12 +640,12 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_match_all)
|
|||
auto matcher = TRY(construct(vm, *constructor, regexp_object, PrimitiveString::create(vm, move(flags))));
|
||||
|
||||
// 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")).
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto last_index_value = TRY(regexp_object->get(vm.names.lastIndex, cache2));
|
||||
auto last_index = TRY(last_index_value.to_length(vm));
|
||||
|
||||
// 8. Perform ? Set(matcher, "lastIndex", lastIndex, true).
|
||||
static Bytecode::StaticPropertyLookupCache cache3;
|
||||
static auto& cache3 = *new Bytecode::StaticPropertyLookupCache;
|
||||
TRY(matcher->set(vm.names.lastIndex, Value(last_index), cache3));
|
||||
|
||||
// 13. Return CreateRegExpStringIterator(matcher, S, global, fullUnicode).
|
||||
|
|
@ -675,7 +680,7 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_replace_impl(VM& vm, Object& re
|
|||
auto& realm = *vm.current_realm();
|
||||
bool exec_is_builtin = false;
|
||||
if (typed_regexp) {
|
||||
static Bytecode::StaticPropertyLookupCache exec_cache;
|
||||
static auto& exec_cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto exec_val = TRY(regexp_object.get(vm.names.exec, exec_cache));
|
||||
if (auto exec_fn = exec_val.as_if<FunctionObject>())
|
||||
exec_is_builtin = exec_fn->builtin() == Bytecode::Builtin::RegExpPrototypeExec;
|
||||
|
|
@ -715,11 +720,11 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_replace_impl(VM& vm, Object& re
|
|||
// fast path (e.g. redefining exec). Do the Get and re-check exec.
|
||||
bool fast_path_valid = true;
|
||||
if (is_global) {
|
||||
static Bytecode::StaticPropertyLookupCache unicode_cache;
|
||||
static auto& unicode_cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto unicode_val = TRY(regexp_object.get(vm.names.unicode, unicode_cache));
|
||||
full_unicode = unicode_val.to_boolean();
|
||||
// Re-verify exec is still the builtin after potential side effects.
|
||||
static Bytecode::StaticPropertyLookupCache exec_recheck;
|
||||
static auto& exec_recheck = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto exec_val2 = TRY(regexp_object.get(vm.names.exec, exec_recheck));
|
||||
auto exec_fn2 = exec_val2.as_if<FunctionObject>();
|
||||
if (!exec_fn2 || exec_fn2->builtin() != Bytecode::Builtin::RegExpPrototypeExec)
|
||||
|
|
@ -733,7 +738,7 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_replace_impl(VM& vm, Object& re
|
|||
|
||||
size_t last_index = 0;
|
||||
if (is_global || is_sticky) {
|
||||
static Bytecode::StaticPropertyLookupCache li_cache;
|
||||
static auto& li_cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto li_value = TRY(typed_regexp->get(vm.names.lastIndex, li_cache));
|
||||
last_index = TRY(li_value.to_length(vm));
|
||||
}
|
||||
|
|
@ -780,7 +785,7 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_replace_impl(VM& vm, Object& re
|
|||
while (true) {
|
||||
if (last_index > length_s) {
|
||||
if (is_sticky || is_global) {
|
||||
static Bytecode::StaticPropertyLookupCache li_cache2;
|
||||
static auto& li_cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
TRY(typed_regexp->set(vm.names.lastIndex, Value(0), li_cache2));
|
||||
}
|
||||
break;
|
||||
|
|
@ -797,7 +802,7 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_replace_impl(VM& vm, Object& re
|
|||
|
||||
if (!matched) {
|
||||
if (is_sticky || is_global) {
|
||||
static Bytecode::StaticPropertyLookupCache li_cache2;
|
||||
static auto& li_cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
TRY(typed_regexp->set(vm.names.lastIndex, Value(0), li_cache2));
|
||||
}
|
||||
break;
|
||||
|
|
@ -814,7 +819,7 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_replace_impl(VM& vm, Object& re
|
|||
// For global, lastIndex is always reset to 0 after the loop,
|
||||
// so skip intermediate updates.
|
||||
if (is_sticky && !is_global) {
|
||||
static Bytecode::StaticPropertyLookupCache li_cache3;
|
||||
static auto& li_cache3 = *new Bytecode::StaticPropertyLookupCache;
|
||||
TRY(typed_regexp->set(vm.names.lastIndex, Value(match_end), li_cache3));
|
||||
}
|
||||
|
||||
|
|
@ -888,7 +893,7 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_replace_impl(VM& vm, Object& re
|
|||
}
|
||||
|
||||
// 7. Let flags be ? ToString(? Get(rx, "flags")).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto flags_value = TRY(regexp_object.get(vm.names.flags, cache));
|
||||
auto flags = TRY(flags_value.to_string(vm));
|
||||
|
||||
|
|
@ -898,7 +903,7 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_replace_impl(VM& vm, Object& re
|
|||
// 9. If global is true, then
|
||||
if (global) {
|
||||
// a. Perform ? Set(rx, "lastIndex", +0𝔽, true).
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
TRY(regexp_object.set(vm.names.lastIndex, Value(0), cache2));
|
||||
}
|
||||
|
||||
|
|
@ -962,7 +967,7 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_replace_impl(VM& vm, Object& re
|
|||
auto matched_length = matched->length_in_utf16_code_units();
|
||||
|
||||
// e. Let position be ? ToIntegerOrInfinity(? Get(result, "index")).
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto position_value = TRY(result->get(vm.names.index, cache2));
|
||||
double position = TRY(position_value.to_integer_or_infinity(vm));
|
||||
|
||||
|
|
@ -992,7 +997,7 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_replace_impl(VM& vm, Object& re
|
|||
}
|
||||
|
||||
// j. Let namedCaptures be ? Get(result, "groups").
|
||||
static Bytecode::StaticPropertyLookupCache cache3;
|
||||
static auto& cache3 = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto named_captures = TRY(result->get(vm.names.groups, cache3));
|
||||
|
||||
String replacement;
|
||||
|
|
@ -1066,13 +1071,13 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_search)
|
|||
auto string = TRY(vm.argument(0).to_primitive_string(vm));
|
||||
|
||||
// 4. Let previousLastIndex be ? Get(rx, "lastIndex").
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto previous_last_index = TRY(regexp_object->get(vm.names.lastIndex, cache));
|
||||
|
||||
// 5. If SameValue(previousLastIndex, +0𝔽) is false, then
|
||||
if (!same_value(previous_last_index, Value(0))) {
|
||||
// a. Perform ? Set(rx, "lastIndex", +0𝔽, true).
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
TRY(regexp_object->set(vm.names.lastIndex, Value(0), cache2));
|
||||
}
|
||||
|
||||
|
|
@ -1080,13 +1085,13 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_search)
|
|||
auto result = TRY(regexp_exec(vm, regexp_object, string));
|
||||
|
||||
// 7. Let currentLastIndex be ? Get(rx, "lastIndex").
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto current_last_index = TRY(regexp_object->get(vm.names.lastIndex, cache2));
|
||||
|
||||
// 8. If SameValue(currentLastIndex, previousLastIndex) is false, then
|
||||
if (!same_value(current_last_index, previous_last_index)) {
|
||||
// a. Perform ? Set(rx, "lastIndex", previousLastIndex, true).
|
||||
static Bytecode::StaticPropertyLookupCache cache3;
|
||||
static auto& cache3 = *new Bytecode::StaticPropertyLookupCache;
|
||||
TRY(regexp_object->set(vm.names.lastIndex, previous_last_index, cache3));
|
||||
}
|
||||
|
||||
|
|
@ -1095,7 +1100,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::symbol_search)
|
|||
return Value(-1);
|
||||
|
||||
// 10. Return ? Get(result, "index").
|
||||
static Bytecode::StaticPropertyLookupCache cache3;
|
||||
static auto& cache3 = *new Bytecode::StaticPropertyLookupCache;
|
||||
return TRY(result.get(vm, vm.names.index, cache3));
|
||||
}
|
||||
|
||||
|
|
@ -1149,7 +1154,7 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_split_impl(VM& vm, Object& rege
|
|||
auto* typed_regexp = as_if<RegExpObject>(regexp_object);
|
||||
bool exec_is_builtin = false;
|
||||
if (typed_regexp) {
|
||||
static Bytecode::StaticPropertyLookupCache exec_cache;
|
||||
static auto& exec_cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto exec_val = TRY(regexp_object.get(vm.names.exec, exec_cache));
|
||||
if (auto exec_fn = exec_val.as_if<FunctionObject>())
|
||||
exec_is_builtin = exec_fn->builtin() == Bytecode::Builtin::RegExpPrototypeExec;
|
||||
|
|
@ -1285,7 +1290,7 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_split_impl(VM& vm, Object& rege
|
|||
auto* constructor = TRY(species_constructor(vm, regexp_object, realm.intrinsics().regexp_constructor()));
|
||||
|
||||
// 5. Let flags be ? ToString(? Get(rx, "flags")).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto flags_value = TRY(regexp_object.get(vm.names.flags, cache));
|
||||
auto flags = TRY(flags_value.to_string(vm));
|
||||
|
||||
|
|
@ -1342,7 +1347,7 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_split_impl(VM& vm, Object& rege
|
|||
// 19. Repeat, while q < size,
|
||||
while (next_search_from < string->length_in_utf16_code_units()) {
|
||||
// a. Perform ? Set(splitter, "lastIndex", 𝔽(q), SplitBehavior::KeepEmpty).
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
TRY(splitter->set(vm.names.lastIndex, Value(next_search_from), cache2));
|
||||
|
||||
// b. Let z be ? RegExpExec(splitter, S).
|
||||
|
|
@ -1357,7 +1362,7 @@ ThrowCompletionOr<Value> RegExpPrototype::symbol_split_impl(VM& vm, Object& rege
|
|||
// d. Else,
|
||||
|
||||
// i. Let e be ℝ(? ToLength(? Get(splitter, "lastIndex"))).
|
||||
static Bytecode::StaticPropertyLookupCache cache3;
|
||||
static auto& cache3 = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto last_index_value = TRY(splitter->get(vm.names.lastIndex, cache3));
|
||||
auto last_index = TRY(last_index_value.to_length(vm));
|
||||
|
||||
|
|
@ -1441,7 +1446,7 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::test)
|
|||
auto& realm = *vm.current_realm();
|
||||
bool exec_is_builtin = false;
|
||||
if (typed_regexp) {
|
||||
static Bytecode::StaticPropertyLookupCache exec_cache;
|
||||
static auto& exec_cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto exec_val = TRY(regexp_object->get(vm.names.exec, exec_cache));
|
||||
if (auto exec_fn = exec_val.as_if<FunctionObject>())
|
||||
exec_is_builtin = exec_fn->builtin() == Bytecode::Builtin::RegExpPrototypeExec;
|
||||
|
|
@ -1513,12 +1518,12 @@ JS_DEFINE_NATIVE_FUNCTION(RegExpPrototype::to_string)
|
|||
auto regexp_object = TRY(this_object(vm));
|
||||
|
||||
// 3. Let pattern be ? ToString(? Get(R, "source")).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto source_attr = TRY(regexp_object->get(vm.names.source, cache));
|
||||
auto pattern = TRY(source_attr.to_string(vm));
|
||||
|
||||
// 4. Let flags be ? ToString(? Get(R, "flags")).
|
||||
static Bytecode::StaticPropertyLookupCache cache2;
|
||||
static auto& cache2 = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto flags_attr = TRY(regexp_object->get(vm.names.flags, cache2));
|
||||
auto flags = TRY(flags_attr.to_string(vm));
|
||||
|
||||
|
|
|
|||
|
|
@ -631,7 +631,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::match)
|
|||
auto regexp = vm.argument(0);
|
||||
if (regexp.is_object()) {
|
||||
// a. Let matcher be ? GetMethod(regexp, @@match).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto matcher = TRY(regexp.get_method(vm, vm.well_known_symbol_match(), cache));
|
||||
|
||||
// b. If matcher is not undefined, then
|
||||
|
|
@ -679,7 +679,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::match_all)
|
|||
}
|
||||
|
||||
// c. Let matcher be ? GetMethod(regexp, @@matchAll).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto matcher = TRY(regexp.get_method(vm, vm.well_known_symbol_match_all(), cache));
|
||||
|
||||
// d. If matcher is not undefined, then
|
||||
|
|
@ -850,7 +850,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::replace)
|
|||
// 2. If searchValue is an Object, then
|
||||
if (search_value.is_object()) {
|
||||
// a. Let replacer be ? GetMethod(searchValue, @@replace).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto replacer = TRY(search_value.get_method(vm, vm.well_known_symbol_replace(), cache));
|
||||
|
||||
// b. If replacer is not undefined, then
|
||||
|
|
@ -952,7 +952,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::replace_all)
|
|||
}
|
||||
|
||||
// c. Let replacer be ? GetMethod(searchValue, @@replace).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto replacer = TRY(search_value.get_method(vm, vm.well_known_symbol_replace(), cache));
|
||||
|
||||
// d. If replacer is not undefined, then
|
||||
|
|
@ -1059,7 +1059,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::search)
|
|||
// 2. If regexp is an Object, then
|
||||
if (regexp.is_object()) {
|
||||
// a. Let searcher be ? GetMethod(regexp, @@search).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto searcher = TRY(regexp.get_method(vm, vm.well_known_symbol_search(), cache));
|
||||
|
||||
// b. If searcher is not undefined, then
|
||||
|
|
@ -1144,7 +1144,7 @@ JS_DEFINE_NATIVE_FUNCTION(StringPrototype::split)
|
|||
// 3. If separator is an Object, then
|
||||
if (separator_argument.is_object()) {
|
||||
// a. Let splitter be ? GetMethod(separator, @@split).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto splitter = TRY(separator_argument.get_method(vm, vm.well_known_symbol_split(), cache));
|
||||
// b. If splitter is not undefined, then
|
||||
if (splitter) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibCrypto/BigFraction/BigFraction.h>
|
||||
#include <LibJS/Runtime/Date.h>
|
||||
#include <LibJS/Runtime/PropertyKey.h>
|
||||
|
|
@ -382,7 +383,7 @@ ThrowCompletionOr<UnitValue> get_temporal_unit_valued_option(VM& vm, Object cons
|
|||
// 2. Append "auto" to allowedStrings.
|
||||
// 3. NOTE: For each singular Temporal unit name that is contained within allowedStrings, the corresponding plural
|
||||
// name is also contained within it.
|
||||
static auto allowed_strings = [&]() {
|
||||
static NeverDestroyed<Vector<StringView>> allowed_strings { [&]() {
|
||||
Vector<StringView> allowed_strings;
|
||||
allowed_strings.ensure_capacity((temporal_units.size() * 2) + 1);
|
||||
|
||||
|
|
@ -393,7 +394,7 @@ ThrowCompletionOr<UnitValue> get_temporal_unit_valued_option(VM& vm, Object cons
|
|||
|
||||
allowed_strings.unchecked_append("auto"sv);
|
||||
return allowed_strings;
|
||||
}();
|
||||
}() };
|
||||
|
||||
// 4. If default is UNSET, then
|
||||
// a. Let defaultValue be undefined.
|
||||
|
|
@ -406,7 +407,7 @@ ThrowCompletionOr<UnitValue> get_temporal_unit_valued_option(VM& vm, Object cons
|
|||
[](Unit unit) -> OptionDefault { return temporal_unit_to_string(unit); });
|
||||
|
||||
// 6. Let value be ? GetOption(options, key, STRING, allowedStrings, defaultValue).
|
||||
auto value = TRY(get_option(vm, options, key, OptionType::String, allowed_strings, default_value));
|
||||
auto value = TRY(get_option(vm, options, key, OptionType::String, *allowed_strings, default_value));
|
||||
|
||||
// 7. If value is undefined, return UNSET.
|
||||
if (value.is_undefined())
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/GenericShorthands.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/NonnullRawPtr.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <LibJS/Runtime/Temporal/Calendar.h>
|
||||
|
|
@ -292,7 +293,7 @@ Vector<String> const& available_calendars()
|
|||
// in canonical form (12.1) identifying the calendars for which the implementation provides the functionality of
|
||||
// Intl.DateTimeFormat objects, including their aliases (e.g., both "islamicc" and "islamic-civil"). The List must
|
||||
// consist of the "Calendar Type" value of every row of Table 1, except the header row.
|
||||
static auto calendars = []() {
|
||||
static NeverDestroyed<Vector<String>> calendars { []() {
|
||||
auto calendars = Unicode::available_calendars();
|
||||
|
||||
for (auto calendar : CLDR_CALENDAR_TYPES) {
|
||||
|
|
@ -302,9 +303,9 @@ Vector<String> const& available_calendars()
|
|||
|
||||
quick_sort(calendars);
|
||||
return calendars;
|
||||
}();
|
||||
}() };
|
||||
|
||||
return calendars;
|
||||
return *calendars;
|
||||
}
|
||||
|
||||
// 12.2.1 ParseMonthCode ( argument ), https://tc39.es/proposal-temporal/#sec-temporal-parsemonthcode
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ Duration::Duration(double years, double months, double weeks, double days, doubl
|
|||
}
|
||||
|
||||
// maxTimeDuration = 2**53 × 10**9 - 1 = 9,007,199,254,740,991,999,999,999
|
||||
TimeDuration const MAX_TIME_DURATION = "9007199254740991999999999"_sbigint;
|
||||
TimeDuration const& MAX_TIME_DURATION = *new TimeDuration("9007199254740991999999999"_sbigint);
|
||||
|
||||
// 7.5.4 ZeroDateDuration ( ), https://tc39.es/proposal-temporal/#sec-temporal-zerodateduration
|
||||
DateDuration zero_date_duration(VM& vm)
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ struct PartialDuration {
|
|||
Optional<double> nanoseconds;
|
||||
};
|
||||
|
||||
extern TimeDuration const MAX_TIME_DURATION;
|
||||
extern TimeDuration const& MAX_TIME_DURATION;
|
||||
|
||||
// 7.5.3 Internal Duration Records, https://tc39.es/proposal-temporal/#sec-temporal-internal-duration-records
|
||||
struct InternalDuration {
|
||||
|
|
|
|||
|
|
@ -40,27 +40,27 @@ void Instant::visit_edges(Cell::Visitor& visitor)
|
|||
}
|
||||
|
||||
// nsMaxInstant = 10**8 × nsPerDay = 8.64 × 10**21
|
||||
Crypto::SignedBigInteger const NANOSECONDS_MAX_INSTANT = "8640000000000000000000"_sbigint;
|
||||
Crypto::SignedBigInteger const& NANOSECONDS_MAX_INSTANT = *new Crypto::SignedBigInteger("8640000000000000000000"_sbigint);
|
||||
|
||||
// nsMinInstant = -nsMaxInstant = -8.64 × 10**21
|
||||
Crypto::SignedBigInteger const NANOSECONDS_MIN_INSTANT = "-8640000000000000000000"_sbigint;
|
||||
Crypto::SignedBigInteger const& NANOSECONDS_MIN_INSTANT = *new Crypto::SignedBigInteger("-8640000000000000000000"_sbigint);
|
||||
|
||||
// nsPerDay = 10**6 × ℝ(msPerDay) = 8.64 × 10**13
|
||||
Crypto::UnsignedBigInteger const NANOSECONDS_PER_DAY = 86400000000000_bigint;
|
||||
Crypto::UnsignedBigInteger const& NANOSECONDS_PER_DAY = *new Crypto::UnsignedBigInteger(86400000000000_bigint);
|
||||
|
||||
// Non-standard:
|
||||
Crypto::UnsignedBigInteger const NANOSECONDS_PER_HOUR = 3600000000000_bigint;
|
||||
Crypto::UnsignedBigInteger const NANOSECONDS_PER_MINUTE = 60000000000_bigint;
|
||||
Crypto::UnsignedBigInteger const NANOSECONDS_PER_SECOND = 1000000000_bigint;
|
||||
Crypto::UnsignedBigInteger const NANOSECONDS_PER_MILLISECOND = 1000000_bigint;
|
||||
Crypto::UnsignedBigInteger const NANOSECONDS_PER_MICROSECOND = 1000_bigint;
|
||||
Crypto::UnsignedBigInteger const NANOSECONDS_PER_NANOSECOND = 1_bigint;
|
||||
Crypto::UnsignedBigInteger const& NANOSECONDS_PER_HOUR = *new Crypto::UnsignedBigInteger(3600000000000_bigint);
|
||||
Crypto::UnsignedBigInteger const& NANOSECONDS_PER_MINUTE = *new Crypto::UnsignedBigInteger(60000000000_bigint);
|
||||
Crypto::UnsignedBigInteger const& NANOSECONDS_PER_SECOND = *new Crypto::UnsignedBigInteger(1000000000_bigint);
|
||||
Crypto::UnsignedBigInteger const& NANOSECONDS_PER_MILLISECOND = *new Crypto::UnsignedBigInteger(1000000_bigint);
|
||||
Crypto::UnsignedBigInteger const& NANOSECONDS_PER_MICROSECOND = *new Crypto::UnsignedBigInteger(1000_bigint);
|
||||
Crypto::UnsignedBigInteger const& NANOSECONDS_PER_NANOSECOND = *new Crypto::UnsignedBigInteger(1_bigint);
|
||||
|
||||
Crypto::UnsignedBigInteger const MICROSECONDS_PER_MILLISECOND = 1000_bigint;
|
||||
Crypto::UnsignedBigInteger const MILLISECONDS_PER_SECOND = 1000_bigint;
|
||||
Crypto::UnsignedBigInteger const SECONDS_PER_MINUTE = 60_bigint;
|
||||
Crypto::UnsignedBigInteger const MINUTES_PER_HOUR = 60_bigint;
|
||||
Crypto::UnsignedBigInteger const HOURS_PER_DAY = 24_bigint;
|
||||
Crypto::UnsignedBigInteger const& MICROSECONDS_PER_MILLISECOND = *new Crypto::UnsignedBigInteger(1000_bigint);
|
||||
Crypto::UnsignedBigInteger const& MILLISECONDS_PER_SECOND = *new Crypto::UnsignedBigInteger(1000_bigint);
|
||||
Crypto::UnsignedBigInteger const& SECONDS_PER_MINUTE = *new Crypto::UnsignedBigInteger(60_bigint);
|
||||
Crypto::UnsignedBigInteger const& MINUTES_PER_HOUR = *new Crypto::UnsignedBigInteger(60_bigint);
|
||||
Crypto::UnsignedBigInteger const& HOURS_PER_DAY = *new Crypto::UnsignedBigInteger(24_bigint);
|
||||
|
||||
// 8.5.1 IsValidEpochNanoseconds ( epochNanoseconds ), https://tc39.es/proposal-temporal/#sec-temporal-isvalidepochnanoseconds
|
||||
bool is_valid_epoch_nanoseconds(Crypto::SignedBigInteger const& epoch_nanoseconds)
|
||||
|
|
|
|||
|
|
@ -34,27 +34,27 @@ private:
|
|||
};
|
||||
|
||||
// https://tc39.es/proposal-temporal/#eqn-nsMaxInstant
|
||||
extern Crypto::SignedBigInteger const NANOSECONDS_MAX_INSTANT;
|
||||
extern Crypto::SignedBigInteger const& NANOSECONDS_MAX_INSTANT;
|
||||
|
||||
// https://tc39.es/proposal-temporal/#eqn-nsMinInstant
|
||||
extern Crypto::SignedBigInteger const NANOSECONDS_MIN_INSTANT;
|
||||
extern Crypto::SignedBigInteger const& NANOSECONDS_MIN_INSTANT;
|
||||
|
||||
// https://tc39.es/proposal-temporal/#eqn-nsPerDay
|
||||
extern Crypto::UnsignedBigInteger const NANOSECONDS_PER_DAY;
|
||||
extern Crypto::UnsignedBigInteger const& NANOSECONDS_PER_DAY;
|
||||
|
||||
// Non-standard:
|
||||
extern Crypto::UnsignedBigInteger const NANOSECONDS_PER_HOUR;
|
||||
extern Crypto::UnsignedBigInteger const NANOSECONDS_PER_MINUTE;
|
||||
extern Crypto::UnsignedBigInteger const NANOSECONDS_PER_SECOND;
|
||||
extern Crypto::UnsignedBigInteger const NANOSECONDS_PER_MILLISECOND;
|
||||
extern Crypto::UnsignedBigInteger const NANOSECONDS_PER_MICROSECOND;
|
||||
extern Crypto::UnsignedBigInteger const NANOSECONDS_PER_NANOSECOND;
|
||||
extern Crypto::UnsignedBigInteger const& NANOSECONDS_PER_HOUR;
|
||||
extern Crypto::UnsignedBigInteger const& NANOSECONDS_PER_MINUTE;
|
||||
extern Crypto::UnsignedBigInteger const& NANOSECONDS_PER_SECOND;
|
||||
extern Crypto::UnsignedBigInteger const& NANOSECONDS_PER_MILLISECOND;
|
||||
extern Crypto::UnsignedBigInteger const& NANOSECONDS_PER_MICROSECOND;
|
||||
extern Crypto::UnsignedBigInteger const& NANOSECONDS_PER_NANOSECOND;
|
||||
|
||||
extern Crypto::UnsignedBigInteger const MICROSECONDS_PER_MILLISECOND;
|
||||
extern Crypto::UnsignedBigInteger const MILLISECONDS_PER_SECOND;
|
||||
extern Crypto::UnsignedBigInteger const SECONDS_PER_MINUTE;
|
||||
extern Crypto::UnsignedBigInteger const MINUTES_PER_HOUR;
|
||||
extern Crypto::UnsignedBigInteger const HOURS_PER_DAY;
|
||||
extern Crypto::UnsignedBigInteger const& MICROSECONDS_PER_MILLISECOND;
|
||||
extern Crypto::UnsignedBigInteger const& MILLISECONDS_PER_SECOND;
|
||||
extern Crypto::UnsignedBigInteger const& SECONDS_PER_MINUTE;
|
||||
extern Crypto::UnsignedBigInteger const& MINUTES_PER_HOUR;
|
||||
extern Crypto::UnsignedBigInteger const& HOURS_PER_DAY;
|
||||
|
||||
bool is_valid_epoch_nanoseconds(Crypto::SignedBigInteger const& epoch_nanoseconds);
|
||||
ThrowCompletionOr<GC::Ref<Instant>> create_temporal_instant(VM&, BigInt const& epoch_nanoseconds, GC::Ptr<FunctionObject> new_target = {});
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Date.h>
|
||||
#include <LibJS/Runtime/Temporal/Calendar.h>
|
||||
|
|
@ -51,10 +52,18 @@ ISODateTime combine_iso_date_and_time_record(ISODate iso_date, Time const& time)
|
|||
}
|
||||
|
||||
// nsMinInstant - nsPerDay
|
||||
static auto const DATETIME_NANOSECONDS_MIN = "-8640000086400000000000"_sbigint;
|
||||
static auto const& datetime_nanoseconds_min()
|
||||
{
|
||||
static NeverDestroyed<Crypto::SignedBigInteger> value { "-8640000086400000000000"_sbigint };
|
||||
return *value;
|
||||
}
|
||||
|
||||
// nsMaxInstant + nsPerDay
|
||||
static auto const DATETIME_NANOSECONDS_MAX = "8640000086400000000000"_sbigint;
|
||||
static auto const& datetime_nanoseconds_max()
|
||||
{
|
||||
static NeverDestroyed<Crypto::SignedBigInteger> value { "8640000086400000000000"_sbigint };
|
||||
return *value;
|
||||
}
|
||||
|
||||
// 5.5.4 ISODateTimeWithinLimits ( isoDateTime ), https://tc39.es/proposal-temporal/#sec-temporal-isodatetimewithinlimits
|
||||
bool iso_date_time_within_limits(ISODateTime const& iso_date_time)
|
||||
|
|
@ -67,11 +76,11 @@ bool iso_date_time_within_limits(ISODateTime const& iso_date_time)
|
|||
auto nanoseconds = get_utc_epoch_nanoseconds(iso_date_time);
|
||||
|
||||
// 3. If ns ≤ nsMinInstant - nsPerDay, return false.
|
||||
if (nanoseconds <= DATETIME_NANOSECONDS_MIN)
|
||||
if (nanoseconds <= datetime_nanoseconds_min())
|
||||
return false;
|
||||
|
||||
// 4. If ns ≥ nsMaxInstant + nsPerDay, return false.
|
||||
if (nanoseconds >= DATETIME_NANOSECONDS_MAX)
|
||||
if (nanoseconds >= datetime_nanoseconds_max())
|
||||
return false;
|
||||
|
||||
// 5. Return true.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
#include <LibJS/Runtime/Date.h>
|
||||
#include <LibJS/Runtime/Intl/AbstractOperations.h>
|
||||
|
|
@ -510,12 +511,16 @@ bool time_zone_equals(StringView one, StringView two)
|
|||
}
|
||||
|
||||
// OPTIMIZATION: The result of parsing a time zone identifier will not change, so we can cache the result.
|
||||
static HashMap<String, ParsedTimeZoneIdentifier> s_time_zone_id_cache;
|
||||
static auto& time_zone_id_cache()
|
||||
{
|
||||
static NeverDestroyed<HashMap<String, ParsedTimeZoneIdentifier>> cache;
|
||||
return *cache;
|
||||
}
|
||||
|
||||
// 11.1.16 ParseTimeZoneIdentifier ( identifier ), https://tc39.es/proposal-temporal/#sec-parsetimezoneidentifier
|
||||
ThrowCompletionOr<ParsedTimeZoneIdentifier> parse_time_zone_identifier(VM& vm, String const& identifier)
|
||||
{
|
||||
if (auto result = s_time_zone_id_cache.get(identifier); result.has_value())
|
||||
if (auto result = time_zone_id_cache().get(identifier); result.has_value())
|
||||
return *result;
|
||||
|
||||
// 1. Let parseResult be ParseText(StringToCodePoints(identifier), TimeZoneIdentifier).
|
||||
|
|
@ -526,7 +531,7 @@ ThrowCompletionOr<ParsedTimeZoneIdentifier> parse_time_zone_identifier(VM& vm, S
|
|||
return vm.throw_completion<RangeError>(ErrorType::TemporalInvalidTimeZoneString, identifier);
|
||||
|
||||
auto result = parse_time_zone_identifier(*parse_result);
|
||||
s_time_zone_id_cache.set(identifier, result);
|
||||
time_zone_id_cache().set(identifier, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
@ -535,7 +540,7 @@ ThrowCompletionOr<ParsedTimeZoneIdentifier> parse_time_zone_identifier(VM& vm, S
|
|||
ParsedTimeZoneIdentifier const& parse_time_zone_identifier(String const& identifier)
|
||||
{
|
||||
// OPTIMIZATION: Some callers can assume that parsing will succeed.
|
||||
return s_time_zone_id_cache.ensure(identifier, [&]() {
|
||||
return time_zone_id_cache().ensure(identifier, [&]() {
|
||||
// 1. Let parseResult be ParseText(StringToCodePoints(identifier), TimeZoneIdentifier).
|
||||
auto parse_result = parse_iso8601(Production::TimeZoneIdentifier, identifier);
|
||||
VERIFY(parse_result.has_value());
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
#include <AK/Assertions.h>
|
||||
#include <AK/ByteString.h>
|
||||
#include <AK/CharacterTypes.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/StringConversions.h>
|
||||
#include <AK/Utf16String.h>
|
||||
|
|
@ -58,7 +59,11 @@ static inline bool same_type_for_equality(Value const& lhs, Value const& rhs)
|
|||
return false;
|
||||
}
|
||||
|
||||
static Crypto::SignedBigInteger const BIGINT_ZERO { 0 };
|
||||
static auto const& bigint_zero()
|
||||
{
|
||||
static NeverDestroyed<Crypto::SignedBigInteger> zero { 0 };
|
||||
return *zero;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE bool both_number(Value const& lhs, Value const& rhs)
|
||||
{
|
||||
|
|
@ -306,7 +311,7 @@ ThrowCompletionOr<bool> Value::is_regexp(VM& vm) const
|
|||
return false;
|
||||
|
||||
// 2. Let matcher be ? Get(argument, @@match).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto matcher = TRY(as_object().get(vm.well_known_symbol_match(), cache));
|
||||
|
||||
// 3. If matcher is not undefined, return ToBoolean(matcher).
|
||||
|
|
@ -554,7 +559,7 @@ bool Value::to_boolean_slow_case() const
|
|||
case STRING_TAG:
|
||||
return !as_string().is_empty();
|
||||
case BIGINT_TAG:
|
||||
return as_bigint().big_integer() != BIGINT_ZERO;
|
||||
return as_bigint().big_integer() != bigint_zero();
|
||||
case OBJECT_TAG:
|
||||
// B.3.6.1 Changes to ToBoolean, https://tc39.es/ecma262/#sec-IsHTMLDDA-internal-slot-to-boolean
|
||||
// 3. If argument is an Object and argument has an [[IsHTMLDDA]] internal slot, return false.
|
||||
|
|
@ -575,7 +580,7 @@ ThrowCompletionOr<Value> Value::to_primitive_slow_case(VM& vm, PreferredType pre
|
|||
// 1. If input is an Object, then
|
||||
if (is_object()) {
|
||||
// a. Let exoticToPrim be ? GetMethod(input, @@toPrimitive).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto exotic_to_primitive = TRY(get_method(vm, vm.well_known_symbol_to_primitive(), cache));
|
||||
|
||||
// b. If exoticToPrim is not undefined, then
|
||||
|
|
@ -934,7 +939,7 @@ static Optional<BigInt*> string_to_bigint(VM& vm, StringView string)
|
|||
// 4. Let mv be the MV of literal.
|
||||
// 5. Assert: mv is an integer.
|
||||
auto bigint = MUST(Crypto::SignedBigInteger::from_base(result->base, result->literal));
|
||||
if (result->is_negative && (bigint != BIGINT_ZERO))
|
||||
if (result->is_negative && (bigint != bigint_zero()))
|
||||
bigint.negate();
|
||||
|
||||
// 6. Return ℤ(mv).
|
||||
|
|
@ -1615,8 +1620,8 @@ ThrowCompletionOr<Value> unary_minus(VM& vm, Value lhs)
|
|||
|
||||
// 6.1.6.2.1 BigInt::unaryMinus ( x ), https://tc39.es/ecma262/#sec-numeric-types-bigint-unaryMinus
|
||||
// 1. If x is 0ℤ, return 0ℤ.
|
||||
if (old_value.as_bigint().big_integer() == BIGINT_ZERO)
|
||||
return BigInt::create(vm, BIGINT_ZERO);
|
||||
if (old_value.as_bigint().big_integer() == bigint_zero())
|
||||
return BigInt::create(vm, bigint_zero());
|
||||
|
||||
// 2. Return the BigInt value that represents the negation of ℝ(x).
|
||||
auto big_integer_negated = old_value.as_bigint().big_integer();
|
||||
|
|
@ -1944,7 +1949,7 @@ ThrowCompletionOr<Value> div(VM& vm, Value lhs, Value rhs)
|
|||
auto x = lhs_numeric.as_bigint().big_integer();
|
||||
auto y = rhs_numeric.as_bigint().big_integer();
|
||||
// 1. If y is 0ℤ, throw a RangeError exception.
|
||||
if (y == BIGINT_ZERO)
|
||||
if (y == bigint_zero())
|
||||
return vm.throw_completion<RangeError>(ErrorType::DivisionByZero);
|
||||
// 2. Let quotient be ℝ(x) / ℝ(y).
|
||||
// 3. Return the BigInt value that represents quotient rounded towards 0 to the next integer value.
|
||||
|
|
@ -1984,7 +1989,7 @@ ThrowCompletionOr<Value> mod(VM& vm, Value lhs, Value rhs)
|
|||
auto n = lhs_numeric.as_bigint().big_integer();
|
||||
auto d = rhs_numeric.as_bigint().big_integer();
|
||||
// 1. If d is 0ℤ, throw a RangeError exception.
|
||||
if (d == BIGINT_ZERO)
|
||||
if (d == bigint_zero())
|
||||
return vm.throw_completion<RangeError>(ErrorType::DivisionByZero);
|
||||
// 2. If n is 0ℤ, return 0ℤ.
|
||||
// 3. Let quotient be ℝ(n) / ℝ(d).
|
||||
|
|
@ -2153,7 +2158,7 @@ ThrowCompletionOr<Value> instance_of(VM& vm, Value value, Value target)
|
|||
return vm.throw_completion<TypeError>(ErrorType::NotAnObject, target);
|
||||
|
||||
// 2. Let instOfHandler be ? GetMethod(target, @@hasInstance).
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto instance_of_handler = TRY(target.get_method(vm, vm.well_known_symbol_has_instance(), cache));
|
||||
|
||||
// 3. If instOfHandler is not undefined, then
|
||||
|
|
@ -2199,7 +2204,7 @@ ThrowCompletionOr<Value> ordinary_has_instance(VM& vm, Value lhs, Value rhs)
|
|||
auto* lhs_object = &lhs.as_object();
|
||||
|
||||
// 4. Let P be ? Get(C, "prototype").
|
||||
static Bytecode::StaticPropertyLookupCache cache;
|
||||
static auto& cache = *new Bytecode::StaticPropertyLookupCache;
|
||||
auto rhs_prototype = TRY(rhs.get(vm, vm.names.prototype, cache));
|
||||
|
||||
// 5. If P is not an Object, throw a TypeError exception.
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/Debug.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/Utf16String.h>
|
||||
#include <LibGfx/Palette.h>
|
||||
#include <LibJS/RustFFI.h>
|
||||
|
|
@ -154,13 +155,13 @@ void SyntaxHighlighter::rehighlight(Palette const& palette)
|
|||
|
||||
Vector<Syntax::Highlighter::MatchingTokenPair> SyntaxHighlighter::matching_token_pairs_impl() const
|
||||
{
|
||||
static Vector<Syntax::Highlighter::MatchingTokenPair> pairs;
|
||||
if (pairs.is_empty()) {
|
||||
pairs.append({ pack_token_data(TokenType::CurlyOpen, TokenCategory::Punctuation), pack_token_data(TokenType::CurlyClose, TokenCategory::Punctuation) });
|
||||
pairs.append({ pack_token_data(TokenType::ParenOpen, TokenCategory::Punctuation), pack_token_data(TokenType::ParenClose, TokenCategory::Punctuation) });
|
||||
pairs.append({ pack_token_data(TokenType::BracketOpen, TokenCategory::Punctuation), pack_token_data(TokenType::BracketClose, TokenCategory::Punctuation) });
|
||||
static NeverDestroyed<Vector<Syntax::Highlighter::MatchingTokenPair>> pairs;
|
||||
if (pairs->is_empty()) {
|
||||
pairs->append({ pack_token_data(TokenType::CurlyOpen, TokenCategory::Punctuation), pack_token_data(TokenType::CurlyClose, TokenCategory::Punctuation) });
|
||||
pairs->append({ pack_token_data(TokenType::ParenOpen, TokenCategory::Punctuation), pack_token_data(TokenType::ParenClose, TokenCategory::Punctuation) });
|
||||
pairs->append({ pack_token_data(TokenType::BracketOpen, TokenCategory::Punctuation), pack_token_data(TokenType::BracketClose, TokenCategory::Punctuation) });
|
||||
}
|
||||
return pairs;
|
||||
return *pairs;
|
||||
}
|
||||
|
||||
bool SyntaxHighlighter::token_types_equal(u64 token1, u64 token2) const
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <AK/GenericLexer.h>
|
||||
#include <AK/JsonObject.h>
|
||||
#include <AK/MemoryStream.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/RedBlackTree.h>
|
||||
#include <AK/ScopeGuard.h>
|
||||
#include <AK/ScopedValueRollback.h>
|
||||
|
|
@ -929,8 +930,10 @@ ErrorOr<void> Editor::handle_read_event()
|
|||
Utf8View input_view { StringView { m_incomplete_data.data(), valid_bytes } };
|
||||
size_t consumed_code_points = 0;
|
||||
|
||||
static Vector<u8, 4> csi_parameter_bytes;
|
||||
static Vector<u8> csi_intermediate_bytes;
|
||||
static NeverDestroyed<Vector<u8, 4>> s_csi_parameter_bytes;
|
||||
static NeverDestroyed<Vector<u8>> s_csi_intermediate_bytes;
|
||||
auto& csi_parameter_bytes = *s_csi_parameter_bytes;
|
||||
auto& csi_intermediate_bytes = *s_csi_intermediate_bytes;
|
||||
Vector<unsigned, 4> csi_parameters;
|
||||
u8 csi_final;
|
||||
enum CSIMod {
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ namespace Media {
|
|||
|
||||
AudioDevices& AudioDevices::the()
|
||||
{
|
||||
static AudioDevices devices;
|
||||
static AudioDevices& devices = *new AudioDevices;
|
||||
return devices;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,25 +6,31 @@
|
|||
|
||||
#include "PulseAudioWrappers.h"
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibMedia/Audio/SampleSpecification.h>
|
||||
#include <LibSync/Mutex.h>
|
||||
|
||||
namespace Audio {
|
||||
|
||||
static PulseAudioContext* s_pulse_audio_context;
|
||||
static Sync::RecursiveMutex s_pulse_audio_context_mutex;
|
||||
|
||||
static Sync::RecursiveMutex& pulse_audio_context_mutex()
|
||||
{
|
||||
static NeverDestroyed<Sync::RecursiveMutex> mutex;
|
||||
return *mutex;
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<PulseAudioContext>> PulseAudioContext::the()
|
||||
{
|
||||
auto instantiation_locker = Sync::MutexLocker(s_pulse_audio_context_mutex);
|
||||
auto instantiation_locker = Sync::MutexLocker(pulse_audio_context_mutex());
|
||||
|
||||
// Lock and unlock the mutex to ensure that the mutex is fully unlocked at application
|
||||
// exit.
|
||||
static bool registered_atexit_callback = false;
|
||||
if (!registered_atexit_callback) {
|
||||
auto atexit_result = atexit([]() {
|
||||
s_pulse_audio_context_mutex.lock();
|
||||
s_pulse_audio_context_mutex.unlock();
|
||||
pulse_audio_context_mutex().lock();
|
||||
pulse_audio_context_mutex().unlock();
|
||||
});
|
||||
if (atexit_result)
|
||||
return Error::from_string_literal("Unable to set PulseAudioContext atexit action");
|
||||
|
|
@ -112,7 +118,7 @@ ErrorOr<NonnullRefPtr<PulseAudioContext>> PulseAudioContext::the()
|
|||
|
||||
bool PulseAudioContext::is_connected()
|
||||
{
|
||||
auto locker = Sync::MutexLocker(s_pulse_audio_context_mutex);
|
||||
auto locker = Sync::MutexLocker(pulse_audio_context_mutex());
|
||||
return s_pulse_audio_context != nullptr;
|
||||
}
|
||||
|
||||
|
|
@ -125,7 +131,7 @@ PulseAudioContext::PulseAudioContext(pa_threaded_mainloop* main_loop, pa_mainloo
|
|||
|
||||
PulseAudioContext::~PulseAudioContext()
|
||||
{
|
||||
auto locker = Sync::MutexLocker(s_pulse_audio_context_mutex);
|
||||
auto locker = Sync::MutexLocker(pulse_audio_context_mutex());
|
||||
|
||||
{
|
||||
auto loop_locker = main_loop_locker();
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <AK/CharacterTypes.h>
|
||||
#include <AK/Find.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <AK/Traits.h>
|
||||
#include <LibUnicode/CharacterTypes.h>
|
||||
|
|
@ -53,8 +54,17 @@ static constexpr GeneralCategory GENERAL_CATEGORY_SEPARATOR = U_CHAR_CATEGORY_CO
|
|||
static constexpr GeneralCategory GENERAL_CATEGORY_OTHER = U_CHAR_CATEGORY_COUNT + 8;
|
||||
static constexpr GeneralCategory GENERAL_CATEGORY_LIMIT = U_CHAR_CATEGORY_COUNT + 9;
|
||||
|
||||
static HashMap<GeneralCategory, NonnullOwnPtr<icu::UnicodeSet>> s_category_sets_with_case_closure;
|
||||
static HashMap<Property, NonnullOwnPtr<icu::UnicodeSet>> s_property_sets_with_case_closure;
|
||||
static auto& category_sets_with_case_closure()
|
||||
{
|
||||
static NeverDestroyed<HashMap<GeneralCategory, NonnullOwnPtr<icu::UnicodeSet>>> sets;
|
||||
return *sets;
|
||||
}
|
||||
|
||||
static auto& property_sets_with_case_closure()
|
||||
{
|
||||
static NeverDestroyed<HashMap<Property, NonnullOwnPtr<icu::UnicodeSet>>> sets;
|
||||
return *sets;
|
||||
}
|
||||
|
||||
Optional<GeneralCategory> general_category_from_string(StringView general_category)
|
||||
{
|
||||
|
|
@ -123,7 +133,7 @@ bool code_point_has_general_category(u32 code_point, GeneralCategory general_cat
|
|||
if (case_sensitivity == CaseSensitivity::CaseSensitive)
|
||||
return false;
|
||||
|
||||
auto& set = s_category_sets_with_case_closure.ensure(general_category, [&] {
|
||||
auto& set = category_sets_with_case_closure().ensure(general_category, [&] {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
auto new_set = make<icu::UnicodeSet>();
|
||||
new_set->applyIntPropertyValue(UCHAR_GENERAL_CATEGORY_MASK, static_cast<int32_t>(category_mask), status);
|
||||
|
|
@ -231,7 +241,7 @@ bool code_point_has_property(u32 code_point, Property property, CaseSensitivity
|
|||
if (case_sensitivity == CaseSensitivity::CaseSensitive)
|
||||
return false;
|
||||
|
||||
auto& set = s_property_sets_with_case_closure.ensure(property, [&] {
|
||||
auto& set = property_sets_with_case_closure().ensure(property, [&] {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
auto new_set = make<icu::UnicodeSet>();
|
||||
new_set->applyIntPropertyValue(icu_property, 1, status);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibUnicode/CurrencyCode.h>
|
||||
|
||||
namespace Unicode {
|
||||
|
|
@ -13,7 +14,7 @@ static auto const& ensure_currency_codes()
|
|||
{
|
||||
// https://www.iso.org/iso-4217-currency-codes.html
|
||||
// https://www.six-group.com/dam/download/financial-information/data-center/iso-currrency/amendments/lists/list_one.xml
|
||||
static HashMap<StringView, CurrencyCode> currency_codes {
|
||||
static NeverDestroyed<HashMap<StringView, CurrencyCode>> currency_codes { HashMap<StringView, CurrencyCode> {
|
||||
{ "AED"sv, { 2 } },
|
||||
{ "AFN"sv, { 2 } },
|
||||
{ "ALL"sv, { 2 } },
|
||||
|
|
@ -193,9 +194,9 @@ static auto const& ensure_currency_codes()
|
|||
{ "ZAR"sv, { 2 } },
|
||||
{ "ZMW"sv, { 2 } },
|
||||
{ "ZWL"sv, { 2 } },
|
||||
};
|
||||
} };
|
||||
|
||||
return currency_codes;
|
||||
return *currency_codes;
|
||||
}
|
||||
|
||||
Optional<CurrencyCode const&> get_currency_code(StringView currency)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <AK/Utf16View.h>
|
||||
#include <LibUnicode/ICU.h>
|
||||
|
|
@ -17,15 +18,24 @@
|
|||
|
||||
namespace Unicode {
|
||||
|
||||
static HashMap<String, OwnPtr<LocaleData>> s_locale_cache;
|
||||
static HashMap<String, OwnPtr<TimeZoneData>> s_time_zone_cache;
|
||||
static auto& locale_cache()
|
||||
{
|
||||
static NeverDestroyed<HashMap<String, OwnPtr<LocaleData>>> cache;
|
||||
return *cache;
|
||||
}
|
||||
|
||||
static auto& time_zone_cache()
|
||||
{
|
||||
static NeverDestroyed<HashMap<String, OwnPtr<TimeZoneData>>> cache;
|
||||
return *cache;
|
||||
}
|
||||
|
||||
Optional<LocaleData&> LocaleData::for_locale(StringView locale)
|
||||
{
|
||||
auto locale_data = s_locale_cache.get(locale);
|
||||
auto locale_data = locale_cache().get(locale);
|
||||
|
||||
if (!locale_data.has_value()) {
|
||||
locale_data = s_locale_cache.ensure(MUST(String::from_utf8(locale)), [&]() -> OwnPtr<LocaleData> {
|
||||
locale_data = locale_cache().ensure(MUST(String::from_utf8(locale)), [&]() -> OwnPtr<LocaleData> {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
auto icu_locale = icu::Locale::forLanguageTag(icu_string_piece(locale), status);
|
||||
|
|
@ -164,10 +174,10 @@ icu::TimeZoneNames& LocaleData::time_zone_names()
|
|||
|
||||
Optional<TimeZoneData&> TimeZoneData::for_time_zone(StringView time_zone)
|
||||
{
|
||||
auto time_zone_data = s_time_zone_cache.get(time_zone);
|
||||
auto time_zone_data = time_zone_cache().get(time_zone);
|
||||
|
||||
if (!time_zone_data.has_value()) {
|
||||
time_zone_data = s_time_zone_cache.ensure(MUST(String::from_utf8(time_zone)), [&]() -> OwnPtr<TimeZoneData> {
|
||||
time_zone_data = time_zone_cache().ensure(MUST(String::from_utf8(time_zone)), [&]() -> OwnPtr<TimeZoneData> {
|
||||
auto icu_time_zone = adopt_own_if_nonnull(icu::TimeZone::createTimeZone(icu_string(time_zone)));
|
||||
if (!icu_time_zone || *icu_time_zone == icu::TimeZone::getUnknown())
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <AK/AllOf.h>
|
||||
#include <AK/GenericLexer.h>
|
||||
#include <AK/HashTable.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibUnicode/ICU.h>
|
||||
|
|
@ -530,7 +531,7 @@ static void define_locales_without_scripts(HashTable<String>& locales)
|
|||
|
||||
bool is_locale_available(StringView locale)
|
||||
{
|
||||
static auto available_locales = []() {
|
||||
static NeverDestroyed<HashTable<String>> available_locales { []() {
|
||||
i32 count = 0;
|
||||
auto const* locale_list = icu::Locale::getAvailableLocales(count);
|
||||
|
||||
|
|
@ -549,9 +550,9 @@ bool is_locale_available(StringView locale)
|
|||
|
||||
define_locales_without_scripts(available_locales);
|
||||
return available_locales;
|
||||
}();
|
||||
}() };
|
||||
|
||||
return available_locales.contains(locale);
|
||||
return available_locales->contains(locale);
|
||||
}
|
||||
|
||||
Style style_from_string(StringView style)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/Array.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/NonnullOwnPtr.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <LibUnicode/ICU.h>
|
||||
|
|
@ -16,7 +17,11 @@
|
|||
|
||||
namespace Unicode {
|
||||
|
||||
static Optional<String> cached_system_time_zone;
|
||||
static auto& cached_system_time_zone()
|
||||
{
|
||||
static NeverDestroyed<Optional<String>> cached_system_time_zone;
|
||||
return *cached_system_time_zone;
|
||||
}
|
||||
|
||||
static String current_time_zone_impl(OwnPtr<icu::TimeZone> time_zone)
|
||||
{
|
||||
|
|
@ -49,12 +54,12 @@ static String current_default_time_zone()
|
|||
|
||||
String current_time_zone()
|
||||
{
|
||||
return cached_system_time_zone.ensure([] { return current_host_time_zone(); });
|
||||
return cached_system_time_zone().ensure([] { return current_host_time_zone(); });
|
||||
}
|
||||
|
||||
void clear_system_time_zone_cache()
|
||||
{
|
||||
cached_system_time_zone.clear();
|
||||
cached_system_time_zone().clear();
|
||||
}
|
||||
|
||||
ErrorOr<void> set_current_time_zone(StringView time_zone)
|
||||
|
|
@ -64,7 +69,7 @@ ErrorOr<void> set_current_time_zone(StringView time_zone)
|
|||
return Error::from_string_literal("Unable to find the provided time zone");
|
||||
|
||||
icu::TimeZone::setDefault(time_zone_data->time_zone());
|
||||
cached_system_time_zone = current_default_time_zone();
|
||||
cached_system_time_zone() = current_default_time_zone();
|
||||
|
||||
return {};
|
||||
}
|
||||
|
|
@ -128,8 +133,8 @@ static Vector<String> icu_available_time_zones(Optional<ByteString> const& regio
|
|||
|
||||
Vector<String> const& available_time_zones()
|
||||
{
|
||||
static auto time_zones = icu_available_time_zones({});
|
||||
return time_zones;
|
||||
static NeverDestroyed<Vector<String>> time_zones { icu_available_time_zones({}) };
|
||||
return *time_zones;
|
||||
}
|
||||
|
||||
Vector<String> available_time_zones_in_region(StringView region)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <AK/ScopeGuard.h>
|
||||
#include <LibUnicode/DateTimeFormat.h>
|
||||
|
|
@ -37,14 +38,14 @@ Vector<String> available_keyword_values(StringView locale, StringView key)
|
|||
|
||||
Vector<String> const& available_calendars()
|
||||
{
|
||||
static auto calendars = []() {
|
||||
static NeverDestroyed<Vector<String>> calendars { []() {
|
||||
auto calendars = available_calendars("und"sv);
|
||||
|
||||
quick_sort(calendars);
|
||||
return calendars;
|
||||
}();
|
||||
}() };
|
||||
|
||||
return calendars;
|
||||
return *calendars;
|
||||
}
|
||||
|
||||
Vector<String> available_calendars(StringView locale)
|
||||
|
|
@ -68,7 +69,7 @@ Vector<String> available_calendars(StringView locale)
|
|||
|
||||
Vector<String> const& available_currencies()
|
||||
{
|
||||
static auto currencies = []() -> Vector<String> {
|
||||
static NeverDestroyed<Vector<String>> currencies { []() -> Vector<String> {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
auto* currencies = ucurr_openISOCurrencies(UCURR_ALL, &status);
|
||||
|
|
@ -95,26 +96,26 @@ Vector<String> const& available_currencies()
|
|||
|
||||
quick_sort(result);
|
||||
return result;
|
||||
}();
|
||||
}() };
|
||||
|
||||
return currencies;
|
||||
return *currencies;
|
||||
}
|
||||
|
||||
Vector<String> const& available_collation_case_orderings()
|
||||
{
|
||||
static Vector<String> case_orderings { "false"_string, "lower"_string, "upper"_string };
|
||||
return case_orderings;
|
||||
static NeverDestroyed<Vector<String>> case_orderings { Vector<String> { "false"_string, "lower"_string, "upper"_string } };
|
||||
return *case_orderings;
|
||||
}
|
||||
|
||||
Vector<String> const& available_collation_numeric_orderings()
|
||||
{
|
||||
static Vector<String> case_orderings { "false"_string, "true"_string };
|
||||
return case_orderings;
|
||||
static NeverDestroyed<Vector<String>> case_orderings { Vector<String> { "false"_string, "true"_string } };
|
||||
return *case_orderings;
|
||||
}
|
||||
|
||||
Vector<String> const& available_collations()
|
||||
{
|
||||
static auto collations = []() -> Vector<String> {
|
||||
static NeverDestroyed<Vector<String>> collations { []() -> Vector<String> {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
auto keywords = adopt_own_if_nonnull(icu::Collator::getKeywordValues("collation", status));
|
||||
|
|
@ -129,9 +130,9 @@ Vector<String> const& available_collations()
|
|||
|
||||
quick_sort(collations);
|
||||
return collations;
|
||||
}();
|
||||
}() };
|
||||
|
||||
return collations;
|
||||
return *collations;
|
||||
}
|
||||
|
||||
Vector<String> available_collations(StringView locale)
|
||||
|
|
@ -160,8 +161,8 @@ Vector<String> available_collations(StringView locale)
|
|||
|
||||
Vector<String> const& available_hour_cycles()
|
||||
{
|
||||
static Vector<String> case_orderings { "h11"_string, "h12"_string, "h23"_string, "h24"_string };
|
||||
return case_orderings;
|
||||
static NeverDestroyed<Vector<String>> hour_cycles { Vector<String> { "h11"_string, "h12"_string, "h23"_string, "h24"_string } };
|
||||
return *hour_cycles;
|
||||
}
|
||||
|
||||
Vector<String> available_hour_cycles(StringView locale)
|
||||
|
|
@ -183,7 +184,7 @@ Vector<String> available_hour_cycles(StringView locale)
|
|||
|
||||
Vector<String> const& available_number_systems()
|
||||
{
|
||||
static auto number_systems = []() -> Vector<String> {
|
||||
static NeverDestroyed<Vector<String>> number_systems { []() -> Vector<String> {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
auto keywords = adopt_own_if_nonnull(icu::NumberingSystem::getAvailableNames(status));
|
||||
|
|
@ -200,9 +201,9 @@ Vector<String> const& available_number_systems()
|
|||
|
||||
quick_sort(number_systems);
|
||||
return number_systems;
|
||||
}();
|
||||
}() };
|
||||
|
||||
return number_systems;
|
||||
return *number_systems;
|
||||
}
|
||||
|
||||
Vector<String> available_number_systems(StringView locale)
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/Enumerate.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/SaturatingMath.h>
|
||||
#include <LibCore/System.h>
|
||||
#include <LibWasm/AbstractMachine/AbstractMachine.h>
|
||||
|
|
@ -16,21 +17,25 @@
|
|||
|
||||
namespace Wasm {
|
||||
|
||||
static Vector<ModuleStats> s_module_stats;
|
||||
static auto& module_stats()
|
||||
{
|
||||
static NeverDestroyed<Vector<ModuleStats>> stats;
|
||||
return *stats;
|
||||
}
|
||||
|
||||
void record_module_stats(ModuleStats stats)
|
||||
{
|
||||
s_module_stats.append(move(stats));
|
||||
module_stats().append(move(stats));
|
||||
}
|
||||
|
||||
void dump_module_stats()
|
||||
{
|
||||
if (s_module_stats.is_empty()) {
|
||||
if (module_stats().is_empty()) {
|
||||
warnln("wasm-stats: no modules compiled yet");
|
||||
return;
|
||||
}
|
||||
|
||||
warnln("wasm-stats: {} module(s) compiled", s_module_stats.size());
|
||||
warnln("wasm-stats: {} module(s) compiled", module_stats().size());
|
||||
warnln("wasm-stats: hash input KiB parse ms validate ms cl ms cl blob KiB funcs cache");
|
||||
|
||||
AK::Duration total_parse;
|
||||
|
|
@ -40,7 +45,7 @@ void dump_module_stats()
|
|||
size_t total_blob = 0;
|
||||
size_t total_hits = 0;
|
||||
|
||||
for (auto const& s : s_module_stats) {
|
||||
for (auto const& s : module_stats()) {
|
||||
StringBuilder hash_prefix;
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
hash_prefix.appendff("{:02x}", s.wasm_hash[i]);
|
||||
|
|
|
|||
|
|
@ -5973,7 +5973,7 @@ CompiledInstructions try_compile_instructions(Expression const& expression, Span
|
|||
I64Const,
|
||||
I64ConstGetLocal,
|
||||
} pattern_state { InsnPatternState::Nothing };
|
||||
static Instruction nop { Instructions::nop };
|
||||
static auto& nop = *new Instruction { Instructions::nop };
|
||||
|
||||
size_t calls_in_expression = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -141,9 +141,14 @@ struct CacheState {
|
|||
Vector<BatchInput> pending_batch;
|
||||
};
|
||||
|
||||
static thread_local CacheState s_cranelift_cache_state;
|
||||
static thread_local u32 s_active_function_index = NumericLimits<u32>::max();
|
||||
|
||||
static CacheState& cranelift_cache_state()
|
||||
{
|
||||
static thread_local auto* state = new CacheState;
|
||||
return *state;
|
||||
}
|
||||
|
||||
static u64 compute_layout_hash(RuntimeHelpers const& h)
|
||||
{
|
||||
auto fnv1a = [](u64 hash, u64 value) {
|
||||
|
|
@ -1262,7 +1267,7 @@ static void try_cranelift_compile_batch(Vector<BatchInput>& batch)
|
|||
? ReadonlySpan<CraneliftTrap> {}
|
||||
: ReadonlySpan<CraneliftTrap> { reinterpret_cast<CraneliftTrap const*>(base + reloc_region_start + trap_offset), trap_count };
|
||||
|
||||
auto& capture = s_cranelift_cache_state.cache_capture;
|
||||
auto& capture = cranelift_cache_state().cache_capture;
|
||||
if (capture.capturing && batch[i].function_index != NumericLimits<u32>::max()) {
|
||||
if (auto copy = ByteBuffer::copy(code_bytes.data(), code_bytes.size()); !copy.is_error()) {
|
||||
CacheRecord rec;
|
||||
|
|
@ -1305,8 +1310,8 @@ bool try_cranelift_compile(CompiledInstructions& compiled, u32 result_arity)
|
|||
|
||||
// Cache hit: install from the parsed blob instead of going through cranelift.
|
||||
// dispatches[] has just been populated by try_compile_instructions, so handler_ptr is ready to be set.
|
||||
if (s_cranelift_cache_state.pending_install.active && s_active_function_index != NumericLimits<u32>::max()) {
|
||||
auto record = s_cranelift_cache_state.pending_install.records.take(s_active_function_index);
|
||||
if (cranelift_cache_state().pending_install.active && s_active_function_index != NumericLimits<u32>::max()) {
|
||||
auto record = cranelift_cache_state().pending_install.records.take(s_active_function_index);
|
||||
if (record.has_value()) {
|
||||
static auto cache_install_helpers = make_runtime_helpers();
|
||||
if (install_compiled_function(
|
||||
|
|
@ -1319,7 +1324,7 @@ bool try_cranelift_compile(CompiledInstructions& compiled, u32 result_arity)
|
|||
return true;
|
||||
}
|
||||
// Put it back so we can try later.
|
||||
s_cranelift_cache_state.pending_install.records.set(s_active_function_index, record.release_value());
|
||||
cranelift_cache_state().pending_install.records.set(s_active_function_index, record.release_value());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1352,9 +1357,9 @@ bool try_cranelift_compile(CompiledInstructions& compiled, u32 result_arity)
|
|||
static size_t s_min_insns = read_size_env("CRANELIFT_MIN_INSNS", 0);
|
||||
static size_t s_min_fn = read_size_env("CRANELIFT_MIN_FN", 0);
|
||||
static size_t s_max_fn = read_size_env("CRANELIFT_MAX_FN", NumericLimits<size_t>::max());
|
||||
static auto s_skip_fn = read_set_env("CRANELIFT_SKIP_FN");
|
||||
static auto s_only_fn = read_set_env("CRANELIFT_ONLY_FN");
|
||||
static auto s_dump_fn = read_set_env("CRANELIFT_DUMP_FN");
|
||||
static auto& s_skip_fn = *new HashTable<size_t>(read_set_env("CRANELIFT_SKIP_FN"));
|
||||
static auto& s_only_fn = *new HashTable<size_t>(read_set_env("CRANELIFT_ONLY_FN"));
|
||||
static auto& s_dump_fn = *new HashTable<size_t>(read_set_env("CRANELIFT_DUMP_FN"));
|
||||
static bool s_trace = getenv("CRANELIFT_TRACE") != nullptr;
|
||||
|
||||
static size_t s_func_counter = 0;
|
||||
|
|
@ -1435,22 +1440,22 @@ bool try_cranelift_compile(CompiledInstructions& compiled, u32 result_arity)
|
|||
}
|
||||
}
|
||||
|
||||
s_cranelift_cache_state.pending_batch.append({ move(flat), result_arity, s_active_function_index, &compiled });
|
||||
cranelift_cache_state().pending_batch.append({ move(flat), result_arity, s_active_function_index, &compiled });
|
||||
return false; // Not compiled yet, will be compiled in flush.
|
||||
#endif
|
||||
}
|
||||
|
||||
void flush_cranelift_batch()
|
||||
{
|
||||
if (s_cranelift_cache_state.pending_batch.is_empty())
|
||||
if (cranelift_cache_state().pending_batch.is_empty())
|
||||
return;
|
||||
try_cranelift_compile_batch(s_cranelift_cache_state.pending_batch);
|
||||
s_cranelift_cache_state.pending_batch.clear();
|
||||
try_cranelift_compile_batch(cranelift_cache_state().pending_batch);
|
||||
cranelift_cache_state().pending_batch.clear();
|
||||
}
|
||||
|
||||
void discard_cranelift_batch()
|
||||
{
|
||||
s_cranelift_cache_state.pending_batch.clear();
|
||||
cranelift_cache_state().pending_batch.clear();
|
||||
}
|
||||
|
||||
void free_cranelift_code(void* handle)
|
||||
|
|
@ -1473,30 +1478,30 @@ void set_cranelift_active_function_index(u32 function_index)
|
|||
|
||||
void begin_cranelift_cache_capture()
|
||||
{
|
||||
s_cranelift_cache_state.cache_capture.capturing = true;
|
||||
s_cranelift_cache_state.cache_capture.records.clear();
|
||||
cranelift_cache_state().cache_capture.capturing = true;
|
||||
cranelift_cache_state().cache_capture.records.clear();
|
||||
}
|
||||
|
||||
void abort_cranelift_cache_capture()
|
||||
{
|
||||
s_cranelift_cache_state.cache_capture.capturing = false;
|
||||
s_cranelift_cache_state.cache_capture.records.clear();
|
||||
cranelift_cache_state().cache_capture.capturing = false;
|
||||
cranelift_cache_state().cache_capture.records.clear();
|
||||
}
|
||||
|
||||
void abort_cranelift_cache_install()
|
||||
{
|
||||
s_cranelift_cache_state.pending_install.active = false;
|
||||
s_cranelift_cache_state.pending_install.records.clear();
|
||||
cranelift_cache_state().pending_install.active = false;
|
||||
cranelift_cache_state().pending_install.records.clear();
|
||||
}
|
||||
|
||||
Optional<ByteBuffer> serialize_cranelift_cache_blob(ReadonlyBytes wasm_hash)
|
||||
{
|
||||
ScopeGuard reset = [] {
|
||||
s_cranelift_cache_state.cache_capture.capturing = false;
|
||||
s_cranelift_cache_state.cache_capture.records.clear();
|
||||
cranelift_cache_state().cache_capture.capturing = false;
|
||||
cranelift_cache_state().cache_capture.records.clear();
|
||||
};
|
||||
|
||||
auto const& capture = s_cranelift_cache_state.cache_capture;
|
||||
auto const& capture = cranelift_cache_state().cache_capture;
|
||||
|
||||
if (!capture.capturing || capture.records.is_empty())
|
||||
return {};
|
||||
|
|
@ -1618,10 +1623,10 @@ bool try_install_cranelift_cache_blob(ReadonlyBytes expected_wasm_hash, Readonly
|
|||
__builtin_memcpy(&trap, blob.data() + trap_off + j * sizeof(CraneliftTrap), sizeof(CraneliftTrap));
|
||||
rec.traps.unchecked_append(trap);
|
||||
}
|
||||
s_cranelift_cache_state.pending_install.records.set(entry->function_index, move(rec));
|
||||
cranelift_cache_state().pending_install.records.set(entry->function_index, move(rec));
|
||||
}
|
||||
|
||||
s_cranelift_cache_state.pending_install.active = true;
|
||||
cranelift_cache_state().pending_install.active = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@
|
|||
namespace Wasm {
|
||||
|
||||
struct Names {
|
||||
static HashMap<OpCode, ByteString> instruction_names;
|
||||
static HashMap<ByteString, OpCode> instructions_by_name;
|
||||
static HashMap<OpCode, ByteString>& instruction_names;
|
||||
static HashMap<ByteString, OpCode>& instructions_by_name;
|
||||
};
|
||||
|
||||
ByteString instruction_name(OpCode const& opcode)
|
||||
|
|
@ -845,7 +845,7 @@ void Printer::print(Wasm::Reference const& value)
|
|||
|
||||
}
|
||||
|
||||
HashMap<Wasm::OpCode, ByteString> Wasm::Names::instruction_names {
|
||||
HashMap<Wasm::OpCode, ByteString>& Wasm::Names::instruction_names = *new HashMap<Wasm::OpCode, ByteString> {
|
||||
{ Instructions::unreachable, "unreachable" },
|
||||
{ Instructions::nop, "nop" },
|
||||
{ Instructions::block, "block" },
|
||||
|
|
@ -1368,4 +1368,4 @@ HashMap<Wasm::OpCode, ByteString> Wasm::Names::instruction_names {
|
|||
{ Instructions::synthetic_i64_shrs2local, "synthetic:i64.shrs2local" },
|
||||
{ Instructions::synthetic_local_seti64_const, "synthetic:local.seti64_const" },
|
||||
};
|
||||
HashMap<ByteString, Wasm::OpCode> Wasm::Names::instructions_by_name;
|
||||
HashMap<ByteString, Wasm::OpCode>& Wasm::Names::instructions_by_name = *new HashMap<ByteString, Wasm::OpCode>;
|
||||
|
|
|
|||
|
|
@ -922,7 +922,7 @@ struct Names {
|
|||
ErrorOr<HostFunction> Implementation::function_by_name(StringView name)
|
||||
{
|
||||
auto name_for_comparison = TRY(FlyString::from_utf8(name));
|
||||
static auto names = TRY(Names::construct());
|
||||
static auto& names = *new Names(TRY(Names::construct()));
|
||||
|
||||
#define IMPL(x) \
|
||||
if (name_for_comparison == names.x) \
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
namespace Web::ARIA::AttributeNames {
|
||||
|
||||
#define __ENUMERATE_ARIA_ATTRIBUTE(name, attribute) \
|
||||
FlyString name = attribute##_fly_string;
|
||||
FlyString const& name = *new FlyString(attribute##_fly_string);
|
||||
ENUMERATE_ARIA_ATTRIBUTES
|
||||
#undef __ENUMERATE_ARIA_ATTRIBUTE
|
||||
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ namespace Web::ARIA::AttributeNames {
|
|||
__ENUMERATE_ARIA_ATTRIBUTE(aria_value_text, "aria-valuetext")
|
||||
|
||||
#define __ENUMERATE_ARIA_ATTRIBUTE(name, attribute) \
|
||||
extern FlyString name;
|
||||
extern FlyString const& name;
|
||||
ENUMERATE_ARIA_ATTRIBUTES
|
||||
#undef __ENUMERATE_ARIA_ATTRIBUTE
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibWeb/ARIA/ARIAMixin.h>
|
||||
#include <LibWeb/ARIA/AriaRoles.h>
|
||||
#include <LibWeb/ARIA/RoleType.h>
|
||||
|
|
@ -47,54 +48,54 @@ constexpr StateAndProperties supported_properties_array[] = {
|
|||
|
||||
HashTable<StateAndProperties> const& RoleType::supported_states() const
|
||||
{
|
||||
static HashTable<StateAndProperties> states;
|
||||
if (states.is_empty())
|
||||
states.set_from(supported_state_array);
|
||||
return states;
|
||||
static NeverDestroyed<HashTable<StateAndProperties>> states;
|
||||
if (states->is_empty())
|
||||
states->set_from(supported_state_array);
|
||||
return *states;
|
||||
}
|
||||
|
||||
HashTable<StateAndProperties> const& RoleType::supported_properties() const
|
||||
{
|
||||
static HashTable<StateAndProperties> properties;
|
||||
if (properties.is_empty())
|
||||
properties.set_from(supported_properties_array);
|
||||
return properties;
|
||||
static NeverDestroyed<HashTable<StateAndProperties>> properties;
|
||||
if (properties->is_empty())
|
||||
properties->set_from(supported_properties_array);
|
||||
return *properties;
|
||||
}
|
||||
|
||||
HashTable<StateAndProperties> const& RoleType::required_states() const
|
||||
{
|
||||
static HashTable<StateAndProperties> states;
|
||||
return states;
|
||||
static NeverDestroyed<HashTable<StateAndProperties>> states;
|
||||
return *states;
|
||||
}
|
||||
|
||||
HashTable<StateAndProperties> const& RoleType::required_properties() const
|
||||
{
|
||||
static HashTable<StateAndProperties> properties;
|
||||
return properties;
|
||||
static NeverDestroyed<HashTable<StateAndProperties>> properties;
|
||||
return *properties;
|
||||
}
|
||||
|
||||
HashTable<StateAndProperties> const& RoleType::prohibited_properties() const
|
||||
{
|
||||
static HashTable<StateAndProperties> properties;
|
||||
return properties;
|
||||
static NeverDestroyed<HashTable<StateAndProperties>> properties;
|
||||
return *properties;
|
||||
}
|
||||
|
||||
HashTable<StateAndProperties> const& RoleType::prohibited_states() const
|
||||
{
|
||||
static HashTable<StateAndProperties> states;
|
||||
return states;
|
||||
static NeverDestroyed<HashTable<StateAndProperties>> states;
|
||||
return *states;
|
||||
}
|
||||
|
||||
HashTable<Role> const& RoleType::required_context_roles() const
|
||||
{
|
||||
static HashTable<Role> roles;
|
||||
return roles;
|
||||
static NeverDestroyed<HashTable<Role>> roles;
|
||||
return *roles;
|
||||
}
|
||||
|
||||
HashTable<Role> const& RoleType::required_owned_elements() const
|
||||
{
|
||||
static HashTable<Role> roles;
|
||||
return roles;
|
||||
static NeverDestroyed<HashTable<Role>> roles;
|
||||
return *roles;
|
||||
}
|
||||
|
||||
ErrorOr<void> RoleType::serialize_as_json(JsonObjectSerializer<StringBuilder>& object) const
|
||||
|
|
|
|||
|
|
@ -9,18 +9,19 @@
|
|||
#include <AK/FlyString.h>
|
||||
#include <AK/Forward.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibGC/Heap.h>
|
||||
#include <LibJS/Forward.h>
|
||||
#include <LibJS/Heap/Cell.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibWeb/Export.h>
|
||||
|
||||
#define WEB_SET_PROTOTYPE_FOR_INTERFACE_WITH_CUSTOM_NAME(interface_class, interface_name) \
|
||||
do { \
|
||||
static auto name = #interface_name##_fly_string; \
|
||||
if (!shape().prototype()) { \
|
||||
set_prototype(&Bindings::ensure_web_prototype<Bindings::interface_class##Prototype>(realm, name)); \
|
||||
} \
|
||||
#define WEB_SET_PROTOTYPE_FOR_INTERFACE_WITH_CUSTOM_NAME(interface_class, interface_name) \
|
||||
do { \
|
||||
static NeverDestroyed<FlyString> name { #interface_name##_fly_string }; \
|
||||
if (!shape().prototype()) { \
|
||||
set_prototype(&Bindings::ensure_web_prototype<Bindings::interface_class##Prototype>(realm, *name)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define WEB_SET_PROTOTYPE_FOR_INTERFACE(interface_name) WEB_SET_PROTOTYPE_FOR_INTERFACE_WITH_CUSTOM_NAME(interface_name, interface_name)
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibGC/DeferGC.h>
|
||||
#include <LibJS/Module.h>
|
||||
#include <LibJS/Runtime/AbstractOperations.h>
|
||||
|
|
@ -53,7 +54,11 @@
|
|||
|
||||
namespace Web::Bindings {
|
||||
|
||||
static RefPtr<JS::VM> s_main_thread_vm;
|
||||
static auto& main_thread_vm_ptr()
|
||||
{
|
||||
static NeverDestroyed<RefPtr<JS::VM>> vm;
|
||||
return *vm;
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/webappapis.html#active-script
|
||||
HTML::Script* active_script()
|
||||
|
|
@ -93,37 +98,37 @@ static NonnullOwnPtr<JS::Agent> create_agent(GC::Heap& heap, AgentType type)
|
|||
|
||||
void initialize_main_thread_vm(AgentType type)
|
||||
{
|
||||
VERIFY(!s_main_thread_vm);
|
||||
VERIFY(!main_thread_vm_ptr());
|
||||
|
||||
s_main_thread_vm = JS::VM::create();
|
||||
s_main_thread_vm->set_agent(create_agent(s_main_thread_vm->heap(), type));
|
||||
main_thread_vm_ptr() = JS::VM::create();
|
||||
main_thread_vm_ptr()->set_agent(create_agent(main_thread_vm_ptr()->heap(), type));
|
||||
|
||||
s_main_thread_vm->on_unimplemented_property_access = [](auto const& object, auto const& property_key) {
|
||||
main_thread_vm_ptr()->on_unimplemented_property_access = [](auto const& object, auto const& property_key) {
|
||||
dbgln("FIXME: Unimplemented IDL interface: '{}.{}'", object.class_name(), property_key.to_string());
|
||||
};
|
||||
|
||||
// NOTE: We intentionally leak the main thread JavaScript VM.
|
||||
// This avoids doing an exhaustive garbage collection on process exit.
|
||||
s_main_thread_vm->ref();
|
||||
main_thread_vm_ptr()->ref();
|
||||
|
||||
// 8.1.6.1 HostEnsureCanAddPrivateElement(O), https://html.spec.whatwg.org/multipage/webappapis.html#the-hostensurecanaddprivateelement-implementation
|
||||
s_main_thread_vm->host_ensure_can_add_private_element = [](JS::Object const& object) -> JS::ThrowCompletionOr<void> {
|
||||
main_thread_vm_ptr()->host_ensure_can_add_private_element = [](JS::Object const& object) -> JS::ThrowCompletionOr<void> {
|
||||
// 1. If O is a WindowProxy object, or implements Location, then return ThrowCompletion(a new TypeError).
|
||||
if (is<HTML::WindowProxy>(object) || is<HTML::Location>(object))
|
||||
return s_main_thread_vm->throw_completion<JS::TypeError>("Cannot add private elements to window or location object"sv);
|
||||
return main_thread_vm_ptr()->throw_completion<JS::TypeError>("Cannot add private elements to window or location object"sv);
|
||||
|
||||
// 2. Return NormalCompletion(unused).
|
||||
return {};
|
||||
};
|
||||
|
||||
// 8.1.6.2 HostEnsureCanCompileStrings(realm, parameterStrings, bodyString, codeString, compilationType, parameterArgs, bodyArg), https://html.spec.whatwg.org/multipage/webappapis.html#hostensurecancompilestrings(realm,-parameterstrings,-bodystring,-codestring,-compilationtype,-parameterargs,-bodyarg)
|
||||
s_main_thread_vm->host_ensure_can_compile_strings = [](JS::Realm& realm, ReadonlySpan<String> parameter_strings, StringView body_string, StringView code_string, JS::CompilationType compilation_type, ReadonlySpan<JS::Value> parameter_args, JS::Value body_arg) -> JS::ThrowCompletionOr<void> {
|
||||
main_thread_vm_ptr()->host_ensure_can_compile_strings = [](JS::Realm& realm, ReadonlySpan<String> parameter_strings, StringView body_string, StringView code_string, JS::CompilationType compilation_type, ReadonlySpan<JS::Value> parameter_args, JS::Value body_arg) -> JS::ThrowCompletionOr<void> {
|
||||
// 1. Perform ? EnsureCSPDoesNotBlockStringCompilation(realm, parameterStrings, bodyString, codeString, compilationType, parameterArgs, bodyArg). [CSP]
|
||||
return ContentSecurityPolicy::ensure_csp_does_not_block_string_compilation(realm, parameter_strings, body_string, code_string, compilation_type, parameter_args, body_arg);
|
||||
};
|
||||
|
||||
// 8.1.6.3 HostGetCodeForEval(argument), https://html.spec.whatwg.org/multipage/webappapis.html#hostgetcodeforeval(argument)
|
||||
s_main_thread_vm->host_get_code_for_eval = [](JS::Object const& argument) -> GC::Ptr<JS::PrimitiveString> {
|
||||
main_thread_vm_ptr()->host_get_code_for_eval = [](JS::Object const& argument) -> GC::Ptr<JS::PrimitiveString> {
|
||||
// 1. If argument is a TrustedScript object, then return argument's data.
|
||||
if (auto const* trusted_script = as_if<TrustedTypes::TrustedScript>(argument); trusted_script)
|
||||
return JS::PrimitiveString::create(argument.vm(), trusted_script->to_string());
|
||||
|
|
@ -133,8 +138,8 @@ void initialize_main_thread_vm(AgentType type)
|
|||
};
|
||||
|
||||
// 8.1.5.3 HostPromiseRejectionTracker(promise, operation), https://html.spec.whatwg.org/multipage/webappapis.html#the-hostpromiserejectiontracker-implementation
|
||||
s_main_thread_vm->host_promise_rejection_tracker = [](JS::Promise& promise, JS::Promise::RejectionOperation operation) {
|
||||
auto& vm = *s_main_thread_vm;
|
||||
main_thread_vm_ptr()->host_promise_rejection_tracker = [](JS::Promise& promise, JS::Promise::RejectionOperation operation) {
|
||||
auto& vm = *main_thread_vm_ptr();
|
||||
|
||||
// 1. Let script be the running script.
|
||||
// The running script is the script in the [[HostDefined]] field in the ScriptOrModule component of the running JavaScript execution context.
|
||||
|
|
@ -188,7 +193,7 @@ void initialize_main_thread_vm(AgentType type)
|
|||
|
||||
// 4. Queue a global task on the DOM manipulation task source given global to fire an event named rejectionhandled at global, using PromiseRejectionEvent,
|
||||
// with the promise attribute initialized to promise, and the reason attribute initialized to the value of promise's [[PromiseResult]] internal slot.
|
||||
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, global, GC::create_function(s_main_thread_vm->heap(), [&global, &promise] {
|
||||
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, global, GC::create_function(main_thread_vm_ptr()->heap(), [&global, &promise] {
|
||||
// FIXME: This currently assumes that global is a WindowObject.
|
||||
auto& window = as<HTML::Window>(global);
|
||||
|
||||
|
|
@ -208,7 +213,7 @@ void initialize_main_thread_vm(AgentType type)
|
|||
};
|
||||
|
||||
// 8.1.5.4.1 HostCallJobCallback(callback, V, argumentsList), https://html.spec.whatwg.org/multipage/webappapis.html#hostcalljobcallback
|
||||
s_main_thread_vm->host_call_job_callback = [](JS::JobCallback& callback, JS::Value this_value, ReadonlySpan<JS::Value> arguments_list) {
|
||||
main_thread_vm_ptr()->host_call_job_callback = [](JS::JobCallback& callback, JS::Value this_value, ReadonlySpan<JS::Value> arguments_list) {
|
||||
auto& callback_host_defined = as<WebEngineCustomJobCallbackData>(*callback.custom_data());
|
||||
|
||||
// 1. Let incumbent settings be callback.[[HostDefined]].[[IncumbentSettings]].
|
||||
|
|
@ -222,15 +227,15 @@ void initialize_main_thread_vm(AgentType type)
|
|||
|
||||
// 4. If script execution context is not null, then push script execution context onto the JavaScript execution context stack.
|
||||
if (script_execution_context)
|
||||
s_main_thread_vm->push_execution_context(*script_execution_context);
|
||||
main_thread_vm_ptr()->push_execution_context(*script_execution_context);
|
||||
|
||||
// 5. Let result be Call(callback.[[Callback]], V, argumentsList).
|
||||
auto result = JS::call(*s_main_thread_vm, callback.callback(), this_value, arguments_list);
|
||||
auto result = JS::call(*main_thread_vm_ptr(), callback.callback(), this_value, arguments_list);
|
||||
|
||||
// 6. If script execution context is not null, then pop script execution context from the JavaScript execution context stack.
|
||||
if (script_execution_context) {
|
||||
VERIFY(&s_main_thread_vm->running_execution_context() == script_execution_context);
|
||||
s_main_thread_vm->pop_execution_context();
|
||||
VERIFY(&main_thread_vm_ptr()->running_execution_context() == script_execution_context);
|
||||
main_thread_vm_ptr()->pop_execution_context();
|
||||
}
|
||||
|
||||
// 7. Clean up after running a callback with incumbent settings.
|
||||
|
|
@ -241,12 +246,12 @@ void initialize_main_thread_vm(AgentType type)
|
|||
};
|
||||
|
||||
// 8.1.5.4.2 HostEnqueueFinalizationRegistryCleanupJob(finalizationRegistry), https://html.spec.whatwg.org/multipage/webappapis.html#hostenqueuefinalizationregistrycleanupjob
|
||||
s_main_thread_vm->host_enqueue_finalization_registry_cleanup_job = [](JS::FinalizationRegistry& finalization_registry) {
|
||||
main_thread_vm_ptr()->host_enqueue_finalization_registry_cleanup_job = [](JS::FinalizationRegistry& finalization_registry) {
|
||||
// 1. Let global be finalizationRegistry.[[Realm]]'s global object.
|
||||
auto& global = finalization_registry.realm().global_object();
|
||||
|
||||
// 2. Queue a global task on the JavaScript engine task source given global to perform the following steps:
|
||||
HTML::queue_global_task(HTML::Task::Source::JavaScriptEngine, global, GC::create_function(s_main_thread_vm->heap(), [&finalization_registry] {
|
||||
HTML::queue_global_task(HTML::Task::Source::JavaScriptEngine, global, GC::create_function(main_thread_vm_ptr()->heap(), [&finalization_registry] {
|
||||
// 1. Let entry be finalizationRegistry.[[CleanupCallback]].[[Callback]].[[Realm]]'s environment settings object.
|
||||
// AD-HOC: The spec assumes [[Callback]] has a [[Realm]] internal slot, but Proxy and BoundFunction
|
||||
// exotic objects do not. Use GetFunctionRealm to unwrap these exotic objects, falling back to
|
||||
|
|
@ -274,8 +279,8 @@ void initialize_main_thread_vm(AgentType type)
|
|||
};
|
||||
|
||||
// 8.1.5.4.3 HostEnqueuePromiseJob(job, realm), https://html.spec.whatwg.org/multipage/webappapis.html#hostenqueuepromisejob
|
||||
s_main_thread_vm->host_enqueue_promise_job = [](GC::Ref<GC::Function<JS::ThrowCompletionOr<JS::Value>()>> job, JS::Realm* realm) {
|
||||
auto& vm = *s_main_thread_vm;
|
||||
main_thread_vm_ptr()->host_enqueue_promise_job = [](GC::Ref<GC::Function<JS::ThrowCompletionOr<JS::Value>()>> job, JS::Realm* realm) {
|
||||
auto& vm = *main_thread_vm_ptr();
|
||||
|
||||
// IMPLEMENTATION DEFINED: The JS spec says we must take implementation defined steps to make the currently active script or module at the time of HostEnqueuePromiseJob being invoked
|
||||
// also be the active script or module of the job at the time of its invocation.
|
||||
|
|
@ -341,12 +346,12 @@ void initialize_main_thread_vm(AgentType type)
|
|||
}));
|
||||
};
|
||||
|
||||
s_main_thread_vm->host_promise_job_queue_is_empty = []() -> bool {
|
||||
main_thread_vm_ptr()->host_promise_job_queue_is_empty = []() -> bool {
|
||||
return HTML::main_thread_event_loop().microtask_queue_empty();
|
||||
};
|
||||
|
||||
// 8.1.5.4.4 HostMakeJobCallback(callable), https://html.spec.whatwg.org/multipage/webappapis.html#hostmakejobcallback
|
||||
s_main_thread_vm->host_make_job_callback = [](JS::FunctionObject& callable) -> GC::Ref<JS::JobCallback> {
|
||||
main_thread_vm_ptr()->host_make_job_callback = [](JS::FunctionObject& callable) -> GC::Ref<JS::JobCallback> {
|
||||
// 1. Let incumbent settings be the incumbent settings object.
|
||||
auto& incumbent_settings = HTML::incumbent_settings_object();
|
||||
|
||||
|
|
@ -375,11 +380,11 @@ void initialize_main_thread_vm(AgentType type)
|
|||
|
||||
// 5. Return the JobCallback Record { [[Callback]]: callable, [[HostDefined]]: { [[IncumbentSettings]]: incumbent settings, [[ActiveScriptContext]]: script execution context } }.
|
||||
auto host_defined = adopt_own(*new WebEngineCustomJobCallbackData(incumbent_settings, move(script_execution_context)));
|
||||
return JS::JobCallback::create(*s_main_thread_vm, callable, move(host_defined));
|
||||
return JS::JobCallback::create(*main_thread_vm_ptr(), callable, move(host_defined));
|
||||
};
|
||||
|
||||
// 8.1.6.7.1 HostGetImportMetaProperties(moduleRecord), https://html.spec.whatwg.org/multipage/webappapis.html#hostgetimportmetaproperties
|
||||
s_main_thread_vm->host_get_import_meta_properties = [](JS::SourceTextModule& module_record) {
|
||||
main_thread_vm_ptr()->host_get_import_meta_properties = [](JS::SourceTextModule& module_record) {
|
||||
auto& realm = module_record.realm();
|
||||
auto& vm = realm.vm();
|
||||
|
||||
|
|
@ -420,14 +425,14 @@ void initialize_main_thread_vm(AgentType type)
|
|||
};
|
||||
|
||||
// 8.1.6.7.2 HostGetSupportedImportAttributes(), https://html.spec.whatwg.org/multipage/webappapis.html#hostgetsupportedimportassertions
|
||||
s_main_thread_vm->host_get_supported_import_attributes = []() -> Vector<Utf16String> {
|
||||
main_thread_vm_ptr()->host_get_supported_import_attributes = []() -> Vector<Utf16String> {
|
||||
// 1. Return « "type" ».
|
||||
return { "type"_utf16 };
|
||||
};
|
||||
|
||||
// 8.1.6.7.3 HostLoadImportedModule(referrer, moduleRequest, loadState, payload), https://html.spec.whatwg.org/multipage/webappapis.html#hostloadimportedmodule
|
||||
s_main_thread_vm->host_load_imported_module = [](JS::ImportedModuleReferrer referrer, JS::ModuleRequest const& module_request, GC::Ptr<JS::GraphLoadingState::HostDefined> load_state, JS::ImportedModulePayload payload) -> void {
|
||||
auto& vm = *s_main_thread_vm;
|
||||
main_thread_vm_ptr()->host_load_imported_module = [](JS::ImportedModuleReferrer referrer, JS::ModuleRequest const& module_request, GC::Ptr<JS::GraphLoadingState::HostDefined> load_state, JS::ImportedModulePayload payload) -> void {
|
||||
auto& vm = *main_thread_vm_ptr();
|
||||
|
||||
// 1. Let settingsObject be the current settings object.
|
||||
GC::Ref<HTML::EnvironmentSettingsObject> settings_object = HTML::current_settings_object();
|
||||
|
|
@ -649,20 +654,20 @@ void initialize_main_thread_vm(AgentType type)
|
|||
HTML::fetch_single_imported_module_script(settings_object->realm(), url.release_value(), *fetch_client, destination, fetch_options, settings_object, fetch_referrer, module_request, perform_fetch, on_single_fetch_complete);
|
||||
};
|
||||
|
||||
s_main_thread_vm->host_unrecognized_date_string = [](StringView date) {
|
||||
main_thread_vm_ptr()->host_unrecognized_date_string = [](StringView date) {
|
||||
dbgln("Unable to parse date string: \"{}\"", date);
|
||||
};
|
||||
|
||||
s_main_thread_vm->host_resize_array_buffer = [default_host_resize_array_buffer = move(s_main_thread_vm->host_resize_array_buffer)](JS::ArrayBuffer& buffer, size_t new_byte_length) -> JS::ThrowCompletionOr<JS::HandledByHost> {
|
||||
auto wasm_handled = TRY(WebAssembly::Detail::host_resize_array_buffer(*s_main_thread_vm, buffer, new_byte_length));
|
||||
main_thread_vm_ptr()->host_resize_array_buffer = [default_host_resize_array_buffer = move(main_thread_vm_ptr()->host_resize_array_buffer)](JS::ArrayBuffer& buffer, size_t new_byte_length) -> JS::ThrowCompletionOr<JS::HandledByHost> {
|
||||
auto wasm_handled = TRY(WebAssembly::Detail::host_resize_array_buffer(*main_thread_vm_ptr(), buffer, new_byte_length));
|
||||
if (wasm_handled == JS::HandledByHost::Handled)
|
||||
return JS::HandledByHost::Handled;
|
||||
|
||||
return default_host_resize_array_buffer(buffer, new_byte_length);
|
||||
};
|
||||
|
||||
s_main_thread_vm->host_grow_shared_array_buffer = [default_host_grow_shared_array_buffer = move(s_main_thread_vm->host_grow_shared_array_buffer)](JS::ArrayBuffer& buffer, size_t new_byte_length) -> JS::ThrowCompletionOr<JS::HandledByHost> {
|
||||
auto wasm_handled = TRY(WebAssembly::Detail::host_grow_shared_array_buffer(*s_main_thread_vm, buffer, new_byte_length));
|
||||
main_thread_vm_ptr()->host_grow_shared_array_buffer = [default_host_grow_shared_array_buffer = move(main_thread_vm_ptr()->host_grow_shared_array_buffer)](JS::ArrayBuffer& buffer, size_t new_byte_length) -> JS::ThrowCompletionOr<JS::HandledByHost> {
|
||||
auto wasm_handled = TRY(WebAssembly::Detail::host_grow_shared_array_buffer(*main_thread_vm_ptr(), buffer, new_byte_length));
|
||||
if (wasm_handled == JS::HandledByHost::Handled)
|
||||
return JS::HandledByHost::Handled;
|
||||
|
||||
|
|
@ -672,8 +677,8 @@ void initialize_main_thread_vm(AgentType type)
|
|||
|
||||
JS::VM& main_thread_vm()
|
||||
{
|
||||
VERIFY(s_main_thread_vm);
|
||||
return *s_main_thread_vm;
|
||||
VERIFY(main_thread_vm_ptr());
|
||||
return *main_thread_vm_ptr();
|
||||
}
|
||||
|
||||
// https://dom.spec.whatwg.org/#queue-a-mutation-observer-compound-microtask
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include "CSSNestedDeclarations.h"
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibWeb/Bindings/CSSNestedDeclarations.h>
|
||||
#include <LibWeb/Bindings/Intrinsics.h>
|
||||
#include <LibWeb/CSS/CSSScopeRule.h>
|
||||
|
|
@ -48,7 +49,7 @@ void CSSNestedDeclarations::visit_edges(Cell::Visitor& visitor)
|
|||
|
||||
static SelectorList absolutize_parent_selectors(CSSNestedDeclarations const& nested_declarations)
|
||||
{
|
||||
static SelectorList s_where_scope_selector_list {
|
||||
static NeverDestroyed<SelectorList> where_scope_selector_list { SelectorList {
|
||||
Selector::create({
|
||||
Selector::CompoundSelector {
|
||||
.combinator = Selector::Combinator::None,
|
||||
|
|
@ -77,7 +78,7 @@ static SelectorList absolutize_parent_selectors(CSSNestedDeclarations const& nes
|
|||
},
|
||||
},
|
||||
}),
|
||||
};
|
||||
} };
|
||||
|
||||
for (auto const* parent_rule = nested_declarations.parent_rule(); parent_rule; parent_rule = parent_rule->parent_rule()) {
|
||||
if (auto const* parent_style_rule = as_if<CSSStyleRule>(parent_rule))
|
||||
|
|
@ -86,7 +87,7 @@ static SelectorList absolutize_parent_selectors(CSSNestedDeclarations const& nes
|
|||
// https://drafts.csswg.org/css-cascade-6/#scoped-declarations
|
||||
// Declarations may be used directly with the body of a @scope rule. Contiguous runs of declarations are
|
||||
// wrapped in nested declarations rules, which match the scoping root with zero specificity.
|
||||
return s_where_scope_selector_list;
|
||||
return *where_scope_selector_list;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ namespace Web::CSS {
|
|||
// https://drafts.csswg.org/css-counter-styles-3/#decimal
|
||||
NonnullRefPtr<CounterStyle const> CounterStyle::decimal()
|
||||
{
|
||||
static auto decimal_counter_style = CounterStyle::create(
|
||||
static auto const& decimal_counter_style = CounterStyle::create(
|
||||
"decimal"_fly_string,
|
||||
GenericCounterStyleAlgorithm { CounterStyleSystem::Numeric, { "0"_fly_string, "1"_fly_string, "2"_fly_string, "3"_fly_string, "4"_fly_string, "5"_fly_string, "6"_fly_string, "7"_fly_string, "8"_fly_string, "9"_fly_string } },
|
||||
CounterStyleNegativeSign { .prefix = "-"_fly_string, .suffix = ""_fly_string },
|
||||
|
|
@ -21,7 +21,8 @@ NonnullRefPtr<CounterStyle const> CounterStyle::decimal()
|
|||
". "_fly_string,
|
||||
{ { NumericLimits<i32>::min(), NumericLimits<i32>::max() } },
|
||||
{},
|
||||
CounterStylePad { .minimum_length = 0, .symbol = ""_fly_string });
|
||||
CounterStylePad { .minimum_length = 0, .symbol = ""_fly_string })
|
||||
.leak_ref();
|
||||
|
||||
return decimal_counter_style;
|
||||
}
|
||||
|
|
@ -29,7 +30,7 @@ NonnullRefPtr<CounterStyle const> CounterStyle::decimal()
|
|||
// https://drafts.csswg.org/css-counter-styles-3/#disc
|
||||
NonnullRefPtr<CounterStyle const> CounterStyle::disc()
|
||||
{
|
||||
static auto disc_counter_style = CounterStyle::create(
|
||||
static auto const& disc_counter_style = CounterStyle::create(
|
||||
"disc"_fly_string,
|
||||
GenericCounterStyleAlgorithm { CounterStyleSystem::Cyclic, { "•"_fly_string } },
|
||||
CounterStyleNegativeSign { .prefix = ""_fly_string, .suffix = " "_fly_string },
|
||||
|
|
@ -37,7 +38,8 @@ NonnullRefPtr<CounterStyle const> CounterStyle::disc()
|
|||
" "_fly_string,
|
||||
{ { NumericLimits<i32>::min(), NumericLimits<i32>::max() } },
|
||||
"decimal"_fly_string,
|
||||
CounterStylePad { .minimum_length = 0, .symbol = ""_fly_string });
|
||||
CounterStylePad { .minimum_length = 0, .symbol = ""_fly_string })
|
||||
.leak_ref();
|
||||
|
||||
return disc_counter_style;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -684,7 +684,7 @@ NonnullRefPtr<Gfx::FontCascadeList const> FontComputer::compute_font_for_style_v
|
|||
Gfx::Font const& FontComputer::initial_font() const
|
||||
{
|
||||
// FIXME: This is not correct.
|
||||
static auto font = ComputedProperties::font_fallback(false, false, 12);
|
||||
static auto const& font = ComputedProperties::font_fallback(false, false, 12).leak_ref();
|
||||
return font;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -105,10 +105,10 @@ static RefPtr<StyleValue const> interpolate_scale(DOM::Element& element, Calcula
|
|||
if (a_from.to_keyword() == Keyword::None && a_to.to_keyword() == Keyword::None)
|
||||
return a_from;
|
||||
|
||||
static auto one = TransformationStyleValue::create(PropertyID::Scale, TransformFunction::Scale, { NumberStyleValue::create(1), NumberStyleValue::create(1) });
|
||||
static auto const& one = TransformationStyleValue::create(PropertyID::Scale, TransformFunction::Scale, { NumberStyleValue::create(1), NumberStyleValue::create(1) }).leak_ref();
|
||||
|
||||
auto const& from = a_from.to_keyword() == Keyword::None ? *one : a_from;
|
||||
auto const& to = a_to.to_keyword() == Keyword::None ? *one : a_to;
|
||||
auto const& from = a_from.to_keyword() == Keyword::None ? one : a_from;
|
||||
auto const& to = a_to.to_keyword() == Keyword::None ? one : a_to;
|
||||
|
||||
auto const& from_transform = from.as_transformation();
|
||||
auto const& to_transform = to.as_transformation();
|
||||
|
|
@ -122,9 +122,9 @@ static RefPtr<StyleValue const> interpolate_scale(DOM::Element& element, Calcula
|
|||
RefPtr<StyleValue const> interpolated_z;
|
||||
|
||||
if (from_transform.values().size() == 3 || to_transform.values().size() == 3) {
|
||||
static auto one_value = NumberStyleValue::create(1);
|
||||
auto from = from_transform.values().size() == 3 ? from_transform.values()[2] : one_value;
|
||||
auto to = to_transform.values().size() == 3 ? to_transform.values()[2] : one_value;
|
||||
static auto const& one_value = NumberStyleValue::create(1).leak_ref();
|
||||
auto from = from_transform.values().size() == 3 ? from_transform.values()[2] : ValueComparingNonnullRefPtr<StyleValue const> { one_value };
|
||||
auto to = to_transform.values().size() == 3 ? to_transform.values()[2] : ValueComparingNonnullRefPtr<StyleValue const> { one_value };
|
||||
interpolated_z = interpolate_value(element, calculation_context, from, to, delta, allow_discrete);
|
||||
if (!interpolated_z)
|
||||
return {};
|
||||
|
|
@ -363,11 +363,11 @@ static RefPtr<StyleValue const> interpolate_translate(DOM::Element& element, Cal
|
|||
if (a_from.to_keyword() == Keyword::None && a_to.to_keyword() == Keyword::None)
|
||||
return a_from;
|
||||
|
||||
static auto zero_px = LengthStyleValue::create(Length::make_px(0));
|
||||
static auto zero = TransformationStyleValue::create(PropertyID::Translate, TransformFunction::Translate, { zero_px, zero_px });
|
||||
static auto const& zero_px = LengthStyleValue::create(Length::make_px(0)).leak_ref();
|
||||
static auto const& zero = TransformationStyleValue::create(PropertyID::Translate, TransformFunction::Translate, { zero_px, zero_px }).leak_ref();
|
||||
|
||||
auto const& from = a_from.to_keyword() == Keyword::None ? *zero : a_from;
|
||||
auto const& to = a_to.to_keyword() == Keyword::None ? *zero : a_to;
|
||||
auto const& from = a_from.to_keyword() == Keyword::None ? zero : a_from;
|
||||
auto const& to = a_to.to_keyword() == Keyword::None ? zero : a_to;
|
||||
|
||||
auto const& from_transform = from.as_transformation();
|
||||
auto const& to_transform = to.as_transformation();
|
||||
|
|
@ -426,11 +426,11 @@ static RefPtr<StyleValue const> interpolate_rotate(DOM::Element& element, Calcul
|
|||
if (a_from.to_keyword() == Keyword::None && a_to.to_keyword() == Keyword::None)
|
||||
return a_from;
|
||||
|
||||
static auto zero_degrees_value = AngleStyleValue::create(Angle::make_degrees(0));
|
||||
static auto zero = TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::Rotate, { zero_degrees_value });
|
||||
static auto const& zero_degrees_value = AngleStyleValue::create(Angle::make_degrees(0)).leak_ref();
|
||||
static auto const& zero = TransformationStyleValue::create(PropertyID::Rotate, TransformFunction::Rotate, { zero_degrees_value }).leak_ref();
|
||||
|
||||
auto const& from = a_from.to_keyword() == Keyword::None ? *zero : a_from;
|
||||
auto const& to = a_to.to_keyword() == Keyword::None ? *zero : a_to;
|
||||
auto const& from = a_from.to_keyword() == Keyword::None ? zero : a_from;
|
||||
auto const& to = a_to.to_keyword() == Keyword::None ? zero : a_to;
|
||||
|
||||
auto const& from_transform = from.as_transformation();
|
||||
auto const& to_transform = to.as_transformation();
|
||||
|
|
@ -674,9 +674,9 @@ ValueComparingRefPtr<StyleValue const> interpolate_property(DOM::Element& elemen
|
|||
}
|
||||
|
||||
if (property_id == PropertyID::FontStyle) {
|
||||
auto static oblique_0deg_value = FontStyleStyleValue::create(FontStyleKeyword::Oblique, AngleStyleValue::create(Angle::make_degrees(0)));
|
||||
auto from_value = from->as_font_style().font_style() == FontStyleKeyword::Normal ? oblique_0deg_value : from;
|
||||
auto to_value = to->as_font_style().font_style() == FontStyleKeyword::Normal ? oblique_0deg_value : to;
|
||||
static auto const& oblique_0deg_value = FontStyleStyleValue::create(FontStyleKeyword::Oblique, AngleStyleValue::create(Angle::make_degrees(0))).leak_ref();
|
||||
auto from_value = from->as_font_style().font_style() == FontStyleKeyword::Normal ? ValueComparingNonnullRefPtr<StyleValue const> { oblique_0deg_value } : from;
|
||||
auto to_value = to->as_font_style().font_style() == FontStyleKeyword::Normal ? ValueComparingNonnullRefPtr<StyleValue const> { oblique_0deg_value } : to;
|
||||
return interpolate_value(element, calculation_context, from_value, to_value, delta, allow_discrete);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,8 +49,8 @@ String serialize_parsing_error(ParsingError const& error)
|
|||
|
||||
ErrorReporter& ErrorReporter::the()
|
||||
{
|
||||
static ErrorReporter s_error_reporter {};
|
||||
return s_error_reporter;
|
||||
static ErrorReporter& error_reporter = *new ErrorReporter;
|
||||
return error_reporter;
|
||||
}
|
||||
|
||||
void ErrorReporter::report(ParsingError&& error)
|
||||
|
|
|
|||
|
|
@ -22,9 +22,9 @@ namespace Web {
|
|||
|
||||
GC::Ref<JS::Realm> internal_css_realm()
|
||||
{
|
||||
static GC::Root<JS::Realm> realm;
|
||||
static GC::Root<HTML::Window> window;
|
||||
static OwnPtr<JS::ExecutionContext> execution_context;
|
||||
static auto& realm = *new GC::Root<JS::Realm>;
|
||||
static auto& window = *new GC::Root<HTML::Window>;
|
||||
static auto& execution_context = *new OwnPtr<JS::ExecutionContext>;
|
||||
if (!realm) {
|
||||
execution_context = Bindings::create_a_new_javascript_realm(
|
||||
Bindings::main_thread_vm(),
|
||||
|
|
|
|||
|
|
@ -4637,7 +4637,7 @@ RefPtr<StyleValue const> Parser::parse_scroll_timeline_value(TokenStream<Compone
|
|||
auto transaction = tokens.begin_transaction();
|
||||
|
||||
do {
|
||||
static auto default_axis = property_initial_value(PropertyID::ScrollTimelineAxis)->as_value_list().values()[0];
|
||||
static auto const& default_axis = *new ValueComparingNonnullRefPtr<StyleValue const>(property_initial_value(PropertyID::ScrollTimelineAxis)->as_value_list().values()[0]);
|
||||
|
||||
tokens.discard_whitespace();
|
||||
|
||||
|
|
@ -5981,11 +5981,17 @@ RefPtr<StyleValue const> Parser::parse_view_timeline_value(TokenStream<Component
|
|||
VERIFY(name);
|
||||
names.append(name.release_nonnull());
|
||||
|
||||
static auto default_axis = property_initial_value(PropertyID::ViewTimelineAxis)->as_value_list().values()[0];
|
||||
static auto default_inset = property_initial_value(PropertyID::ViewTimelineInset)->as_value_list().values()[0];
|
||||
static auto const& default_axis = *new ValueComparingNonnullRefPtr<StyleValue const>(property_initial_value(PropertyID::ViewTimelineAxis)->as_value_list().values()[0]);
|
||||
static auto const& default_inset = *new ValueComparingNonnullRefPtr<StyleValue const>(property_initial_value(PropertyID::ViewTimelineInset)->as_value_list().values()[0]);
|
||||
|
||||
axes.append(axis ? axis.release_nonnull() : default_axis);
|
||||
insets.append(inset ? inset.release_nonnull() : default_inset);
|
||||
if (axis)
|
||||
axes.append(axis.release_nonnull());
|
||||
else
|
||||
axes.append(default_axis);
|
||||
if (inset)
|
||||
insets.append(inset.release_nonnull());
|
||||
else
|
||||
insets.append(default_inset);
|
||||
};
|
||||
|
||||
tokens.discard_whitespace();
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "Selector.h"
|
||||
#include <AK/GenericShorthands.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibWeb/CSS/CSSStyleRule.h>
|
||||
#include <LibWeb/CSS/Parser/ErrorReporter.h>
|
||||
#include <LibWeb/CSS/Serialize.h>
|
||||
|
|
@ -946,7 +947,7 @@ SelectorList adapt_nested_relative_selector_list(SelectorList const& selectors,
|
|||
SelectorList absolutize_selectors_relative_to(SelectorList const& selectors, GC::Ptr<CSSRule const> parent)
|
||||
{
|
||||
// NB: We use `:where(:scope)` to avoid adding specificity.
|
||||
static Selector::SimpleSelector const s_where_scope_selector {
|
||||
static NeverDestroyed<Selector::SimpleSelector> where_scope_selector { Selector::SimpleSelector {
|
||||
.type = Selector::SimpleSelector::Type::PseudoClass,
|
||||
.value = Selector::SimpleSelector::PseudoClassSelector {
|
||||
.type = PseudoClass::Where,
|
||||
|
|
@ -966,7 +967,7 @@ SelectorList absolutize_selectors_relative_to(SelectorList const& selectors, GC:
|
|||
}),
|
||||
},
|
||||
},
|
||||
};
|
||||
} };
|
||||
|
||||
// Replace all occurrences of `&` with the nearest ancestor style rule's selector list wrapped in `:is(...)`,
|
||||
// or if we have no such ancestor, with `:scope`.
|
||||
|
|
@ -994,7 +995,7 @@ SelectorList absolutize_selectors_relative_to(SelectorList const& selectors, GC:
|
|||
};
|
||||
}
|
||||
|
||||
return s_where_scope_selector;
|
||||
return *where_scope_selector;
|
||||
}();
|
||||
|
||||
SelectorList absolutized_selectors;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include <AK/Function.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/Math.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/NonnullRawPtr.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <LibGfx/Font/FontDatabase.h>
|
||||
|
|
@ -158,10 +159,10 @@ void StyleComputer::visit_edges(Visitor& visitor)
|
|||
|
||||
Optional<String> StyleComputer::user_agent_style_sheet_source(StringView name)
|
||||
{
|
||||
extern String default_stylesheet_source;
|
||||
extern String quirks_mode_stylesheet_source;
|
||||
extern String mathml_stylesheet_source;
|
||||
extern String svg_stylesheet_source;
|
||||
extern String const& default_stylesheet_source;
|
||||
extern String const& quirks_mode_stylesheet_source;
|
||||
extern String const& mathml_stylesheet_source;
|
||||
extern String const& svg_stylesheet_source;
|
||||
|
||||
if (name == "CSS/Default.css"sv)
|
||||
return default_stylesheet_source;
|
||||
|
|
@ -2197,9 +2198,9 @@ GC::Ptr<ComputedProperties> StyleComputer::compute_style_impl(DOM::AbstractEleme
|
|||
if (did_change_custom_properties.has_value()) {
|
||||
auto new_custom_property_data = abstract_element.custom_property_data();
|
||||
if (old_custom_property_data.ptr() != new_custom_property_data.ptr()) {
|
||||
static OrderedHashMap<FlyString, StyleProperty> const empty_own_values;
|
||||
auto const& old_own = old_custom_property_data ? old_custom_property_data->own_values() : empty_own_values;
|
||||
auto const& new_own = new_custom_property_data ? new_custom_property_data->own_values() : empty_own_values;
|
||||
static NeverDestroyed<OrderedHashMap<FlyString, StyleProperty>> empty_own_values;
|
||||
auto const& old_own = old_custom_property_data ? old_custom_property_data->own_values() : *empty_own_values;
|
||||
auto const& new_own = new_custom_property_data ? new_custom_property_data->own_values() : *empty_own_values;
|
||||
if (old_own != new_own)
|
||||
*did_change_custom_properties = true;
|
||||
}
|
||||
|
|
@ -2235,8 +2236,8 @@ RefPtr<StyleValue const> StyleComputer::recascade_font_size_if_needed(DOM::Abstr
|
|||
|
||||
// FIXME: This should be configurable.
|
||||
constexpr CSSPixels default_monospace_font_size_in_px = 13;
|
||||
static auto monospace_font_family_name = Platform::FontPlugin::the().generic_font_name(Platform::GenericFont::Monospace, 400, 0);
|
||||
static auto monospace_font = Gfx::FontDatabase::the().get(monospace_font_family_name, default_monospace_font_size_in_px * 0.75f, 400, Gfx::FontWidth::Normal, 0);
|
||||
static auto const& monospace_font_family_name = *new String(Platform::FontPlugin::the().generic_font_name(Platform::GenericFont::Monospace, 400, 0));
|
||||
static auto const& monospace_font = Gfx::FontDatabase::the().get(monospace_font_family_name, default_monospace_font_size_in_px * 0.75f, 400, Gfx::FontWidth::Normal, 0).release_nonnull().leak_ref();
|
||||
|
||||
// Reconstruct the line of ancestor elements we need to inherit style from, and then do the cascade again
|
||||
// but only for the font-size property.
|
||||
|
|
@ -2305,7 +2306,7 @@ RefPtr<StyleValue const> StyleComputer::recascade_font_size_if_needed(DOM::Abstr
|
|||
bool did_resolve_viewport_relative_length = false;
|
||||
Length::ResolutionContext resolution_context {
|
||||
.viewport_rect = viewport_rect(),
|
||||
.font_metrics = { current_size_in_px, monospace_font->with_size(current_size_in_px * 0.75f)->pixel_metrics(), inherited_line_height },
|
||||
.font_metrics = { current_size_in_px, monospace_font.with_size(current_size_in_px * 0.75f)->pixel_metrics(), inherited_line_height },
|
||||
.root_font_metrics = m_root_element_font_metrics,
|
||||
.font_metrics_depend_on_viewport_metrics = current_size_depends_on_viewport_metrics || inherited_font_metrics_depend_on_viewport_metrics,
|
||||
.root_font_metrics_depend_on_viewport_metrics = m_root_element_font_metrics_depend_on_viewport_metrics,
|
||||
|
|
@ -2864,7 +2865,7 @@ NonnullRefPtr<StyleValue const> StyleComputer::compute_corner_shape(NonnullRefPt
|
|||
case Keyword::Round:
|
||||
// The corner shape is a quarter of a convex ellipse. Equivalent to superellipse(1).
|
||||
// NB: We cache this value since 'round' is the initial value of the `corner-*-*-shape` properties
|
||||
static NonnullRefPtr<StyleValue const> const cached_round_value = SuperellipseStyleValue::create(NumberStyleValue::create(1));
|
||||
static auto const& cached_round_value = SuperellipseStyleValue::create(NumberStyleValue::create(1)).leak_ref();
|
||||
return cached_round_value;
|
||||
case Keyword::Squircle:
|
||||
// The corner shape is a quarter of a "squircle", a convex curve between round and square. Equivalent to superellipse(2).
|
||||
|
|
|
|||
|
|
@ -199,9 +199,9 @@ void StyleScope::build_rule_cache_if_needed() const
|
|||
|
||||
static CSSStyleSheet& default_stylesheet()
|
||||
{
|
||||
static GC::Root<CSSStyleSheet> sheet;
|
||||
static auto& sheet = *new GC::Root<CSSStyleSheet>;
|
||||
if (!sheet.cell()) {
|
||||
extern String default_stylesheet_source;
|
||||
extern String const& default_stylesheet_source;
|
||||
sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingParams(internal_css_realm(), Parser::IsUAStyleSheet::Yes), default_stylesheet_source));
|
||||
}
|
||||
return *sheet;
|
||||
|
|
@ -209,9 +209,9 @@ static CSSStyleSheet& default_stylesheet()
|
|||
|
||||
static CSSStyleSheet& quirks_mode_stylesheet()
|
||||
{
|
||||
static GC::Root<CSSStyleSheet> sheet;
|
||||
static auto& sheet = *new GC::Root<CSSStyleSheet>;
|
||||
if (!sheet.cell()) {
|
||||
extern String quirks_mode_stylesheet_source;
|
||||
extern String const& quirks_mode_stylesheet_source;
|
||||
sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingParams(internal_css_realm(), Parser::IsUAStyleSheet::Yes), quirks_mode_stylesheet_source));
|
||||
}
|
||||
return *sheet;
|
||||
|
|
@ -219,9 +219,9 @@ static CSSStyleSheet& quirks_mode_stylesheet()
|
|||
|
||||
static CSSStyleSheet& mathml_stylesheet()
|
||||
{
|
||||
static GC::Root<CSSStyleSheet> sheet;
|
||||
static auto& sheet = *new GC::Root<CSSStyleSheet>;
|
||||
if (!sheet.cell()) {
|
||||
extern String mathml_stylesheet_source;
|
||||
extern String const& mathml_stylesheet_source;
|
||||
sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingParams(internal_css_realm(), Parser::IsUAStyleSheet::Yes), mathml_stylesheet_source));
|
||||
}
|
||||
return *sheet;
|
||||
|
|
@ -229,9 +229,9 @@ static CSSStyleSheet& mathml_stylesheet()
|
|||
|
||||
static CSSStyleSheet& svg_stylesheet()
|
||||
{
|
||||
static GC::Root<CSSStyleSheet> sheet;
|
||||
static auto& sheet = *new GC::Root<CSSStyleSheet>;
|
||||
if (!sheet.cell()) {
|
||||
extern String svg_stylesheet_source;
|
||||
extern String const& svg_stylesheet_source;
|
||||
sheet = GC::make_root(parse_css_stylesheet(CSS::Parser::ParsingParams(internal_css_realm(), Parser::IsUAStyleSheet::Yes), svg_stylesheet_source));
|
||||
}
|
||||
return *sheet;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ class EmptyOptionalStyleValue final : public StyleValueWithDefaultOperators<Empt
|
|||
public:
|
||||
static ValueComparingNonnullRefPtr<EmptyOptionalStyleValue> create()
|
||||
{
|
||||
auto static const instance = adopt_ref(*new (nothrow) EmptyOptionalStyleValue());
|
||||
static auto& instance = adopt_ref(*new (nothrow) EmptyOptionalStyleValue()).leak_ref();
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ class GuaranteedInvalidStyleValue final : public StyleValueWithDefaultOperators<
|
|||
public:
|
||||
static ValueComparingNonnullRefPtr<GuaranteedInvalidStyleValue> create()
|
||||
{
|
||||
static ValueComparingNonnullRefPtr<GuaranteedInvalidStyleValue> instance = adopt_ref(*new (nothrow) GuaranteedInvalidStyleValue());
|
||||
static auto& instance = adopt_ref(*new (nothrow) GuaranteedInvalidStyleValue()).leak_ref();
|
||||
return instance;
|
||||
}
|
||||
virtual ~GuaranteedInvalidStyleValue() override = default;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/AnyOf.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibGfx/DecodedImageFrame.h>
|
||||
#include <LibWeb/CSS/CSSStyleSheet.h>
|
||||
#include <LibWeb/CSS/ComputedValues.h>
|
||||
|
|
@ -25,7 +26,11 @@
|
|||
|
||||
namespace Web::CSS {
|
||||
|
||||
static HashTable<ImageStyleValue const*> s_active_animation_timers;
|
||||
static HashTable<ImageStyleValue const*>& active_animation_timers()
|
||||
{
|
||||
static NeverDestroyed<HashTable<ImageStyleValue const*>> timers;
|
||||
return *timers;
|
||||
}
|
||||
|
||||
ValueComparingNonnullRefPtr<ImageStyleValue const> ImageStyleValue::create(URL const& url)
|
||||
{
|
||||
|
|
@ -48,7 +53,7 @@ ImageStyleValue::~ImageStyleValue() = default;
|
|||
u64 ImageStyleValue::active_animation_timer_count(DOM::Document const& document)
|
||||
{
|
||||
u64 count = 0;
|
||||
for (auto const* image_style_value : s_active_animation_timers) {
|
||||
for (auto const* image_style_value : active_animation_timers()) {
|
||||
if (any_of(image_style_value->m_clients, [&](auto const* client) {
|
||||
return client->document() == &document;
|
||||
}))
|
||||
|
|
@ -125,14 +130,14 @@ void ImageStyleValue::start_animation_timer_if_needed(DOM::Document& document) c
|
|||
|
||||
m_timer->set_interval(current_frame_duration());
|
||||
m_timer->start();
|
||||
s_active_animation_timers.set(this);
|
||||
active_animation_timers().set(this);
|
||||
}
|
||||
|
||||
void ImageStyleValue::stop_animation_timer() const
|
||||
{
|
||||
if (m_timer && m_timer->is_active()) {
|
||||
m_timer->stop();
|
||||
s_active_animation_timers.remove(this);
|
||||
active_animation_timers().remove(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -20,23 +20,23 @@ public:
|
|||
{
|
||||
switch (keyword) {
|
||||
case Keyword::Inherit: {
|
||||
static ValueComparingNonnullRefPtr<KeywordStyleValue const> const inherit_instance = adopt_ref(*new (nothrow) KeywordStyleValue(Keyword::Inherit));
|
||||
static auto const& inherit_instance = adopt_ref(*new (nothrow) KeywordStyleValue(Keyword::Inherit)).leak_ref();
|
||||
return inherit_instance;
|
||||
}
|
||||
case Keyword::Initial: {
|
||||
static ValueComparingNonnullRefPtr<KeywordStyleValue const> const initial_instance = adopt_ref(*new (nothrow) KeywordStyleValue(Keyword::Initial));
|
||||
static auto const& initial_instance = adopt_ref(*new (nothrow) KeywordStyleValue(Keyword::Initial)).leak_ref();
|
||||
return initial_instance;
|
||||
}
|
||||
case Keyword::Revert: {
|
||||
static ValueComparingNonnullRefPtr<KeywordStyleValue const> const revert_instance = adopt_ref(*new (nothrow) KeywordStyleValue(Keyword::Revert));
|
||||
static auto const& revert_instance = adopt_ref(*new (nothrow) KeywordStyleValue(Keyword::Revert)).leak_ref();
|
||||
return revert_instance;
|
||||
}
|
||||
case Keyword::RevertLayer: {
|
||||
static ValueComparingNonnullRefPtr<KeywordStyleValue const> const revert_layer_instance = adopt_ref(*new (nothrow) KeywordStyleValue(Keyword::RevertLayer));
|
||||
static auto const& revert_layer_instance = adopt_ref(*new (nothrow) KeywordStyleValue(Keyword::RevertLayer)).leak_ref();
|
||||
return revert_layer_instance;
|
||||
}
|
||||
case Keyword::Unset: {
|
||||
static ValueComparingNonnullRefPtr<KeywordStyleValue const> const unset_instance = adopt_ref(*new (nothrow) KeywordStyleValue(Keyword::Unset));
|
||||
static auto const& unset_instance = adopt_ref(*new (nothrow) KeywordStyleValue(Keyword::Unset)).leak_ref();
|
||||
return unset_instance;
|
||||
}
|
||||
default:
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@ ValueComparingNonnullRefPtr<LengthStyleValue const> LengthStyleValue::create(Len
|
|||
{
|
||||
if (length.is_px()) {
|
||||
if (length.raw_value() == 0) {
|
||||
static auto value = adopt_ref(*new (nothrow) LengthStyleValue(CSS::Length::make_px(0)));
|
||||
static auto const& value = adopt_ref(*new (nothrow) LengthStyleValue(CSS::Length::make_px(0))).leak_ref();
|
||||
return value;
|
||||
}
|
||||
if (length.raw_value() == 1) {
|
||||
static auto value = adopt_ref(*new (nothrow) LengthStyleValue(CSS::Length::make_px(1)));
|
||||
static auto const& value = adopt_ref(*new (nothrow) LengthStyleValue(CSS::Length::make_px(1))).leak_ref();
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/Debug.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <LibWeb/CSS/Parser/Tokenizer.h>
|
||||
#include <LibWeb/CSS/SyntaxHighlighter/SyntaxHighlighter.h>
|
||||
|
||||
|
|
@ -156,14 +157,14 @@ void SyntaxHighlighter::rehighlight(Palette const& palette)
|
|||
|
||||
Vector<Syntax::Highlighter::MatchingTokenPair> SyntaxHighlighter::matching_token_pairs_impl() const
|
||||
{
|
||||
static Vector<Syntax::Highlighter::MatchingTokenPair> pairs;
|
||||
if (pairs.is_empty()) {
|
||||
pairs.append({ static_cast<u64>(CSS::Parser::Token::Type::OpenCurly), static_cast<u64>(CSS::Parser::Token::Type::CloseCurly) });
|
||||
pairs.append({ static_cast<u64>(CSS::Parser::Token::Type::OpenParen), static_cast<u64>(CSS::Parser::Token::Type::CloseParen) });
|
||||
pairs.append({ static_cast<u64>(CSS::Parser::Token::Type::OpenSquare), static_cast<u64>(CSS::Parser::Token::Type::CloseSquare) });
|
||||
pairs.append({ static_cast<u64>(CSS::Parser::Token::Type::CDO), static_cast<u64>(CSS::Parser::Token::Type::CDC) });
|
||||
static NeverDestroyed<Vector<Syntax::Highlighter::MatchingTokenPair>> pairs;
|
||||
if (pairs->is_empty()) {
|
||||
pairs->append({ static_cast<u64>(CSS::Parser::Token::Type::OpenCurly), static_cast<u64>(CSS::Parser::Token::Type::CloseCurly) });
|
||||
pairs->append({ static_cast<u64>(CSS::Parser::Token::Type::OpenParen), static_cast<u64>(CSS::Parser::Token::Type::CloseParen) });
|
||||
pairs->append({ static_cast<u64>(CSS::Parser::Token::Type::OpenSquare), static_cast<u64>(CSS::Parser::Token::Type::CloseSquare) });
|
||||
pairs->append({ static_cast<u64>(CSS::Parser::Token::Type::CDO), static_cast<u64>(CSS::Parser::Token::Type::CDC) });
|
||||
}
|
||||
return pairs;
|
||||
return *pairs;
|
||||
}
|
||||
|
||||
bool SyntaxHighlighter::token_types_equal(u64 token0, u64 token1) const
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
#include <AK/Base64.h>
|
||||
#include <AK/FlyString.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibCrypto/Hash/SHA2.h>
|
||||
#include <LibWeb/ContentSecurityPolicy/Directives/DirectiveOperations.h>
|
||||
|
|
@ -32,55 +33,59 @@ namespace Web::ContentSecurityPolicy::Directives {
|
|||
// Will return an ordered set of the fallback directives for a specific directive.
|
||||
// The returned ordered set is sorted from most relevant to least relevant and it includes the effective directive
|
||||
// itself.
|
||||
static HashMap<StringView, Vector<StringView>> fetch_directive_fallback_list {
|
||||
// "script-src-elem"
|
||||
// 1. Return << "script-src-elem", "script-src", "default-src" >>.
|
||||
{ "script-src-elem"sv, { "script-src-elem"sv, "script-src"sv, "default-src"sv } },
|
||||
static auto const& fetch_directive_fallback_list()
|
||||
{
|
||||
static NeverDestroyed<HashMap<StringView, Vector<StringView>>> list { HashMap<StringView, Vector<StringView>> {
|
||||
// "script-src-elem"
|
||||
// 1. Return << "script-src-elem", "script-src", "default-src" >>.
|
||||
{ "script-src-elem"sv, { "script-src-elem"sv, "script-src"sv, "default-src"sv } },
|
||||
|
||||
// "script-src-attr"
|
||||
// 1. Return << "script-src-attr", "script-src", "default-src" >>.
|
||||
{ "script-src-attr"sv, { "script-src-attr"sv, "script-src"sv, "default-src"sv } },
|
||||
// "script-src-attr"
|
||||
// 1. Return << "script-src-attr", "script-src", "default-src" >>.
|
||||
{ "script-src-attr"sv, { "script-src-attr"sv, "script-src"sv, "default-src"sv } },
|
||||
|
||||
// "style-src-elem"
|
||||
// 1. Return << "style-src-elem", "style-src", "default-src" >>.
|
||||
{ "style-src-elem"sv, { "style-src-elem"sv, "style-src"sv, "default-src"sv } },
|
||||
// "style-src-elem"
|
||||
// 1. Return << "style-src-elem", "style-src", "default-src" >>.
|
||||
{ "style-src-elem"sv, { "style-src-elem"sv, "style-src"sv, "default-src"sv } },
|
||||
|
||||
// "style-src-attr"
|
||||
// 1. Return << "style-src-attr", "style-src", "default-src" >>.
|
||||
{ "style-src-attr"sv, { "style-src-attr"sv, "style-src"sv, "default-src"sv } },
|
||||
// "style-src-attr"
|
||||
// 1. Return << "style-src-attr", "style-src", "default-src" >>.
|
||||
{ "style-src-attr"sv, { "style-src-attr"sv, "style-src"sv, "default-src"sv } },
|
||||
|
||||
// "worker-src"
|
||||
// 1. Return << "worker-src", "child-src", "script-src", "default-src" >>.
|
||||
{ "worker-src"sv, { "worker-src"sv, "child-src"sv, "script-src"sv, "default-src"sv } },
|
||||
// "worker-src"
|
||||
// 1. Return << "worker-src", "child-src", "script-src", "default-src" >>.
|
||||
{ "worker-src"sv, { "worker-src"sv, "child-src"sv, "script-src"sv, "default-src"sv } },
|
||||
|
||||
// "connect-src"
|
||||
// 1. Return << "connect-src", "default-src" >>.
|
||||
{ "connect-src"sv, { "connect-src"sv, "default-src"sv } },
|
||||
// "connect-src"
|
||||
// 1. Return << "connect-src", "default-src" >>.
|
||||
{ "connect-src"sv, { "connect-src"sv, "default-src"sv } },
|
||||
|
||||
// "manifest-src"
|
||||
// 1. Return << "manifest-src", "default-src" >>.
|
||||
{ "manifest-src"sv, { "manifest-src"sv, "default-src"sv } },
|
||||
// "manifest-src"
|
||||
// 1. Return << "manifest-src", "default-src" >>.
|
||||
{ "manifest-src"sv, { "manifest-src"sv, "default-src"sv } },
|
||||
|
||||
// "object-src"
|
||||
// 1. Return << "object-src", "default-src" >>.
|
||||
{ "object-src"sv, { "object-src"sv, "default-src"sv } },
|
||||
// "object-src"
|
||||
// 1. Return << "object-src", "default-src" >>.
|
||||
{ "object-src"sv, { "object-src"sv, "default-src"sv } },
|
||||
|
||||
// "frame-src"
|
||||
// 1. Return << "frame-src", "child-src", "default-src" >>.
|
||||
{ "frame-src"sv, { "frame-src"sv, "child-src"sv, "default-src"sv } },
|
||||
// "frame-src"
|
||||
// 1. Return << "frame-src", "child-src", "default-src" >>.
|
||||
{ "frame-src"sv, { "frame-src"sv, "child-src"sv, "default-src"sv } },
|
||||
|
||||
// "media-src"
|
||||
// 1. Return << "media-src", "default-src" >>.
|
||||
{ "media-src"sv, { "media-src"sv, "default-src"sv } },
|
||||
// "media-src"
|
||||
// 1. Return << "media-src", "default-src" >>.
|
||||
{ "media-src"sv, { "media-src"sv, "default-src"sv } },
|
||||
|
||||
// "font-src"
|
||||
// 1. Return << "font-src", "default-src" >>.
|
||||
{ "font-src"sv, { "font-src"sv, "default-src"sv } },
|
||||
// "font-src"
|
||||
// 1. Return << "font-src", "default-src" >>.
|
||||
{ "font-src"sv, { "font-src"sv, "default-src"sv } },
|
||||
|
||||
// "img-src"
|
||||
// 1. Return << "img-src", "default-src" >>.
|
||||
{ "img-src"sv, { "img-src"sv, "default-src"sv } },
|
||||
};
|
||||
// "img-src"
|
||||
// 1. Return << "img-src", "default-src" >>.
|
||||
{ "img-src"sv, { "img-src"sv, "default-src"sv } },
|
||||
} };
|
||||
return *list;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webappsec-csp/#effective-directive-for-a-request
|
||||
Optional<FlyString> get_the_effective_directive_for_request(GC::Ref<Fetch::Infrastructure::Request const> request)
|
||||
|
|
@ -186,8 +191,8 @@ Vector<StringView> get_fetch_directive_fallback_list(Optional<FlyString> directi
|
|||
if (!directive_name.has_value())
|
||||
return {};
|
||||
|
||||
auto list_iterator = fetch_directive_fallback_list.find(directive_name.value());
|
||||
if (list_iterator == fetch_directive_fallback_list.end())
|
||||
auto list_iterator = fetch_directive_fallback_list().find(directive_name.value());
|
||||
if (list_iterator == fetch_directive_fallback_list().end())
|
||||
return {};
|
||||
|
||||
return list_iterator->value;
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
namespace Web::ContentSecurityPolicy::Directives::KeywordSources {
|
||||
|
||||
#define __ENUMERATE_KEYWORD_SOURCE(name, value) \
|
||||
FlyString name = value##_fly_string;
|
||||
FlyString const& name = *new FlyString(value##_fly_string);
|
||||
ENUMERATE_KEYWORD_SOURCES
|
||||
#undef __ENUMERATE_KEYWORD_SOURCE
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ namespace Web::ContentSecurityPolicy::Directives::KeywordSources {
|
|||
__ENUMERATE_KEYWORD_SOURCE(UnsafeAllowRedirects, "'unsafe-allow-redirects'") \
|
||||
__ENUMERATE_KEYWORD_SOURCE(WasmUnsafeEval, "'wasm-unsafe-eval'")
|
||||
|
||||
#define __ENUMERATE_KEYWORD_SOURCE(name, value) extern FlyString name;
|
||||
#define __ENUMERATE_KEYWORD_SOURCE(name, value) extern FlyString const& name;
|
||||
ENUMERATE_KEYWORD_SOURCES
|
||||
#undef __ENUMERATE_KEYWORD_SOURCE
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
namespace Web::ContentSecurityPolicy::Directives::KeywordTrustedTypes {
|
||||
|
||||
#define __ENUMERATE_KEYWORD_TRUSTED_TYPE(name, value) \
|
||||
FlyString name = value##_fly_string;
|
||||
FlyString const& name = *new FlyString(value##_fly_string);
|
||||
ENUMERATE_KEYWORD_TRUSTED_TYPES
|
||||
#undef __ENUMERATE_KEYWORD_TRUSTED_TYPE
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Web::ContentSecurityPolicy::Directives::KeywordTrustedTypes {
|
|||
__ENUMERATE_KEYWORD_TRUSTED_TYPE(None, "'none'") \
|
||||
__ENUMERATE_KEYWORD_TRUSTED_TYPE(WildCard, "*")
|
||||
|
||||
#define __ENUMERATE_KEYWORD_TRUSTED_TYPE(name, value) extern FlyString name;
|
||||
#define __ENUMERATE_KEYWORD_TRUSTED_TYPE(name, value) extern FlyString const& name;
|
||||
ENUMERATE_KEYWORD_TRUSTED_TYPES
|
||||
#undef __ENUMERATE_KEYWORD_TRUSTED_TYPE
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
namespace Web::ContentSecurityPolicy::Directives::Names {
|
||||
|
||||
#define __ENUMERATE_DIRECTIVE_NAME(name, value) \
|
||||
FlyString name = value##_fly_string;
|
||||
FlyString const& name = *new FlyString(value##_fly_string);
|
||||
ENUMERATE_DIRECTIVE_NAMES
|
||||
#undef __ENUMERATE_DIRECTIVE_NAME
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ namespace Web::ContentSecurityPolicy::Directives::Names {
|
|||
__ENUMERATE_DIRECTIVE_NAME(WebRTC, "webrtc") \
|
||||
__ENUMERATE_DIRECTIVE_NAME(WorkerSrc, "worker-src")
|
||||
|
||||
#define __ENUMERATE_DIRECTIVE_NAME(name, value) extern FlyString name;
|
||||
#define __ENUMERATE_DIRECTIVE_NAME(name, value) extern FlyString const& name;
|
||||
ENUMERATE_DIRECTIVE_NAMES
|
||||
#undef __ENUMERATE_DIRECTIVE_NAME
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/QuickSort.h>
|
||||
#include <LibCrypto/Hash/HashManager.h>
|
||||
#include <LibJS/Runtime/ArrayBuffer.h>
|
||||
|
|
@ -1573,8 +1574,8 @@ GC::Ref<WebIDL::Promise> SubtleCrypto::decapsulate_bits(AlgorithmIdentifier deca
|
|||
|
||||
SupportedAlgorithmsMap& supported_algorithms_internal()
|
||||
{
|
||||
static SupportedAlgorithmsMap s_supported_algorithms;
|
||||
return s_supported_algorithms;
|
||||
static NeverDestroyed<SupportedAlgorithmsMap> supported_algorithms;
|
||||
return *supported_algorithms;
|
||||
}
|
||||
|
||||
// https://w3c.github.io/webcrypto/#algorithm-normalization-internal
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <LibJS/Runtime/ExternalMemory.h>
|
||||
#include <LibWeb/Bindings/DOMTokenList.h>
|
||||
|
|
@ -237,7 +238,7 @@ WebIDL::ExceptionOr<bool> DOMTokenList::supports(StringView token)
|
|||
// https://dom.spec.whatwg.org/#concept-domtokenlist-validation
|
||||
WebIDL::ExceptionOr<bool> DOMTokenList::run_validation_steps(StringView token)
|
||||
{
|
||||
static HashMap<SupportedTokenKey, Vector<StringView>> supported_tokens_map = {
|
||||
static NeverDestroyed<HashMap<SupportedTokenKey, Vector<StringView>>> supported_tokens_map { HashMap<SupportedTokenKey, Vector<StringView>> {
|
||||
// https://html.spec.whatwg.org/multipage/links.html#linkTypes
|
||||
{ { HTML::TagNames::link, HTML::AttributeNames::rel },
|
||||
{ "modulepreload"sv, "preload"sv, "preconnect"sv, "dns-prefetch"sv, "stylesheet"sv, "icon"sv, "alternate"sv, "prefetch"sv, "prerender"sv, "next"sv, "manifest"sv, "apple-touch-icon"sv, "apple-touch-icon-precomposed"sv, "canonical"sv } },
|
||||
|
|
@ -251,10 +252,10 @@ WebIDL::ExceptionOr<bool> DOMTokenList::run_validation_steps(StringView token)
|
|||
// https://html.spec.whatwg.org/multipage/iframe-embed-object.html#attr-iframe-sandbox
|
||||
{ { HTML::TagNames::iframe, HTML::AttributeNames::sandbox },
|
||||
{ "allow-downloads"sv, "allow-forms"sv, "allow-modals"sv, "allow-orientation-lock"sv, "allow-pointer-lock"sv, "allow-popups"sv, "allow-popups-to-escape-sandbox"sv, "allow-presentation"sv, "allow-same-origin"sv, "allow-scripts"sv, "allow-top-navigation"sv, "allow-top-navigation-by-user-activation"sv, "allow-top-navigation-to-custom-protocols"sv } },
|
||||
};
|
||||
} };
|
||||
|
||||
// 1. If set’s element and attribute name does not define supported tokens, then throw a TypeError.
|
||||
auto supported_tokens = supported_tokens_map.get({ m_associated_element->local_name(), m_associated_attribute });
|
||||
auto supported_tokens = supported_tokens_map->get({ m_associated_element->local_name(), m_associated_attribute });
|
||||
if (!supported_tokens.has_value())
|
||||
return WebIDL::SimpleException { WebIDL::SimpleExceptionType::TypeError, MUST(String::formatted("Attribute {} does not define any supported tokens", m_associated_attribute)) };
|
||||
|
||||
|
|
|
|||
|
|
@ -3547,8 +3547,8 @@ DocumentType const* Document::doctype() const
|
|||
|
||||
String const& Document::compat_mode() const
|
||||
{
|
||||
static String const back_compat = "BackCompat"_string;
|
||||
static String const css1_compat = "CSS1Compat"_string;
|
||||
static String const& back_compat = *new String("BackCompat"_string);
|
||||
static String const& css1_compat = *new String("CSS1Compat"_string);
|
||||
|
||||
if (m_quirks_mode == QuirksMode::Yes)
|
||||
return back_compat;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,10 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include <AK/Debug.h>
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <AK/NeverDestroyed.h>
|
||||
#include <AK/Utf16FlyString.h>
|
||||
#include <LibCore/Promise.h>
|
||||
#include <LibCore/Resource.h>
|
||||
|
|
@ -421,7 +423,7 @@ static GC::Ref<DOM::Document> load_pdf_document(HTML::NavigationParams const& na
|
|||
VERIFY(navigation_params.response->url().has_value());
|
||||
auto pdf_url = navigation_params.response->url().value();
|
||||
|
||||
static auto const s_viewer_bytes = MUST(Core::Resource::load_from_uri("resource://ladybird/pdfjs/web/viewer.html"sv))->clone_data();
|
||||
static NeverDestroyed<ByteBuffer> viewer_bytes { MUST(Core::Resource::load_from_uri("resource://ladybird/pdfjs/web/viewer.html"sv))->clone_data() };
|
||||
|
||||
auto document = MUST(DOM::Document::create_and_initialize(DOM::Document::Type::HTML, "text/html"_string, navigation_params));
|
||||
document->set_origin(URL::Origin("resource"_string, String {}, {}));
|
||||
|
|
@ -441,7 +443,7 @@ static GC::Ref<DOM::Document> load_pdf_document(HTML::NavigationParams const& na
|
|||
document->add_event_listener_without_options("ladybirdviewerready"_fly_string, *DOM::IDLEventListener::create(realm, *callback));
|
||||
|
||||
Platform::EventLoopPlugin::the().deferred_invoke(GC::create_function(document->heap(), [document, pdf_url] {
|
||||
auto parser = HTML::HTMLParser::create_with_uncertain_encoding(document, s_viewer_bytes);
|
||||
auto parser = HTML::HTMLParser::create_with_uncertain_encoding(document, *viewer_bytes);
|
||||
if (document->ready_to_run_scripts()) {
|
||||
parser->run(pdf_url);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
namespace Web::DOM::MutationType {
|
||||
|
||||
#define __ENUMERATE_MUTATION_TYPE(name) \
|
||||
FlyString name = #name##_fly_string;
|
||||
FlyString const& name = *new FlyString(#name##_fly_string);
|
||||
ENUMERATE_MUTATION_TYPES
|
||||
#undef __ENUMERATE_MUTATION_TYPE
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ namespace Web::DOM::MutationType {
|
|||
__ENUMERATE_MUTATION_TYPE(characterData) \
|
||||
__ENUMERATE_MUTATION_TYPE(childList)
|
||||
|
||||
#define __ENUMERATE_MUTATION_TYPE(name) extern WEB_API FlyString name;
|
||||
#define __ENUMERATE_MUTATION_TYPE(name) extern WEB_API FlyString const& name;
|
||||
ENUMERATE_MUTATION_TYPES
|
||||
#undef __ENUMERATE_MUTATION_TYPE
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue