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