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