Home | History | Annotate | Download | only in v8
      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