2009-11-10 Anton Muhin <antonm@chromium.org>
[WebKit-https.git] / WebCore / bindings / v8 / V8Proxy.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 "V8Proxy.h"
33
34 #include "ChromiumBridge.h"
35 #include "CSSMutableStyleDeclaration.h"
36 #include "DateExtension.h"
37 #include "DOMObjectsInclude.h"
38 #include "DocumentLoader.h"
39 #include "FrameLoaderClient.h"
40 #include "InspectorTimelineAgent.h"
41 #include "Page.h"
42 #include "PageGroup.h"
43 #include "ScriptController.h"
44 #include "StorageNamespace.h"
45 #include "V8Binding.h"
46 #include "V8Collection.h"
47 #include "V8ConsoleMessage.h"
48 #include "V8CustomBinding.h"
49 #include "V8DOMMap.h"
50 #include "V8DOMWindow.h"
51 #include "V8HiddenPropertyName.h"
52 #include "V8Index.h"
53 #include "V8IsolatedWorld.h"
54 #include "WorkerContextExecutionProxy.h"
55
56 #include <algorithm>
57 #include <utility>
58 #include <v8.h>
59 #include <v8-debug.h>
60 #include <wtf/Assertions.h>
61 #include <wtf/OwnArrayPtr.h>
62 #include <wtf/StdLibExtras.h>
63 #include <wtf/UnusedParam.h>
64
65 namespace WebCore {
66
67 v8::Persistent<v8::Context> V8Proxy::m_utilityContext;
68
69 // Static list of registered extensions
70 V8Extensions V8Proxy::m_extensions;
71
72 const char* V8Proxy::kContextDebugDataType = "type";
73 const char* V8Proxy::kContextDebugDataValue = "value";
74
75 void batchConfigureAttributes(v8::Handle<v8::ObjectTemplate> instance, v8::Handle<v8::ObjectTemplate> proto, const BatchedAttribute* attributes, size_t attributeCount)
76 {
77     for (size_t i = 0; i < attributeCount; ++i)
78         configureAttribute(instance, proto, attributes[i]);
79 }
80
81 void batchConfigureConstants(v8::Handle<v8::FunctionTemplate> functionDescriptor, v8::Handle<v8::ObjectTemplate> proto, const BatchedConstant* constants, size_t constantCount)
82 {
83     for (size_t i = 0; i < constantCount; ++i) {
84         const BatchedConstant* constant = &constants[i];
85         functionDescriptor->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly);
86         proto->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly);
87     }
88 }
89
90 typedef HashMap<Node*, v8::Object*> DOMNodeMap;
91 typedef HashMap<void*, v8::Object*> DOMObjectMap;
92
93 #if ENABLE(SVG)
94 // Map of SVG objects with contexts to their contexts
95 static HashMap<void*, SVGElement*>& svgObjectToContextMap()
96 {
97     typedef HashMap<void*, SVGElement*> SvgObjectToContextMap;
98     DEFINE_STATIC_LOCAL(SvgObjectToContextMap, staticSvgObjectToContextMap, ());
99     return staticSvgObjectToContextMap;
100 }
101
102 void V8Proxy::setSVGContext(void* object, SVGElement* context)
103 {
104     if (!object)
105         return;
106
107     SVGElement* oldContext = svgObjectToContextMap().get(object);
108
109     if (oldContext == context)
110         return;
111
112     if (oldContext)
113         oldContext->deref();
114
115     if (context)
116         context->ref();
117
118     svgObjectToContextMap().set(object, context);
119 }
120
121 SVGElement* V8Proxy::svgContext(void* object)
122 {
123     return svgObjectToContextMap().get(object);
124 }
125
126 #endif
127
128 typedef HashMap<int, v8::FunctionTemplate*> FunctionTemplateMap;
129
130 bool AllowAllocation::m_current = false;
131
132 void logInfo(Frame* frame, const String& message, const String& url)
133 {
134     Page* page = frame->page();
135     if (!page)
136         return;
137     V8ConsoleMessage consoleMessage(message, url, 0);
138     consoleMessage.dispatchNow(page);
139 }
140
141 enum DelayReporting {
142     ReportLater,
143     ReportNow
144 };
145
146 static void reportUnsafeAccessTo(Frame* target, DelayReporting delay)
147 {
148     ASSERT(target);
149     Document* targetDocument = target->document();
150     if (!targetDocument)
151         return;
152
153     Frame* source = V8Proxy::retrieveFrameForEnteredContext();
154     if (!source || !source->document())
155         return; // Ignore error if the source document is gone.
156
157     Document* sourceDocument = source->document();
158
159     // FIXME: This error message should contain more specifics of why the same
160     // origin check has failed.
161     String str = String::format("Unsafe JavaScript attempt to access frame "
162                                 "with URL %s from frame with URL %s. "
163                                 "Domains, protocols and ports must match.\n",
164                                 targetDocument->url().string().utf8().data(),
165                                 sourceDocument->url().string().utf8().data());
166
167     // Build a console message with fake source ID and line number.
168     const String kSourceID = "";
169     const int kLineNumber = 1;
170     V8ConsoleMessage message(str, kSourceID, kLineNumber);
171
172     if (delay == ReportNow) {
173         // NOTE: Safari prints the message in the target page, but it seems like
174         // it should be in the source page. Even for delayed messages, we put it in
175         // the source page; see V8ConsoleMessage::processDelayed().
176         message.dispatchNow(source->page());
177     } else {
178         ASSERT(delay == ReportLater);
179         // We cannot safely report the message eagerly, because this may cause
180         // allocations and GCs internally in V8 and we cannot handle that at this
181         // point. Therefore we delay the reporting.
182         message.dispatchLater();
183     }
184 }
185
186 static void reportUnsafeJavaScriptAccess(v8::Local<v8::Object> host, v8::AccessType type, v8::Local<v8::Value> data)
187 {
188     Frame* target = V8Custom::GetTargetFrame(host, data);
189     if (target)
190         reportUnsafeAccessTo(target, ReportLater);
191 }
192
193 static void handleFatalErrorInV8()
194 {
195     // FIXME: We temporarily deal with V8 internal error situations
196     // such as out-of-memory by crashing the renderer.
197     CRASH();
198 }
199
200 static void reportFatalErrorInV8(const char* location, const char* message)
201 {
202     // V8 is shutdown, we cannot use V8 api.
203     // The only thing we can do is to disable JavaScript.
204     // FIXME: clean up V8Proxy and disable JavaScript.
205     printf("V8 error: %s (%s)\n", message, location);
206     handleFatalErrorInV8();
207 }
208
209 V8Proxy::V8Proxy(Frame* frame)
210     : m_frame(frame)
211     , m_inlineCode(false)
212     , m_timerCallback(false)
213     , m_recursion(0)
214 {
215 }
216
217 V8Proxy::~V8Proxy()
218 {
219     clearForClose();
220     destroyGlobal();
221 }
222
223 void V8Proxy::destroyGlobal()
224 {
225     if (!m_global.IsEmpty()) {
226 #ifndef NDEBUG
227         V8GCController::unregisterGlobalHandle(this, m_global);
228 #endif
229         m_global.Dispose();
230         m_global.Clear();
231     }
232 }
233
234 v8::Handle<v8::Script> V8Proxy::compileScript(v8::Handle<v8::String> code, const String& fileName, int baseLine)
235 {
236     const uint16_t* fileNameString = fromWebCoreString(fileName);
237     v8::Handle<v8::String> name = v8::String::New(fileNameString, fileName.length());
238     v8::Handle<v8::Integer> line = v8::Integer::New(baseLine);
239     v8::ScriptOrigin origin(name, line);
240     v8::Handle<v8::Script> script = v8::Script::Compile(code, &origin);
241     return script;
242 }
243
244 bool V8Proxy::handleOutOfMemory()
245 {
246     v8::Local<v8::Context> context = v8::Context::GetCurrent();
247
248     if (!context->HasOutOfMemoryException())
249         return false;
250
251     // Warning, error, disable JS for this frame?
252     Frame* frame = V8Proxy::retrieveFrame(context);
253
254     V8Proxy* proxy = V8Proxy::retrieve(frame);
255     if (proxy) {
256         // Clean m_context, and event handlers.
257         proxy->clearForClose();
258
259         proxy->destroyGlobal();
260     }
261
262     ChromiumBridge::notifyJSOutOfMemory(frame);
263
264     // Disable JS.
265     Settings* settings = frame->settings();
266     ASSERT(settings);
267     settings->setJavaScriptEnabled(false);
268
269     return true;
270 }
271
272 void V8Proxy::evaluateInIsolatedWorld(int worldID, const Vector<ScriptSourceCode>& sources, int extensionGroup)
273 {
274     initContextIfNeeded();
275
276     v8::HandleScope handleScope;
277     V8IsolatedWorld* world = 0;
278
279     if (worldID > 0) {
280         IsolatedWorldMap::iterator iter = m_isolatedWorlds.find(worldID);
281         if (iter != m_isolatedWorlds.end()) {
282             world = iter->second;
283         } else {
284             world = new V8IsolatedWorld(this, extensionGroup);
285             if (world->context().IsEmpty()) {
286                 delete world;
287                 return;
288             }
289
290             m_isolatedWorlds.set(worldID, world);
291
292             // Setup context id for JS debugger.
293             setInjectedScriptContextDebugId(world->context());
294         }
295     } else {
296         world = new V8IsolatedWorld(this, extensionGroup);
297         if (world->context().IsEmpty()) {
298             delete world;
299             return;
300         }
301     }
302
303     v8::Local<v8::Context> context = v8::Local<v8::Context>::New(world->context());
304     v8::Context::Scope context_scope(context);
305     for (size_t i = 0; i < sources.size(); ++i)
306       evaluate(sources[i], 0);
307
308     if (worldID == 0)
309       world->destroy();
310 }
311
312 void V8Proxy::evaluateInNewContext(const Vector<ScriptSourceCode>& sources, int extensionGroup)
313 {
314     initContextIfNeeded();
315
316     v8::HandleScope handleScope;
317
318     // Set up the DOM window as the prototype of the new global object.
319     v8::Handle<v8::Context> windowContext = m_context;
320     v8::Handle<v8::Object> windowGlobal = windowContext->Global();
321     v8::Handle<v8::Object> windowWrapper = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, windowGlobal);
322
323     ASSERT(V8DOMWrapper::convertDOMWrapperToNative<DOMWindow>(windowWrapper) == m_frame->domWindow());
324
325     v8::Persistent<v8::Context> context = createNewContext(v8::Handle<v8::Object>(), extensionGroup);
326     if (context.IsEmpty())
327         return;
328
329     v8::Context::Scope contextScope(context);
330
331     // Setup context id for JS debugger.
332     setInjectedScriptContextDebugId(context);
333
334     v8::Handle<v8::Object> global = context->Global();
335
336     v8::Handle<v8::String> implicitProtoString = v8::String::New("__proto__");
337     global->Set(implicitProtoString, windowWrapper);
338
339     // Give the code running in the new context a way to get access to the
340     // original context.
341     global->Set(v8::String::New("contentWindow"), windowGlobal);
342
343     m_frame->loader()->client()->didCreateIsolatedScriptContext();
344
345     // Run code in the new context.
346     for (size_t i = 0; i < sources.size(); ++i)
347         evaluate(sources[i], 0);
348
349     // Using the default security token means that the canAccess is always
350     // called, which is slow.
351     // FIXME: Use tokens where possible. This will mean keeping track of all
352     // created contexts so that they can all be updated when the document domain
353     // changes.
354     context->UseDefaultSecurityToken();
355     context.Dispose();
356 }
357
358 void V8Proxy::setInjectedScriptContextDebugId(v8::Handle<v8::Context> targetContext)
359 {
360     // Setup context id for JS debugger.
361     v8::Context::Scope contextScope(targetContext);
362     v8::Handle<v8::Object> contextData = v8::Object::New();
363
364     v8::Handle<v8::Value> windowContextData = m_context->GetData();
365     if (windowContextData->IsObject()) {
366         v8::Handle<v8::String> propertyName = v8::String::New(kContextDebugDataValue);
367         contextData->Set(propertyName, v8::Object::Cast(*windowContextData)->Get(propertyName));
368     }
369     contextData->Set(v8::String::New(kContextDebugDataType), v8::String::New("injected"));
370     targetContext->SetData(contextData);
371 }
372
373 v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* node)
374 {
375     ASSERT(v8::Context::InContext());
376
377     V8GCController::checkMemoryUsage();
378
379 #if ENABLE(INSPECTOR)
380     if (InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0)
381         timelineAgent->willEvaluateScript(source.url().isNull() ? String() : source.url().string(), source.startLine());
382 #endif
383
384     v8::Local<v8::Value> result;
385     {
386         // Isolate exceptions that occur when compiling and executing
387         // the code. These exceptions should not interfere with
388         // javascript code we might evaluate from C++ when returning
389         // from here.
390         v8::TryCatch tryCatch;
391         tryCatch.SetVerbose(true);
392
393         // Compile the script.
394         v8::Local<v8::String> code = v8ExternalString(source.source());
395         ChromiumBridge::traceEventBegin("v8.compile", node, "");
396
397         // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at
398         // 1, whereas v8 starts at 0.
399         v8::Handle<v8::Script> script = compileScript(code, source.url(), source.startLine() - 1);
400         ChromiumBridge::traceEventEnd("v8.compile", node, "");
401
402         ChromiumBridge::traceEventBegin("v8.run", node, "");
403         // Set inlineCode to true for <a href="javascript:doSomething()">
404         // and false for <script>doSomething</script>. We make a rough guess at
405         // this based on whether the script source has a URL.
406         result = runScript(script, source.url().string().isNull());
407     }
408     ChromiumBridge::traceEventEnd("v8.run", node, "");
409
410 #if ENABLE(INSPECTOR)
411     if (InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0)
412         timelineAgent->didEvaluateScript();
413 #endif
414
415     return result;
416 }
417
418 v8::Local<v8::Value> V8Proxy::runScript(v8::Handle<v8::Script> script, bool isInlineCode)
419 {
420     if (script.IsEmpty())
421         return notHandledByInterceptor();
422
423     V8GCController::checkMemoryUsage();
424     // Compute the source string and prevent against infinite recursion.
425     if (m_recursion >= kMaxRecursionDepth) {
426         v8::Local<v8::String> code = v8ExternalString("throw RangeError('Recursion too deep')");
427         // FIXME: Ideally, we should be able to re-use the origin of the
428         // script passed to us as the argument instead of using an empty string
429         // and 0 baseLine.
430         script = compileScript(code, "", 0);
431     }
432
433     if (handleOutOfMemory())
434         ASSERT(script.IsEmpty());
435
436     if (script.IsEmpty())
437         return notHandledByInterceptor();
438
439     // Save the previous value of the inlineCode flag and update the flag for
440     // the duration of the script invocation.
441     bool previousInlineCode = inlineCode();
442     setInlineCode(isInlineCode);
443
444     // Run the script and keep track of the current recursion depth.
445     v8::Local<v8::Value> result;
446     {
447         V8ConsoleMessage::Scope scope;
448
449         // See comment in V8Proxy::callFunction.
450         m_frame->keepAlive();
451
452         m_recursion++;
453         result = script->Run();
454         m_recursion--;
455     }
456
457     // Release the storage mutex if applicable.
458     releaseStorageMutex();
459
460     if (handleOutOfMemory())
461         ASSERT(result.IsEmpty());
462
463     // Handle V8 internal error situation (Out-of-memory).
464     if (result.IsEmpty())
465         return notHandledByInterceptor();
466
467     // Restore inlineCode flag.
468     setInlineCode(previousInlineCode);
469
470     if (v8::V8::IsDead())
471         handleFatalErrorInV8();
472
473     return result;
474 }
475
476 v8::Local<v8::Value> V8Proxy::callFunction(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[])
477 {
478     V8GCController::checkMemoryUsage();
479     v8::Local<v8::Value> result;
480     {
481         V8ConsoleMessage::Scope scope;
482
483         if (m_recursion >= kMaxRecursionDepth) {
484             v8::Local<v8::String> code = v8::String::New("throw new RangeError('Maximum call stack size exceeded.')");
485             if (code.IsEmpty())
486                 return result;
487             v8::Local<v8::Script> script = v8::Script::Compile(code);
488             if (script.IsEmpty())
489                 return result;
490             script->Run();
491             return result;
492         }
493
494         // Evaluating the JavaScript could cause the frame to be deallocated,
495         // so we start the keep alive timer here.
496         // Frame::keepAlive method adds the ref count of the frame and sets a
497         // timer to decrease the ref count. It assumes that the current JavaScript
498         // execution finishs before firing the timer.
499         m_frame->keepAlive();
500
501         m_recursion++;
502         result = function->Call(receiver, argc, args);
503         m_recursion--;
504     }
505
506     // Release the storage mutex if applicable.
507     releaseStorageMutex();
508
509     if (v8::V8::IsDead())
510         handleFatalErrorInV8();
511
512     return result;
513 }
514
515 v8::Local<v8::Value> V8Proxy::newInstance(v8::Handle<v8::Function> constructor, int argc, v8::Handle<v8::Value> args[])
516 {
517     // No artificial limitations on the depth of recursion, see comment in
518     // V8Proxy::callFunction.
519     v8::Local<v8::Value> result;
520     {
521         V8ConsoleMessage::Scope scope;
522
523         // See comment in V8Proxy::callFunction.
524         m_frame->keepAlive();
525
526         result = constructor->NewInstance(argc, args);
527     }
528
529     if (v8::V8::IsDead())
530         handleFatalErrorInV8();
531
532     return result;
533 }
534
535 v8::Local<v8::Object> V8Proxy::createWrapperFromCacheSlowCase(V8ClassIndex::V8WrapperType type)
536 {
537     // Not in cache.
538     int classIndex = V8ClassIndex::ToInt(type);
539     initContextIfNeeded();
540     v8::Context::Scope scope(m_context);
541     v8::Local<v8::Function> function = V8DOMWrapper::getConstructor(type, getHiddenObjectPrototype(m_context));
542     v8::Local<v8::Object> instance = SafeAllocation::newInstance(function);
543     if (!instance.IsEmpty()) {
544         m_wrapperBoilerplates->Set(v8::Integer::New(classIndex), instance);
545         return instance->Clone();
546     }
547     return notHandledByInterceptor();
548 }
549
550 bool V8Proxy::isContextInitialized()
551 {
552     // m_context, m_global, and m_wrapperBoilerplates should
553     // all be non-empty if if m_context is non-empty.
554     ASSERT(m_context.IsEmpty() || !m_global.IsEmpty());
555     ASSERT(m_context.IsEmpty() || !m_wrapperBoilerplates.IsEmpty());
556     return !m_context.IsEmpty();
557 }
558
559 DOMWindow* V8Proxy::retrieveWindow(v8::Handle<v8::Context> context)
560 {
561     v8::Handle<v8::Object> global = context->Global();
562     ASSERT(!global.IsEmpty());
563     global = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, global);
564     ASSERT(!global.IsEmpty());
565     return V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, global);
566 }
567
568 Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context)
569 {
570     DOMWindow* window = retrieveWindow(context);
571     Frame* frame = window->frame();
572     if (frame && frame->domWindow() == window)
573         return frame;
574     // We return 0 here because |context| is detached from the Frame.  If we
575     // did return |frame| we could get in trouble because the frame could be
576     // navigated to another security origin.
577     return 0;
578 }
579
580 Frame* V8Proxy::retrieveFrameForEnteredContext()
581 {
582     v8::Handle<v8::Context> context = v8::Context::GetEntered();
583     if (context.IsEmpty())
584         return 0;
585     return retrieveFrame(context);
586 }
587
588 Frame* V8Proxy::retrieveFrameForCurrentContext()
589 {
590     v8::Handle<v8::Context> context = v8::Context::GetCurrent();
591     if (context.IsEmpty())
592         return 0;
593     return retrieveFrame(context);
594 }
595
596 Frame* V8Proxy::retrieveFrameForCallingContext()
597 {
598     v8::Handle<v8::Context> context = v8::Context::GetCalling();
599     if (context.IsEmpty())
600         return 0;
601     return retrieveFrame(context);
602 }
603
604 V8Proxy* V8Proxy::retrieve()
605 {
606     DOMWindow* window = retrieveWindow(currentContext());
607     ASSERT(window);
608     return retrieve(window->frame());
609 }
610
611 V8Proxy* V8Proxy::retrieve(Frame* frame)
612 {
613     if (!frame)
614         return 0;
615     return frame->script()->isEnabled() ? frame->script()->proxy() : 0;
616 }
617
618 V8Proxy* V8Proxy::retrieve(ScriptExecutionContext* context)
619 {
620     if (!context->isDocument())
621         return 0;
622     return retrieve(static_cast<Document*>(context)->frame());
623 }
624
625 void V8Proxy::disconnectFrame()
626 {
627 }
628
629 void V8Proxy::updateDocumentWrapper(v8::Handle<v8::Value> wrapper)
630 {
631     clearDocumentWrapper();
632
633     ASSERT(m_document.IsEmpty());
634     m_document = v8::Persistent<v8::Value>::New(wrapper);
635 #ifndef NDEBUG
636     V8GCController::registerGlobalHandle(PROXY, this, m_document);
637 #endif
638 }
639
640 void V8Proxy::clearDocumentWrapper()
641 {
642     if (!m_document.IsEmpty()) {
643 #ifndef NDEBUG
644         V8GCController::unregisterGlobalHandle(this, m_document);
645 #endif
646         m_document.Dispose();
647         m_document.Clear();
648     }
649 }
650
651 void V8Proxy::updateDocumentWrapperCache()
652 {
653     v8::HandleScope handleScope;
654     v8::Context::Scope contextScope(m_context);
655
656     // If the document has no frame, NodeToV8Object might get the
657     // document wrapper for a document that is about to be deleted.
658     // If the ForceSet below causes a garbage collection, the document
659     // might get deleted and the global handle for the document
660     // wrapper cleared. Using the cleared global handle will lead to
661     // crashes. In this case we clear the cache and let the DOMWindow
662     // accessor handle access to the document.
663     if (!m_frame->document()->frame()) {
664         clearDocumentWrapperCache();
665         return;
666     }
667
668     v8::Handle<v8::Value> documentWrapper = V8DOMWrapper::convertNodeToV8Object(m_frame->document());
669
670     // If instantiation of the document wrapper fails, clear the cache
671     // and let the DOMWindow accessor handle access to the document.
672     if (documentWrapper.IsEmpty()) {
673         clearDocumentWrapperCache();
674         return;
675     }
676     m_context->Global()->ForceSet(v8::String::New("document"), documentWrapper, static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
677 }
678
679 void V8Proxy::clearDocumentWrapperCache()
680 {
681     ASSERT(!m_context.IsEmpty());
682     m_context->Global()->ForceDelete(v8::String::New("document"));
683 }
684
685 void V8Proxy::disposeContextHandles()
686 {
687     if (!m_context.IsEmpty()) {
688         m_frame->loader()->client()->didDestroyScriptContextForFrame();
689         m_context.Dispose();
690         m_context.Clear();
691     }
692
693     if (!m_wrapperBoilerplates.IsEmpty()) {
694 #ifndef NDEBUG
695         V8GCController::unregisterGlobalHandle(this, m_wrapperBoilerplates);
696 #endif
697         m_wrapperBoilerplates.Dispose();
698         m_wrapperBoilerplates.Clear();
699     }
700 }
701
702 void V8Proxy::releaseStorageMutex()
703 {
704     // If we've just left a top level script context and local storage has been
705     // instantiated, we must ensure that any storage locks have been freed.
706     // Per http://dev.w3.org/html5/spec/Overview.html#storage-mutex
707     if (m_recursion != 0)
708         return;
709     Page* page = m_frame->page();
710     if (!page)
711         return;
712     if (page->group().hasLocalStorage())
713         page->group().localStorage()->unlock();
714 }
715
716 void V8Proxy::resetIsolatedWorlds()
717 {
718     for (IsolatedWorldMap::iterator iter = m_isolatedWorlds.begin();
719          iter != m_isolatedWorlds.end(); ++iter) {
720         iter->second->destroy();
721     }
722     m_isolatedWorlds.clear();
723 }
724
725 void V8Proxy::clearForClose()
726 {
727     resetIsolatedWorlds();
728
729     if (!m_context.IsEmpty()) {
730         v8::HandleScope handleScope;
731
732         clearDocumentWrapper();
733         disposeContextHandles();
734     }
735 }
736
737 void V8Proxy::clearForNavigation()
738 {
739     resetIsolatedWorlds();
740
741     if (!m_context.IsEmpty()) {
742         v8::HandleScope handle;
743         clearDocumentWrapper();
744
745         v8::Context::Scope contextScope(m_context);
746
747         // Clear the document wrapper cache before turning on access checks on
748         // the old DOMWindow wrapper. This way, access to the document wrapper
749         // will be protected by the security checks on the DOMWindow wrapper.
750         clearDocumentWrapperCache();
751
752         // Turn on access check on the old DOMWindow wrapper.
753         v8::Handle<v8::Object> wrapper = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, m_global);
754         ASSERT(!wrapper.IsEmpty());
755         wrapper->TurnOnAccessCheck();
756
757         // Separate the context from its global object.
758         m_context->DetachGlobal();
759
760         disposeContextHandles();
761     }
762 }
763
764 void V8Proxy::setSecurityToken()
765 {
766     Document* document = m_frame->document();
767     // Setup security origin and security token.
768     if (!document) {
769         m_context->UseDefaultSecurityToken();
770         return;
771     }
772
773     // Ask the document's SecurityOrigin to generate a security token.
774     // If two tokens are equal, then the SecurityOrigins canAccess each other.
775     // If two tokens are not equal, then we have to call canAccess.
776     // Note: we can't use the HTTPOrigin if it was set from the DOM.
777     SecurityOrigin* origin = document->securityOrigin();
778     String token;
779     if (!origin->domainWasSetInDOM())
780         token = document->securityOrigin()->toString();
781
782     // An empty or "null" token means we always have to call
783     // canAccess. The toString method on securityOrigins returns the
784     // string "null" for empty security origins and for security
785     // origins that should only allow access to themselves. In this
786     // case, we use the global object as the security token to avoid
787     // calling canAccess when a script accesses its own objects.
788     if (token.isEmpty() || token == "null") {
789         m_context->UseDefaultSecurityToken();
790         return;
791     }
792
793     CString utf8Token = token.utf8();
794     // NOTE: V8 does identity comparison in fast path, must use a symbol
795     // as the security token.
796     m_context->SetSecurityToken(v8::String::NewSymbol(utf8Token.data(), utf8Token.length()));
797 }
798
799 void V8Proxy::updateDocument()
800 {
801     if (!m_frame->document())
802         return;
803
804     if (m_global.IsEmpty())
805         return;
806
807     // There is an existing JavaScript wrapper for the global object
808     // of this frame. JavaScript code in other frames might hold a
809     // reference to this wrapper. We eagerly initialize the JavaScript
810     // context for the new document to make property access on the
811     // global object wrapper succeed.
812     initContextIfNeeded();
813
814     // Bail out if context initialization failed.
815     if (m_context.IsEmpty())
816         return;
817
818     // We have a new document and we need to update the cache.
819     updateDocumentWrapperCache();
820
821     updateSecurityOrigin();
822 }
823
824 void V8Proxy::updateSecurityOrigin()
825 {
826     v8::HandleScope scope;
827     setSecurityToken();
828 }
829
830 // Same origin policy implementation:
831 //
832 // Same origin policy prevents JS code from domain A access JS & DOM objects
833 // in a different domain B. There are exceptions and several objects are
834 // accessible by cross-domain code. For example, the window.frames object is
835 // accessible by code from a different domain, but window.document is not.
836 //
837 // The binding code sets security check callbacks on a function template,
838 // and accessing instances of the template calls the callback function.
839 // The callback function checks same origin policy.
840 //
841 // Callback functions are expensive. V8 uses a security token string to do
842 // fast access checks for the common case where source and target are in the
843 // same domain. A security token is a string object that represents
844 // the protocol/url/port of a domain.
845 //
846 // There are special cases where a security token matching is not enough.
847 // For example, JavaScript can set its domain to a super domain by calling
848 // document.setDomain(...). In these cases, the binding code can reset
849 // a context's security token to its global object so that the fast access
850 // check will always fail.
851
852 // Check if the current execution context can access a target frame.
853 // First it checks same domain policy using the lexical context
854 //
855 // This is equivalent to KJS::Window::allowsAccessFrom(ExecState*, String&).
856 bool V8Proxy::canAccessPrivate(DOMWindow* targetWindow)
857 {
858     ASSERT(targetWindow);
859
860     String message;
861
862     DOMWindow* originWindow = retrieveWindow(currentContext());
863     if (originWindow == targetWindow)
864         return true;
865
866     if (!originWindow)
867         return false;
868
869     const SecurityOrigin* activeSecurityOrigin = originWindow->securityOrigin();
870     const SecurityOrigin* targetSecurityOrigin = targetWindow->securityOrigin();
871
872     // We have seen crashes were the security origin of the target has not been
873     // initialized. Defend against that.
874     if (!targetSecurityOrigin)
875         return false;
876
877     if (activeSecurityOrigin->canAccess(targetSecurityOrigin))
878         return true;
879
880     // Allow access to a "about:blank" page if the dynamic context is a
881     // detached context of the same frame as the blank page.
882     if (targetSecurityOrigin->isEmpty() && originWindow->frame() == targetWindow->frame())
883         return true;
884
885     return false;
886 }
887
888 bool V8Proxy::canAccessFrame(Frame* target, bool reportError)
889 {
890     // The subject is detached from a frame, deny accesses.
891     if (!target)
892         return false;
893
894     if (!canAccessPrivate(target->domWindow())) {
895         if (reportError)
896             reportUnsafeAccessTo(target, ReportNow);
897         return false;
898     }
899     return true;
900 }
901
902 bool V8Proxy::checkNodeSecurity(Node* node)
903 {
904     if (!node)
905         return false;
906
907     Frame* target = node->document()->frame();
908
909     if (!target)
910         return false;
911
912     return canAccessFrame(target, true);
913 }
914
915 v8::Persistent<v8::Context> V8Proxy::createNewContext(v8::Handle<v8::Object> global, int extensionGroup)
916 {
917     v8::Persistent<v8::Context> result;
918
919     // The activeDocumentLoader pointer could be NULL during frame shutdown.
920     if (!m_frame->loader()->activeDocumentLoader())
921         return result;
922
923     // Create a new environment using an empty template for the shadow
924     // object. Reuse the global object if one has been created earlier.
925     v8::Persistent<v8::ObjectTemplate> globalTemplate = V8DOMWindow::GetShadowObjectTemplate();
926     if (globalTemplate.IsEmpty())
927         return result;
928
929     // Install a security handler with V8.
930     globalTemplate->SetAccessCheckCallbacks(V8Custom::v8DOMWindowNamedSecurityCheck, V8Custom::v8DOMWindowIndexedSecurityCheck, v8::Integer::New(V8ClassIndex::DOMWINDOW));
931     globalTemplate->SetInternalFieldCount(V8Custom::kDOMWindowInternalFieldCount);
932
933     // Used to avoid sleep calls in unload handlers.
934     if (!registeredExtensionWithV8(DateExtension::get()))
935         registerExtension(DateExtension::get(), String());
936
937     // Dynamically tell v8 about our extensions now.
938     OwnArrayPtr<const char*> extensionNames(new const char*[m_extensions.size()]);
939     int index = 0;
940     for (size_t i = 0; i < m_extensions.size(); ++i) {
941         if (m_extensions[i].group && m_extensions[i].group != extensionGroup)
942             continue;
943
944         // Note: we check the loader URL here instead of the document URL
945         // because we might be currently loading an URL into a blank page.
946         // See http://code.google.com/p/chromium/issues/detail?id=10924
947         if (m_extensions[i].scheme.length() > 0 && (m_extensions[i].scheme != m_frame->loader()->activeDocumentLoader()->url().protocol() || m_extensions[i].scheme != m_frame->page()->mainFrame()->loader()->activeDocumentLoader()->url().protocol()))
948             continue;
949
950         extensionNames[index++] = m_extensions[i].extension->name();
951     }
952     v8::ExtensionConfiguration extensions(index, extensionNames.get());
953     result = v8::Context::New(&extensions, globalTemplate, global);
954
955     return result;
956 }
957
958 bool V8Proxy::installDOMWindow(v8::Handle<v8::Context> context, DOMWindow* window)
959 {
960     v8::Handle<v8::String> implicitProtoString = v8::String::New("__proto__");
961     if (implicitProtoString.IsEmpty())
962         return false;
963
964     // Create a new JS window object and use it as the prototype for the  shadow global object.
965     v8::Handle<v8::Function> windowConstructor = V8DOMWrapper::getConstructor(V8ClassIndex::DOMWINDOW, getHiddenObjectPrototype(context));
966     v8::Local<v8::Object> jsWindow = SafeAllocation::newInstance(windowConstructor);
967     // Bail out if allocation failed.
968     if (jsWindow.IsEmpty())
969         return false;
970
971     // Wrap the window.
972     V8DOMWrapper::setDOMWrapper(jsWindow, V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), window);
973     V8DOMWrapper::setDOMWrapper(v8::Handle<v8::Object>::Cast(jsWindow->GetPrototype()), V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), window);
974
975     window->ref();
976     V8DOMWrapper::setJSWrapperForDOMObject(window, v8::Persistent<v8::Object>::New(jsWindow));
977
978     // Insert the window instance as the prototype of the shadow object.
979     v8::Handle<v8::Object> v8Global = context->Global();
980     V8DOMWrapper::setDOMWrapper(v8::Handle<v8::Object>::Cast(v8Global->GetPrototype()), V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), window);
981     v8Global->Set(implicitProtoString, jsWindow);
982     return true;
983 }
984
985 // Create a new environment and setup the global object.
986 //
987 // The global object corresponds to a DOMWindow instance. However, to
988 // allow properties of the JS DOMWindow instance to be shadowed, we
989 // use a shadow object as the global object and use the JS DOMWindow
990 // instance as the prototype for that shadow object. The JS DOMWindow
991 // instance is undetectable from javascript code because the __proto__
992 // accessors skip that object.
993 //
994 // The shadow object and the DOMWindow instance are seen as one object
995 // from javascript. The javascript object that corresponds to a
996 // DOMWindow instance is the shadow object. When mapping a DOMWindow
997 // instance to a V8 object, we return the shadow object.
998 //
999 // To implement split-window, see
1000 //   1) https://bugs.webkit.org/show_bug.cgi?id=17249
1001 //   2) https://wiki.mozilla.org/Gecko:SplitWindow
1002 //   3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639
1003 // we need to split the shadow object further into two objects:
1004 // an outer window and an inner window. The inner window is the hidden
1005 // prototype of the outer window. The inner window is the default
1006 // global object of the context. A variable declared in the global
1007 // scope is a property of the inner window.
1008 //
1009 // The outer window sticks to a Frame, it is exposed to JavaScript
1010 // via window.window, window.self, window.parent, etc. The outer window
1011 // has a security token which is the domain. The outer window cannot
1012 // have its own properties. window.foo = 'x' is delegated to the
1013 // inner window.
1014 //
1015 // When a frame navigates to a new page, the inner window is cut off
1016 // the outer window, and the outer window identify is preserved for
1017 // the frame. However, a new inner window is created for the new page.
1018 // If there are JS code holds a closure to the old inner window,
1019 // it won't be able to reach the outer window via its global object.
1020 void V8Proxy::initContextIfNeeded()
1021 {
1022     // Bail out if the context has already been initialized.
1023     if (!m_context.IsEmpty())
1024         return;
1025
1026     // Create a handle scope for all local handles.
1027     v8::HandleScope handleScope;
1028
1029     // Setup the security handlers and message listener. This only has
1030     // to be done once.
1031     static bool isV8Initialized = false;
1032     if (!isV8Initialized) {
1033         // Tells V8 not to call the default OOM handler, binding code
1034         // will handle it.
1035         v8::V8::IgnoreOutOfMemoryException();
1036         v8::V8::SetFatalErrorHandler(reportFatalErrorInV8);
1037
1038         v8::V8::SetGlobalGCPrologueCallback(&V8GCController::gcPrologue);
1039         v8::V8::SetGlobalGCEpilogueCallback(&V8GCController::gcEpilogue);
1040
1041         v8::V8::AddMessageListener(&V8ConsoleMessage::handler);
1042
1043         v8::V8::SetFailedAccessCheckCallbackFunction(reportUnsafeJavaScriptAccess);
1044
1045         isV8Initialized = true;
1046     }
1047
1048
1049     m_context = createNewContext(m_global, 0);
1050     if (m_context.IsEmpty())
1051         return;
1052
1053     v8::Local<v8::Context> v8Context = v8::Local<v8::Context>::New(m_context);
1054     v8::Context::Scope contextScope(v8Context);
1055
1056     // Store the first global object created so we can reuse it.
1057     if (m_global.IsEmpty()) {
1058         m_global = v8::Persistent<v8::Object>::New(v8Context->Global());
1059         // Bail out if allocation of the first global objects fails.
1060         if (m_global.IsEmpty()) {
1061             disposeContextHandles();
1062             return;
1063         }
1064 #ifndef NDEBUG
1065         V8GCController::registerGlobalHandle(PROXY, this, m_global);
1066 #endif
1067     }
1068
1069     installHiddenObjectPrototype(v8Context);
1070     m_wrapperBoilerplates = v8::Persistent<v8::Array>::New(v8::Array::New(V8ClassIndex::WRAPPER_TYPE_COUNT));
1071     // Bail out if allocation failed.
1072     if (m_wrapperBoilerplates.IsEmpty()) {
1073         disposeContextHandles();
1074         return;
1075     }
1076 #ifndef NDEBUG
1077     V8GCController::registerGlobalHandle(PROXY, this, m_wrapperBoilerplates);
1078 #endif
1079
1080     if (!installDOMWindow(v8Context, m_frame->domWindow()))
1081         disposeContextHandles();
1082
1083     updateDocument();
1084
1085     setSecurityToken();
1086
1087     m_frame->loader()->client()->didCreateScriptContextForFrame();
1088     m_frame->loader()->dispatchWindowObjectAvailable();
1089 }
1090
1091 void V8Proxy::setDOMException(int exceptionCode)
1092 {
1093     if (exceptionCode <= 0)
1094         return;
1095
1096     ExceptionCodeDescription description;
1097     getExceptionCodeDescription(exceptionCode, description);
1098
1099     v8::Handle<v8::Value> exception;
1100     switch (description.type) {
1101     case DOMExceptionType:
1102         exception = V8DOMWrapper::convertToV8Object(V8ClassIndex::DOMCOREEXCEPTION, DOMCoreException::create(description));
1103         break;
1104     case RangeExceptionType:
1105         exception = V8DOMWrapper::convertToV8Object(V8ClassIndex::RANGEEXCEPTION, RangeException::create(description));
1106         break;
1107     case EventExceptionType:
1108         exception = V8DOMWrapper::convertToV8Object(V8ClassIndex::EVENTEXCEPTION, EventException::create(description));
1109         break;
1110     case XMLHttpRequestExceptionType:
1111         exception = V8DOMWrapper::convertToV8Object(V8ClassIndex::XMLHTTPREQUESTEXCEPTION, XMLHttpRequestException::create(description));
1112         break;
1113 #if ENABLE(SVG)
1114     case SVGExceptionType:
1115         exception = V8DOMWrapper::convertToV8Object(V8ClassIndex::SVGEXCEPTION, SVGException::create(description));
1116         break;
1117 #endif
1118 #if ENABLE(XPATH)
1119     case XPathExceptionType:
1120         exception = V8DOMWrapper::convertToV8Object(V8ClassIndex::XPATHEXCEPTION, XPathException::create(description));
1121         break;
1122 #endif
1123     }
1124
1125     ASSERT(!exception.IsEmpty());
1126     v8::ThrowException(exception);
1127 }
1128
1129 v8::Handle<v8::Value> V8Proxy::throwError(ErrorType type, const char* message)
1130 {
1131     switch (type) {
1132     case RangeError:
1133         return v8::ThrowException(v8::Exception::RangeError(v8String(message)));
1134     case ReferenceError:
1135         return v8::ThrowException(v8::Exception::ReferenceError(v8String(message)));
1136     case SyntaxError:
1137         return v8::ThrowException(v8::Exception::SyntaxError(v8String(message)));
1138     case TypeError:
1139         return v8::ThrowException(v8::Exception::TypeError(v8String(message)));
1140     case GeneralError:
1141         return v8::ThrowException(v8::Exception::Error(v8String(message)));
1142     default:
1143         ASSERT_NOT_REACHED();
1144         return notHandledByInterceptor();
1145     }
1146 }
1147
1148 v8::Local<v8::Context> V8Proxy::context(Frame* frame)
1149 {
1150     v8::Local<v8::Context> context = V8Proxy::mainWorldContext(frame);
1151     if (context.IsEmpty())
1152         return v8::Local<v8::Context>();
1153
1154     if (V8IsolatedWorld* world = V8IsolatedWorld::getEntered()) {
1155         context = v8::Local<v8::Context>::New(world->context());
1156         if (frame != V8Proxy::retrieveFrame(context))
1157             return v8::Local<v8::Context>();
1158     }
1159
1160     return context;
1161 }
1162
1163 v8::Local<v8::Context> V8Proxy::context()
1164 {
1165     if (V8IsolatedWorld* world = V8IsolatedWorld::getEntered()) {
1166         RefPtr<SharedPersistent<v8::Context> > context = world->sharedContext();
1167         if (m_frame != V8Proxy::retrieveFrame(context->get()))
1168             return v8::Local<v8::Context>();
1169         return v8::Local<v8::Context>::New(context->get());
1170     }
1171     initContextIfNeeded();
1172     return v8::Local<v8::Context>::New(m_context);;
1173 }
1174
1175 v8::Local<v8::Context> V8Proxy::mainWorldContext(Frame* frame)
1176 {
1177     V8Proxy* proxy = retrieve(frame);
1178     if (!proxy)
1179         return v8::Local<v8::Context>();
1180
1181     proxy->initContextIfNeeded();
1182     return v8::Local<v8::Context>::New(proxy->m_context);
1183 }
1184
1185 v8::Local<v8::Context> V8Proxy::currentContext()
1186 {
1187     return v8::Context::GetCurrent();
1188 }
1189
1190 v8::Handle<v8::Value> V8Proxy::checkNewLegal(const v8::Arguments& args)
1191 {
1192     if (!AllowAllocation::m_current)
1193         return throwError(TypeError, "Illegal constructor");
1194
1195     return args.This();
1196 }
1197
1198 void V8Proxy::bindJsObjectToWindow(Frame* frame, const char* name, int type, v8::Handle<v8::FunctionTemplate> descriptor, void* impl)
1199 {
1200     // Get environment.
1201     v8::Handle<v8::Context> v8Context = V8Proxy::mainWorldContext(frame);
1202     if (v8Context.IsEmpty())
1203         return; // JS not enabled.
1204
1205     v8::Context::Scope scope(v8Context);
1206     v8::Handle<v8::Object> instance = descriptor->GetFunction();
1207     V8DOMWrapper::setDOMWrapper(instance, type, impl);
1208
1209     v8::Handle<v8::Object> global = v8Context->Global();
1210     global->Set(v8::String::New(name), instance);
1211 }
1212
1213 void V8Proxy::processConsoleMessages()
1214 {
1215     V8ConsoleMessage::processDelayed();
1216 }
1217
1218 // Create the utility context for holding JavaScript functions used internally
1219 // which are not visible to JavaScript executing on the page.
1220 void V8Proxy::createUtilityContext()
1221 {
1222     ASSERT(m_utilityContext.IsEmpty());
1223
1224     v8::HandleScope scope;
1225     v8::Handle<v8::ObjectTemplate> globalTemplate = v8::ObjectTemplate::New();
1226     m_utilityContext = v8::Context::New(0, globalTemplate);
1227     v8::Context::Scope contextScope(m_utilityContext);
1228
1229     // Compile JavaScript function for retrieving the source line of the top
1230     // JavaScript stack frame.
1231     DEFINE_STATIC_LOCAL(const char*, frameSourceLineSource,
1232         ("function frameSourceLine(exec_state) {"
1233         "  return exec_state.frame(0).sourceLine();"
1234         "}"));
1235     v8::Script::Compile(v8::String::New(frameSourceLineSource))->Run();
1236
1237     // Compile JavaScript function for retrieving the source name of the top
1238     // JavaScript stack frame.
1239     DEFINE_STATIC_LOCAL(const char*, frameSourceNameSource,
1240         ("function frameSourceName(exec_state) {"
1241         "  var frame = exec_state.frame(0);"
1242         "  if (frame.func().resolved() && "
1243         "      frame.func().script() && "
1244         "      frame.func().script().name()) {"
1245         "    return frame.func().script().name();"
1246         "  }"
1247         "}"));
1248     v8::Script::Compile(v8::String::New(frameSourceNameSource))->Run();
1249 }
1250
1251 bool V8Proxy::sourceLineNumber(int& result)
1252 {
1253     v8::HandleScope scope;
1254     v8::Handle<v8::Context> v8UtilityContext = V8Proxy::utilityContext();
1255     if (v8UtilityContext.IsEmpty())
1256         return false;
1257     v8::Context::Scope contextScope(v8UtilityContext);
1258     v8::Handle<v8::Function> frameSourceLine;
1259     frameSourceLine = v8::Local<v8::Function>::Cast(v8UtilityContext->Global()->Get(v8::String::New("frameSourceLine")));
1260     if (frameSourceLine.IsEmpty())
1261         return false;
1262     v8::Handle<v8::Value> value = v8::Debug::Call(frameSourceLine);
1263     if (value.IsEmpty())
1264         return false;
1265     result = value->Int32Value();
1266     return true;
1267 }
1268
1269 bool V8Proxy::sourceName(String& result)
1270 {
1271     v8::HandleScope scope;
1272     v8::Handle<v8::Context> v8UtilityContext = utilityContext();
1273     if (v8UtilityContext.IsEmpty())
1274         return false;
1275     v8::Context::Scope contextScope(v8UtilityContext);
1276     v8::Handle<v8::Function> frameSourceName;
1277     frameSourceName = v8::Local<v8::Function>::Cast(v8UtilityContext->Global()->Get(v8::String::New("frameSourceName")));
1278     if (frameSourceName.IsEmpty())
1279         return false;
1280     v8::Handle<v8::Value> value = v8::Debug::Call(frameSourceName);
1281     if (value.IsEmpty())
1282         return false;
1283     result = toWebCoreString(value);
1284     return true;
1285 }
1286
1287 void V8Proxy::registerExtensionWithV8(v8::Extension* extension)
1288 {
1289     // If the extension exists in our list, it was already registered with V8.
1290     if (!registeredExtensionWithV8(extension))
1291         v8::RegisterExtension(extension);
1292 }
1293
1294 bool V8Proxy::registeredExtensionWithV8(v8::Extension* extension)
1295 {
1296     for (size_t i = 0; i < m_extensions.size(); ++i) {
1297         if (m_extensions[i].extension == extension)
1298             return true;
1299     }
1300
1301     return false;
1302 }
1303
1304 void V8Proxy::registerExtension(v8::Extension* extension, const String& schemeRestriction)
1305 {
1306     registerExtensionWithV8(extension);
1307     V8ExtensionInfo info = {schemeRestriction, 0, extension};
1308     m_extensions.append(info);
1309 }
1310
1311 void V8Proxy::registerExtension(v8::Extension* extension, int extensionGroup)
1312 {
1313     registerExtensionWithV8(extension);
1314     V8ExtensionInfo info = {String(), extensionGroup, extension};
1315     m_extensions.append(info);
1316 }
1317
1318 bool V8Proxy::setContextDebugId(int debugId)
1319 {
1320     ASSERT(debugId > 0);
1321     if (m_context.IsEmpty())
1322         return false;
1323     v8::HandleScope scope;
1324     if (!m_context->GetData()->IsUndefined())
1325         return false;
1326
1327     v8::Context::Scope contextScope(m_context);
1328     v8::Handle<v8::Object> contextData = v8::Object::New();
1329     contextData->Set(v8::String::New(kContextDebugDataType), v8::String::New("page"));
1330     contextData->Set(v8::String::New(kContextDebugDataValue), v8::Integer::New(debugId));
1331     m_context->SetData(contextData);
1332     return true;
1333 }
1334
1335 int V8Proxy::contextDebugId(v8::Handle<v8::Context> context)
1336 {
1337     v8::HandleScope scope;
1338     if (!context->GetData()->IsObject())
1339         return -1;
1340     v8::Handle<v8::Value> data = context->GetData()->ToObject()->Get( v8::String::New(kContextDebugDataValue));
1341     return data->IsInt32() ? data->Int32Value() : -1;
1342 }
1343
1344 v8::Handle<v8::Value> V8Proxy::getHiddenObjectPrototype(v8::Handle<v8::Context> context)
1345 {
1346     return context->Global()->GetHiddenValue(V8HiddenPropertyName::objectPrototype());
1347 }
1348
1349 void V8Proxy::installHiddenObjectPrototype(v8::Handle<v8::Context> context)
1350 {
1351     v8::Handle<v8::String> objectString = v8::String::New("Object");
1352     v8::Handle<v8::String> prototypeString = v8::String::New("prototype");
1353     v8::Handle<v8::String> hiddenObjectPrototypeString = V8HiddenPropertyName::objectPrototype();
1354     // Bail out if allocation failed.
1355     if (objectString.IsEmpty() || prototypeString.IsEmpty() || hiddenObjectPrototypeString.IsEmpty())
1356         return;
1357
1358     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(context->Global()->Get(objectString));
1359     v8::Handle<v8::Value> objectPrototype = object->Get(prototypeString);
1360
1361     context->Global()->SetHiddenValue(hiddenObjectPrototypeString, objectPrototype);
1362 }
1363
1364 v8::Local<v8::Context> toV8Context(ScriptExecutionContext* context)
1365 {
1366     if (context->isDocument()) {
1367         if (V8Proxy* proxy = V8Proxy::retrieve(context))
1368             return proxy->context();
1369     } else if (context->isWorkerContext()) {
1370         if (WorkerContextExecutionProxy* proxy = static_cast<WorkerContext*>(context)->script()->proxy())
1371             return proxy->context();
1372     }
1373     return v8::Local<v8::Context>();
1374 }
1375
1376 }  // namespace WebCore