Home | History | Annotate | Download | only in v8
      1 /*
      2  * Copyright (C) 2012 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 are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "bindings/v8/V8PerContextData.h"
     33 
     34 #include "bindings/v8/V8Binding.h"
     35 #include "bindings/v8/V8ObjectConstructor.h"
     36 #include "wtf/StringExtras.h"
     37 
     38 namespace WebCore {
     39 
     40 template<typename Map>
     41 static void disposeMapWithUnsafePersistentValues(Map* map)
     42 {
     43     typename Map::iterator it = map->begin();
     44     for (; it != map->end(); ++it)
     45         it->value.dispose();
     46     map->clear();
     47 }
     48 
     49 void V8PerContextData::dispose()
     50 {
     51     v8::HandleScope handleScope(m_isolate);
     52     v8::Local<v8::Context>::New(m_isolate, m_context)->SetAlignedPointerInEmbedderData(v8ContextPerContextDataIndex, 0);
     53 
     54     disposeMapWithUnsafePersistentValues(&m_wrapperBoilerplates);
     55     disposeMapWithUnsafePersistentValues(&m_constructorMap);
     56     m_customElementBindings.clear();
     57 
     58     m_context.Dispose();
     59 }
     60 
     61 #define V8_STORE_PRIMORDIAL(name, Name) \
     62 { \
     63     ASSERT(m_##name##Prototype.isEmpty()); \
     64     v8::Handle<v8::String> symbol = v8::String::NewSymbol(#Name); \
     65     if (symbol.IsEmpty()) \
     66         return false; \
     67     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(v8::Local<v8::Context>::New(m_isolate, m_context)->Global()->Get(symbol)); \
     68     if (object.IsEmpty()) \
     69         return false; \
     70     v8::Handle<v8::Value> prototypeValue = object->Get(prototypeString); \
     71     if (prototypeValue.IsEmpty()) \
     72         return false; \
     73     m_##name##Prototype.set(m_isolate, prototypeValue);  \
     74 }
     75 
     76 bool V8PerContextData::init()
     77 {
     78     v8::Handle<v8::Context> context = v8::Local<v8::Context>::New(m_isolate, m_context);
     79     context->SetAlignedPointerInEmbedderData(v8ContextPerContextDataIndex, this);
     80 
     81     v8::Handle<v8::String> prototypeString = v8::String::NewSymbol("prototype");
     82     if (prototypeString.IsEmpty())
     83         return false;
     84 
     85     V8_STORE_PRIMORDIAL(error, Error);
     86 
     87     return true;
     88 }
     89 
     90 #undef V8_STORE_PRIMORDIAL
     91 
     92 v8::Local<v8::Object> V8PerContextData::createWrapperFromCacheSlowCase(WrapperTypeInfo* type)
     93 {
     94     ASSERT(!m_errorPrototype.isEmpty());
     95 
     96     v8::Context::Scope scope(v8::Local<v8::Context>::New(m_isolate, m_context));
     97     v8::Local<v8::Function> function = constructorForType(type);
     98     v8::Local<v8::Object> instance = V8ObjectConstructor::newInstance(function);
     99     if (!instance.IsEmpty()) {
    100         m_wrapperBoilerplates.set(type, UnsafePersistent<v8::Object>(m_isolate, instance));
    101         return instance->Clone();
    102     }
    103     return v8::Local<v8::Object>();
    104 }
    105 
    106 v8::Local<v8::Function> V8PerContextData::constructorForTypeSlowCase(WrapperTypeInfo* type)
    107 {
    108     ASSERT(!m_errorPrototype.isEmpty());
    109 
    110     v8::Context::Scope scope(v8::Local<v8::Context>::New(m_isolate, m_context));
    111     v8::Handle<v8::FunctionTemplate> functionTemplate = type->getTemplate(m_isolate, worldType(m_isolate));
    112     // Getting the function might fail if we're running out of stack or memory.
    113     v8::TryCatch tryCatch;
    114     v8::Local<v8::Function> function = functionTemplate->GetFunction();
    115     if (function.IsEmpty())
    116         return v8::Local<v8::Function>();
    117 
    118     if (type->parentClass) {
    119         v8::Local<v8::Object> proto = constructorForType(const_cast<WrapperTypeInfo*>(type->parentClass));
    120         if (proto.IsEmpty())
    121             return v8::Local<v8::Function>();
    122         function->SetPrototype(proto);
    123     }
    124 
    125     v8::Local<v8::Value> prototypeValue = function->Get(v8::String::NewSymbol("prototype"));
    126     if (!prototypeValue.IsEmpty() && prototypeValue->IsObject()) {
    127         v8::Local<v8::Object> prototypeObject = v8::Local<v8::Object>::Cast(prototypeValue);
    128         if (prototypeObject->InternalFieldCount() == v8PrototypeInternalFieldcount
    129             && type->wrapperTypePrototype == WrapperTypeObjectPrototype)
    130             prototypeObject->SetAlignedPointerInInternalField(v8PrototypeTypeIndex, type);
    131         type->installPerContextPrototypeProperties(prototypeObject, m_isolate);
    132         if (type->wrapperTypePrototype == WrapperTypeErrorPrototype)
    133             prototypeObject->SetPrototype(m_errorPrototype.newLocal(m_isolate));
    134     }
    135 
    136     m_constructorMap.set(type, UnsafePersistent<v8::Function>(m_isolate, function));
    137 
    138     return function;
    139 }
    140 
    141 void V8PerContextData::addCustomElementBinding(CustomElementDefinition* definition, PassOwnPtr<CustomElementBinding> binding)
    142 {
    143     ASSERT(!m_customElementBindings->contains(definition));
    144     m_customElementBindings->add(definition, binding);
    145 }
    146 
    147 void V8PerContextData::clearCustomElementBinding(CustomElementDefinition* definition)
    148 {
    149     CustomElementBindingMap::iterator it = m_customElementBindings->find(definition);
    150     ASSERT(it != m_customElementBindings->end());
    151     m_customElementBindings->remove(it);
    152 }
    153 
    154 CustomElementBinding* V8PerContextData::customElementBinding(CustomElementDefinition* definition)
    155 {
    156     CustomElementBindingMap::const_iterator it = m_customElementBindings->find(definition);
    157     ASSERT(it != m_customElementBindings->end());
    158     return it->value.get();
    159 }
    160 
    161 
    162 static v8::Handle<v8::Value> createDebugData(const char* worldName, int debugId)
    163 {
    164     char buffer[32];
    165     unsigned wanted;
    166     if (debugId == -1)
    167         wanted = snprintf(buffer, sizeof(buffer), "%s", worldName);
    168     else
    169         wanted = snprintf(buffer, sizeof(buffer), "%s,%d", worldName, debugId);
    170 
    171     if (wanted < sizeof(buffer))
    172         return v8::String::NewSymbol(buffer);
    173 
    174     return v8::Undefined();
    175 };
    176 
    177 static v8::Handle<v8::Value> debugData(v8::Handle<v8::Context> context)
    178 {
    179     v8::Context::Scope contextScope(context);
    180     return context->GetEmbedderData(v8ContextDebugIdIndex);
    181 }
    182 
    183 static void setDebugData(v8::Handle<v8::Context> context, v8::Handle<v8::Value> value)
    184 {
    185     v8::Context::Scope contextScope(context);
    186     context->SetEmbedderData(v8ContextDebugIdIndex, value);
    187 }
    188 
    189 bool V8PerContextDebugData::setContextDebugData(v8::Handle<v8::Context> context, const char* worldName, int debugId)
    190 {
    191     if (!debugData(context)->IsUndefined())
    192         return false;
    193     v8::HandleScope scope;
    194     v8::Handle<v8::Value> debugData = createDebugData(worldName, debugId);
    195     setDebugData(context, debugData);
    196     return true;
    197 }
    198 
    199 int V8PerContextDebugData::contextDebugId(v8::Handle<v8::Context> context)
    200 {
    201     v8::HandleScope scope;
    202     v8::Handle<v8::Value> data = debugData(context);
    203 
    204     if (!data->IsString())
    205         return -1;
    206     v8::String::AsciiValue ascii(data);
    207     char* comma = strnstr(*ascii, ",", ascii.length());
    208     if (!comma)
    209         return -1;
    210     return atoi(comma + 1);
    211 }
    212 
    213 } // namespace WebCore
    214