d12151f8a61acc2e0882bcdd2e61ce368072b6a6
[WebKit-https.git] / Source / 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 "CachedMetadata.h"
35 #include "DateExtension.h"
36 #include "Document.h"
37 #include "DocumentLoader.h"
38 #include "ExceptionHeaders.h"
39 #include "ExceptionInterfaces.h"
40 #include "Frame.h"
41 #include "FrameLoaderClient.h"
42 #include "IDBFactoryBackendInterface.h"
43 #include "InspectorInstrumentation.h"
44 #include "PlatformSupport.h"
45 #include "ScriptCallStack.h"
46 #include "ScriptCallStackFactory.h"
47 #include "ScriptSourceCode.h"
48 #include "SecurityOrigin.h"
49 #include "Settings.h"
50 #include "StylePropertySet.h"
51 #include "V8Binding.h"
52 #include "V8BindingState.h"
53 #include "V8Collection.h"
54 #include "V8DOMCoreException.h"
55 #include "V8DOMMap.h"
56 #include "V8DOMWindow.h"
57 #include "V8HiddenPropertyName.h"
58 #include "V8IsolatedContext.h"
59 #include "V8RecursionScope.h"
60 #include "WorkerContext.h"
61 #include "WorkerContextExecutionProxy.h"
62
63 #include <algorithm>
64 #include <stdio.h>
65 #include <utility>
66 #include <wtf/Assertions.h>
67 #include <wtf/OwnArrayPtr.h>
68 #include <wtf/OwnPtr.h>
69 #include <wtf/StdLibExtras.h>
70 #include <wtf/StringExtras.h>
71 #include <wtf/UnusedParam.h>
72 #include <wtf/text/StringBuilder.h>
73 #include <wtf/text/WTFString.h>
74
75 #if PLATFORM(CHROMIUM)
76 #include "TraceEvent.h"
77 #endif
78
79 namespace WebCore {
80
81 static V8Extensions& staticExtensionsList()
82 {
83     DEFINE_STATIC_LOCAL(V8Extensions, extensions, ());
84     return extensions;
85 }
86
87 void batchConfigureAttributes(v8::Handle<v8::ObjectTemplate> instance, 
88                               v8::Handle<v8::ObjectTemplate> proto, 
89                               const BatchedAttribute* attributes, 
90                               size_t attributeCount)
91 {
92     for (size_t i = 0; i < attributeCount; ++i)
93         configureAttribute(instance, proto, attributes[i]);
94 }
95
96 void batchConfigureCallbacks(v8::Handle<v8::ObjectTemplate> proto, 
97                              v8::Handle<v8::Signature> signature, 
98                              v8::PropertyAttribute attributes,
99                              const BatchedCallback* callbacks,
100                              size_t callbackCount)
101 {
102     for (size_t i = 0; i < callbackCount; ++i) {
103         proto->Set(v8::String::New(callbacks[i].name),
104                    v8::FunctionTemplate::New(callbacks[i].callback, 
105                                              v8::Handle<v8::Value>(),
106                                              signature),
107                    attributes);
108     }
109 }
110
111 void batchConfigureConstants(v8::Handle<v8::FunctionTemplate> functionDescriptor,
112                              v8::Handle<v8::ObjectTemplate> proto,
113                              const BatchedConstant* constants,
114                              size_t constantCount)
115 {
116     for (size_t i = 0; i < constantCount; ++i) {
117         const BatchedConstant* constant = &constants[i];
118         functionDescriptor->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly);
119         proto->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly);
120     }
121 }
122
123 typedef HashMap<Node*, v8::Object*> DOMNodeMap;
124 typedef HashMap<void*, v8::Object*> DOMObjectMap;
125 typedef HashMap<int, v8::FunctionTemplate*> FunctionTemplateMap;
126
127 void V8Proxy::reportUnsafeAccessTo(Frame* target)
128 {
129     ASSERT(target);
130     Document* targetDocument = target->document();
131     if (!targetDocument)
132         return;
133
134     Frame* source = V8Proxy::retrieveFrameForEnteredContext();
135     if (!source)
136         return;
137
138     Document* sourceDocument = source->document();
139     if (!sourceDocument)
140         return; // Ignore error if the source document is gone.
141
142     // FIXME: This error message should contain more specifics of why the same
143     // origin check has failed.
144     String str = "Unsafe JavaScript attempt to access frame with URL " + targetDocument->url().string() +
145                  " from frame with URL " + sourceDocument->url().string() + ". Domains, protocols and ports must match.\n";
146
147     RefPtr<ScriptCallStack> stackTrace = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true);
148
149     // NOTE: Safari prints the message in the target page, but it seems like
150     // it should be in the source page. Even for delayed messages, we put it in
151     // the source page.
152     sourceDocument->addConsoleMessage(JSMessageSource, LogMessageType, ErrorMessageLevel, str, stackTrace.release());
153 }
154
155 static void handleFatalErrorInV8()
156 {
157     // FIXME: We temporarily deal with V8 internal error situations
158     // such as out-of-memory by crashing the renderer.
159     CRASH();
160 }
161
162 static v8::Local<v8::Value> handleMaxRecursionDepthExceeded()
163 {
164     V8Proxy::throwError(V8Proxy::RangeError, "Maximum call stack size exceeded.");
165     return v8::Local<v8::Value>();
166 }
167
168 V8Proxy::V8Proxy(Frame* frame)
169     : m_frame(frame)
170     , m_windowShell(V8DOMWindowShell::create(frame))
171 {
172 }
173
174 V8Proxy::~V8Proxy()
175 {
176     clearForClose();
177     windowShell()->destroyGlobal();
178 }
179
180 v8::Handle<v8::Script> V8Proxy::compileScript(v8::Handle<v8::String> code, const String& fileName, const TextPosition& scriptStartPosition, v8::ScriptData* scriptData)
181 {
182     const uint16_t* fileNameString = fromWebCoreString(fileName);
183     v8::Handle<v8::String> name = v8::String::New(fileNameString, fileName.length());
184     v8::Handle<v8::Integer> line = v8::Integer::New(scriptStartPosition.m_line.zeroBasedInt());
185     v8::Handle<v8::Integer> column = v8::Integer::New(scriptStartPosition.m_column.zeroBasedInt());
186     v8::ScriptOrigin origin(name, line, column);
187     v8::Handle<v8::Script> script = v8::Script::Compile(code, &origin, scriptData);
188     return script;
189 }
190
191 bool V8Proxy::handleOutOfMemory()
192 {
193     v8::Local<v8::Context> context = v8::Context::GetCurrent();
194
195     if (!context->HasOutOfMemoryException())
196         return false;
197
198     // Warning, error, disable JS for this frame?
199     Frame* frame = V8Proxy::retrieveFrame(context);
200
201     V8Proxy* proxy = V8Proxy::retrieve(frame);
202     if (proxy) {
203         // Clean m_context, and event handlers.
204         proxy->clearForClose();
205
206         proxy->windowShell()->destroyGlobal();
207     }
208
209 #if PLATFORM(CHROMIUM)
210     PlatformSupport::notifyJSOutOfMemory(frame);
211 #endif
212
213     // Disable JS.
214     Settings* settings = frame->settings();
215     ASSERT(settings);
216     settings->setScriptEnabled(false);
217
218     return true;
219 }
220
221 void V8Proxy::evaluateInIsolatedWorld(int worldID, const Vector<ScriptSourceCode>& sources, int extensionGroup, WTF::Vector<v8::Local<v8::Value> >* results)
222 {
223     // FIXME: This will need to get reorganized once we have a windowShell for the isolated world.
224     if (!windowShell()->initContextIfNeeded())
225         return;
226
227     v8::HandleScope handleScope;
228     V8IsolatedContext* isolatedContext = 0;
229
230     if (worldID > 0) {
231         IsolatedWorldMap::iterator iter = m_isolatedWorlds.find(worldID);
232         if (iter != m_isolatedWorlds.end()) {
233             isolatedContext = iter->second;
234         } else {
235             isolatedContext = new V8IsolatedContext(this, extensionGroup, worldID);
236             if (isolatedContext->context().IsEmpty()) {
237                 delete isolatedContext;
238                 return;
239             }
240
241             // FIXME: We should change this to using window shells to match JSC.
242             m_isolatedWorlds.set(worldID, isolatedContext);
243         }
244
245         IsolatedWorldSecurityOriginMap::iterator securityOriginIter = m_isolatedWorldSecurityOrigins.find(worldID);
246         if (securityOriginIter != m_isolatedWorldSecurityOrigins.end())
247             isolatedContext->setSecurityOrigin(securityOriginIter->second);
248     } else {
249         isolatedContext = new V8IsolatedContext(this, extensionGroup, worldID);
250         if (isolatedContext->context().IsEmpty()) {
251             delete isolatedContext;
252             return;
253         }
254     }
255
256     v8::Local<v8::Context> context = v8::Local<v8::Context>::New(isolatedContext->context());
257     v8::Context::Scope context_scope(context);
258
259     if (results) {
260         for (size_t i = 0; i < sources.size(); ++i)
261             results->append(evaluate(sources[i], 0));
262     } else {
263         for (size_t i = 0; i < sources.size(); ++i)
264             evaluate(sources[i], 0);
265     }
266
267     if (worldID == 0)
268         isolatedContext->destroy();
269 }
270
271 void V8Proxy::setIsolatedWorldSecurityOrigin(int worldID, PassRefPtr<SecurityOrigin> prpSecurityOriginIn)
272 {
273     ASSERT(worldID);
274     RefPtr<SecurityOrigin> securityOrigin = prpSecurityOriginIn;
275     m_isolatedWorldSecurityOrigins.set(worldID, securityOrigin);
276     IsolatedWorldMap::iterator iter = m_isolatedWorlds.find(worldID);
277     if (iter != m_isolatedWorlds.end())
278         iter->second->setSecurityOrigin(securityOrigin);
279 }
280
281 PassOwnPtr<v8::ScriptData> V8Proxy::precompileScript(v8::Handle<v8::String> code, CachedScript* cachedScript)
282 {
283     // A pseudo-randomly chosen ID used to store and retrieve V8 ScriptData from
284     // the CachedScript. If the format changes, this ID should be changed too.
285     static const unsigned dataTypeID = 0xECC13BD7;
286
287     // Very small scripts are not worth the effort to preparse.
288     static const int minPreparseLength = 1024;
289
290     if (!cachedScript || code->Length() < minPreparseLength)
291         return nullptr;
292
293     CachedMetadata* cachedMetadata = cachedScript->cachedMetadata(dataTypeID);
294     if (cachedMetadata)
295         return adoptPtr(v8::ScriptData::New(cachedMetadata->data(), cachedMetadata->size()));
296
297     OwnPtr<v8::ScriptData> scriptData = adoptPtr(v8::ScriptData::PreCompile(code));
298     cachedScript->setCachedMetadata(dataTypeID, scriptData->Data(), scriptData->Length());
299
300     return scriptData.release();
301 }
302
303 v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* node)
304 {
305     ASSERT(v8::Context::InContext());
306
307     V8GCController::checkMemoryUsage();
308
309     InspectorInstrumentationCookie cookie = InspectorInstrumentation::willEvaluateScript(m_frame, source.url().isNull() ? String() : source.url().string(), source.startLine());
310
311     v8::Local<v8::Value> result;
312     {
313         // Isolate exceptions that occur when compiling and executing
314         // the code. These exceptions should not interfere with
315         // javascript code we might evaluate from C++ when returning
316         // from here.
317         v8::TryCatch tryCatch;
318         tryCatch.SetVerbose(true);
319
320         // Compile the script.
321         v8::Local<v8::String> code = v8ExternalString(source.source());
322 #if PLATFORM(CHROMIUM)
323         TRACE_EVENT_BEGIN0("v8", "v8.compile");
324 #endif
325         OwnPtr<v8::ScriptData> scriptData = precompileScript(code, source.cachedScript());
326
327         // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at
328         // 1, whereas v8 starts at 0.
329         v8::Handle<v8::Script> script = compileScript(code, source.url(), source.startPosition(), scriptData.get());
330 #if PLATFORM(CHROMIUM)
331         TRACE_EVENT_END0("v8", "v8.compile");
332         TRACE_EVENT0("v8", "v8.run");
333 #endif
334         result = runScript(script);
335     }
336
337     InspectorInstrumentation::didEvaluateScript(cookie);
338
339     return result;
340 }
341
342 v8::Local<v8::Value> V8Proxy::runScript(v8::Handle<v8::Script> script)
343 {
344     if (script.IsEmpty())
345         return v8::Local<v8::Value>();
346
347     V8GCController::checkMemoryUsage();
348     if (V8RecursionScope::recursionLevel() >= kMaxRecursionDepth)
349         return handleMaxRecursionDepthExceeded();
350
351     if (handleOutOfMemory())
352         ASSERT(script.IsEmpty());
353
354     // Keep Frame (and therefore ScriptController and V8Proxy) alive.
355     RefPtr<Frame> protect(frame());
356
357     // Run the script and keep track of the current recursion depth.
358     v8::Local<v8::Value> result;
359     v8::TryCatch tryCatch;
360     tryCatch.SetVerbose(true);
361     {
362         V8RecursionScope recursionScope(frame()->document());
363         result = script->Run();
364     }
365
366     if (handleOutOfMemory())
367         ASSERT(result.IsEmpty());
368
369     // Handle V8 internal error situation (Out-of-memory).
370     if (tryCatch.HasCaught()) {
371         ASSERT(result.IsEmpty());
372         return v8::Local<v8::Value>();
373     }
374
375     if (result.IsEmpty())
376         return v8::Local<v8::Value>();
377
378     if (v8::V8::IsDead())
379         handleFatalErrorInV8();
380
381     return result;
382 }
383
384 v8::Local<v8::Value> V8Proxy::callFunction(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[])
385 {
386     // Keep Frame (and therefore ScriptController and V8Proxy) alive.
387     RefPtr<Frame> protect(frame());
388     return V8Proxy::instrumentedCallFunction(frame(), function, receiver, argc, args);
389 }
390
391 static inline void resourceInfo(const v8::Handle<v8::Function> function, String& resourceName, int& lineNumber)
392 {
393     v8::ScriptOrigin origin = function->GetScriptOrigin();
394     if (origin.ResourceName().IsEmpty()) {
395         resourceName = "undefined";
396         lineNumber = 1;
397     } else {
398         resourceName = toWebCoreString(origin.ResourceName());
399         lineNumber = function->GetScriptLineNumber() + 1;
400     }
401 }
402
403 static inline String resourceString(const v8::Handle<v8::Function> function)
404 {
405     String resourceName;
406     int lineNumber;
407     resourceInfo(function, resourceName, lineNumber);
408
409     StringBuilder builder;
410     builder.append(resourceName);
411     builder.append(':');
412     builder.append(String::number(lineNumber));
413     return builder.toString();
414 }
415
416 v8::Local<v8::Value> V8Proxy::instrumentedCallFunction(Frame* frame, v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[])
417 {
418     V8GCController::checkMemoryUsage();
419
420     if (V8RecursionScope::recursionLevel() >= kMaxRecursionDepth)
421         return handleMaxRecursionDepthExceeded();
422
423     ScriptExecutionContext* context = frame ? frame->document() : 0;
424
425     InspectorInstrumentationCookie cookie;
426     if (InspectorInstrumentation::hasFrontends() && context) {
427         String resourceName;
428         int lineNumber;
429         resourceInfo(function, resourceName, lineNumber);
430         cookie = InspectorInstrumentation::willCallFunction(context, resourceName, lineNumber);
431     }
432
433     v8::Local<v8::Value> result;
434     {
435 #if PLATFORM(CHROMIUM)
436         TRACE_EVENT1("v8", "v8.callFunction", "callsite", resourceString(function).utf8());
437 #endif
438         V8RecursionScope recursionScope(context);
439         result = function->Call(receiver, argc, args);
440     }
441
442     InspectorInstrumentation::didCallFunction(cookie);
443
444     if (v8::V8::IsDead())
445         handleFatalErrorInV8();
446
447     return result;
448 }
449
450 v8::Local<v8::Value> V8Proxy::newInstance(v8::Handle<v8::Function> constructor, int argc, v8::Handle<v8::Value> args[])
451 {
452 #if PLATFORM(CHROMIUM)
453     TRACE_EVENT0("v8", "v8.newInstance");
454 #endif
455
456     // No artificial limitations on the depth of recursion, see comment in
457     // V8Proxy::callFunction.
458     v8::Local<v8::Value> result;
459     {
460         V8RecursionScope recursionScope(frame() ? frame()->document() : 0);
461         result = constructor->NewInstance(argc, args);
462     }
463
464     if (v8::V8::IsDead())
465         handleFatalErrorInV8();
466
467     return result;
468 }
469
470 DOMWindow* V8Proxy::retrieveWindow(v8::Handle<v8::Context> context)
471 {
472     v8::Handle<v8::Object> global = context->Global();
473     ASSERT(!global.IsEmpty());
474     global = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), global);
475     ASSERT(!global.IsEmpty());
476     return V8DOMWindow::toNative(global);
477 }
478
479 Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context)
480 {
481     DOMWindow* window = retrieveWindow(context);
482     Frame* frame = window->frame();
483     if (frame && frame->domWindow() == window)
484         return frame;
485     // We return 0 here because |context| is detached from the Frame.  If we
486     // did return |frame| we could get in trouble because the frame could be
487     // navigated to another security origin.
488     return 0;
489 }
490
491 Frame* V8Proxy::retrieveFrameForEnteredContext()
492 {
493     v8::Handle<v8::Context> context = v8::Context::GetEntered();
494     if (context.IsEmpty())
495         return 0;
496     return retrieveFrame(context);
497 }
498
499 Frame* V8Proxy::retrieveFrameForCurrentContext()
500 {
501     v8::Handle<v8::Context> context = v8::Context::GetCurrent();
502     if (context.IsEmpty())
503         return 0;
504     return retrieveFrame(context);
505 }
506
507 DOMWindow* V8Proxy::retrieveWindowForCallingContext()
508 {
509     v8::Handle<v8::Context> context = v8::Context::GetCalling();
510     if (context.IsEmpty())
511         return 0;
512     return retrieveWindow(context);
513 }
514
515 Frame* V8Proxy::retrieveFrameForCallingContext()
516 {
517     v8::Handle<v8::Context> context = v8::Context::GetCalling();
518     if (context.IsEmpty())
519         return 0;
520     return retrieveFrame(context);
521 }
522
523 V8Proxy* V8Proxy::retrieve()
524 {
525     DOMWindow* window = retrieveWindow(currentContext());
526     ASSERT(window);
527     return retrieve(window->frame());
528 }
529
530 V8Proxy* V8Proxy::retrieve(Frame* frame)
531 {
532     return frame ? frame->script()->proxy() : 0;
533 }
534
535 V8Proxy* V8Proxy::retrieve(ScriptExecutionContext* context)
536 {
537     if (!context || !context->isDocument())
538         return 0;
539     return retrieve(static_cast<Document*>(context)->frame());
540 }
541
542 V8BindingPerContextData* V8Proxy::retrievePerContextData(Frame* frame)
543 {
544     V8IsolatedContext* isolatedContext;
545     if (UNLIKELY(!!(isolatedContext = V8IsolatedContext::getEntered())))
546         return isolatedContext->perContextData();
547     return V8Proxy::retrieve(frame)->windowShell()->perContextData();
548 }
549
550 void V8Proxy::resetIsolatedWorlds()
551 {
552     for (IsolatedWorldMap::iterator iter = m_isolatedWorlds.begin();
553          iter != m_isolatedWorlds.end(); ++iter) {
554         iter->second->destroy();
555     }
556     m_isolatedWorlds.clear();
557     m_isolatedWorldSecurityOrigins.clear();
558 }
559
560 void V8Proxy::clearForClose()
561 {
562     resetIsolatedWorlds();
563     windowShell()->clearForClose();
564 }
565
566 void V8Proxy::clearForNavigation()
567 {
568     resetIsolatedWorlds();
569     windowShell()->clearForNavigation();
570 }
571
572 static v8::Handle<v8::Value> DOMExceptionStackGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
573 {
574     ASSERT(info.Data()->IsObject());
575     return info.Data()->ToObject()->Get(v8String("stack", info.GetIsolate()));
576 }
577
578 static void DOMExceptionStackSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
579 {
580     ASSERT(info.Data()->IsObject());
581     info.Data()->ToObject()->Set(v8String("stack", info.GetIsolate()), value);
582 }
583
584 #define TRY_TO_CREATE_EXCEPTION(interfaceName) \
585     case interfaceName##Type: \
586         exception = toV8(interfaceName::create(description), isolate); \
587         break;
588
589 void V8Proxy::setDOMException(int ec, v8::Isolate* isolate)
590 {
591     if (ec <= 0)
592         return;
593
594     ExceptionCodeDescription description(ec);
595
596     v8::Handle<v8::Value> exception;
597     switch (description.type) {
598         DOM_EXCEPTION_INTERFACES_FOR_EACH(TRY_TO_CREATE_EXCEPTION)
599     }
600
601     if (exception.IsEmpty())
602         return;
603
604     // Attach an Error object to the DOMException. This is then lazily used to get the stack value.
605     v8::Handle<v8::Value> error = v8::Exception::Error(v8String(description.description, isolate));
606     ASSERT(!error.IsEmpty());
607     ASSERT(exception->IsObject());
608     exception->ToObject()->SetAccessor(v8String("stack", isolate), DOMExceptionStackGetter, DOMExceptionStackSetter, error);
609
610     v8::ThrowException(exception);
611 }
612
613 #undef TRY_TO_CREATE_EXCEPTION
614
615 v8::Handle<v8::Value> V8Proxy::throwError(ErrorType type, const char* message, v8::Isolate* isolate)
616 {
617     switch (type) {
618     case RangeError:
619         return v8::ThrowException(v8::Exception::RangeError(v8String(message, isolate)));
620     case ReferenceError:
621         return v8::ThrowException(v8::Exception::ReferenceError(v8String(message, isolate)));
622     case SyntaxError:
623         return v8::ThrowException(v8::Exception::SyntaxError(v8String(message, isolate)));
624     case TypeError:
625         return v8::ThrowException(v8::Exception::TypeError(v8String(message, isolate)));
626     case GeneralError:
627         return v8::ThrowException(v8::Exception::Error(v8String(message, isolate)));
628     default:
629         ASSERT_NOT_REACHED();
630         return v8::Handle<v8::Value>();
631     }
632 }
633
634 v8::Handle<v8::Value> V8Proxy::throwTypeError(const char* message)
635 {
636     return throwError(TypeError, (message ? message : "Type error"));
637 }
638
639 v8::Handle<v8::Value> V8Proxy::throwNotEnoughArgumentsError(v8::Isolate* isolate)
640 {
641     return throwError(TypeError, "Not enough arguments", isolate);
642 }
643
644 v8::Local<v8::Context> V8Proxy::context(Frame* frame)
645 {
646     v8::Local<v8::Context> context = V8Proxy::mainWorldContext(frame);
647     if (context.IsEmpty())
648         return v8::Local<v8::Context>();
649
650     if (V8IsolatedContext* isolatedContext = V8IsolatedContext::getEntered()) {
651         context = v8::Local<v8::Context>::New(isolatedContext->context());
652         if (frame != V8Proxy::retrieveFrame(context))
653             return v8::Local<v8::Context>();
654     }
655
656     return context;
657 }
658
659 v8::Local<v8::Context> V8Proxy::context()
660 {
661     if (V8IsolatedContext* isolatedContext = V8IsolatedContext::getEntered()) {
662         RefPtr<SharedPersistent<v8::Context> > context = isolatedContext->sharedContext();
663         if (m_frame != V8Proxy::retrieveFrame(context->get()))
664             return v8::Local<v8::Context>();
665         return v8::Local<v8::Context>::New(context->get());
666     }
667     return mainWorldContext();
668 }
669
670 v8::Local<v8::Context> V8Proxy::mainWorldContext()
671 {
672     windowShell()->initContextIfNeeded();
673     return v8::Local<v8::Context>::New(windowShell()->context());
674 }
675
676 v8::Local<v8::Context> V8Proxy::isolatedWorldContext(int worldId)
677 {
678     IsolatedWorldMap::iterator iter = m_isolatedWorlds.find(worldId);
679     if (iter == m_isolatedWorlds.end())
680         return v8::Local<v8::Context>();
681     return v8::Local<v8::Context>::New(iter->second->context());
682 }
683
684 bool V8Proxy::matchesCurrentContext()
685 {
686     v8::Handle<v8::Context> context;
687     if (V8IsolatedContext* isolatedContext = V8IsolatedContext::getEntered()) {
688         context = isolatedContext->sharedContext()->get();
689         if (m_frame != V8Proxy::retrieveFrame(context))
690             return false;
691     } else {
692         windowShell()->initContextIfNeeded();
693         context = windowShell()->context();
694     }
695     return context == context->GetCurrent();
696 }
697
698 v8::Local<v8::Context> V8Proxy::mainWorldContext(Frame* frame)
699 {
700     V8Proxy* proxy = retrieve(frame);
701     if (!proxy)
702         return v8::Local<v8::Context>();
703
704     return proxy->mainWorldContext();
705 }
706
707 v8::Local<v8::Context> V8Proxy::currentContext()
708 {
709     return v8::Context::GetCurrent();
710 }
711
712 v8::Handle<v8::Value> V8Proxy::checkNewLegal(const v8::Arguments& args)
713 {
714     if (ConstructorMode::current() == ConstructorMode::CreateNewObject)
715         return throwError(TypeError, "Illegal constructor", args.GetIsolate());
716
717     return args.This();
718 }
719
720 void V8Proxy::registerExtensionWithV8(v8::Extension* extension)
721 {
722     // If the extension exists in our list, it was already registered with V8.
723     if (!registeredExtensionWithV8(extension))
724         v8::RegisterExtension(extension);
725 }
726
727 bool V8Proxy::registeredExtensionWithV8(v8::Extension* extension)
728 {
729     const V8Extensions& registeredExtensions = extensions();
730     for (size_t i = 0; i < registeredExtensions.size(); ++i) {
731         if (registeredExtensions[i] == extension)
732             return true;
733     }
734
735     return false;
736 }
737
738 void V8Proxy::registerExtension(v8::Extension* extension)
739 {
740     registerExtensionWithV8(extension);
741     staticExtensionsList().append(extension);
742 }
743
744 const V8Extensions& V8Proxy::extensions()
745 {
746     return staticExtensionsList();
747 }
748
749 bool V8Proxy::setContextDebugId(int debugId)
750 {
751     ASSERT(debugId > 0);
752     v8::HandleScope scope;
753     v8::Handle<v8::Context> context = windowShell()->context();
754     if (context.IsEmpty())
755         return false;
756     if (!context->GetData()->IsUndefined())
757         return false;
758
759     v8::Context::Scope contextScope(context);
760
761     char buffer[32];
762     snprintf(buffer, sizeof(buffer), "page,%d", debugId);
763     context->SetData(v8::String::New(buffer));
764
765     return true;
766 }
767
768 int V8Proxy::contextDebugId(v8::Handle<v8::Context> context)
769 {
770     v8::HandleScope scope;
771     if (!context->GetData()->IsString())
772         return -1;
773     v8::String::AsciiValue ascii(context->GetData());
774     char* comma = strnstr(*ascii, ",", ascii.length());
775     if (!comma)
776         return -1;
777     return atoi(comma + 1);
778 }
779
780 void V8Proxy::collectIsolatedContexts(Vector<std::pair<ScriptState*, SecurityOrigin*> >& result)
781 {
782     v8::HandleScope handleScope;
783     for (IsolatedWorldMap::iterator it = m_isolatedWorlds.begin(); it != m_isolatedWorlds.end(); ++it) {
784         V8IsolatedContext* isolatedContext = it->second;
785         if (!isolatedContext->securityOrigin())
786             continue;
787         v8::Handle<v8::Context> v8Context = isolatedContext->context();
788         if (v8Context.IsEmpty())
789             continue;
790         ScriptState* scriptState = ScriptState::forContext(v8::Local<v8::Context>::New(v8Context));
791         result.append(std::pair<ScriptState*, SecurityOrigin*>(scriptState, isolatedContext->securityOrigin()));
792     }
793 }
794
795 v8::Local<v8::Context> toV8Context(ScriptExecutionContext* context, const WorldContextHandle& worldContext)
796 {
797     if (context->isDocument()) {
798         if (V8Proxy* proxy = V8Proxy::retrieve(context))
799             return worldContext.adjustedContext(proxy);
800 #if ENABLE(WORKERS)
801     } else if (context->isWorkerContext()) {
802         if (WorkerContextExecutionProxy* proxy = static_cast<WorkerContext*>(context)->script()->proxy())
803             return proxy->context();
804 #endif
805     }
806     return v8::Local<v8::Context>();
807 }
808
809 }  // namespace WebCore