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/ScriptState.h" 35 #include "bindings/v8/V8Binding.h" 36 #include "bindings/v8/V8ObjectConstructor.h" 37 #include "wtf/StringExtras.h" 38 39 #include <stdlib.h> 40 41 namespace WebCore { 42 43 V8PerContextData::V8PerContextData(v8::Handle<v8::Context> context) 44 : m_wrapperBoilerplates(context->GetIsolate()) 45 , m_constructorMap(context->GetIsolate()) 46 , m_isolate(context->GetIsolate()) 47 , m_contextHolder(adoptPtr(new gin::ContextHolder(context->GetIsolate()))) 48 , m_context(m_isolate, context) 49 , m_customElementBindings(adoptPtr(new CustomElementBindingMap())) 50 , m_activityLogger(0) 51 { 52 m_contextHolder->SetContext(context); 53 54 v8::Context::Scope contextScope(context); 55 ASSERT(m_errorPrototype.isEmpty()); 56 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(context->Global()->Get(v8AtomicString(m_isolate, "Error"))); 57 ASSERT(!object.IsEmpty()); 58 v8::Handle<v8::Value> prototypeValue = object->Get(v8AtomicString(m_isolate, "prototype")); 59 ASSERT(!prototypeValue.IsEmpty()); 60 m_errorPrototype.set(m_isolate, prototypeValue); 61 } 62 63 V8PerContextData::~V8PerContextData() 64 { 65 } 66 67 PassOwnPtr<V8PerContextData> V8PerContextData::create(v8::Handle<v8::Context> context) 68 { 69 return adoptPtr(new V8PerContextData(context)); 70 } 71 72 V8PerContextData* V8PerContextData::from(v8::Handle<v8::Context> context) 73 { 74 return ScriptState::from(context)->perContextData(); 75 } 76 77 v8::Local<v8::Object> V8PerContextData::createWrapperFromCacheSlowCase(const WrapperTypeInfo* type) 78 { 79 ASSERT(!m_errorPrototype.isEmpty()); 80 81 v8::Context::Scope scope(context()); 82 v8::Local<v8::Function> function = constructorForType(type); 83 v8::Local<v8::Object> instanceTemplate = V8ObjectConstructor::newInstance(m_isolate, function); 84 if (!instanceTemplate.IsEmpty()) { 85 m_wrapperBoilerplates.Set(type, instanceTemplate); 86 return instanceTemplate->Clone(); 87 } 88 return v8::Local<v8::Object>(); 89 } 90 91 v8::Local<v8::Function> V8PerContextData::constructorForTypeSlowCase(const WrapperTypeInfo* type) 92 { 93 ASSERT(!m_errorPrototype.isEmpty()); 94 95 v8::Context::Scope scope(context()); 96 v8::Handle<v8::FunctionTemplate> functionTemplate = type->domTemplate(m_isolate); 97 // Getting the function might fail if we're running out of stack or memory. 98 v8::TryCatch tryCatch; 99 v8::Local<v8::Function> function = functionTemplate->GetFunction(); 100 if (function.IsEmpty()) 101 return v8::Local<v8::Function>(); 102 103 if (type->parentClass) { 104 v8::Local<v8::Object> prototypeTemplate = constructorForType(type->parentClass); 105 if (prototypeTemplate.IsEmpty()) 106 return v8::Local<v8::Function>(); 107 function->SetPrototype(prototypeTemplate); 108 } 109 110 v8::Local<v8::Value> prototypeValue = function->Get(v8AtomicString(m_isolate, "prototype")); 111 if (!prototypeValue.IsEmpty() && prototypeValue->IsObject()) { 112 v8::Local<v8::Object> prototypeObject = v8::Local<v8::Object>::Cast(prototypeValue); 113 if (prototypeObject->InternalFieldCount() == v8PrototypeInternalFieldcount 114 && type->wrapperTypePrototype == WrapperTypeObjectPrototype) 115 prototypeObject->SetAlignedPointerInInternalField(v8PrototypeTypeIndex, const_cast<WrapperTypeInfo*>(type)); 116 type->installPerContextEnabledMethods(prototypeObject, m_isolate); 117 if (type->wrapperTypePrototype == WrapperTypeExceptionPrototype) 118 prototypeObject->SetPrototype(m_errorPrototype.newLocal(m_isolate)); 119 } 120 121 m_constructorMap.Set(type, function); 122 123 return function; 124 } 125 126 v8::Local<v8::Object> V8PerContextData::prototypeForType(const WrapperTypeInfo* type) 127 { 128 v8::Local<v8::Object> constructor = constructorForType(type); 129 if (constructor.IsEmpty()) 130 return v8::Local<v8::Object>(); 131 return constructor->Get(v8String(m_isolate, "prototype")).As<v8::Object>(); 132 } 133 134 void V8PerContextData::addCustomElementBinding(CustomElementDefinition* definition, PassOwnPtr<CustomElementBinding> binding) 135 { 136 ASSERT(!m_customElementBindings->contains(definition)); 137 m_customElementBindings->add(definition, binding); 138 } 139 140 void V8PerContextData::clearCustomElementBinding(CustomElementDefinition* definition) 141 { 142 CustomElementBindingMap::iterator it = m_customElementBindings->find(definition); 143 ASSERT_WITH_SECURITY_IMPLICATION(it != m_customElementBindings->end()); 144 m_customElementBindings->remove(it); 145 } 146 147 CustomElementBinding* V8PerContextData::customElementBinding(CustomElementDefinition* definition) 148 { 149 CustomElementBindingMap::const_iterator it = m_customElementBindings->find(definition); 150 ASSERT_WITH_SECURITY_IMPLICATION(it != m_customElementBindings->end()); 151 return it->value.get(); 152 } 153 154 155 static v8::Handle<v8::Value> createDebugData(const char* worldName, int debugId, v8::Isolate* isolate) 156 { 157 char buffer[32]; 158 unsigned wanted; 159 if (debugId == -1) 160 wanted = snprintf(buffer, sizeof(buffer), "%s", worldName); 161 else 162 wanted = snprintf(buffer, sizeof(buffer), "%s,%d", worldName, debugId); 163 164 if (wanted < sizeof(buffer)) 165 return v8AtomicString(isolate, buffer); 166 167 return v8::Undefined(isolate); 168 } 169 170 static v8::Handle<v8::Value> debugData(v8::Handle<v8::Context> context) 171 { 172 v8::Context::Scope contextScope(context); 173 return context->GetEmbedderData(v8ContextDebugIdIndex); 174 } 175 176 static void setDebugData(v8::Handle<v8::Context> context, v8::Handle<v8::Value> value) 177 { 178 v8::Context::Scope contextScope(context); 179 context->SetEmbedderData(v8ContextDebugIdIndex, value); 180 } 181 182 bool V8PerContextDebugData::setContextDebugData(v8::Handle<v8::Context> context, const char* worldName, int debugId) 183 { 184 if (!debugData(context)->IsUndefined()) 185 return false; 186 v8::HandleScope scope(context->GetIsolate()); 187 v8::Handle<v8::Value> debugData = createDebugData(worldName, debugId, context->GetIsolate()); 188 setDebugData(context, debugData); 189 return true; 190 } 191 192 int V8PerContextDebugData::contextDebugId(v8::Handle<v8::Context> context) 193 { 194 v8::HandleScope scope(context->GetIsolate()); 195 v8::Handle<v8::Value> data = debugData(context); 196 197 if (!data->IsString()) 198 return -1; 199 v8::String::Utf8Value utf8(data); 200 char* comma = strnstr(*utf8, ",", utf8.length()); 201 if (!comma) 202 return -1; 203 return atoi(comma + 1); 204 } 205 206 } // namespace WebCore 207