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