diff options
author | Konstantin Tokarev <annulen@yandex.ru> | 2016-08-25 19:20:41 +0300 |
---|---|---|
committer | Konstantin Tokarev <annulen@yandex.ru> | 2017-02-02 12:30:55 +0000 |
commit | 6882a04fb36642862b11efe514251d32070c3d65 (patch) | |
tree | b7959826000b061fd5ccc7512035c7478742f7b0 /Source/JavaScriptCore/runtime/JSStringJoiner.h | |
parent | ab6df191029eeeb0b0f16f127d553265659f739e (diff) | |
download | qtwebkit-6882a04fb36642862b11efe514251d32070c3d65.tar.gz |
Imported QtWebKit TP3 (git b57bc6801f1876c3220d5a4bfea33d620d477443)
Change-Id: I3b1d8a2808782c9f34d50240000e20cb38d3680f
Reviewed-by: Konstantin Tokarev <annulen@yandex.ru>
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSStringJoiner.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSStringJoiner.h | 122 |
1 files changed, 97 insertions, 25 deletions
diff --git a/Source/JavaScriptCore/runtime/JSStringJoiner.h b/Source/JavaScriptCore/runtime/JSStringJoiner.h index 73950c6d7..255fd3e11 100644 --- a/Source/JavaScriptCore/runtime/JSStringJoiner.h +++ b/Source/JavaScriptCore/runtime/JSStringJoiner.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, 2013 Apple Inc. All rights reserved. + * Copyright (C) 2012-2015 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,49 +26,121 @@ #ifndef JSStringJoiner_h #define JSStringJoiner_h +#include "ExceptionHelpers.h" #include "JSCJSValue.h" -#include <wtf/Vector.h> -#include <wtf/text/WTFString.h> namespace JSC { -class ExecState; - - class JSStringJoiner { public: - JSStringJoiner(const String& separator, size_t stringCount); + JSStringJoiner(ExecState&, LChar separator, unsigned stringCount); + JSStringJoiner(ExecState&, StringView separator, unsigned stringCount); - void append(const String&); - JSValue join(ExecState*); + void append(ExecState&, JSValue); + bool appendWithoutSideEffects(ExecState&, JSValue); + void appendEmptyString(); + + JSValue join(ExecState&); private: - String m_separator; - Vector<String> m_strings; + void append(StringViewWithUnderlyingString&&); + void append8Bit(const String&); + void appendLiteral(const Identifier&); + unsigned joinedLength(ExecState&) const; + LChar m_singleCharacterSeparator; + StringView m_separator; + Vector<StringViewWithUnderlyingString> m_strings; Checked<unsigned, RecordOverflow> m_accumulatedStringsLength; - bool m_isValid; - bool m_is8Bits; + bool m_isAll8Bit { true }; }; -inline JSStringJoiner::JSStringJoiner(const String& separator, size_t stringCount) +inline JSStringJoiner::JSStringJoiner(ExecState& state, StringView separator, unsigned stringCount) : m_separator(separator) - , m_isValid(true) - , m_is8Bits(m_separator.is8Bit()) + , m_isAll8Bit(m_separator.is8Bit()) +{ + if (!m_strings.tryReserveCapacity(stringCount)) + throwOutOfMemoryError(&state); +} + +inline JSStringJoiner::JSStringJoiner(ExecState& state, LChar separator, unsigned stringCount) + : m_singleCharacterSeparator(separator) + , m_separator { &m_singleCharacterSeparator, 1 } +{ + if (!m_strings.tryReserveCapacity(stringCount)) + throwOutOfMemoryError(&state); +} + +ALWAYS_INLINE void JSStringJoiner::append(StringViewWithUnderlyingString&& string) +{ + m_accumulatedStringsLength += string.view.length(); + m_isAll8Bit = m_isAll8Bit && string.view.is8Bit(); + m_strings.uncheckedAppend(WTFMove(string)); +} + +ALWAYS_INLINE void JSStringJoiner::append8Bit(const String& string) +{ + ASSERT(string.is8Bit()); + m_accumulatedStringsLength += string.length(); + m_strings.uncheckedAppend({ string, string }); +} + +ALWAYS_INLINE void JSStringJoiner::appendLiteral(const Identifier& literal) +{ + m_accumulatedStringsLength += literal.length(); + ASSERT(literal.string().is8Bit()); + m_strings.uncheckedAppend({ literal.string(), { } }); +} + +ALWAYS_INLINE void JSStringJoiner::appendEmptyString() { - ASSERT(!m_separator.isNull()); - m_isValid = m_strings.tryReserveCapacity(stringCount); + m_strings.uncheckedAppend({ { }, { } }); } -inline void JSStringJoiner::append(const String& str) +ALWAYS_INLINE bool JSStringJoiner::appendWithoutSideEffects(ExecState& state, JSValue value) { - if (!m_isValid) - return; + // The following code differs from using the result of JSValue::toString in the following ways: + // 1) It's inlined more than JSValue::toString is. + // 2) It includes conversion to WTF::String in a way that avoids allocating copies of substrings. + // 3) It doesn't create a JSString for numbers, true, or false. + // 4) It turns undefined and null into the empty string instead of "undefined" and "null". + // 5) It uses optimized code paths for all the cases known to be 8-bit and for the empty string. + // If we might make an effectful calls, return false. Otherwise return true. + + if (value.isCell()) { + if (!value.asCell()->isString()) + return false; + + append(asString(value)->viewWithUnderlyingString(state)); + return true; + } - m_strings.append(str); - if (!str.isNull()) { - m_accumulatedStringsLength += str.length(); - m_is8Bits = m_is8Bits && str.is8Bit(); + if (value.isInt32()) { + append8Bit(state.vm().numericStrings.add(value.asInt32())); + return true; + } + if (value.isDouble()) { + append8Bit(state.vm().numericStrings.add(value.asDouble())); + return true; + } + if (value.isTrue()) { + append8Bit(state.vm().propertyNames->trueKeyword.string()); + return true; + } + if (value.isFalse()) { + append8Bit(state.vm().propertyNames->falseKeyword.string()); + return true; + } + ASSERT(value.isUndefinedOrNull()); + appendEmptyString(); + return true; +} + +ALWAYS_INLINE void JSStringJoiner::append(ExecState& state, JSValue value) +{ + if (!appendWithoutSideEffects(state, value)) { + JSString* jsString = value.toString(&state); + append(jsString->viewWithUnderlyingString(state)); } } |