diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/runtime/JSStringJoiner.h | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSStringJoiner.h')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSStringJoiner.h | 131 |
1 files changed, 103 insertions, 28 deletions
diff --git a/Source/JavaScriptCore/runtime/JSStringJoiner.h b/Source/JavaScriptCore/runtime/JSStringJoiner.h index 73950c6d7..34ace1480 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-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -23,55 +23,130 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef JSStringJoiner_h -#define JSStringJoiner_h +#pragma once +#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); + ~JSStringJoiner(); - 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()) { - ASSERT(!m_separator.isNull()); - m_isValid = m_strings.tryReserveCapacity(stringCount); + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + if (UNLIKELY(!m_strings.tryReserveCapacity(stringCount))) + throwOutOfMemoryError(&state, scope); } -inline void JSStringJoiner::append(const String& str) +inline JSStringJoiner::JSStringJoiner(ExecState& state, LChar separator, unsigned stringCount) + : m_singleCharacterSeparator(separator) + , m_separator { &m_singleCharacterSeparator, 1 } { - if (!m_isValid) - return; + VM& vm = state.vm(); + auto scope = DECLARE_THROW_SCOPE(vm); + if (UNLIKELY(!m_strings.tryReserveCapacity(stringCount))) + throwOutOfMemoryError(&state, scope); +} + +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(), { } }); +} - m_strings.append(str); - if (!str.isNull()) { - m_accumulatedStringsLength += str.length(); - m_is8Bits = m_is8Bits && str.is8Bit(); +ALWAYS_INLINE void JSStringJoiner::appendEmptyString() +{ + m_strings.uncheckedAppend({ { }, { } }); +} + +ALWAYS_INLINE bool JSStringJoiner::appendWithoutSideEffects(ExecState& state, JSValue value) +{ + // 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()) { + JSString* jsString; + if (!value.asCell()->isString()) + return false; + jsString = asString(value); + append(jsString->viewWithUnderlyingString(state)); + return true; + } + + 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)); + } } -#endif +} // namespace JSC |