summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/JSStringJoiner.h
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2017-06-27 06:07:23 +0000
commit1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch)
tree46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/JavaScriptCore/runtime/JSStringJoiner.h
parent32761a6cee1d0dee366b885b7b9c777e67885688 (diff)
downloadWebKitGtk-tarball-master.tar.gz
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSStringJoiner.h')
-rw-r--r--Source/JavaScriptCore/runtime/JSStringJoiner.h131
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