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