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