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