f4b1eb7460723c1bd8f74a7a154a3d7a8b88a52d
[WebKit-https.git] / Source / WebCore / bindings / v8 / V8DOMWindowShell.cpp
1 /*
2  * Copyright (C) 2008, 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 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 "V8DOMWindowShell.h"
33
34 #include "PlatformBridge.h"
35 #include "CSSMutableStyleDeclaration.h"
36 #include "DateExtension.h"
37 #include "DocumentLoader.h"
38 #include "Frame.h"
39 #include "FrameLoaderClient.h"
40 #include "Page.h"
41 #include "PageGroup.h"
42 #include "ScriptCallStack.h"
43 #include "ScriptCallStackFactory.h"
44 #include "ScriptController.h"
45 #include "StorageNamespace.h"
46 #include "V8Binding.h"
47 #include "V8BindingState.h"
48 #include "V8Collection.h"
49 #include "V8DOMMap.h"
50 #include "V8DOMWindow.h"
51 #include "V8Document.h"
52 #include "V8GCForContextDispose.h"
53 #include "V8HTMLDocument.h"
54 #include "V8HiddenPropertyName.h"
55 #include "V8History.h"
56 #include "V8Location.h"
57 #include "V8Proxy.h"
58 #include "WorkerContextExecutionProxy.h"
59
60 #include <algorithm>
61 #include <stdio.h>
62 #include <utility>
63 #include <v8-debug.h>
64 #include <v8.h>
65 #include <wtf/Assertions.h>
66 #include <wtf/OwnArrayPtr.h>
67 #include <wtf/StdLibExtras.h>
68 #include <wtf/StringExtras.h>
69 #include <wtf/UnusedParam.h>
70 #include <wtf/text/CString.h>
71
72 namespace WebCore {
73
74 static void handleFatalErrorInV8()
75 {
76     // FIXME: We temporarily deal with V8 internal error situations
77     // such as out-of-memory by crashing the renderer.
78     CRASH();
79 }
80
81 static void reportFatalErrorInV8(const char* location, const char* message)
82 {
83     // V8 is shutdown, we cannot use V8 api.
84     // The only thing we can do is to disable JavaScript.
85     // FIXME: clean up V8Proxy and disable JavaScript.
86     int memoryUsageMB = -1;
87 #if PLATFORM(CHROMIUM)
88     memoryUsageMB = ChromiumBridge::actualMemoryUsageMB();
89 #endif
90     printf("V8 error: %s (%s).  Current memory usage: %d MB\n", message, location, memoryUsageMB);
91     handleFatalErrorInV8();
92 }
93
94 static void v8UncaughtExceptionHandler(v8::Handle<v8::Message> message, v8::Handle<v8::Value> data)
95 {
96     // Use the frame where JavaScript is called from.
97     Frame* frame = V8Proxy::retrieveFrameForEnteredContext();
98     if (!frame)
99         return;
100
101     v8::Handle<v8::String> errorMessageString = message->Get();
102     ASSERT(!errorMessageString.IsEmpty());
103     String errorMessage = toWebCoreString(errorMessageString);
104
105     v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
106     RefPtr<ScriptCallStack> callStack;
107     // Currently stack trace is only collected when inspector is open.
108     if (!stackTrace.IsEmpty() && stackTrace->GetFrameCount() > 0)
109         callStack = createScriptCallStack(stackTrace, ScriptCallStack::maxCallStackSizeToCapture);
110
111     v8::Handle<v8::Value> resourceName = message->GetScriptResourceName();
112     bool useURL = resourceName.IsEmpty() || !resourceName->IsString();
113     Document* document = frame->document();
114     String resourceNameString = useURL ? document->url() : toWebCoreString(resourceName);
115     document->reportException(errorMessage, message->GetLineNumber(), resourceNameString, callStack);
116 }
117
118 // Returns the owner frame pointer of a DOM wrapper object. It only works for
119 // these DOM objects requiring cross-domain access check.
120 static Frame* getTargetFrame(v8::Local<v8::Object> host, v8::Local<v8::Value> data)
121 {
122     Frame* target = 0;
123     WrapperTypeInfo* type = WrapperTypeInfo::unwrap(data);
124     if (V8DOMWindow::info.equals(type)) {
125         v8::Handle<v8::Object> window = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), host);
126         if (window.IsEmpty())
127             return target;
128
129         DOMWindow* targetWindow = V8DOMWindow::toNative(window);
130         target = targetWindow->frame();
131     } else if (V8History::info.equals(type)) {
132         History* history = V8History::toNative(host);
133         target = history->frame();
134     } else if (V8Location::info.equals(type)) {
135         Location* location = V8Location::toNative(host);
136         target = location->frame();
137     }
138     return target;
139 }
140
141 static void reportUnsafeJavaScriptAccess(v8::Local<v8::Object> host, v8::AccessType type, v8::Local<v8::Value> data)
142 {
143     Frame* target = getTargetFrame(host, data);
144     if (target)
145         V8Proxy::reportUnsafeAccessTo(target);
146 }
147
148 PassRefPtr<V8DOMWindowShell> V8DOMWindowShell::create(Frame* frame)
149 {
150     return adoptRef(new V8DOMWindowShell(frame));
151 }
152
153 V8DOMWindowShell::V8DOMWindowShell(Frame* frame)
154     : m_frame(frame)
155 {
156 }
157
158 bool V8DOMWindowShell::isContextInitialized()
159 {
160     // m_context, m_global, and m_wrapperBoilerplates should
161     // all be non-empty if if m_context is non-empty.
162     ASSERT(m_context.IsEmpty() || !m_global.IsEmpty());
163     return !m_context.IsEmpty();
164 }
165
166 void V8DOMWindowShell::disposeContextHandles()
167 {
168     if (!m_context.IsEmpty()) {
169         m_frame->loader()->client()->didDestroyScriptContextForFrame();
170         m_context.Dispose();
171         m_context.Clear();
172
173         // It's likely that disposing the context has created a lot of
174         // garbage. Notify V8 about this so it'll have a chance of cleaning
175         // it up when idle.
176         V8GCForContextDispose::instance().notifyContextDisposed();
177     }
178
179     WrapperBoilerplateMap::iterator it = m_wrapperBoilerplates.begin();
180     for (; it != m_wrapperBoilerplates.end(); ++it) {
181         v8::Persistent<v8::Object> wrapper = it->second;
182         wrapper.Dispose();
183         wrapper.Clear();
184     }
185     m_wrapperBoilerplates.clear();
186 }
187
188 void V8DOMWindowShell::destroyGlobal()
189 {
190     if (!m_global.IsEmpty()) {
191 #ifndef NDEBUG
192         V8GCController::unregisterGlobalHandle(this, m_global);
193 #endif
194         m_global.Dispose();
195         m_global.Clear();
196     }
197 }
198
199 void V8DOMWindowShell::clearForClose()
200 {
201     if (!m_context.IsEmpty()) {
202         v8::HandleScope handleScope;
203
204         clearDocumentWrapper();
205         disposeContextHandles();
206     }
207 }
208
209 void V8DOMWindowShell::clearForNavigation()
210 {
211     if (!m_context.IsEmpty()) {
212         v8::HandleScope handle;
213         clearDocumentWrapper();
214
215         v8::Context::Scope contextScope(m_context);
216
217         // Clear the document wrapper cache before turning on access checks on
218         // the old DOMWindow wrapper. This way, access to the document wrapper
219         // will be protected by the security checks on the DOMWindow wrapper.
220         clearDocumentWrapperCache();
221
222         // Turn on access check on the old DOMWindow wrapper.
223         v8::Handle<v8::Object> wrapper = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), m_global);
224         ASSERT(!wrapper.IsEmpty());
225         wrapper->TurnOnAccessCheck();
226
227         // Separate the context from its global object.
228         m_context->DetachGlobal();
229
230         disposeContextHandles();
231     }
232 }
233
234 // Create a new environment and setup the global object.
235 //
236 // The global object corresponds to a DOMWindow instance. However, to
237 // allow properties of the JS DOMWindow instance to be shadowed, we
238 // use a shadow object as the global object and use the JS DOMWindow
239 // instance as the prototype for that shadow object. The JS DOMWindow
240 // instance is undetectable from javascript code because the __proto__
241 // accessors skip that object.
242 //
243 // The shadow object and the DOMWindow instance are seen as one object
244 // from javascript. The javascript object that corresponds to a
245 // DOMWindow instance is the shadow object. When mapping a DOMWindow
246 // instance to a V8 object, we return the shadow object.
247 //
248 // To implement split-window, see
249 //   1) https://bugs.webkit.org/show_bug.cgi?id=17249
250 //   2) https://wiki.mozilla.org/Gecko:SplitWindow
251 //   3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639
252 // we need to split the shadow object further into two objects:
253 // an outer window and an inner window. The inner window is the hidden
254 // prototype of the outer window. The inner window is the default
255 // global object of the context. A variable declared in the global
256 // scope is a property of the inner window.
257 //
258 // The outer window sticks to a Frame, it is exposed to JavaScript
259 // via window.window, window.self, window.parent, etc. The outer window
260 // has a security token which is the domain. The outer window cannot
261 // have its own properties. window.foo = 'x' is delegated to the
262 // inner window.
263 //
264 // When a frame navigates to a new page, the inner window is cut off
265 // the outer window, and the outer window identify is preserved for
266 // the frame. However, a new inner window is created for the new page.
267 // If there are JS code holds a closure to the old inner window,
268 // it won't be able to reach the outer window via its global object.
269 bool V8DOMWindowShell::initContextIfNeeded()
270 {
271     // Bail out if the context has already been initialized.
272     if (!m_context.IsEmpty())
273         return false;
274
275     // Create a handle scope for all local handles.
276     v8::HandleScope handleScope;
277
278     // Setup the security handlers and message listener. This only has
279     // to be done once.
280     static bool isV8Initialized = false;
281     if (!isV8Initialized) {
282         // Tells V8 not to call the default OOM handler, binding code
283         // will handle it.
284         v8::V8::IgnoreOutOfMemoryException();
285         v8::V8::SetFatalErrorHandler(reportFatalErrorInV8);
286
287         v8::V8::SetGlobalGCPrologueCallback(&V8GCController::gcPrologue);
288         v8::V8::SetGlobalGCEpilogueCallback(&V8GCController::gcEpilogue);
289
290         v8::V8::AddMessageListener(&v8UncaughtExceptionHandler);
291
292         v8::V8::SetFailedAccessCheckCallbackFunction(reportUnsafeJavaScriptAccess);
293
294         isV8Initialized = true;
295     }
296
297
298     m_context = createNewContext(m_global, 0);
299     if (m_context.IsEmpty())
300         return false;
301
302     v8::Local<v8::Context> v8Context = v8::Local<v8::Context>::New(m_context);
303     v8::Context::Scope contextScope(v8Context);
304
305     // Store the first global object created so we can reuse it.
306     if (m_global.IsEmpty()) {
307         m_global = v8::Persistent<v8::Object>::New(v8Context->Global());
308         // Bail out if allocation of the first global objects fails.
309         if (m_global.IsEmpty()) {
310             disposeContextHandles();
311             return false;
312         }
313 #ifndef NDEBUG
314         V8GCController::registerGlobalHandle(PROXY, this, m_global);
315 #endif
316     }
317
318     if (!installHiddenObjectPrototype(v8Context)) {
319         disposeContextHandles();
320         return false;
321     }
322
323     if (!installDOMWindow(v8Context, m_frame->domWindow())) {
324         disposeContextHandles();
325         return false;
326     }
327
328     updateDocument();
329
330     setSecurityToken();
331
332     m_frame->loader()->client()->didCreateScriptContextForFrame();
333
334     // FIXME: This is wrong. We should actually do this for the proper world once
335     // we do isolated worlds the WebCore way.
336     m_frame->loader()->dispatchDidClearWindowObjectInWorld(0);
337
338     return true;
339 }
340
341 v8::Persistent<v8::Context> V8DOMWindowShell::createNewContext(v8::Handle<v8::Object> global, int extensionGroup)
342 {
343     v8::Persistent<v8::Context> result;
344
345     // The activeDocumentLoader pointer could be 0 during frame shutdown.
346     if (!m_frame->loader()->activeDocumentLoader())
347         return result;
348
349     // Create a new environment using an empty template for the shadow
350     // object. Reuse the global object if one has been created earlier.
351     v8::Persistent<v8::ObjectTemplate> globalTemplate = V8DOMWindow::GetShadowObjectTemplate();
352     if (globalTemplate.IsEmpty())
353         return result;
354
355     // Used to avoid sleep calls in unload handlers.
356     if (!V8Proxy::registeredExtensionWithV8(DateExtension::get()))
357         V8Proxy::registerExtension(DateExtension::get());
358
359     // Dynamically tell v8 about our extensions now.
360     const V8Extensions& extensions = V8Proxy::extensions();
361     OwnArrayPtr<const char*> extensionNames(new const char*[extensions.size()]);
362     int index = 0;
363     for (size_t i = 0; i < extensions.size(); ++i) {
364         // Ensure our date extension is always allowed.
365         if (extensions[i] != DateExtension::get()
366             && !m_frame->loader()->client()->allowScriptExtension(extensions[i]->name(), extensionGroup))
367             continue;
368
369         extensionNames[index++] = extensions[i]->name();
370     }
371     v8::ExtensionConfiguration extensionConfiguration(index, extensionNames.get());
372     result = v8::Context::New(&extensionConfiguration, globalTemplate, global);
373
374     return result;
375 }
376
377 void V8DOMWindowShell::setContext(v8::Handle<v8::Context> context)
378 {
379     // if we already have a context, clear it before setting the new one.
380     if (!m_context.IsEmpty()) {
381         m_context.Dispose();
382         m_context.Clear();
383     }
384     m_context = v8::Persistent<v8::Context>::New(context);
385 }
386
387 bool V8DOMWindowShell::installDOMWindow(v8::Handle<v8::Context> context, DOMWindow* window)
388 {
389     // Create a new JS window object and use it as the prototype for the  shadow global object.
390     v8::Handle<v8::Function> windowConstructor = V8DOMWrapper::getConstructor(&V8DOMWindow::info, getHiddenObjectPrototype(context));
391     v8::Local<v8::Object> jsWindow = SafeAllocation::newInstance(windowConstructor);
392     // Bail out if allocation failed.
393     if (jsWindow.IsEmpty())
394         return false;
395
396     // Wrap the window.
397     V8DOMWrapper::setDOMWrapper(jsWindow, &V8DOMWindow::info, window);
398     V8DOMWrapper::setDOMWrapper(v8::Handle<v8::Object>::Cast(jsWindow->GetPrototype()), &V8DOMWindow::info, window);
399
400     window->ref();
401     V8DOMWrapper::setJSWrapperForDOMObject(window, v8::Persistent<v8::Object>::New(jsWindow));
402
403     // Insert the window instance as the prototype of the shadow object.
404     v8::Handle<v8::Object> v8RealGlobal = v8::Handle<v8::Object>::Cast(context->Global()->GetPrototype());
405     V8DOMWrapper::setDOMWrapper(v8RealGlobal, &V8DOMWindow::info, window);
406     v8RealGlobal->SetPrototype(jsWindow);
407     return true;
408 }
409
410 void V8DOMWindowShell::updateDocumentWrapper(v8::Handle<v8::Object> wrapper)
411 {
412     clearDocumentWrapper();
413
414     ASSERT(m_document.IsEmpty());
415     m_document = v8::Persistent<v8::Object>::New(wrapper);
416 #ifndef NDEBUG
417     V8GCController::registerGlobalHandle(PROXY, this, m_document);
418 #endif
419 }
420
421 void V8DOMWindowShell::clearDocumentWrapper()
422 {
423     if (!m_document.IsEmpty()) {
424 #ifndef NDEBUG
425         V8GCController::unregisterGlobalHandle(this, m_document);
426 #endif
427         m_document.Dispose();
428         m_document.Clear();
429     }
430 }
431
432 static void checkDocumentWrapper(v8::Handle<v8::Object> wrapper, Document* document)
433 {
434     ASSERT(V8Document::toNative(wrapper) == document);
435     ASSERT(!document->isHTMLDocument() || (V8Document::toNative(v8::Handle<v8::Object>::Cast(wrapper->GetPrototype())) == document));
436 }
437
438 void V8DOMWindowShell::updateDocumentWrapperCache()
439 {
440     v8::HandleScope handleScope;
441     v8::Context::Scope contextScope(m_context);
442
443     // If the document has no frame, NodeToV8Object might get the
444     // document wrapper for a document that is about to be deleted.
445     // If the ForceSet below causes a garbage collection, the document
446     // might get deleted and the global handle for the document
447     // wrapper cleared. Using the cleared global handle will lead to
448     // crashes. In this case we clear the cache and let the DOMWindow
449     // accessor handle access to the document.
450     if (!m_frame->document()->frame()) {
451         clearDocumentWrapperCache();
452         return;
453     }
454
455     v8::Handle<v8::Value> documentWrapper = toV8(m_frame->document());
456     ASSERT(documentWrapper == m_document || m_document.IsEmpty());
457     if (m_document.IsEmpty())
458         updateDocumentWrapper(v8::Handle<v8::Object>::Cast(documentWrapper));
459     checkDocumentWrapper(m_document, m_frame->document());
460
461     // If instantiation of the document wrapper fails, clear the cache
462     // and let the DOMWindow accessor handle access to the document.
463     if (documentWrapper.IsEmpty()) {
464         clearDocumentWrapperCache();
465         return;
466     }
467     ASSERT(documentWrapper->IsObject());
468     m_context->Global()->ForceSet(v8::String::New("document"), documentWrapper, static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
469 }
470
471 void V8DOMWindowShell::clearDocumentWrapperCache()
472 {
473     ASSERT(!m_context.IsEmpty());
474     m_context->Global()->ForceDelete(v8::String::New("document"));
475 }
476
477 void V8DOMWindowShell::setSecurityToken()
478 {
479     Document* document = m_frame->document();
480     // Setup security origin and security token.
481     if (!document) {
482         m_context->UseDefaultSecurityToken();
483         return;
484     }
485
486     // Ask the document's SecurityOrigin to generate a security token.
487     // If two tokens are equal, then the SecurityOrigins canAccess each other.
488     // If two tokens are not equal, then we have to call canAccess.
489     // Note: we can't use the HTTPOrigin if it was set from the DOM.
490     SecurityOrigin* origin = document->securityOrigin();
491     String token;
492     if (!origin->domainWasSetInDOM())
493         token = document->securityOrigin()->toString();
494
495     // An empty or "null" token means we always have to call
496     // canAccess. The toString method on securityOrigins returns the
497     // string "null" for empty security origins and for security
498     // origins that should only allow access to themselves. In this
499     // case, we use the global object as the security token to avoid
500     // calling canAccess when a script accesses its own objects.
501     if (token.isEmpty() || token == "null") {
502         m_context->UseDefaultSecurityToken();
503         return;
504     }
505
506     CString utf8Token = token.utf8();
507     // NOTE: V8 does identity comparison in fast path, must use a symbol
508     // as the security token.
509     m_context->SetSecurityToken(v8::String::NewSymbol(utf8Token.data(), utf8Token.length()));
510 }
511
512 void V8DOMWindowShell::updateDocument()
513 {
514     if (!m_frame->document())
515         return;
516
517     if (m_global.IsEmpty())
518         return;
519
520     // There is an existing JavaScript wrapper for the global object
521     // of this frame. JavaScript code in other frames might hold a
522     // reference to this wrapper. We eagerly initialize the JavaScript
523     // context for the new document to make property access on the
524     // global object wrapper succeed.
525     initContextIfNeeded();
526
527     // Bail out if context initialization failed.
528     if (m_context.IsEmpty())
529         return;
530
531     // We have a new document and we need to update the cache.
532     updateDocumentWrapperCache();
533
534     updateSecurityOrigin();
535 }
536
537 v8::Handle<v8::Value> getter(v8::Local<v8::String> property, const v8::AccessorInfo& info)
538 {
539     // FIXME(antonm): consider passing AtomicStringImpl directly.
540     AtomicString name = v8StringToAtomicWebCoreString(property);
541     HTMLDocument* htmlDocument = V8HTMLDocument::toNative(info.Holder());
542     ASSERT(htmlDocument);
543     v8::Handle<v8::Value> result = V8HTMLDocument::GetNamedProperty(htmlDocument, name);
544     if (!result.IsEmpty())
545         return result;
546     v8::Handle<v8::Value> prototype = info.Holder()->GetPrototype();
547     if (prototype->IsObject())
548         return prototype.As<v8::Object>()->Get(property);
549     return v8::Undefined();
550 }
551
552 void V8DOMWindowShell::namedItemAdded(HTMLDocument* doc, const AtomicString& name)
553 {
554     initContextIfNeeded();
555
556     v8::HandleScope handleScope;
557     v8::Context::Scope contextScope(m_context);
558
559     ASSERT(!m_document.IsEmpty());
560     checkDocumentWrapper(m_document, doc);
561     m_document->SetAccessor(v8String(name), getter);
562 }
563
564 void V8DOMWindowShell::namedItemRemoved(HTMLDocument* doc, const AtomicString& name)
565 {
566 }
567
568 void V8DOMWindowShell::updateSecurityOrigin()
569 {
570     v8::HandleScope scope;
571     setSecurityToken();
572 }
573
574 v8::Handle<v8::Value> V8DOMWindowShell::getHiddenObjectPrototype(v8::Handle<v8::Context> context)
575 {
576     return context->Global()->GetHiddenValue(V8HiddenPropertyName::objectPrototype());
577 }
578
579 bool V8DOMWindowShell::installHiddenObjectPrototype(v8::Handle<v8::Context> context)
580 {
581     v8::Handle<v8::String> objectString = v8::String::New("Object");
582     v8::Handle<v8::String> prototypeString = v8::String::New("prototype");
583     v8::Handle<v8::String> hiddenObjectPrototypeString = V8HiddenPropertyName::objectPrototype();
584     // Bail out if allocation failed.
585     if (objectString.IsEmpty() || prototypeString.IsEmpty() || hiddenObjectPrototypeString.IsEmpty())
586         return false;
587
588     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(context->Global()->Get(objectString));
589     // Bail out if fetching failed.
590     if (object.IsEmpty())
591         return false;
592     v8::Handle<v8::Value> objectPrototype = object->Get(prototypeString);
593     // Bail out if fetching failed.
594     if (objectPrototype.IsEmpty())
595         return false;
596
597     context->Global()->SetHiddenValue(hiddenObjectPrototypeString, objectPrototype);
598
599     return true;
600 }
601
602 v8::Local<v8::Object> V8DOMWindowShell::createWrapperFromCacheSlowCase(WrapperTypeInfo* type)
603 {
604     // Not in cache.
605     initContextIfNeeded();
606     v8::Context::Scope scope(m_context);
607     v8::Local<v8::Function> function = V8DOMWrapper::getConstructor(type, getHiddenObjectPrototype(m_context));
608     v8::Local<v8::Object> instance = SafeAllocation::newInstance(function);
609     if (!instance.IsEmpty()) {
610         m_wrapperBoilerplates.set(type, v8::Persistent<v8::Object>::New(instance));
611         return instance->Clone();
612     }
613     return notHandledByInterceptor();
614 }
615
616 void V8DOMWindowShell::setLocation(DOMWindow* window, const String& locationString)
617 {
618     State<V8Binding>* state = V8BindingState::Only();
619     window->setLocation(locationString, state->activeWindow(), state->firstWindow());
620 }
621
622 } // WebCore