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