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     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