2010-04-07 Sheriff Bot <webkit.review.bot@gmail.com>
[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 "CSSMutableStyleDeclaration.h"
35 #include "DateExtension.h"
36 #include "DocumentLoader.h"
37 #include "Frame.h"
38 #include "FrameLoaderClient.h"
39 #include "InspectorTimelineAgent.h"
40 #include "Page.h"
41 #include "PageGroup.h"
42 #include "PlatformBridge.h"
43 #include "SVGElement.h"
44 #include "ScriptController.h"
45 #include "Settings.h"
46 #include "StorageNamespace.h"
47 #include "V8Binding.h"
48 #include "V8BindingState.h"
49 #include "V8Collection.h"
50 #include "V8ConsoleMessage.h"
51 #include "V8DOMCoreException.h"
52 #include "V8DOMMap.h"
53 #include "V8DOMWindow.h"
54 #include "V8EventException.h"
55 #include "V8HiddenPropertyName.h"
56 #include "V8IsolatedContext.h"
57 #include "V8RangeException.h"
58 #include "V8XMLHttpRequestException.h"
59 #include "V8XPathException.h"
60 #include "WorkerContext.h"
61 #include "WorkerContextExecutionProxy.h"
62
63 #if ENABLE(SVG)
64 #include "V8SVGException.h"
65 #endif
66
67 #include <algorithm>
68 #include <stdio.h>
69 #include <utility>
70 #include <v8.h>
71 #include <v8-debug.h>
72 #include <wtf/Assertions.h>
73 #include <wtf/OwnArrayPtr.h>
74 #include <wtf/StdLibExtras.h>
75 #include <wtf/StringExtras.h>
76 #include <wtf/UnusedParam.h>
77
78 namespace WebCore {
79
80 v8::Persistent<v8::Context> V8Proxy::m_utilityContext;
81
82 // Static list of registered extensions
83 V8Extensions V8Proxy::m_extensions;
84
85 void batchConfigureAttributes(v8::Handle<v8::ObjectTemplate> instance, 
86                               v8::Handle<v8::ObjectTemplate> proto, 
87                               const BatchedAttribute* attributes, 
88                               size_t attributeCount)
89 {
90     for (size_t i = 0; i < attributeCount; ++i)
91         configureAttribute(instance, proto, attributes[i]);
92 }
93
94 void batchConfigureCallbacks(v8::Handle<v8::ObjectTemplate> proto, 
95                              v8::Handle<v8::Signature> signature, 
96                              v8::PropertyAttribute attributes,
97                              const BatchedCallback* callbacks,
98                              size_t callbackCount)
99 {
100     for (size_t i = 0; i < callbackCount; ++i) {
101         proto->Set(v8::String::New(callbacks[i].name),
102                    v8::FunctionTemplate::New(callbacks[i].callback, 
103                                              v8::Handle<v8::Value>(),
104                                              signature),
105                    attributes);
106     }
107 }
108
109 void batchConfigureConstants(v8::Handle<v8::FunctionTemplate> functionDescriptor,
110                              v8::Handle<v8::ObjectTemplate> proto,
111                              const BatchedConstant* constants,
112                              size_t constantCount)
113 {
114     for (size_t i = 0; i < constantCount; ++i) {
115         const BatchedConstant* constant = &constants[i];
116         functionDescriptor->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly);
117         proto->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly);
118     }
119 }
120
121 typedef HashMap<Node*, v8::Object*> DOMNodeMap;
122 typedef HashMap<void*, v8::Object*> DOMObjectMap;
123
124 #if ENABLE(SVG)
125 // Map of SVG objects with contexts to their contexts
126 static HashMap<void*, SVGElement*>& svgObjectToContextMap()
127 {
128     typedef HashMap<void*, SVGElement*> SvgObjectToContextMap;
129     DEFINE_STATIC_LOCAL(SvgObjectToContextMap, staticSvgObjectToContextMap, ());
130     return staticSvgObjectToContextMap;
131 }
132
133 void V8Proxy::setSVGContext(void* object, SVGElement* context)
134 {
135     if (!object)
136         return;
137
138     SVGElement* oldContext = svgObjectToContextMap().get(object);
139
140     if (oldContext == context)
141         return;
142
143     if (oldContext)
144         oldContext->deref();
145
146     if (context)
147         context->ref();
148
149     svgObjectToContextMap().set(object, context);
150 }
151
152 SVGElement* V8Proxy::svgContext(void* object)
153 {
154     return svgObjectToContextMap().get(object);
155 }
156
157 #endif
158
159 typedef HashMap<int, v8::FunctionTemplate*> FunctionTemplateMap;
160
161 bool AllowAllocation::m_current = false;
162
163 void logInfo(Frame* frame, const String& message, const String& url)
164 {
165     Page* page = frame->page();
166     if (!page)
167         return;
168     V8ConsoleMessage consoleMessage(message, url, 0);
169     consoleMessage.dispatchNow(page);
170 }
171
172 enum DelayReporting {
173     ReportLater,
174     ReportNow
175 };
176
177 void V8Proxy::reportUnsafeAccessTo(Frame* target, DelayReporting delay)
178 {
179     ASSERT(target);
180     Document* targetDocument = target->document();
181     if (!targetDocument)
182         return;
183
184     Frame* source = V8Proxy::retrieveFrameForEnteredContext();
185     if (!source || !source->document())
186         return; // Ignore error if the source document is gone.
187
188     Document* sourceDocument = source->document();
189
190     // FIXME: This error message should contain more specifics of why the same
191     // origin check has failed.
192     String str = String::format("Unsafe JavaScript attempt to access frame "
193                                 "with URL %s from frame with URL %s. "
194                                 "Domains, protocols and ports must match.\n",
195                                 targetDocument->url().string().utf8().data(),
196                                 sourceDocument->url().string().utf8().data());
197
198     // Build a console message with fake source ID and line number.
199     const String kSourceID = "";
200     const int kLineNumber = 1;
201     V8ConsoleMessage message(str, kSourceID, kLineNumber);
202
203     if (delay == ReportNow) {
204         // NOTE: Safari prints the message in the target page, but it seems like
205         // it should be in the source page. Even for delayed messages, we put it in
206         // the source page; see V8ConsoleMessage::processDelayed().
207         message.dispatchNow(source->page());
208     } else {
209         ASSERT(delay == ReportLater);
210         // We cannot safely report the message eagerly, because this may cause
211         // allocations and GCs internally in V8 and we cannot handle that at this
212         // point. Therefore we delay the reporting.
213         message.dispatchLater();
214     }
215 }
216
217 static void handleFatalErrorInV8()
218 {
219     // FIXME: We temporarily deal with V8 internal error situations
220     // such as out-of-memory by crashing the renderer.
221     CRASH();
222 }
223
224 V8Proxy::V8Proxy(Frame* frame)
225     : m_frame(frame)
226     , m_windowShell(V8DOMWindowShell::create(frame))
227     , m_inlineCode(false)
228     , m_timerCallback(false)
229     , m_recursion(0)
230 {
231 }
232
233 V8Proxy::~V8Proxy()
234 {
235     clearForClose();
236     windowShell()->destroyGlobal();
237 }
238
239 v8::Handle<v8::Script> V8Proxy::compileScript(v8::Handle<v8::String> code, const String& fileName, int baseLine)
240 {
241     const uint16_t* fileNameString = fromWebCoreString(fileName);
242     v8::Handle<v8::String> name = v8::String::New(fileNameString, fileName.length());
243     v8::Handle<v8::Integer> line = v8::Integer::New(baseLine);
244     v8::ScriptOrigin origin(name, line);
245     v8::Handle<v8::Script> script = v8::Script::Compile(code, &origin);
246     return script;
247 }
248
249 bool V8Proxy::handleOutOfMemory()
250 {
251     v8::Local<v8::Context> context = v8::Context::GetCurrent();
252
253     if (!context->HasOutOfMemoryException())
254         return false;
255
256     // Warning, error, disable JS for this frame?
257     Frame* frame = V8Proxy::retrieveFrame(context);
258
259     V8Proxy* proxy = V8Proxy::retrieve(frame);
260     if (proxy) {
261         // Clean m_context, and event handlers.
262         proxy->clearForClose();
263
264         proxy->windowShell()->destroyGlobal();
265     }
266
267 #if PLATFORM(CHROMIUM)
268     PlatformBridge::notifyJSOutOfMemory(frame);
269 #endif
270
271     // Disable JS.
272     Settings* settings = frame->settings();
273     ASSERT(settings);
274     settings->setJavaScriptEnabled(false);
275
276     return true;
277 }
278
279 void V8Proxy::evaluateInIsolatedWorld(int worldID, const Vector<ScriptSourceCode>& sources, int extensionGroup)
280 {
281     // FIXME: This will need to get reorganized once we have a windowShell for the isolated world.
282     windowShell()->initContextIfNeeded();
283
284     v8::HandleScope handleScope;
285     V8IsolatedContext* isolatedContext = 0;
286
287     if (worldID > 0) {
288         IsolatedWorldMap::iterator iter = m_isolatedWorlds.find(worldID);
289         if (iter != m_isolatedWorlds.end()) {
290             isolatedContext = iter->second;
291         } else {
292             isolatedContext = new V8IsolatedContext(this, extensionGroup);
293             if (isolatedContext->context().IsEmpty()) {
294                 delete isolatedContext;
295                 return;
296             }
297
298             // FIXME: We should change this to using window shells to match JSC.
299             m_isolatedWorlds.set(worldID, isolatedContext);
300
301             // Setup context id for JS debugger.
302             if (!setInjectedScriptContextDebugId(isolatedContext->context())) {
303                 m_isolatedWorlds.take(worldID);
304                 delete isolatedContext;
305                 return;
306             }
307         }
308     } else {
309         isolatedContext = new V8IsolatedContext(this, extensionGroup);
310         if (isolatedContext->context().IsEmpty()) {
311             delete isolatedContext;
312             return;
313         }
314     }
315
316     v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolatedContext->context());
317     v8::Context::Scope context_scope(context);
318     for (size_t i = 0; i < sources.size(); ++i)
319       evaluate(sources[i], 0);
320
321     if (worldID == 0)
322       isolatedContext->destroy();
323 }
324
325 bool V8Proxy::setInjectedScriptContextDebugId(v8::Handle<v8::Context> targetContext)
326 {
327     // Setup context id for JS debugger.
328     v8::Context::Scope contextScope(targetContext);
329     v8::Handle<v8::Context> context = windowShell()->context();
330     if (context.IsEmpty())
331         return false;
332     int debugId = contextDebugId(context);
333
334     char buffer[32];
335     if (debugId == -1)
336         snprintf(buffer, sizeof(buffer), "injected");
337     else
338         snprintf(buffer, sizeof(buffer), "injected,%d", debugId);
339     targetContext->SetData(v8::String::New(buffer));
340
341     return true;
342 }
343
344 v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* node)
345 {
346     ASSERT(v8::Context::InContext());
347
348     V8GCController::checkMemoryUsage();
349
350 #if ENABLE(INSPECTOR)
351     if (InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0)
352         timelineAgent->willEvaluateScript(source.url().isNull() ? String() : source.url().string(), source.startLine());
353 #endif
354
355     v8::Local<v8::Value> result;
356     {
357         // Isolate exceptions that occur when compiling and executing
358         // the code. These exceptions should not interfere with
359         // javascript code we might evaluate from C++ when returning
360         // from here.
361         v8::TryCatch tryCatch;
362         tryCatch.SetVerbose(true);
363
364         // Compile the script.
365         v8::Local<v8::String> code = v8ExternalString(source.source());
366 #if PLATFORM(CHROMIUM)
367         PlatformBridge::traceEventBegin("v8.compile", node, "");
368 #endif
369
370         // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at
371         // 1, whereas v8 starts at 0.
372         v8::Handle<v8::Script> script = compileScript(code, source.url(), source.startLine() - 1);
373 #if PLATFORM(CHROMIUM)
374         PlatformBridge::traceEventEnd("v8.compile", node, "");
375
376         PlatformBridge::traceEventBegin("v8.run", node, "");
377 #endif
378         // Set inlineCode to true for <a href="javascript:doSomething()">
379         // and false for <script>doSomething</script>. We make a rough guess at
380         // this based on whether the script source has a URL.
381         result = runScript(script, source.url().string().isNull());
382     }
383 #if PLATFORM(CHROMIUM)
384     PlatformBridge::traceEventEnd("v8.run", node, "");
385 #endif
386
387 #if ENABLE(INSPECTOR)
388     if (InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0)
389         timelineAgent->didEvaluateScript();
390 #endif
391
392     return result;
393 }
394
395 v8::Local<v8::Value> V8Proxy::runScript(v8::Handle<v8::Script> script, bool isInlineCode)
396 {
397     if (script.IsEmpty())
398         return notHandledByInterceptor();
399
400     V8GCController::checkMemoryUsage();
401     // Compute the source string and prevent against infinite recursion.
402     if (m_recursion >= kMaxRecursionDepth) {
403         v8::Local<v8::String> code = v8ExternalString("throw RangeError('Recursion too deep')");
404         // FIXME: Ideally, we should be able to re-use the origin of the
405         // script passed to us as the argument instead of using an empty string
406         // and 0 baseLine.
407         script = compileScript(code, "", 0);
408     }
409
410     if (handleOutOfMemory())
411         ASSERT(script.IsEmpty());
412
413     if (script.IsEmpty())
414         return notHandledByInterceptor();
415
416     // Save the previous value of the inlineCode flag and update the flag for
417     // the duration of the script invocation.
418     bool previousInlineCode = inlineCode();
419     setInlineCode(isInlineCode);
420
421     // Run the script and keep track of the current recursion depth.
422     v8::Local<v8::Value> result;
423     {
424         V8ConsoleMessage::Scope scope;
425
426         // See comment in V8Proxy::callFunction.
427         m_frame->keepAlive();
428
429         m_recursion++;
430         result = script->Run();
431         m_recursion--;
432     }
433
434     // Release the storage mutex if applicable.
435     releaseStorageMutex();
436
437     if (handleOutOfMemory())
438         ASSERT(result.IsEmpty());
439
440     // Handle V8 internal error situation (Out-of-memory).
441     if (result.IsEmpty())
442         return notHandledByInterceptor();
443
444     // Restore inlineCode flag.
445     setInlineCode(previousInlineCode);
446
447     if (v8::V8::IsDead())
448         handleFatalErrorInV8();
449
450     return result;
451 }
452
453 v8::Local<v8::Value> V8Proxy::callFunction(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[])
454 {
455     V8GCController::checkMemoryUsage();
456     v8::Local<v8::Value> result;
457     {
458         V8ConsoleMessage::Scope scope;
459
460         if (m_recursion >= kMaxRecursionDepth) {
461             v8::Local<v8::String> code = v8::String::New("throw new RangeError('Maximum call stack size exceeded.')");
462             if (code.IsEmpty())
463                 return result;
464             v8::Local<v8::Script> script = v8::Script::Compile(code);
465             if (script.IsEmpty())
466                 return result;
467             script->Run();
468             return result;
469         }
470
471         // Evaluating the JavaScript could cause the frame to be deallocated,
472         // so we start the keep alive timer here.
473         // Frame::keepAlive method adds the ref count of the frame and sets a
474         // timer to decrease the ref count. It assumes that the current JavaScript
475         // execution finishs before firing the timer.
476         m_frame->keepAlive();
477
478 #if ENABLE(INSPECTOR)
479         Page* inspectedPage = InspectorTimelineAgent::instanceCount() ? m_frame->page(): 0;
480         if (inspectedPage)
481             if (InspectorTimelineAgent* timelineAgent = inspectedPage->inspectorTimelineAgent()) {
482                 v8::ScriptOrigin origin = function->GetScriptOrigin();
483                 String resourceName("undefined");
484                 int lineNumber = 1;
485                 if (!origin.ResourceName().IsEmpty()) {
486                     resourceName = toWebCoreString(origin.ResourceName());
487                     lineNumber = function->GetScriptLineNumber() + 1;
488                 }
489                 timelineAgent->willCallFunction(resourceName, lineNumber);
490             } else
491                 inspectedPage = 0;
492 #endif // !ENABLE(INSPECTOR)
493
494         m_recursion++;
495         result = function->Call(receiver, argc, args);
496         m_recursion--;
497
498 #if ENABLE(INSPECTOR)
499         if (inspectedPage)
500             if (InspectorTimelineAgent* timelineAgent = inspectedPage->inspectorTimelineAgent())
501                 timelineAgent->didCallFunction();
502 #endif // !ENABLE(INSPECTOR)
503
504     }
505
506     // Release the storage mutex if applicable.
507     releaseStorageMutex();
508
509     if (v8::V8::IsDead())
510         handleFatalErrorInV8();
511
512     return result;
513 }
514
515 v8::Local<v8::Value> V8Proxy::newInstance(v8::Handle<v8::Function> constructor, int argc, v8::Handle<v8::Value> args[])
516 {
517     // No artificial limitations on the depth of recursion, see comment in
518     // V8Proxy::callFunction.
519     v8::Local<v8::Value> result;
520     {
521         V8ConsoleMessage::Scope scope;
522
523         // See comment in V8Proxy::callFunction.
524         m_frame->keepAlive();
525
526         result = constructor->NewInstance(argc, args);
527     }
528
529     if (v8::V8::IsDead())
530         handleFatalErrorInV8();
531
532     return result;
533 }
534
535 DOMWindow* V8Proxy::retrieveWindow(v8::Handle<v8::Context> context)
536 {
537     v8::Handle<v8::Object> global = context->Global();
538     ASSERT(!global.IsEmpty());
539     global = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), global);
540     ASSERT(!global.IsEmpty());
541     return V8DOMWindow::toNative(global);
542 }
543
544 Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context)
545 {
546     DOMWindow* window = retrieveWindow(context);
547     Frame* frame = window->frame();
548     if (frame && frame->domWindow() == window)
549         return frame;
550     // We return 0 here because |context| is detached from the Frame.  If we
551     // did return |frame| we could get in trouble because the frame could be
552     // navigated to another security origin.
553     return 0;
554 }
555
556 Frame* V8Proxy::retrieveFrameForEnteredContext()
557 {
558     v8::Handle<v8::Context> context = v8::Context::GetEntered();
559     if (context.IsEmpty())
560         return 0;
561     return retrieveFrame(context);
562 }
563
564 Frame* V8Proxy::retrieveFrameForCurrentContext()
565 {
566     v8::Handle<v8::Context> context = v8::Context::GetCurrent();
567     if (context.IsEmpty())
568         return 0;
569     return retrieveFrame(context);
570 }
571
572 Frame* V8Proxy::retrieveFrameForCallingContext()
573 {
574     v8::Handle<v8::Context> context = v8::Context::GetCalling();
575     if (context.IsEmpty())
576         return 0;
577     return retrieveFrame(context);
578 }
579
580 V8Proxy* V8Proxy::retrieve()
581 {
582     DOMWindow* window = retrieveWindow(currentContext());
583     ASSERT(window);
584     return retrieve(window->frame());
585 }
586
587 V8Proxy* V8Proxy::retrieve(Frame* frame)
588 {
589     if (!frame)
590         return 0;
591     return frame->script()->canExecuteScripts(NotAboutToExecuteScript) ? frame->script()->proxy() : 0;
592 }
593
594 V8Proxy* V8Proxy::retrieve(ScriptExecutionContext* context)
595 {
596     if (!context || !context->isDocument())
597         return 0;
598     return retrieve(static_cast<Document*>(context)->frame());
599 }
600
601 void V8Proxy::disconnectFrame()
602 {
603 }
604
605 void V8Proxy::releaseStorageMutex()
606 {
607     // If we've just left a top level script context and local storage has been
608     // instantiated, we must ensure that any storage locks have been freed.
609     // Per http://dev.w3.org/html5/spec/Overview.html#storage-mutex
610     if (m_recursion != 0)
611         return;
612     Page* page = m_frame->page();
613     if (!page)
614         return;
615     if (page->group().hasLocalStorage())
616         page->group().localStorage()->unlock();
617 }
618
619 void V8Proxy::resetIsolatedWorlds()
620 {
621     for (IsolatedWorldMap::iterator iter = m_isolatedWorlds.begin();
622          iter != m_isolatedWorlds.end(); ++iter) {
623         iter->second->destroy();
624     }
625     m_isolatedWorlds.clear();
626 }
627
628 void V8Proxy::clearForClose()
629 {
630     resetIsolatedWorlds();
631     windowShell()->clearForClose();
632 }
633
634 void V8Proxy::clearForNavigation()
635 {
636     resetIsolatedWorlds();
637     windowShell()->clearForNavigation();
638 }
639
640 void V8Proxy::setDOMException(int exceptionCode)
641 {
642     if (exceptionCode <= 0)
643         return;
644
645     ExceptionCodeDescription description;
646     getExceptionCodeDescription(exceptionCode, description);
647
648     v8::Handle<v8::Value> exception;
649     switch (description.type) {
650     case DOMExceptionType:
651         exception = toV8(DOMCoreException::create(description));
652         break;
653     case RangeExceptionType:
654         exception = toV8(RangeException::create(description));
655         break;
656     case EventExceptionType:
657         exception = toV8(EventException::create(description));
658         break;
659     case XMLHttpRequestExceptionType:
660         exception = toV8(XMLHttpRequestException::create(description));
661         break;
662 #if ENABLE(SVG)
663     case SVGExceptionType:
664         exception = toV8(SVGException::create(description));
665         break;
666 #endif
667 #if ENABLE(XPATH)
668     case XPathExceptionType:
669         exception = toV8(XPathException::create(description));
670         break;
671 #endif
672     default:
673         ASSERT_NOT_REACHED();
674     }
675
676     if (!exception.IsEmpty())
677         v8::ThrowException(exception);
678 }
679
680 v8::Handle<v8::Value> V8Proxy::throwError(ErrorType type, const char* message)
681 {
682     switch (type) {
683     case RangeError:
684         return v8::ThrowException(v8::Exception::RangeError(v8String(message)));
685     case ReferenceError:
686         return v8::ThrowException(v8::Exception::ReferenceError(v8String(message)));
687     case SyntaxError:
688         return v8::ThrowException(v8::Exception::SyntaxError(v8String(message)));
689     case TypeError:
690         return v8::ThrowException(v8::Exception::TypeError(v8String(message)));
691     case GeneralError:
692         return v8::ThrowException(v8::Exception::Error(v8String(message)));
693     default:
694         ASSERT_NOT_REACHED();
695         return notHandledByInterceptor();
696     }
697 }
698
699 v8::Local<v8::Context> V8Proxy::context(Frame* frame)
700 {
701     v8::Local<v8::Context> context = V8Proxy::mainWorldContext(frame);
702     if (context.IsEmpty())
703         return v8::Local<v8::Context>();
704
705     if (V8IsolatedContext* isolatedContext = V8IsolatedContext::getEntered()) {
706         context = v8::Local<v8::Context>::New(isolatedContext->context());
707         if (frame != V8Proxy::retrieveFrame(context))
708             return v8::Local<v8::Context>();
709     }
710
711     return context;
712 }
713
714 v8::Local<v8::Context> V8Proxy::context()
715 {
716     if (V8IsolatedContext* isolatedContext = V8IsolatedContext::getEntered()) {
717         RefPtr<SharedPersistent<v8::Context> > context = isolatedContext->sharedContext();
718         if (m_frame != V8Proxy::retrieveFrame(context->get()))
719             return v8::Local<v8::Context>();
720         return v8::Local<v8::Context>::New(context->get());
721     }
722     return mainWorldContext();
723 }
724
725 v8::Local<v8::Context> V8Proxy::mainWorldContext()
726 {
727     windowShell()->initContextIfNeeded();
728     return v8::Local<v8::Context>::New(windowShell()->context());
729 }
730
731 v8::Local<v8::Context> V8Proxy::mainWorldContext(Frame* frame)
732 {
733     V8Proxy* proxy = retrieve(frame);
734     if (!proxy)
735         return v8::Local<v8::Context>();
736
737     return proxy->mainWorldContext();
738 }
739
740 v8::Local<v8::Context> V8Proxy::currentContext()
741 {
742     return v8::Context::GetCurrent();
743 }
744
745 v8::Handle<v8::Value> V8Proxy::checkNewLegal(const v8::Arguments& args)
746 {
747     if (!AllowAllocation::m_current)
748         return throwError(TypeError, "Illegal constructor");
749
750     return args.This();
751 }
752
753 void V8Proxy::processConsoleMessages()
754 {
755     V8ConsoleMessage::processDelayed();
756 }
757
758 // Create the utility context for holding JavaScript functions used internally
759 // which are not visible to JavaScript executing on the page.
760 void V8Proxy::createUtilityContext()
761 {
762     ASSERT(m_utilityContext.IsEmpty());
763
764     v8::HandleScope scope;
765     v8::Handle<v8::ObjectTemplate> globalTemplate = v8::ObjectTemplate::New();
766     m_utilityContext = v8::Context::New(0, globalTemplate);
767     v8::Context::Scope contextScope(m_utilityContext);
768
769     // Compile JavaScript function for retrieving the source line of the top
770     // JavaScript stack frame.
771     DEFINE_STATIC_LOCAL(const char*, frameSourceLineSource,
772         ("function frameSourceLine(exec_state) {"
773         "  if (!exec_state.frameCount())"
774         "      return undefined;"
775         "  return exec_state.frame(0).sourceLine();"
776         "}"));
777     v8::Script::Compile(v8::String::New(frameSourceLineSource))->Run();
778
779     // Compile JavaScript function for retrieving the source name of the top
780     // JavaScript stack frame.
781     DEFINE_STATIC_LOCAL(const char*, frameSourceNameSource,
782         ("function frameSourceName(exec_state) {"
783         "  if (!exec_state.frameCount())"
784         "      return undefined;"
785         "  var frame = exec_state.frame(0);"
786         "  if (frame.func().resolved() && "
787         "      frame.func().script() && "
788         "      frame.func().script().name()) {"
789         "    return frame.func().script().name();"
790         "  }"
791         "}"));
792     v8::Script::Compile(v8::String::New(frameSourceNameSource))->Run();
793 }
794
795 bool V8Proxy::sourceLineNumber(int& result)
796 {
797     v8::HandleScope scope;
798     v8::Handle<v8::Context> v8UtilityContext = V8Proxy::utilityContext();
799     if (v8UtilityContext.IsEmpty())
800         return false;
801     v8::Context::Scope contextScope(v8UtilityContext);
802     v8::Handle<v8::Function> frameSourceLine;
803     frameSourceLine = v8::Local<v8::Function>::Cast(v8UtilityContext->Global()->Get(v8::String::New("frameSourceLine")));
804     if (frameSourceLine.IsEmpty())
805         return false;
806     v8::Handle<v8::Value> value = v8::Debug::Call(frameSourceLine);
807     if (value.IsEmpty())
808         return false;
809     result = value->Int32Value();
810     return true;
811 }
812
813 bool V8Proxy::sourceName(String& result)
814 {
815     v8::HandleScope scope;
816     v8::Handle<v8::Context> v8UtilityContext = utilityContext();
817     if (v8UtilityContext.IsEmpty())
818         return false;
819     v8::Context::Scope contextScope(v8UtilityContext);
820     v8::Handle<v8::Function> frameSourceName;
821     frameSourceName = v8::Local<v8::Function>::Cast(v8UtilityContext->Global()->Get(v8::String::New("frameSourceName")));
822     if (frameSourceName.IsEmpty())
823         return false;
824     v8::Handle<v8::Value> value = v8::Debug::Call(frameSourceName);
825     if (value.IsEmpty())
826         return false;
827     result = toWebCoreString(value);
828     return true;
829 }
830
831 void V8Proxy::registerExtensionWithV8(v8::Extension* extension)
832 {
833     // If the extension exists in our list, it was already registered with V8.
834     if (!registeredExtensionWithV8(extension))
835         v8::RegisterExtension(extension);
836 }
837
838 bool V8Proxy::registeredExtensionWithV8(v8::Extension* extension)
839 {
840     for (size_t i = 0; i < m_extensions.size(); ++i) {
841         if (m_extensions[i].extension == extension)
842             return true;
843     }
844
845     return false;
846 }
847
848 void V8Proxy::registerExtension(v8::Extension* extension, const String& schemeRestriction)
849 {
850     registerExtensionWithV8(extension);
851     V8ExtensionInfo info = {schemeRestriction, 0, extension};
852     m_extensions.append(info);
853 }
854
855 void V8Proxy::registerExtension(v8::Extension* extension, int extensionGroup)
856 {
857     registerExtensionWithV8(extension);
858     V8ExtensionInfo info = {String(), extensionGroup, extension};
859     m_extensions.append(info);
860 }
861
862 bool V8Proxy::setContextDebugId(int debugId)
863 {
864     ASSERT(debugId > 0);
865     v8::HandleScope scope;
866     v8::Handle<v8::Context> context = windowShell()->context();
867     if (context.IsEmpty())
868         return false;
869     if (!context->GetData()->IsUndefined())
870         return false;
871
872     v8::Context::Scope contextScope(context);
873
874     char buffer[32];
875     snprintf(buffer, sizeof(buffer), "page,%d", debugId);
876     context->SetData(v8::String::New(buffer));
877
878     return true;
879 }
880
881 int V8Proxy::contextDebugId(v8::Handle<v8::Context> context)
882 {
883     v8::HandleScope scope;
884     if (!context->GetData()->IsString())
885         return -1;
886     v8::String::AsciiValue ascii(context->GetData());
887     char* comma = strnstr(*ascii, ",", ascii.length());
888     if (!comma)
889         return -1;
890     return atoi(comma + 1);
891 }
892
893 v8::Local<v8::Context> toV8Context(ScriptExecutionContext* context, const WorldContextHandle& worldContext)
894 {
895     if (context->isDocument()) {
896         if (V8Proxy* proxy = V8Proxy::retrieve(context))
897             return worldContext.adjustedContext(proxy);
898 #if ENABLE(WORKERS)
899     } else if (context->isWorkerContext()) {
900         if (WorkerContextExecutionProxy* proxy = static_cast<WorkerContext*>(context)->script()->proxy())
901             return proxy->context();
902 #endif
903     }
904     return v8::Local<v8::Context>();
905 }
906
907 }  // namespace WebCore