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 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 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 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 74 const String& webcoreString() { return m_plainString; } 75 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: 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: 112 explicit WebCoreStringResource16(const String& string) 113 : WebCoreStringResourceBase(string) 114 { 115 ASSERT(!string.is8Bit()); 116 } 117 118 explicit WebCoreStringResource16(const AtomicString& string) 119 : WebCoreStringResourceBase(string) 120 { 121 ASSERT(!string.is8Bit()); 122 } 123 124 virtual size_t length() const OVERRIDE { return m_plainString.impl()->length(); } 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: 133 explicit WebCoreStringResource8(const String& string) 134 : WebCoreStringResourceBase(string) 135 { 136 ASSERT(string.is8Bit()); 137 } 138 139 explicit WebCoreStringResource8(const AtomicString& string) 140 : WebCoreStringResourceBase(string) 141 { 142 ASSERT(string.is8Bit()); 143 } 144 145 virtual size_t length() const OVERRIDE { return m_plainString.impl()->length(); } 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: 172 V8StringResource() 173 : m_mode(Externalize) 174 { 175 } 176 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 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 } 221 operator String() const { return toString<String>(); } 222 operator AtomicString() const { return toString<AtomicString>(); } 223 224 private: 225 bool isValid() const; 226 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> 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 247 template<> inline bool V8StringResource<DefaultMode>::isValid() const 248 { 249 return true; 250 } 251 252 template<> inline bool V8StringResource<WithNullCheck>::isValid() const 253 { 254 return !m_v8Object->IsNull(); 255 } 256 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