diff options
Diffstat (limited to 'Userland/Libraries')
-rw-r--r-- | Userland/Libraries/LibJS/Heap/Heap.cpp | 1 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/PrimitiveString.cpp | 62 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/PrimitiveString.h | 7 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/Runtime/VM.h | 8 |
4 files changed, 74 insertions, 4 deletions
diff --git a/Userland/Libraries/LibJS/Heap/Heap.cpp b/Userland/Libraries/LibJS/Heap/Heap.cpp index 254cecf19a..d58758bfdd 100644 --- a/Userland/Libraries/LibJS/Heap/Heap.cpp +++ b/Userland/Libraries/LibJS/Heap/Heap.cpp @@ -57,6 +57,7 @@ Heap::Heap(VM& vm) Heap::~Heap() { + vm().string_cache().clear(); vm().deprecated_string_cache().clear(); collect_garbage(CollectionType::CollectEverything); } diff --git a/Userland/Libraries/LibJS/Runtime/PrimitiveString.cpp b/Userland/Libraries/LibJS/Runtime/PrimitiveString.cpp index 9b57954020..abfaaceb8e 100644 --- a/Userland/Libraries/LibJS/Runtime/PrimitiveString.cpp +++ b/Userland/Libraries/LibJS/Runtime/PrimitiveString.cpp @@ -25,6 +25,11 @@ PrimitiveString::PrimitiveString(PrimitiveString& lhs, PrimitiveString& rhs) { } +PrimitiveString::PrimitiveString(String string) + : m_utf8_string(move(string)) +{ +} + PrimitiveString::PrimitiveString(DeprecatedString string) : m_deprecated_string(move(string)) { @@ -37,6 +42,8 @@ PrimitiveString::PrimitiveString(Utf16String string) PrimitiveString::~PrimitiveString() { + if (has_utf8_string()) + vm().string_cache().remove(*m_utf8_string); if (has_deprecated_string()) vm().deprecated_string_cache().remove(*m_deprecated_string); } @@ -59,18 +66,41 @@ bool PrimitiveString::is_empty() const if (has_utf16_string()) return m_utf16_string->is_empty(); + if (has_utf8_string()) + return m_utf8_string->is_empty(); if (has_deprecated_string()) return m_deprecated_string->is_empty(); VERIFY_NOT_REACHED(); } +ThrowCompletionOr<String> PrimitiveString::utf8_string() const +{ + auto& vm = this->vm(); + TRY(resolve_rope_if_needed()); + + if (!has_utf8_string()) { + if (has_deprecated_string()) + m_utf8_string = TRY_OR_THROW_OOM(vm, String::from_utf8(*m_deprecated_string)); + else if (has_utf16_string()) + m_utf8_string = TRY(m_utf16_string->to_utf8(vm)); + else + VERIFY_NOT_REACHED(); + } + + return *m_utf8_string; +} + ThrowCompletionOr<DeprecatedString> PrimitiveString::deprecated_string() const { TRY(resolve_rope_if_needed()); if (!has_deprecated_string()) { - VERIFY(has_utf16_string()); - m_deprecated_string = TRY(m_utf16_string->to_deprecated_string(vm())); + if (has_utf8_string()) + m_deprecated_string = m_utf8_string->to_deprecated_string(); + else if (has_utf16_string()) + m_deprecated_string = TRY(m_utf16_string->to_deprecated_string(vm())); + else + VERIFY_NOT_REACHED(); } return *m_deprecated_string; @@ -81,8 +111,12 @@ ThrowCompletionOr<Utf16String> PrimitiveString::utf16_string() const TRY(resolve_rope_if_needed()); if (!has_utf16_string()) { - VERIFY(has_deprecated_string()); - m_utf16_string = TRY(Utf16String::create(vm(), *m_deprecated_string)); + if (has_utf8_string()) { + m_utf16_string = TRY(Utf16String::create(vm(), m_utf8_string->bytes_as_string_view())); + } else { + VERIFY(has_deprecated_string()); + m_utf16_string = TRY(Utf16String::create(vm(), *m_deprecated_string)); + } } return *m_utf16_string; @@ -128,6 +162,26 @@ NonnullGCPtr<PrimitiveString> PrimitiveString::create(VM& vm, Utf16String string return vm.heap().allocate_without_realm<PrimitiveString>(move(string)); } +NonnullGCPtr<PrimitiveString> PrimitiveString::create(VM& vm, String string) +{ + if (string.is_empty()) + return vm.empty_string(); + + if (auto bytes = string.bytes_as_string_view(); bytes.length() == 1) { + auto ch = static_cast<u8>(bytes[0]); + if (is_ascii(ch)) + return vm.single_ascii_character_string(ch); + } + + auto& string_cache = vm.string_cache(); + if (auto it = string_cache.find(string); it != string_cache.end()) + return *it->value; + + auto new_string = vm.heap().allocate_without_realm<PrimitiveString>(string); + string_cache.set(move(string), new_string); + return *new_string; +} + NonnullGCPtr<PrimitiveString> PrimitiveString::create(VM& vm, DeprecatedString string) { if (string.is_empty()) diff --git a/Userland/Libraries/LibJS/Runtime/PrimitiveString.h b/Userland/Libraries/LibJS/Runtime/PrimitiveString.h index 9684fb64b1..96e5accb99 100644 --- a/Userland/Libraries/LibJS/Runtime/PrimitiveString.h +++ b/Userland/Libraries/LibJS/Runtime/PrimitiveString.h @@ -9,6 +9,7 @@ #include <AK/DeprecatedString.h> #include <AK/Optional.h> +#include <AK/String.h> #include <AK/StringView.h> #include <LibJS/Forward.h> #include <LibJS/Heap/Cell.h> @@ -23,6 +24,7 @@ class PrimitiveString final : public Cell { public: [[nodiscard]] static NonnullGCPtr<PrimitiveString> create(VM&, Utf16String); + [[nodiscard]] static NonnullGCPtr<PrimitiveString> create(VM&, String); [[nodiscard]] static NonnullGCPtr<PrimitiveString> create(VM&, DeprecatedString); [[nodiscard]] static NonnullGCPtr<PrimitiveString> create(VM&, PrimitiveString&, PrimitiveString&); @@ -34,6 +36,9 @@ public: bool is_empty() const; u32 hash() const; + ThrowCompletionOr<String> utf8_string() const; + bool has_utf8_string() const { return m_utf8_string.has_value(); } + ThrowCompletionOr<DeprecatedString> deprecated_string() const; bool has_deprecated_string() const { return m_deprecated_string.has_value(); } @@ -45,6 +50,7 @@ public: private: explicit PrimitiveString(PrimitiveString&, PrimitiveString&); + explicit PrimitiveString(String); explicit PrimitiveString(DeprecatedString); explicit PrimitiveString(Utf16String); @@ -57,6 +63,7 @@ private: mutable PrimitiveString* m_lhs { nullptr }; mutable PrimitiveString* m_rhs { nullptr }; + mutable Optional<String> m_utf8_string; mutable Optional<DeprecatedString> m_deprecated_string; mutable Optional<Utf16String> m_utf16_string; }; diff --git a/Userland/Libraries/LibJS/Runtime/VM.h b/Userland/Libraries/LibJS/Runtime/VM.h index 8ac1aa219f..4cc9c23894 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.h +++ b/Userland/Libraries/LibJS/Runtime/VM.h @@ -73,11 +73,18 @@ public: JS_ENUMERATE_WELL_KNOWN_SYMBOLS #undef __JS_ENUMERATE + HashMap<String, PrimitiveString*>& string_cache() + { + return m_string_cache; + } + HashMap<DeprecatedString, PrimitiveString*>& deprecated_string_cache() { return m_deprecated_string_cache; } + PrimitiveString& empty_string() { return *m_empty_string; } + PrimitiveString& single_ascii_character_string(u8 character) { VERIFY(character < 0x80); @@ -257,6 +264,7 @@ private: void import_module_dynamically(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability const& promise_capability); void finish_dynamic_import(ScriptOrModule referencing_script_or_module, ModuleRequest module_request, PromiseCapability const& promise_capability, Promise* inner_promise); + HashMap<String, PrimitiveString*> m_string_cache; HashMap<DeprecatedString, PrimitiveString*> m_deprecated_string_cache; Heap m_heap; |