defdb270a37d0a59560cab116ec7ffd68fd12a97
[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 #if ENABLE(INSPECTOR)
378     if (InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0)
379         timelineAgent->willEvaluateScript(source.url().isNull() ? String() : source.url().string(), source.startLine());
380 #endif
381
382     v8::Local<v8::Value> result;
383     {
384         // Isolate exceptions that occur when compiling and executing
385         // the code. These exceptions should not interfere with
386         // javascript code we might evaluate from C++ when returning
387         // from here.
388         v8::TryCatch tryCatch;
389         tryCatch.SetVerbose(true);
390
391         // Compile the script.
392         v8::Local<v8::String> code = v8ExternalString(source.source());
393         ChromiumBridge::traceEventBegin("v8.compile", node, "");
394
395         // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at
396         // 1, whereas v8 starts at 0.
397         v8::Handle<v8::Script> script = compileScript(code, source.url(), source.startLine() - 1);
398         ChromiumBridge::traceEventEnd("v8.compile", node, "");
399
400         ChromiumBridge::traceEventBegin("v8.run", node, "");
401         // Set inlineCode to true for <a href="javascript:doSomething()">
402         // and false for <script>doSomething</script>. We make a rough guess at
403         // this based on whether the script source has a URL.
404         result = runScript(script, source.url().string().isNull());
405     }
406     ChromiumBridge::traceEventEnd("v8.run", node, "");
407
408 #if ENABLE(INSPECTOR)
409     if (InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0)
410         timelineAgent->didEvaluateScript();
411 #endif
412
413     return result;
414 }
415
416 v8::Local<v8::Value> V8Proxy::runScript(v8::Handle<v8::Script> script, bool isInlineCode)
417 {
418     if (script.IsEmpty())
419         return notHandledByInterceptor();
420
421     // Compute the source string and prevent against infinite recursion.
422     if (m_recursion >= kMaxRecursionDepth) {
423         v8::Local<v8::String> code = v8ExternalString("throw RangeError('Recursion too deep')");
424         // FIXME: Ideally, we should be able to re-use the origin of the
425         // script passed to us as the argument instead of using an empty string
426         // and 0 baseLine.
427         script = compileScript(code, "", 0);
428     }
429
430     if (handleOutOfMemory())
431         ASSERT(script.IsEmpty());
432
433     if (script.IsEmpty())
434         return notHandledByInterceptor();
435
436     // Save the previous value of the inlineCode flag and update the flag for
437     // the duration of the script invocation.
438     bool previousInlineCode = inlineCode();
439     setInlineCode(isInlineCode);
440
441     // Run the script and keep track of the current recursion depth.
442     v8::Local<v8::Value> result;
443     {
444         V8ConsoleMessage::Scope scope;
445
446         // See comment in V8Proxy::callFunction.
447         m_frame->keepAlive();
448
449         m_recursion++;
450         result = script->Run();
451         m_recursion--;
452     }
453
454     // Release the storage mutex if applicable.
455     releaseStorageMutex();
456
457     if (handleOutOfMemory())
458         ASSERT(result.IsEmpty());
459
460     // Handle V8 internal error situation (Out-of-memory).
461     if (result.IsEmpty())
462         return notHandledByInterceptor();
463
464     // Restore inlineCode flag.
465     setInlineCode(previousInlineCode);
466
467     if (v8::V8::IsDead())
468         handleFatalErrorInV8();
469
470     return result;
471 }
472
473 v8::Local<v8::Value> V8Proxy::callFunction(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[])
474 {
475     v8::Local<v8::Value> result;
476     {
477         V8ConsoleMessage::Scope scope;
478
479         if (m_recursion >= kMaxRecursionDepth) {
480             v8::Local<v8::String> code = v8::String::New("throw new RangeError('Maximum call stack size exceeded.')");
481             if (code.IsEmpty())
482                 return result;
483             v8::Local<v8::Script> script = v8::Script::Compile(code);
484             if (script.IsEmpty())
485                 return result;
486             script->Run();
487             return result;
488         }
489
490         // Evaluating the JavaScript could cause the frame to be deallocated,
491         // so we start the keep alive timer here.
492         // Frame::keepAlive method adds the ref count of the frame and sets a
493         // timer to decrease the ref count. It assumes that the current JavaScript
494         // execution finishs before firing the timer.
495         m_frame->keepAlive();
496
497         m_recursion++;
498         result = function->Call(receiver, argc, args);
499         m_recursion--;
500     }
501
502     // Release the storage mutex if applicable.
503     releaseStorageMutex();
504
505     if (v8::V8::IsDead())
506         handleFatalErrorInV8();
507
508     return result;
509 }
510
511 v8::Local<v8::Value> V8Proxy::newInstance(v8::Handle<v8::Function> constructor, int argc, v8::Handle<v8::Value> args[])
512 {
513     // No artificial limitations on the depth of recursion, see comment in
514     // V8Proxy::callFunction.
515     v8::Local<v8::Value> result;
516     {
517         V8ConsoleMessage::Scope scope;
518
519         // See comment in V8Proxy::callFunction.
520         m_frame->keepAlive();
521
522         result = constructor->NewInstance(argc, args);
523     }
524
525     if (v8::V8::IsDead())
526         handleFatalErrorInV8();
527
528     return result;
529 }
530
531 v8::Local<v8::Object> V8Proxy::createWrapperFromCacheSlowCase(V8ClassIndex::V8WrapperType type)
532 {
533     // Not in cache.
534     int classIndex = V8ClassIndex::ToInt(type);
535     initContextIfNeeded();
536     v8::Context::Scope scope(m_context);
537     v8::Local<v8::Function> function = V8DOMWrapper::getConstructor(type, getHiddenObjectPrototype(m_context));
538     v8::Local<v8::Object> instance = SafeAllocation::newInstance(function);
539     if (!instance.IsEmpty()) {
540         m_wrapperBoilerplates->Set(v8::Integer::New(classIndex), instance);
541         return instance->Clone();
542     }
543     return notHandledByInterceptor();
544 }
545
546 bool V8Proxy::isContextInitialized()
547 {
548     // m_context, m_global, and m_wrapperBoilerplates should
549     // all be non-empty if if m_context is non-empty.
550     ASSERT(m_context.IsEmpty() || !m_global.IsEmpty());
551     ASSERT(m_context.IsEmpty() || !m_wrapperBoilerplates.IsEmpty());
552     return !m_context.IsEmpty();
553 }
554
555 DOMWindow* V8Proxy::retrieveWindow(v8::Handle<v8::Context> context)
556 {
557     v8::Handle<v8::Object> global = context->Global();
558     ASSERT(!global.IsEmpty());
559     global = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, global);
560     ASSERT(!global.IsEmpty());
561     return V8DOMWrapper::convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, global);
562 }
563
564 Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context)
565 {
566     DOMWindow* window = retrieveWindow(context);
567     Frame* frame = window->frame();
568     if (frame && frame->domWindow() == window)
569         return frame;
570     // We return 0 here because |context| is detached from the Frame.  If we
571     // did return |frame| we could get in trouble because the frame could be
572     // navigated to another security origin.
573     return 0;
574 }
575
576 Frame* V8Proxy::retrieveFrameForEnteredContext()
577 {
578     v8::Handle<v8::Context> context = v8::Context::GetEntered();
579     if (context.IsEmpty())
580         return 0;
581     return retrieveFrame(context);
582 }
583
584 Frame* V8Proxy::retrieveFrameForCurrentContext()
585 {
586     v8::Handle<v8::Context> context = v8::Context::GetCurrent();
587     if (context.IsEmpty())
588         return 0;
589     return retrieveFrame(context);
590 }
591
592 Frame* V8Proxy::retrieveFrameForCallingContext()
593 {
594     v8::Handle<v8::Context> context = v8::Context::GetCalling();
595     if (context.IsEmpty())
596         return 0;
597     return retrieveFrame(context);
598 }
599
600 V8Proxy* V8Proxy::retrieve()
601 {
602     DOMWindow* window = retrieveWindow(currentContext());
603     ASSERT(window);
604     return retrieve(window->frame());
605 }
606
607 V8Proxy* V8Proxy::retrieve(Frame* frame)
608 {
609     if (!frame)
610         return 0;
611     return frame->script()->isEnabled() ? frame->script()->proxy() : 0;
612 }
613
614 V8Proxy* V8Proxy::retrieve(ScriptExecutionContext* context)
615 {
616     if (!context->isDocument())
617         return 0;
618     return retrieve(static_cast<Document*>(context)->frame());
619 }
620
621 void V8Proxy::disconnectFrame()
622 {
623 }
624
625 void V8Proxy::updateDocumentWrapper(v8::Handle<v8::Value> wrapper)
626 {
627     clearDocumentWrapper();
628
629     ASSERT(m_document.IsEmpty());
630     m_document = v8::Persistent<v8::Value>::New(wrapper);
631 #ifndef NDEBUG
632     V8GCController::registerGlobalHandle(PROXY, this, m_document);
633 #endif
634 }
635
636 void V8Proxy::clearDocumentWrapper()
637 {
638     if (!m_document.IsEmpty()) {
639 #ifndef NDEBUG
640         V8GCController::unregisterGlobalHandle(this, m_document);
641 #endif
642         m_document.Dispose();
643         m_document.Clear();
644     }
645 }
646
647 void V8Proxy::updateDocumentWrapperCache()
648 {
649     v8::HandleScope handleScope;
650     v8::Context::Scope contextScope(m_context);
651
652     // If the document has no frame, NodeToV8Object might get the
653     // document wrapper for a document that is about to be deleted.
654     // If the ForceSet below causes a garbage collection, the document
655     // might get deleted and the global handle for the document
656     // wrapper cleared. Using the cleared global handle will lead to
657     // crashes. In this case we clear the cache and let the DOMWindow
658     // accessor handle access to the document.
659     if (!m_frame->document()->frame()) {
660         clearDocumentWrapperCache();
661         return;
662     }
663
664     v8::Handle<v8::Value> documentWrapper = V8DOMWrapper::convertNodeToV8Object(m_frame->document());
665
666     // If instantiation of the document wrapper fails, clear the cache
667     // and let the DOMWindow accessor handle access to the document.
668     if (documentWrapper.IsEmpty()) {
669         clearDocumentWrapperCache();
670         return;
671     }
672     m_context->Global()->ForceSet(v8::String::New("document"), documentWrapper, static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
673 }
674
675 void V8Proxy::clearDocumentWrapperCache()
676 {
677     ASSERT(!m_context.IsEmpty());
678     m_context->Global()->ForceDelete(v8::String::New("document"));
679 }
680
681 void V8Proxy::disposeContextHandles()
682 {
683     if (!m_context.IsEmpty()) {
684         m_frame->loader()->client()->didDestroyScriptContextForFrame();
685         m_context.Dispose();
686         m_context.Clear();
687     }
688
689     if (!m_wrapperBoilerplates.IsEmpty()) {
690 #ifndef NDEBUG
691         V8GCController::unregisterGlobalHandle(this, m_wrapperBoilerplates);
692 #endif
693         m_wrapperBoilerplates.Dispose();
694         m_wrapperBoilerplates.Clear();
695     }
696 }
697
698 void V8Proxy::releaseStorageMutex()
699 {
700     // If we've just left a top level script context and local storage has been
701     // instantiated, we must ensure that any storage locks have been freed.
702     // Per http://dev.w3.org/html5/spec/Overview.html#storage-mutex
703     if (m_recursion != 0)
704         return;
705     Page* page = m_frame->page();
706     if (!page)
707         return;
708     if (page->group().hasLocalStorage())
709         page->group().localStorage()->unlock();
710 }
711
712 void V8Proxy::resetIsolatedWorlds()
713 {
714     for (IsolatedWorldMap::iterator iter = m_isolatedWorlds.begin();
715          iter != m_isolatedWorlds.end(); ++iter) {
716         iter->second->destroy();
717     }
718     m_isolatedWorlds.clear();
719 }
720
721 void V8Proxy::clearForClose()
722 {
723     resetIsolatedWorlds();
724
725     if (!m_context.IsEmpty()) {
726         v8::HandleScope handleScope;
727
728         clearDocumentWrapper();
729         disposeContextHandles();
730     }
731 }
732
733 void V8Proxy::clearForNavigation()
734 {
735     resetIsolatedWorlds();
736
737     if (!m_context.IsEmpty()) {
738         v8::HandleScope handle;
739         clearDocumentWrapper();
740
741         v8::Context::Scope contextScope(m_context);
742
743         // Clear the document wrapper cache before turning on access checks on
744         // the old DOMWindow wrapper. This way, access to the document wrapper
745         // will be protected by the security checks on the DOMWindow wrapper.
746         clearDocumentWrapperCache();
747
748         // Turn on access check on the old DOMWindow wrapper.
749         v8::Handle<v8::Object> wrapper = V8DOMWrapper::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, m_global);
750         ASSERT(!wrapper.IsEmpty());
751         wrapper->TurnOnAccessCheck();
752
753         // Separate the context from its global object.
754         m_context->DetachGlobal();
755
756         disposeContextHandles();
757     }
758 }
759
760 void V8Proxy::setSecurityToken()
761 {
762     Document* document = m_frame->document();
763     // Setup security origin and security token.
764     if (!document) {
765         m_context->UseDefaultSecurityToken();
766         return;
767     }
768
769     // Ask the document's SecurityOrigin to generate a security token.
770     // If two tokens are equal, then the SecurityOrigins canAccess each other.
771     // If two tokens are not equal, then we have to call canAccess.
772     // Note: we can't use the HTTPOrigin if it was set from the DOM.
773     SecurityOrigin* origin = document->securityOrigin();
774     String token;
775     if (!origin->domainWasSetInDOM())
776         token = document->securityOrigin()->toString();
777
778     // An empty or "null" token means we always have to call
779     // canAccess. The toString method on securityOrigins returns the
780     // string "null" for empty security origins and for security
781     // origins that should only allow access to themselves. In this
782     // case, we use the global object as the security token to avoid
783     // calling canAccess when a script accesses its own objects.
784     if (token.isEmpty() || token == "null") {
785         m_context->UseDefaultSecurityToken();
786         return;
787     }
788
789     CString utf8Token = token.utf8();
790     // NOTE: V8 does identity comparison in fast path, must use a symbol
791     // as the security token.
792     m_context->SetSecurityToken(v8::String::NewSymbol(utf8Token.data(), utf8Token.length()));
793 }
794
795 void V8Proxy::updateDocument()
796 {
797     if (!m_frame->document())
798         return;
799
800     if (m_global.IsEmpty())
801         return;
802
803     // There is an existing JavaScript wrapper for the global object
804     // of this frame. JavaScript code in other frames might hold a
805     // reference to this wrapper. We eagerly initialize the JavaScript
806     // context for the new document to make property access on the
807     // global object wrapper succeed.
808     initContextIfNeeded();
809
810     // Bail out if context initialization failed.
811     if (m_context.IsEmpty())
812         return;
813
814     // We have a new document and we need to update the cache.
815     updateDocumentWrapperCache();
816
817     updateSecurityOrigin();
818 }
819
820 void V8Proxy::updateSecurityOrigin()
821 {
822     v8::HandleScope scope;
823     setSecurityToken();
824 }
825
826 // Same origin policy implementation:
827 //
828 // Same origin policy prevents JS code from domain A access JS & DOM objects
829 // in a different domain B. There are exceptions and several objects are
830 // accessible by cross-domain code. For example, the window.frames object is
831 // accessible by code from a different domain, but window.document is not.
832 //
833 // The binding code sets security check callbacks on a function template,
834 // and accessing instances of the template calls the callback function.
835 // The callback function checks same origin policy.
836 //
837 // Callback functions are expensive. V8 uses a security token string to do
838 // fast access checks for the common case where source and target are in the
839 // same domain. A security token is a string object that represents
840 // the protocol/url/port of a domain.
841 //
842 // There are special cases where a security token matching is not enough.
843 // For example, JavaScript can set its domain to a super domain by calling
844 // document.setDomain(...). In these cases, the binding code can reset
845 // a context's security token to its global object so that the fast access
846 // check will always fail.
847
848 // Check if the current execution context can access a target frame.
849 // First it checks same domain policy using the lexical context
850 //
851 // This is equivalent to KJS::Window::allowsAccessFrom(ExecState*, String&).
852 bool V8Proxy::canAccessPrivate(DOMWindow* targetWindow)
853 {
854     ASSERT(targetWindow);
855
856     String message;
857
858     DOMWindow* originWindow = retrieveWindow(currentContext());
859     if (originWindow == targetWindow)
860         return true;
861
862     if (!originWindow)
863         return false;
864
865     const SecurityOrigin* activeSecurityOrigin = originWindow->securityOrigin();
866     const SecurityOrigin* targetSecurityOrigin = targetWindow->securityOrigin();
867
868     // We have seen crashes were the security origin of the target has not been
869     // initialized. Defend against that.
870     if (!targetSecurityOrigin)
871         return false;
872
873     if (activeSecurityOrigin->canAccess(targetSecurityOrigin))
874         return true;
875
876     // Allow access to a "about:blank" page if the dynamic context is a
877     // detached context of the same frame as the blank page.
878     if (targetSecurityOrigin->isEmpty() && originWindow->frame() == targetWindow->frame())
879         return true;
880
881     return false;
882 }
883
884 bool V8Proxy::canAccessFrame(Frame* target, bool reportError)
885 {
886     // The subject is detached from a frame, deny accesses.
887     if (!target)
888         return false;
889
890     if (!canAccessPrivate(target->domWindow())) {
891         if (reportError)
892             reportUnsafeAccessTo(target, ReportNow);
893         return false;
894     }
895     return true;
896 }
897
898 bool V8Proxy::checkNodeSecurity(Node* node)
899 {
900     if (!node)
901         return false;
902
903     Frame* target = node->document()->frame();
904
905     if (!target)
906         return false;
907
908     return canAccessFrame(target, true);
909 }
910
911 v8::Persistent<v8::Context> V8Proxy::createNewContext(v8::Handle<v8::Object> global, int extensionGroup)
912 {
913     v8::Persistent<v8::Context> result;
914
915     // The activeDocumentLoader pointer could be NULL during frame shutdown.
916     if (!m_frame->loader()->activeDocumentLoader())
917         return result;
918
919     // Create a new environment using an empty template for the shadow
920     // object. Reuse the global object if one has been created earlier.
921     v8::Persistent<v8::ObjectTemplate> globalTemplate = V8DOMWindow::GetShadowObjectTemplate();
922     if (globalTemplate.IsEmpty())
923         return result;
924
925     // Install a security handler with V8.
926     globalTemplate->SetAccessCheckCallbacks(V8Custom::v8DOMWindowNamedSecurityCheck, V8Custom::v8DOMWindowIndexedSecurityCheck, v8::Integer::New(V8ClassIndex::DOMWINDOW));
927     globalTemplate->SetInternalFieldCount(V8Custom::kDOMWindowInternalFieldCount);
928
929     // Used to avoid sleep calls in unload handlers.
930     if (!registeredExtensionWithV8(DateExtension::get()))
931         registerExtension(DateExtension::get(), String());
932
933     // Dynamically tell v8 about our extensions now.
934     OwnArrayPtr<const char*> extensionNames(new const char*[m_extensions.size()]);
935     int index = 0;
936     for (size_t i = 0; i < m_extensions.size(); ++i) {
937         if (m_extensions[i].group && m_extensions[i].group != extensionGroup)
938             continue;
939
940         // Note: we check the loader URL here instead of the document URL
941         // because we might be currently loading an URL into a blank page.
942         // See http://code.google.com/p/chromium/issues/detail?id=10924
943         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()))
944             continue;
945
946         extensionNames[index++] = m_extensions[i].extension->name();
947     }
948     v8::ExtensionConfiguration extensions(index, extensionNames.get());
949     result = v8::Context::New(&extensions, globalTemplate, global);
950
951     return result;
952 }
953
954 bool V8Proxy::installDOMWindow(v8::Handle<v8::Context> context, DOMWindow* window)
955 {
956     v8::Handle<v8::String> implicitProtoString = v8::String::New("__proto__");
957     if (implicitProtoString.IsEmpty())
958         return false;
959
960     // Create a new JS window object and use it as the prototype for the  shadow global object.
961     v8::Handle<v8::Function> windowConstructor = V8DOMWrapper::getConstructor(V8ClassIndex::DOMWINDOW, getHiddenObjectPrototype(context));
962     v8::Local<v8::Object> jsWindow = SafeAllocation::newInstance(windowConstructor);
963     // Bail out if allocation failed.
964     if (jsWindow.IsEmpty())
965         return false;
966
967     // Wrap the window.
968     V8DOMWrapper::setDOMWrapper(jsWindow, V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), window);
969     V8DOMWrapper::setDOMWrapper(v8::Handle<v8::Object>::Cast(jsWindow->GetPrototype()), V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), window);
970
971     window->ref();
972     V8DOMWrapper::setJSWrapperForDOMObject(window, v8::Persistent<v8::Object>::New(jsWindow));
973
974     // Insert the window instance as the prototype of the shadow object.
975     v8::Handle<v8::Object> v8Global = context->Global();
976     V8DOMWrapper::setDOMWrapper(v8::Handle<v8::Object>::Cast(v8Global->GetPrototype()), V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), window);
977     v8Global->Set(implicitProtoString, jsWindow);
978     return true;
979 }
980
981 // Create a new environment and setup the global object.
982 //
983 // The global object corresponds to a DOMWindow instance. However, to
984 // allow properties of the JS DOMWindow instance to be shadowed, we
985 // use a shadow object as the global object and use the JS DOMWindow
986 // instance as the prototype for that shadow object. The JS DOMWindow
987 // instance is undetectable from javascript code because the __proto__
988 // accessors skip that object.
989 //
990 // The shadow object and the DOMWindow instance are seen as one object
991 // from javascript. The javascript object that corresponds to a
992 // DOMWindow instance is the shadow object. When mapping a DOMWindow
993 // instance to a V8 object, we return the shadow object.
994 //
995 // To implement split-window, see
996 //   1) https://bugs.webkit.org/show_bug.cgi?id=17249
997 //   2) https://wiki.mozilla.org/Gecko:SplitWindow
998 //   3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639
999 // we need to split the shadow object further into two objects:
1000 // an outer window and an inner window. The inner window is the hidden
1001 // prototype of the outer window. The inner window is the default
1002 // global object of the context. A variable declared in the global
1003 // scope is a property of the inner window.
1004 //
1005 // The outer window sticks to a Frame, it is exposed to JavaScript
1006 // via window.window, window.self, window.parent, etc. The outer window
1007 // has a security token which is the domain. The outer window cannot
1008 // have its own properties. window.foo = 'x' is delegated to the
1009 // inner window.
1010 //
1011 // When a frame navigates to a new page, the inner window is cut off
1012 // the outer window, and the outer window identify is preserved for
1013 // the frame. However, a new inner window is created for the new page.
1014 // If there are JS code holds a closure to the old inner window,
1015 // it won't be able to reach the outer window via its global object.
1016 void V8Proxy::initContextIfNeeded()
1017 {
1018     // Bail out if the context has already been initialized.
1019     if (!m_context.IsEmpty())
1020         return;
1021
1022     // Create a handle scope for all local handles.
1023     v8::HandleScope handleScope;
1024
1025     // Setup the security handlers and message listener. This only has
1026     // to be done once.
1027     static bool isV8Initialized = false;
1028     if (!isV8Initialized) {
1029         // Tells V8 not to call the default OOM handler, binding code
1030         // will handle it.
1031         v8::V8::IgnoreOutOfMemoryException();
1032         v8::V8::SetFatalErrorHandler(reportFatalErrorInV8);
1033
1034         v8::V8::SetGlobalGCPrologueCallback(&V8GCController::gcPrologue);
1035         v8::V8::SetGlobalGCEpilogueCallback(&V8GCController::gcEpilogue);
1036
1037         v8::V8::AddMessageListener(&V8ConsoleMessage::handler);
1038
1039         v8::V8::SetFailedAccessCheckCallbackFunction(reportUnsafeJavaScriptAccess);
1040
1041         isV8Initialized = true;
1042     }
1043
1044
1045     m_context = createNewContext(m_global, 0);
1046     if (m_context.IsEmpty())
1047         return;
1048
1049     v8::Local<v8::Context> v8Context = v8::Local<v8::Context>::New(m_context);
1050     v8::Context::Scope contextScope(v8Context);
1051
1052     // Store the first global object created so we can reuse it.
1053     if (m_global.IsEmpty()) {
1054         m_global = v8::Persistent<v8::Object>::New(v8Context->Global());
1055         // Bail out if allocation of the first global objects fails.
1056         if (m_global.IsEmpty()) {
1057             disposeContextHandles();
1058             return;
1059         }
1060 #ifndef NDEBUG
1061         V8GCController::registerGlobalHandle(PROXY, this, m_global);
1062 #endif
1063     }
1064
1065     installHiddenObjectPrototype(v8Context);
1066     m_wrapperBoilerplates = v8::Persistent<v8::Array>::New(v8::Array::New(V8ClassIndex::WRAPPER_TYPE_COUNT));
1067     // Bail out if allocation failed.
1068     if (m_wrapperBoilerplates.IsEmpty()) {
1069         disposeContextHandles();
1070         return;
1071     }
1072 #ifndef NDEBUG
1073     V8GCController::registerGlobalHandle(PROXY, this, m_wrapperBoilerplates);
1074 #endif
1075
1076     if (!installDOMWindow(v8Context, m_frame->domWindow()))
1077         disposeContextHandles();
1078
1079     updateDocument();
1080
1081     setSecurityToken();
1082
1083     m_frame->loader()->client()->didCreateScriptContextForFrame();
1084     m_frame->loader()->dispatchWindowObjectAvailable();
1085 }
1086
1087 void V8Proxy::setDOMException(int exceptionCode)
1088 {
1089     if (exceptionCode <= 0)
1090         return;
1091
1092     ExceptionCodeDescription description;
1093     getExceptionCodeDescription(exceptionCode, description);
1094
1095     v8::Handle<v8::Value> exception;
1096     switch (description.type) {
1097     case DOMExceptionType:
1098         exception = V8DOMWrapper::convertToV8Object(V8ClassIndex::DOMCOREEXCEPTION, DOMCoreException::create(description));
1099         break;
1100     case RangeExceptionType:
1101         exception = V8DOMWrapper::convertToV8Object(V8ClassIndex::RANGEEXCEPTION, RangeException::create(description));
1102         break;
1103     case EventExceptionType:
1104         exception = V8DOMWrapper::convertToV8Object(V8ClassIndex::EVENTEXCEPTION, EventException::create(description));
1105         break;
1106     case XMLHttpRequestExceptionType:
1107         exception = V8DOMWrapper::convertToV8Object(V8ClassIndex::XMLHTTPREQUESTEXCEPTION, XMLHttpRequestException::create(description));
1108         break;
1109 #if ENABLE(SVG)
1110     case SVGExceptionType:
1111         exception = V8DOMWrapper::convertToV8Object(V8ClassIndex::SVGEXCEPTION, SVGException::create(description));
1112         break;
1113 #endif
1114 #if ENABLE(XPATH)
1115     case XPathExceptionType:
1116         exception = V8DOMWrapper::convertToV8Object(V8ClassIndex::XPATHEXCEPTION, XPathException::create(description));
1117         break;
1118 #endif
1119     }
1120
1121     ASSERT(!exception.IsEmpty());
1122     v8::ThrowException(exception);
1123 }
1124
1125 v8::Handle<v8::Value> V8Proxy::throwError(ErrorType type, const char* message)
1126 {
1127     switch (type) {
1128     case RangeError:
1129         return v8::ThrowException(v8::Exception::RangeError(v8String(message)));
1130     case ReferenceError:
1131         return v8::ThrowException(v8::Exception::ReferenceError(v8String(message)));
1132     case SyntaxError:
1133         return v8::ThrowException(v8::Exception::SyntaxError(v8String(message)));
1134     case TypeError:
1135         return v8::ThrowException(v8::Exception::TypeError(v8String(message)));
1136     case GeneralError:
1137         return v8::ThrowException(v8::Exception::Error(v8String(message)));
1138     default:
1139         ASSERT_NOT_REACHED();
1140         return notHandledByInterceptor();
1141     }
1142 }
1143
1144 v8::Local<v8::Context> V8Proxy::context(Frame* frame)
1145 {
1146     v8::Local<v8::Context> context = V8Proxy::mainWorldContext(frame);
1147     if (context.IsEmpty())
1148         return v8::Local<v8::Context>();
1149
1150     if (V8IsolatedWorld* world = V8IsolatedWorld::getEntered()) {
1151         context = v8::Local<v8::Context>::New(world->context());
1152         if (frame != V8Proxy::retrieveFrame(context))
1153             return v8::Local<v8::Context>();
1154     }
1155
1156     return context;
1157 }
1158
1159 v8::Local<v8::Context> V8Proxy::context()
1160 {
1161     if (V8IsolatedWorld* world = V8IsolatedWorld::getEntered()) {
1162         RefPtr<SharedPersistent<v8::Context> > context = world->sharedContext();
1163         if (m_frame != V8Proxy::retrieveFrame(context->get()))
1164             return v8::Local<v8::Context>();
1165         return v8::Local<v8::Context>::New(context->get());
1166     }
1167     initContextIfNeeded();
1168     return v8::Local<v8::Context>::New(m_context);;
1169 }
1170
1171 v8::Local<v8::Context> V8Proxy::mainWorldContext(Frame* frame)
1172 {
1173     V8Proxy* proxy = retrieve(frame);
1174     if (!proxy)
1175         return v8::Local<v8::Context>();
1176
1177     proxy->initContextIfNeeded();
1178     return v8::Local<v8::Context>::New(proxy->m_context);
1179 }
1180
1181 v8::Local<v8::Context> V8Proxy::currentContext()
1182 {
1183     return v8::Context::GetCurrent();
1184 }
1185
1186 v8::Handle<v8::Value> V8Proxy::checkNewLegal(const v8::Arguments& args)
1187 {
1188     if (!AllowAllocation::m_current)
1189         return throwError(TypeError, "Illegal constructor");
1190
1191     return args.This();
1192 }
1193
1194 void V8Proxy::bindJsObjectToWindow(Frame* frame, const char* name, int type, v8::Handle<v8::FunctionTemplate> descriptor, void* impl)
1195 {
1196     // Get environment.
1197     v8::Handle<v8::Context> v8Context = V8Proxy::mainWorldContext(frame);
1198     if (v8Context.IsEmpty())
1199         return; // JS not enabled.
1200
1201     v8::Context::Scope scope(v8Context);
1202     v8::Handle<v8::Object> instance = descriptor->GetFunction();
1203     V8DOMWrapper::setDOMWrapper(instance, type, impl);
1204
1205     v8::Handle<v8::Object> global = v8Context->Global();
1206     global->Set(v8::String::New(name), instance);
1207 }
1208
1209 void V8Proxy::processConsoleMessages()
1210 {
1211     V8ConsoleMessage::processDelayed();
1212 }
1213
1214 // Create the utility context for holding JavaScript functions used internally
1215 // which are not visible to JavaScript executing on the page.
1216 void V8Proxy::createUtilityContext()
1217 {
1218     ASSERT(m_utilityContext.IsEmpty());
1219
1220     v8::HandleScope scope;
1221     v8::Handle<v8::ObjectTemplate> globalTemplate = v8::ObjectTemplate::New();
1222     m_utilityContext = v8::Context::New(0, globalTemplate);
1223     v8::Context::Scope contextScope(m_utilityContext);
1224
1225     // Compile JavaScript function for retrieving the source line of the top
1226     // JavaScript stack frame.
1227     DEFINE_STATIC_LOCAL(const char*, frameSourceLineSource,
1228         ("function frameSourceLine(exec_state) {"
1229         "  return exec_state.frame(0).sourceLine();"
1230         "}"));
1231     v8::Script::Compile(v8::String::New(frameSourceLineSource))->Run();
1232
1233     // Compile JavaScript function for retrieving the source name of the top
1234     // JavaScript stack frame.
1235     DEFINE_STATIC_LOCAL(const char*, frameSourceNameSource,
1236         ("function frameSourceName(exec_state) {"
1237         "  var frame = exec_state.frame(0);"
1238         "  if (frame.func().resolved() && "
1239         "      frame.func().script() && "
1240         "      frame.func().script().name()) {"
1241         "    return frame.func().script().name();"
1242         "  }"
1243         "}"));
1244     v8::Script::Compile(v8::String::New(frameSourceNameSource))->Run();
1245 }
1246
1247 bool V8Proxy::sourceLineNumber(int& result)
1248 {
1249     v8::HandleScope scope;
1250     v8::Handle<v8::Context> v8UtilityContext = V8Proxy::utilityContext();
1251     if (v8UtilityContext.IsEmpty())
1252         return false;
1253     v8::Context::Scope contextScope(v8UtilityContext);
1254     v8::Handle<v8::Function> frameSourceLine;
1255     frameSourceLine = v8::Local<v8::Function>::Cast(v8UtilityContext->Global()->Get(v8::String::New("frameSourceLine")));
1256     if (frameSourceLine.IsEmpty())
1257         return false;
1258     v8::Handle<v8::Value> value = v8::Debug::Call(frameSourceLine);
1259     if (value.IsEmpty())
1260         return false;
1261     result = value->Int32Value();
1262     return true;
1263 }
1264
1265 bool V8Proxy::sourceName(String& result)
1266 {
1267     v8::HandleScope scope;
1268     v8::Handle<v8::Context> v8UtilityContext = utilityContext();
1269     if (v8UtilityContext.IsEmpty())
1270         return false;
1271     v8::Context::Scope contextScope(v8UtilityContext);
1272     v8::Handle<v8::Function> frameSourceName;
1273     frameSourceName = v8::Local<v8::Function>::Cast(v8UtilityContext->Global()->Get(v8::String::New("frameSourceName")));
1274     if (frameSourceName.IsEmpty())
1275         return false;
1276     v8::Handle<v8::Value> value = v8::Debug::Call(frameSourceName);
1277     if (value.IsEmpty())
1278         return false;
1279     result = toWebCoreString(value);
1280     return true;
1281 }
1282
1283 void V8Proxy::registerExtensionWithV8(v8::Extension* extension)
1284 {
1285     // If the extension exists in our list, it was already registered with V8.
1286     if (!registeredExtensionWithV8(extension))
1287         v8::RegisterExtension(extension);
1288 }
1289
1290 bool V8Proxy::registeredExtensionWithV8(v8::Extension* extension)
1291 {
1292     for (size_t i = 0; i < m_extensions.size(); ++i) {
1293         if (m_extensions[i].extension == extension)
1294             return true;
1295     }
1296
1297     return false;
1298 }
1299
1300 void V8Proxy::registerExtension(v8::Extension* extension, const String& schemeRestriction)
1301 {
1302     registerExtensionWithV8(extension);
1303     V8ExtensionInfo info = {schemeRestriction, 0, extension};
1304     m_extensions.append(info);
1305 }
1306
1307 void V8Proxy::registerExtension(v8::Extension* extension, int extensionGroup)
1308 {
1309     registerExtensionWithV8(extension);
1310     V8ExtensionInfo info = {String(), extensionGroup, extension};
1311     m_extensions.append(info);
1312 }
1313
1314 bool V8Proxy::setContextDebugId(int debugId)
1315 {
1316     ASSERT(debugId > 0);
1317     if (m_context.IsEmpty())
1318         return false;
1319     v8::HandleScope scope;
1320     if (!m_context->GetData()->IsUndefined())
1321         return false;
1322
1323     v8::Context::Scope contextScope(m_context);
1324     v8::Handle<v8::Object> contextData = v8::Object::New();
1325     contextData->Set(v8::String::New(kContextDebugDataType), v8::String::New("page"));
1326     contextData->Set(v8::String::New(kContextDebugDataValue), v8::Integer::New(debugId));
1327     m_context->SetData(contextData);
1328     return true;
1329 }
1330
1331 int V8Proxy::contextDebugId(v8::Handle<v8::Context> context)
1332 {
1333     v8::HandleScope scope;
1334     if (!context->GetData()->IsObject())
1335         return -1;
1336     v8::Handle<v8::Value> data = context->GetData()->ToObject()->Get( v8::String::New(kContextDebugDataValue));
1337     return data->IsInt32() ? data->Int32Value() : -1;
1338 }
1339
1340 v8::Handle<v8::Value> V8Proxy::getHiddenObjectPrototype(v8::Handle<v8::Context> context)
1341 {
1342     return context->Global()->GetHiddenValue(V8HiddenPropertyName::objectPrototype());
1343 }
1344
1345 void V8Proxy::installHiddenObjectPrototype(v8::Handle<v8::Context> context)
1346 {
1347     v8::Handle<v8::String> objectString = v8::String::New("Object");
1348     v8::Handle<v8::String> prototypeString = v8::String::New("prototype");
1349     v8::Handle<v8::String> hiddenObjectPrototypeString = V8HiddenPropertyName::objectPrototype();
1350     // Bail out if allocation failed.
1351     if (objectString.IsEmpty() || prototypeString.IsEmpty() || hiddenObjectPrototypeString.IsEmpty())
1352         return;
1353
1354     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(context->Global()->Get(objectString));
1355     v8::Handle<v8::Value> objectPrototype = object->Get(prototypeString);
1356
1357     context->Global()->SetHiddenValue(hiddenObjectPrototypeString, objectPrototype);
1358 }
1359
1360 v8::Local<v8::Context> toV8Context(ScriptExecutionContext* context)
1361 {
1362     if (context->isDocument()) {
1363         if (V8Proxy* proxy = V8Proxy::retrieve(context))
1364             return proxy->context();
1365     } else if (context->isWorkerContext()) {
1366         if (WorkerContextExecutionProxy* proxy = static_cast<WorkerContext*>(context)->script()->proxy())
1367             return proxy->context();
1368     }
1369     return v8::Local<v8::Context>();
1370 }
1371
1372 }  // namespace WebCore