[v8] Convert string conversion calls to one byte versions
[WebKit-https.git] / Source / WebCore / bindings / v8 / V8StringResource.cpp
1 /*
2  * Copyright (C) 2009 Google 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "V8StringResource.h"
28
29 #include "BindingVisitors.h"
30 #include "V8Binding.h"
31
32 namespace WebCore {
33
34 WebCoreStringResourceBase* WebCoreStringResourceBase::toWebCoreStringResourceBase(v8::Handle<v8::String> string)
35 {
36     v8::String::Encoding encoding;
37     v8::String::ExternalStringResourceBase* resource = string->GetExternalStringResourceBase(&encoding);
38     if (!resource)
39         return 0;
40     if (encoding == v8::String::ONE_BYTE_ENCODING)
41         return static_cast<WebCoreStringResource8*>(resource);
42     return static_cast<WebCoreStringResource16*>(resource);
43 }
44
45 void WebCoreStringResourceBase::visitStrings(ExternalStringVisitor* visitor)
46 {
47     visitor->visitJSExternalString(m_plainString.impl());
48     if (m_plainString.impl() != m_atomicString.impl() && !m_atomicString.isNull())
49         visitor->visitJSExternalString(m_atomicString.impl());
50 }
51
52 template<class StringClass> struct StringTraits {
53     static const StringClass& fromStringResource(WebCoreStringResourceBase*);
54     static bool is16BitAtomicString(StringClass&);
55     template<bool oneByte>
56     static StringClass fromV8String(v8::Handle<v8::String>, int);
57 };
58
59 template<>
60 struct StringTraits<String> {
61     static const String& fromStringResource(WebCoreStringResourceBase* resource)
62     {
63         return resource->webcoreString();
64     }
65     static bool is16BitAtomicString(String& string)
66     {
67         return false;
68     }
69     template<bool oneByte>
70     static String fromV8String(v8::Handle<v8::String>, int);
71 };
72
73 template<>
74 struct StringTraits<AtomicString> {
75     static const AtomicString& fromStringResource(WebCoreStringResourceBase* resource)
76     {
77         return resource->atomicString();
78     }
79     static bool is16BitAtomicString(AtomicString& string)
80     {
81         return !string.string().is8Bit();
82     }
83     template<bool oneByte>
84     static AtomicString fromV8String(v8::Handle<v8::String>, int);
85 };
86
87 template<>
88 String StringTraits<String>::fromV8String<false>(v8::Handle<v8::String> v8String, int length)
89 {
90     ASSERT(v8String->Length() == length);
91     UChar* buffer;
92     String result = String::createUninitialized(length, buffer);
93     v8String->Write(reinterpret_cast<uint16_t*>(buffer), 0, length);
94     return result;
95 }
96
97 template<>
98 AtomicString StringTraits<AtomicString>::fromV8String<false>(v8::Handle<v8::String> v8String, int length)
99 {
100     ASSERT(v8String->Length() == length);
101     static const int inlineBufferSize = 16;
102     if (length <= inlineBufferSize) {
103         UChar inlineBuffer[inlineBufferSize];
104         v8String->Write(reinterpret_cast<uint16_t*>(inlineBuffer), 0, length);
105         return AtomicString(inlineBuffer, length);
106     }
107     UChar* buffer;
108     String result = String::createUninitialized(length, buffer);
109     v8String->Write(reinterpret_cast<uint16_t*>(buffer), 0, length);
110     return AtomicString(result);
111 }
112
113 template<>
114 String StringTraits<String>::fromV8String<true>(v8::Handle<v8::String> v8String, int length)
115 {
116     ASSERT(v8String->Length() == length);
117     LChar* buffer;
118     String result = String::createUninitialized(length, buffer);
119     v8String->WriteOneByte(buffer, 0, length);
120     return result;
121 }
122
123 template<>
124 AtomicString StringTraits<AtomicString>::fromV8String<true>(v8::Handle<v8::String> v8String, int length)
125 {
126     ASSERT(v8String->Length() == length);
127     static const int inlineBufferSize = 32;
128     if (length <= inlineBufferSize) {
129         LChar inlineBuffer[inlineBufferSize];
130         v8String->WriteOneByte(inlineBuffer, 0, length);
131         return AtomicString(inlineBuffer, length);
132     }
133     LChar* buffer;
134     String string = String::createUninitialized(length, buffer);
135     v8String->WriteOneByte(buffer, 0, length);
136     return AtomicString(string);
137 }
138
139 template<typename StringType>
140 StringType v8StringToWebCoreString(v8::Handle<v8::String> v8String, ExternalMode external)
141 {
142     {
143         // A lot of WebCoreStringResourceBase::toWebCoreStringResourceBase is copied here by hand for performance reasons.
144         // This portion of this function is very hot in certain Dromeao benchmarks.
145         v8::String::Encoding encoding;
146         v8::String::ExternalStringResourceBase* resource = v8String->GetExternalStringResourceBase(&encoding);
147         if (LIKELY(!!resource)) {
148             WebCoreStringResourceBase* base;
149             if (encoding == v8::String::ONE_BYTE_ENCODING)
150                 base = static_cast<WebCoreStringResource8*>(resource);
151             else
152                 base = static_cast<WebCoreStringResource16*>(resource);
153             return StringTraits<StringType>::fromStringResource(base);
154         }
155     }
156
157     int length = v8String->Length();
158     if (UNLIKELY(!length))
159         return String("");
160
161     bool oneByte = v8String->IsOneByte();
162     StringType result(oneByte ? StringTraits<StringType>::template fromV8String<true>(v8String, length) : StringTraits<StringType>::template fromV8String<false>(v8String, length));
163
164     if (external != Externalize || !v8String->CanMakeExternal())
165         return result;
166
167     if (oneByte && !StringTraits<StringType>::is16BitAtomicString(result)) {
168         WebCoreStringResource8* stringResource = new WebCoreStringResource8(result);
169         if (UNLIKELY(!v8String->MakeExternal(stringResource)))
170             delete stringResource;
171     } else {
172         WebCoreStringResource16* stringResource = new WebCoreStringResource16(result);
173         if (UNLIKELY(!v8String->MakeExternal(stringResource)))
174             delete stringResource;
175     }
176     return result;
177 }
178     
179 // Explicitly instantiate the above template with the expected parameterizations,
180 // to ensure the compiler generates the code; otherwise link errors can result in GCC 4.4.
181 template String v8StringToWebCoreString<String>(v8::Handle<v8::String>, ExternalMode);
182 template AtomicString v8StringToWebCoreString<AtomicString>(v8::Handle<v8::String>, ExternalMode);
183
184 // Fast but non thread-safe version.
185 String int32ToWebCoreStringFast(int value)
186 {
187     // Caching of small strings below is not thread safe: newly constructed AtomicString
188     // are not safely published.
189     ASSERT(isMainThread());
190
191     // Most numbers used are <= 100. Even if they aren't used there's very little cost in using the space.
192     const int kLowNumbers = 100;
193     DEFINE_STATIC_LOCAL(Vector<AtomicString>, lowNumbers, (kLowNumbers + 1));
194     String webCoreString;
195     if (0 <= value && value <= kLowNumbers) {
196         webCoreString = lowNumbers[value];
197         if (!webCoreString) {
198             AtomicString valueString = AtomicString(String::number(value));
199             lowNumbers[value] = valueString;
200             webCoreString = valueString;
201         }
202     } else
203         webCoreString = String::number(value);
204     return webCoreString;
205 }
206
207 String int32ToWebCoreString(int value)
208 {
209     // If we are on the main thread (this should always true for non-workers), call the faster one.
210     if (isMainThread())
211         return int32ToWebCoreStringFast(value);
212     return String::number(value);
213 }
214
215 } // namespace WebCore