We should support CreateThis in the FTL
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSStringJoiner.cpp
1 /*
2  * Copyright (C) 2012-2016 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "JSStringJoiner.h"
28
29 #include "JSCInlines.h"
30
31 namespace JSC {
32
33 JSStringJoiner::~JSStringJoiner()
34 {
35 }
36
37 template<typename CharacterType>
38 static inline void appendStringToData(CharacterType*& data, StringView string)
39 {
40     string.getCharactersWithUpconvert(data);
41     data += string.length();
42 }
43
44 template<typename CharacterType>
45 static inline String joinStrings(const Vector<StringViewWithUnderlyingString>& strings, StringView separator, unsigned joinedLength)
46 {
47     ASSERT(joinedLength);
48
49     CharacterType* data;
50     String result = StringImpl::tryCreateUninitialized(joinedLength, data);
51     if (UNLIKELY(result.isNull()))
52         return result;
53
54     appendStringToData(data, strings[0].view);
55
56     unsigned size = strings.size();
57
58     switch (separator.length()) {
59     case 0:
60         for (unsigned i = 1; i < size; ++i)
61             appendStringToData(data, strings[i].view);
62         break;
63     case 1: {
64         CharacterType separatorCharacter = separator[0];
65         for (unsigned i = 1; i < size; ++i) {
66             *data++ = separatorCharacter;
67             appendStringToData(data, strings[i].view);
68         }
69         break;
70     }
71     default:
72         for (unsigned i = 1; i < size; ++i) {
73             appendStringToData(data, separator);
74             appendStringToData(data, strings[i].view);
75         }
76     }
77     ASSERT(data == result.characters<CharacterType>() + joinedLength);
78
79     return result;
80 }
81
82 inline unsigned JSStringJoiner::joinedLength(ExecState& state) const
83 {
84     VM& vm = state.vm();
85     auto scope = DECLARE_THROW_SCOPE(vm);
86
87     unsigned numberOfStrings = m_strings.size();
88     if (!numberOfStrings)
89         return 0;
90
91     Checked<int32_t, RecordOverflow> separatorLength = m_separator.length();
92     Checked<int32_t, RecordOverflow> totalSeparatorsLength = separatorLength * (numberOfStrings - 1);
93     Checked<int32_t, RecordOverflow> totalLength = totalSeparatorsLength + m_accumulatedStringsLength;
94
95     int32_t result;
96     if (totalLength.safeGet(result) == CheckedState::DidOverflow) {
97         throwOutOfMemoryError(&state, scope);
98         return 0;
99     }
100     return result;
101 }
102
103 JSValue JSStringJoiner::join(ExecState& state)
104 {
105     VM& vm = state.vm();
106     auto scope = DECLARE_THROW_SCOPE(vm);
107
108     ASSERT(m_strings.size() <= m_strings.capacity());
109
110     unsigned length = joinedLength(state);
111     RETURN_IF_EXCEPTION(scope, JSValue());
112
113     if (!length)
114         return jsEmptyString(&state);
115
116     String result;
117     if (m_isAll8Bit)
118         result = joinStrings<LChar>(m_strings, m_separator, length);
119     else
120         result = joinStrings<UChar>(m_strings, m_separator, length);
121
122     if (result.isNull())
123         return throwOutOfMemoryError(&state, scope);
124
125     return jsString(&state, WTFMove(result));
126 }
127
128 }