summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibJS/Heap/Heap.cpp1
-rw-r--r--Userland/Libraries/LibJS/Runtime/PrimitiveString.cpp62
-rw-r--r--Userland/Libraries/LibJS/Runtime/PrimitiveString.h7
-rw-r--r--Userland/Libraries/LibJS/Runtime/VM.h8
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;