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