• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef V8StringResource_h
27 #define V8StringResource_h
28 
29 #include <v8.h>
30 #include "wtf/Threading.h"
31 #include "wtf/text/AtomicString.h"
32 #include "wtf/text/WTFString.h"
33 
34 namespace WebCore {
35 
36 class ExternalStringVisitor;
37 
38 // WebCoreStringResource is a helper class for v8ExternalString. It is used
39 // to manage the life-cycle of the underlying buffer of the external string.
40 class WebCoreStringResourceBase {
41 public:
WebCoreStringResourceBase(const String & string)42     explicit WebCoreStringResourceBase(const String& string)
43         : m_plainString(string)
44     {
45 #ifndef NDEBUG
46         m_threadId = WTF::currentThread();
47 #endif
48         ASSERT(!string.isNull());
49         v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(memoryConsumption(string));
50     }
51 
WebCoreStringResourceBase(const AtomicString & string)52     explicit WebCoreStringResourceBase(const AtomicString& string)
53         : m_plainString(string.string())
54         , m_atomicString(string)
55     {
56 #ifndef NDEBUG
57         m_threadId = WTF::currentThread();
58 #endif
59         ASSERT(!string.isNull());
60         v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(memoryConsumption(string));
61     }
62 
~WebCoreStringResourceBase()63     virtual ~WebCoreStringResourceBase()
64     {
65 #ifndef NDEBUG
66         ASSERT(m_threadId == WTF::currentThread());
67 #endif
68         int reducedExternalMemory = -memoryConsumption(m_plainString);
69         if (m_plainString.impl() != m_atomicString.impl() && !m_atomicString.isNull())
70             reducedExternalMemory -= memoryConsumption(m_atomicString.string());
71         v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(reducedExternalMemory);
72     }
73 
webcoreString()74     const String& webcoreString() { return m_plainString; }
75 
atomicString()76     const AtomicString& atomicString()
77     {
78 #ifndef NDEBUG
79         ASSERT(m_threadId == WTF::currentThread());
80 #endif
81         if (m_atomicString.isNull()) {
82             m_atomicString = AtomicString(m_plainString);
83             ASSERT(!m_atomicString.isNull());
84             if (m_plainString.impl() != m_atomicString.impl())
85                 v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(memoryConsumption(m_atomicString.string()));
86         }
87         return m_atomicString;
88     }
89 
90 protected:
91     // A shallow copy of the string. Keeps the string buffer alive until the V8 engine garbage collects it.
92     String m_plainString;
93     // If this string is atomic or has been made atomic earlier the
94     // atomic string is held here. In the case where the string starts
95     // off non-atomic and becomes atomic later it is necessary to keep
96     // the original string alive because v8 may keep derived pointers
97     // into that string.
98     AtomicString m_atomicString;
99 
100 private:
memoryConsumption(const String & string)101     static int memoryConsumption(const String& string)
102     {
103         return string.length() * (string.is8Bit() ? sizeof(LChar) : sizeof(UChar));
104     }
105 #ifndef NDEBUG
106     WTF::ThreadIdentifier m_threadId;
107 #endif
108 };
109 
110 class WebCoreStringResource16 FINAL : public WebCoreStringResourceBase, public v8::String::ExternalStringResource {
111 public:
WebCoreStringResource16(const String & string)112     explicit WebCoreStringResource16(const String& string)
113         : WebCoreStringResourceBase(string)
114     {
115         ASSERT(!string.is8Bit());
116     }
117 
WebCoreStringResource16(const AtomicString & string)118     explicit WebCoreStringResource16(const AtomicString& string)
119         : WebCoreStringResourceBase(string)
120     {
121         ASSERT(!string.is8Bit());
122     }
123 
length()124     virtual size_t length() const OVERRIDE { return m_plainString.impl()->length(); }
data()125     virtual const uint16_t* data() const OVERRIDE
126     {
127         return reinterpret_cast<const uint16_t*>(m_plainString.impl()->characters16());
128     }
129 };
130 
131 class WebCoreStringResource8 FINAL : public WebCoreStringResourceBase, public v8::String::ExternalAsciiStringResource {
132 public:
WebCoreStringResource8(const String & string)133     explicit WebCoreStringResource8(const String& string)
134         : WebCoreStringResourceBase(string)
135     {
136         ASSERT(string.is8Bit());
137     }
138 
WebCoreStringResource8(const AtomicString & string)139     explicit WebCoreStringResource8(const AtomicString& string)
140         : WebCoreStringResourceBase(string)
141     {
142         ASSERT(string.is8Bit());
143     }
144 
length()145     virtual size_t length() const OVERRIDE { return m_plainString.impl()->length(); }
data()146     virtual const char* data() const OVERRIDE
147     {
148         return reinterpret_cast<const char*>(m_plainString.impl()->characters8());
149     }
150 };
151 
152 enum ExternalMode {
153     Externalize,
154     DoNotExternalize
155 };
156 
157 template <typename StringType>
158 StringType v8StringToWebCoreString(v8::Handle<v8::String>, ExternalMode);
159 String int32ToWebCoreString(int value);
160 
161 // V8StringResource is an adapter class that converts V8 values to Strings
162 // or AtomicStrings as appropriate, using multiple typecast operators.
163 enum V8StringResourceMode {
164     DefaultMode,
165     WithNullCheck,
166     WithUndefinedOrNullCheck
167 };
168 
169 template <V8StringResourceMode Mode = DefaultMode>
170 class V8StringResource {
171 public:
V8StringResource()172     V8StringResource()
173         : m_mode(Externalize)
174     {
175     }
176 
V8StringResource(v8::Handle<v8::Value> object)177     V8StringResource(v8::Handle<v8::Value> object)
178         : m_v8Object(object)
179         , m_mode(Externalize)
180     {
181     }
182 
183     void operator=(v8::Handle<v8::Value> object)
184     {
185         m_v8Object = object;
186     }
187 
188     void operator=(const String& string)
189     {
190         setString(string);
191     }
192 
prepare()193     bool prepare()
194     {
195         if (m_v8Object.IsEmpty())
196             return true;
197 
198         if (!isValid()) {
199             setString(String());
200             return true;
201         }
202 
203         if (LIKELY(m_v8Object->IsString()))
204             return true;
205 
206         if (LIKELY(m_v8Object->IsInt32())) {
207             setString(int32ToWebCoreString(m_v8Object->Int32Value()));
208             return true;
209         }
210 
211         m_mode = DoNotExternalize;
212         v8::TryCatch block;
213         m_v8Object = m_v8Object->ToString();
214         // Handle the case where an exception is thrown as part of invoking toString on the object.
215         if (block.HasCaught()) {
216             block.ReThrow();
217             return false;
218         }
219         return true;
220     }
String()221     operator String() const { return toString<String>(); }
AtomicString()222     operator AtomicString() const { return toString<AtomicString>(); }
223 
224 private:
225     bool isValid() const;
226 
setString(const String & string)227     void setString(const String& string)
228     {
229         m_string = string;
230         m_v8Object.Clear(); // To signal that String is ready.
231     }
232 
233     template <class StringType>
toString()234     StringType toString() const
235     {
236         if (LIKELY(!m_v8Object.IsEmpty()))
237             return v8StringToWebCoreString<StringType>(const_cast<v8::Handle<v8::Value>*>(&m_v8Object)->As<v8::String>(), m_mode);
238 
239         return StringType(m_string);
240     }
241 
242     v8::Handle<v8::Value> m_v8Object;
243     ExternalMode m_mode;
244     String m_string;
245 };
246 
isValid()247 template<> inline bool V8StringResource<DefaultMode>::isValid() const
248 {
249     return true;
250 }
251 
isValid()252 template<> inline bool V8StringResource<WithNullCheck>::isValid() const
253 {
254     return !m_v8Object->IsNull();
255 }
256 
isValid()257 template<> inline bool V8StringResource<WithUndefinedOrNullCheck>::isValid() const
258 {
259     return !m_v8Object->IsNull() && !m_v8Object->IsUndefined();
260 }
261 
262 } // namespace WebCore
263 
264 #endif // V8StringResource_h
265