86a6fb9af97a621820e1ed147b3d45cb208f9ed7
[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 "DOMObjectsInclude.h"
37 #include "DocumentLoader.h"
38 #include "FrameLoaderClient.h"
39 #include "ScriptController.h"
40 #include "V8Binding.h"
41 #include "V8Collection.h"
42 #include "V8CustomBinding.h"
43 #include "V8DOMMap.h"
44 #include "V8DOMWindow.h"
45 #include "V8Index.h"
46 #include "V8IsolatedWorld.h"
47 #include "WorkerContextExecutionProxy.h"
48
49 #include <algorithm>
50 #include <utility>
51 #include <v8.h>
52 #include <v8-debug.h>
53 #include <wtf/Assertions.h>
54 #include <wtf/OwnArrayPtr.h>
55 #include <wtf/StdLibExtras.h>
56 #include <wtf/UnusedParam.h>
57
58 namespace WebCore {
59
60 v8::Persistent<v8::Context> V8Proxy::m_utilityContext;
61
62 // Static list of registered extensions
63 V8ExtensionList V8Proxy::m_extensions;
64
65 const char* V8Proxy::kContextDebugDataType = "type";
66 const char* V8Proxy::kContextDebugDataValue = "value";
67
68 #ifndef NDEBUG
69 // Keeps track of global handles created (not JS wrappers
70 // of DOM objects). Often these global handles are source
71 // of leaks.
72 //
73 // If you want to let a C++ object hold a persistent handle
74 // to a JS object, you should register the handle here to
75 // keep track of leaks.
76 //
77 // When creating a persistent handle, call:
78 //
79 // #ifndef NDEBUG
80 //    V8Proxy::registerGlobalHandle(type, host, handle);
81 // #endif
82 //
83 // When releasing the handle, call:
84 //
85 // #ifndef NDEBUG
86 //    V8Proxy::unregisterGlobalHandle(type, host, handle);
87 // #endif
88 //
89 typedef HashMap<v8::Value*, GlobalHandleInfo*> GlobalHandleMap;
90
91 static GlobalHandleMap& globalHandleMap()
92 {
93     DEFINE_STATIC_LOCAL(GlobalHandleMap, staticGlobalHandleMap, ());
94     return staticGlobalHandleMap;
95 }
96
97 // The function is the place to set the break point to inspect
98 // live global handles. Leaks are often come from leaked global handles.
99 static void enumerateGlobalHandles()
100 {
101     for (GlobalHandleMap::iterator it = globalHandleMap().begin(), end = globalHandleMap().end(); it != end; ++it) {
102         GlobalHandleInfo* info = it->second;
103         UNUSED_PARAM(info);
104         v8::Value* handle = it->first;
105         UNUSED_PARAM(handle);
106     }
107 }
108
109 void V8Proxy::registerGlobalHandle(GlobalHandleType type, void* host, v8::Persistent<v8::Value> handle)
110 {
111     ASSERT(!globalHandleMap().contains(*handle));
112     globalHandleMap().set(*handle, new GlobalHandleInfo(host, type));
113 }
114
115 void V8Proxy::unregisterGlobalHandle(void* host, v8::Persistent<v8::Value> handle)
116 {
117     ASSERT(globalHandleMap().contains(*handle));
118     GlobalHandleInfo* info = globalHandleMap().take(*handle);
119     ASSERT(info->m_host == host);
120     delete info;
121 }
122 #endif // ifndef NDEBUG
123
124 void batchConfigureAttributes(v8::Handle<v8::ObjectTemplate> instance, v8::Handle<v8::ObjectTemplate> proto, const BatchedAttribute* attributes, size_t attributeCount)
125 {
126     for (size_t i = 0; i < attributeCount; ++i) {
127         const BatchedAttribute* attribute = &attributes[i];
128         (attribute->onProto ? proto : instance)->SetAccessor(v8::String::New(attribute->name),
129             attribute->getter,
130             attribute->setter,
131             attribute->data == V8ClassIndex::INVALID_CLASS_INDEX ? v8::Handle<v8::Value>() : v8::Integer::New(V8ClassIndex::ToInt(attribute->data)),
132             attribute->settings,
133             attribute->attribute);
134     }
135 }
136
137 void batchConfigureConstants(v8::Handle<v8::FunctionTemplate> functionDescriptor, v8::Handle<v8::ObjectTemplate> proto, const BatchedConstant* constants, size_t constantCount)
138 {
139     for (size_t i = 0; i < constantCount; ++i) {
140         const BatchedConstant* constant = &constants[i];
141         functionDescriptor->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly);
142         proto->Set(v8::String::New(constant->name), v8::Integer::New(constant->value), v8::ReadOnly);
143     }
144 }
145
146 typedef HashMap<Node*, v8::Object*> DOMNodeMap;
147 typedef HashMap<void*, v8::Object*> DOMObjectMap;
148
149 #ifndef NDEBUG
150
151 static void enumerateDOMObjectMap(DOMObjectMap& wrapperMap)
152 {
153     for (DOMObjectMap::iterator it = wrapperMap.begin(), end = wrapperMap.end(); it != end; ++it) {
154         v8::Persistent<v8::Object> wrapper(it->second);
155         V8ClassIndex::V8WrapperType type = V8Proxy::domWrapperType(wrapper);
156         void* object = it->first;
157         UNUSED_PARAM(type);
158         UNUSED_PARAM(object);
159     }
160 }
161
162 static void enumerateDOMNodeMap(DOMNodeMap& nodeMap)
163 {
164     for (DOMNodeMap::iterator it = nodeMap.begin(), end = nodeMap.end(); it != end; ++it) {
165         Node* node = it->first;
166         UNUSED_PARAM(node);
167         ASSERT(v8::Persistent<v8::Object>(it->second).IsWeak());
168     }
169 }
170
171 class DOMObjectVisitor : public DOMWrapperMap<void>::Visitor {
172 public:
173     void visitDOMWrapper(void* object, v8::Persistent<v8::Object> wrapper)
174     {
175         V8ClassIndex::V8WrapperType type = V8Proxy::domWrapperType(wrapper);
176         UNUSED_PARAM(type);
177         UNUSED_PARAM(object);
178     }
179 };
180
181 class EnsureWeakDOMNodeVisitor : public DOMWrapperMap<Node>::Visitor {
182 public:
183     void visitDOMWrapper(Node* object, v8::Persistent<v8::Object> wrapper)
184     {
185         UNUSED_PARAM(object);
186         ASSERT(wrapper.IsWeak());
187     }
188 };
189
190 #endif // NDEBUG
191
192 #if ENABLE(SVG)
193 v8::Handle<v8::Value> V8Proxy::convertSVGElementInstanceToV8Object(SVGElementInstance* instance)
194 {
195     if (!instance)
196         return v8::Null();
197
198     v8::Handle<v8::Object> existingInstance = getDOMSVGElementInstanceMap().get(instance);
199     if (!existingInstance.IsEmpty())
200         return existingInstance;
201
202     instance->ref();
203
204     // Instantiate the V8 object and remember it
205     v8::Handle<v8::Object> result = instantiateV8Object(V8ClassIndex::SVGELEMENTINSTANCE, V8ClassIndex::SVGELEMENTINSTANCE, instance);
206     if (!result.IsEmpty()) {
207         // Only update the DOM SVG element map if the result is non-empty.
208         getDOMSVGElementInstanceMap().set(instance, v8::Persistent<v8::Object>::New(result));
209     }
210     return result;
211 }
212
213 // Map of SVG objects with contexts to their contexts
214 static HashMap<void*, SVGElement*>& svgObjectToContextMap()
215 {
216     typedef HashMap<void*, SVGElement*> SvgObjectToContextMap;
217     DEFINE_STATIC_LOCAL(SvgObjectToContextMap, staticSvgObjectToContextMap, ());
218     return staticSvgObjectToContextMap;
219 }
220
221 v8::Handle<v8::Value> V8Proxy::convertSVGObjectWithContextToV8Object(V8ClassIndex::V8WrapperType type, void* object)
222 {
223     if (!object)
224         return v8::Null();
225
226     v8::Persistent<v8::Object> result = getDOMSVGObjectWithContextMap().get(object);
227     if (!result.IsEmpty())
228         return result;
229
230     // Special case: SVGPathSegs need to be downcast to their real type
231     if (type == V8ClassIndex::SVGPATHSEG)
232         type = V8Custom::DowncastSVGPathSeg(object);
233
234     v8::Local<v8::Object> v8Object = instantiateV8Object(type, type, object);
235     if (!v8Object.IsEmpty()) {
236         result = v8::Persistent<v8::Object>::New(v8Object);
237         switch (type) {
238 #define MAKE_CASE(TYPE, NAME)     \
239         case V8ClassIndex::TYPE: static_cast<NAME*>(object)->ref(); break;
240         SVG_OBJECT_TYPES(MAKE_CASE)
241 #undef MAKE_CASE
242 #define MAKE_CASE(TYPE, NAME)     \
243         case V8ClassIndex::TYPE:    \
244             static_cast<V8SVGPODTypeWrapper<NAME>*>(object)->ref(); break;
245         SVG_POD_NATIVE_TYPES(MAKE_CASE)
246 #undef MAKE_CASE
247         default:
248             ASSERT_NOT_REACHED();
249         }
250         getDOMSVGObjectWithContextMap().set(object, result);
251     }
252
253     return result;
254 }
255
256 void V8Proxy::setSVGContext(void* object, SVGElement* context)
257 {
258     if (!object)
259         return;
260
261     SVGElement* oldContext = svgObjectToContextMap().get(object);
262
263     if (oldContext == context)
264         return;
265
266     if (oldContext)
267         oldContext->deref();
268
269     if (context)
270         context->ref();
271
272     svgObjectToContextMap().set(object, context);
273 }
274
275 SVGElement* V8Proxy::svgContext(void* object)
276 {
277     return svgObjectToContextMap().get(object);
278 }
279
280 #endif
281
282 // A map from a DOM node to its JS wrapper, the wrapper
283 // is kept as a strong reference to survive GCs.
284 static DOMObjectMap& gcProtectedMap()
285 {
286     DEFINE_STATIC_LOCAL(DOMObjectMap, staticGcProtectedMap, ());
287     return staticGcProtectedMap;
288 }
289
290 void V8Proxy::gcProtect(void* domObject)
291 {
292     if (!domObject)
293         return;
294     if (gcProtectedMap().contains(domObject))
295         return;
296     if (!getDOMObjectMap().contains(domObject))
297         return;
298
299     // Create a new (strong) persistent handle for the object.
300     v8::Persistent<v8::Object> wrapper = getDOMObjectMap().get(domObject);
301     if (wrapper.IsEmpty())
302         return;
303
304     gcProtectedMap().set(domObject, *v8::Persistent<v8::Object>::New(wrapper));
305 }
306
307 void V8Proxy::gcUnprotect(void* domObject)
308 {
309     if (!domObject)
310         return;
311     if (!gcProtectedMap().contains(domObject))
312         return;
313
314     // Dispose the strong reference.
315     v8::Persistent<v8::Object> wrapper(gcProtectedMap().take(domObject));
316     wrapper.Dispose();
317 }
318
319 class GCPrologueVisitor : public DOMWrapperMap<void>::Visitor {
320 public:
321     void visitDOMWrapper(void* object, v8::Persistent<v8::Object> wrapper)
322     {
323         ASSERT(wrapper.IsWeak());
324         V8ClassIndex::V8WrapperType type = V8Proxy::domWrapperType(wrapper);
325         switch (type) {
326 #define MAKE_CASE(TYPE, NAME)                             \
327         case V8ClassIndex::TYPE: {                    \
328             NAME* impl = static_cast<NAME*>(object);  \
329             if (impl->hasPendingActivity())           \
330                 wrapper.ClearWeak();                  \
331             break;                                    \
332         }
333     ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
334     default:
335         ASSERT_NOT_REACHED();
336 #undef MAKE_CASE
337         }
338
339     // Additional handling of message port ensuring that entangled ports also
340     // have their wrappers entangled. This should ideally be handled when the
341     // ports are actually entangled in MessagePort::entangle, but to avoid
342     // forking MessagePort.* this is postponed to GC time. Having this postponed
343     // has the drawback that the wrappers are "entangled/unentangled" for each
344     // GC even though their entaglement most likely is still the same.
345     if (type == V8ClassIndex::MESSAGEPORT) {
346         // Get the port and its entangled port.
347         MessagePort* port1 = static_cast<MessagePort*>(object);
348         MessagePort* port2 = port1->locallyEntangledPort();
349
350         // If we are remotely entangled, then mark this object as reachable
351         // (we can't determine reachability directly as the remote object is
352         // out-of-proc).
353         if (port1->isEntangled() && !port2)
354             wrapper.ClearWeak();
355
356         if (port2) {
357             // As ports are always entangled in pairs only perform the entanglement
358             // once for each pair (see ASSERT in MessagePort::unentangle()).
359             if (port1 < port2) {
360                 v8::Handle<v8::Value> port1Wrapper = V8Proxy::convertToV8Object(V8ClassIndex::MESSAGEPORT, port1);
361                 v8::Handle<v8::Value> port2Wrapper = V8Proxy::convertToV8Object(V8ClassIndex::MESSAGEPORT, port2);
362                 ASSERT(port1Wrapper->IsObject());
363                 v8::Handle<v8::Object>::Cast(port1Wrapper)->SetInternalField(V8Custom::kMessagePortEntangledPortIndex, port2Wrapper);
364                 ASSERT(port2Wrapper->IsObject());
365                 v8::Handle<v8::Object>::Cast(port2Wrapper)->SetInternalField(V8Custom::kMessagePortEntangledPortIndex, port1Wrapper);
366             }
367         } else {
368             // Remove the wrapper entanglement when a port is not entangled.
369             if (V8Proxy::domObjectHasJSWrapper(port1)) {
370                 v8::Handle<v8::Value> wrapper = V8Proxy::convertToV8Object(V8ClassIndex::MESSAGEPORT, port1);
371                 ASSERT(wrapper->IsObject());
372                 v8::Handle<v8::Object>::Cast(wrapper)->SetInternalField(V8Custom::kMessagePortEntangledPortIndex, v8::Undefined());
373             }
374         }
375     }
376 }
377 };
378
379 class GrouperItem {
380 public:
381     GrouperItem(uintptr_t groupId, Node* node, v8::Persistent<v8::Object> wrapper) 
382         : m_groupId(groupId)
383         , m_node(node)
384         , m_wrapper(wrapper) 
385         {
386         }
387
388     uintptr_t groupId() const { return m_groupId; }
389     Node* node() const { return m_node; }
390     v8::Persistent<v8::Object> wrapper() const { return m_wrapper; }
391
392 private:
393     uintptr_t m_groupId;
394     Node* m_node;
395     v8::Persistent<v8::Object> m_wrapper;
396 };
397
398 bool operator<(const GrouperItem& a, const GrouperItem& b)
399 {
400     return a.groupId() < b.groupId();
401 }
402
403 typedef Vector<GrouperItem> GrouperList;
404
405 class ObjectGrouperVisitor : public DOMWrapperMap<Node>::Visitor {
406 public:
407     ObjectGrouperVisitor()
408     {
409         // FIXME: grouper_.reserveCapacity(node_map.size());  ?
410     }
411
412     void visitDOMWrapper(Node* node, v8::Persistent<v8::Object> wrapper)
413     {
414
415         // If the node is in document, put it in the ownerDocument's object group.
416         //
417         // If an image element was created by JavaScript "new Image",
418         // it is not in a document. However, if the load event has not
419         // been fired (still onloading), it is treated as in the document.
420         //
421         // Otherwise, the node is put in an object group identified by the root
422         // element of the tree to which it belongs.
423         uintptr_t groupId;
424         if (node->inDocument() || (node->hasTagName(HTMLNames::imgTag) && !static_cast<HTMLImageElement*>(node)->haveFiredLoadEvent()))
425             groupId = reinterpret_cast<uintptr_t>(node->document());
426         else {
427             Node* root = node;
428             while (root->parent())
429                 root = root->parent();
430
431             // If the node is alone in its DOM tree (doesn't have a parent or any
432             // children) then the group will be filtered out later anyway.
433             if (root == node && !node->hasChildNodes())
434                 return;
435
436             groupId = reinterpret_cast<uintptr_t>(root);
437         }
438         m_grouper.append(GrouperItem(groupId, node, wrapper));
439     }
440
441     void applyGrouping()
442     {
443         // Group by sorting by the group id.
444         std::sort(m_grouper.begin(), m_grouper.end());
445
446         // FIXME Should probably work in iterators here, but indexes were easier for my simple mind.
447         for (size_t i = 0; i < m_grouper.size(); ) {
448             // Seek to the next key (or the end of the list).
449             size_t nextKeyIndex = m_grouper.size();
450             for (size_t j = i; j < m_grouper.size(); ++j) {
451                 if (m_grouper[i].groupId() != m_grouper[j].groupId()) {
452                     nextKeyIndex = j;
453                     break;
454                 }
455             }
456
457             ASSERT(nextKeyIndex > i);
458
459             // We only care about a group if it has more than one object. If it only
460             // has one object, it has nothing else that needs to be kept alive.
461             if (nextKeyIndex - i <= 1) {
462                 i = nextKeyIndex;
463                 continue;
464             }
465
466             Vector<v8::Persistent<v8::Value> > group;
467             group.reserveCapacity(nextKeyIndex - i);
468             for (; i < nextKeyIndex; ++i) {
469                 Node* node = m_grouper[i].node();
470                 v8::Persistent<v8::Value> wrapper = m_grouper[i].wrapper();
471                 if (!wrapper.IsEmpty())
472                     group.append(wrapper);
473                 /* FIXME: Re-enabled this code to avoid GCing these wrappers!
474                              Currently this depends on looking up the wrapper
475                              during a GC, but we don't know which isolated world
476                              we're in, so it's unclear which map to look in...
477
478                 // If the node is styled and there is a wrapper for the inline
479                 // style declaration, we need to keep that style declaration
480                 // wrapper alive as well, so we add it to the object group.
481                 if (node->isStyledElement()) {
482                   StyledElement* element = reinterpret_cast<StyledElement*>(node);
483                   CSSStyleDeclaration* style = element->inlineStyleDecl();
484                   if (style != NULL) {
485                     wrapper = getDOMObjectMap().get(style);
486                     if (!wrapper.IsEmpty())
487                       group.append(wrapper);
488                   }
489                 }
490                 */
491             }
492
493             if (group.size() > 1)
494                 v8::V8::AddObjectGroup(&group[0], group.size());
495
496             ASSERT(i == nextKeyIndex);
497         }
498     }
499
500 private:
501     GrouperList m_grouper;
502 };
503
504 // Create object groups for DOM tree nodes.
505 static void gcPrologue()
506 {
507     v8::HandleScope scope;
508
509 #ifndef NDEBUG
510     DOMObjectVisitor domObjectVisitor;
511     visitDOMObjectsInCurrentThread(&domObjectVisitor);
512 #endif
513
514     // Run through all objects with possible pending activity making their
515     // wrappers non weak if there is pending activity.
516     GCPrologueVisitor prologueVisitor;
517     visitActiveDOMObjectsInCurrentThread(&prologueVisitor);
518
519     // Create object groups.
520     ObjectGrouperVisitor objectGrouperVisitor;
521     visitDOMNodesInCurrentThread(&objectGrouperVisitor);
522     objectGrouperVisitor.applyGrouping();
523 }
524
525 class GCEpilogueVisitor : public DOMWrapperMap<void>::Visitor {
526 public:
527     void visitDOMWrapper(void* object, v8::Persistent<v8::Object> wrapper)
528     {
529         V8ClassIndex::V8WrapperType type = V8Proxy::domWrapperType(wrapper);
530         switch (type) {
531 #define MAKE_CASE(TYPE, NAME)                                           \
532         case V8ClassIndex::TYPE: {                                  \
533           NAME* impl = static_cast<NAME*>(object);                  \
534           if (impl->hasPendingActivity()) {                         \
535             ASSERT(!wrapper.IsWeak());                              \
536             wrapper.MakeWeak(impl, &weakActiveDOMObjectCallback);   \
537           }                                                         \
538           break;                                                    \
539         }
540 ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
541         default:
542             ASSERT_NOT_REACHED();
543 #undef MAKE_CASE
544     }
545 }
546 };
547
548 static void gcEpilogue()
549 {
550     v8::HandleScope scope;
551
552     // Run through all objects with pending activity making their wrappers weak
553     // again.
554     GCEpilogueVisitor epilogueVisitor;
555     visitActiveDOMObjectsInCurrentThread(&epilogueVisitor);
556
557 #ifndef NDEBUG
558     // Check all survivals are weak.
559     DOMObjectVisitor domObjectVisitor;
560     visitDOMObjectsInCurrentThread(&domObjectVisitor);
561
562     EnsureWeakDOMNodeVisitor weakDOMNodeVisitor;
563     visitDOMNodesInCurrentThread(&weakDOMNodeVisitor);
564
565     enumerateDOMObjectMap(gcProtectedMap());
566     enumerateGlobalHandles();
567 #endif
568 }
569
570 typedef HashMap<int, v8::FunctionTemplate*> FunctionTemplateMap;
571
572 bool AllowAllocation::m_current = false;
573
574 // JavaScriptConsoleMessages encapsulate everything needed to
575 // log messages originating from JavaScript to the Chrome console.
576 class JavaScriptConsoleMessage {
577 public:
578     JavaScriptConsoleMessage(const String& string, const String& sourceID, unsigned lineNumber)
579         : m_string(string)
580         , m_sourceID(sourceID)
581         , m_lineNumber(lineNumber)
582         { 
583         }
584
585     void addToPage(Page*) const;
586
587 private:
588     const String m_string;
589     const String m_sourceID;
590     const unsigned m_lineNumber;
591 };
592
593 void JavaScriptConsoleMessage::addToPage(Page* page) const
594 {
595     ASSERT(page);
596     Console* console = page->mainFrame()->domWindow()->console();
597     console->addMessage(JSMessageSource, ErrorMessageLevel, m_string, m_lineNumber, m_sourceID);
598 }
599
600 // The ConsoleMessageManager handles all console messages that stem
601 // from JavaScript. It keeps a list of messages that have been delayed but
602 // it makes sure to add all messages to the console in the right order.
603 class ConsoleMessageManager {
604 public:
605     // Add a message to the console. May end up calling JavaScript code
606     // indirectly through the inspector so only call this function when
607     // it is safe to do allocations.
608     static void addMessage(Page*, const JavaScriptConsoleMessage&);
609
610     // Add a message to the console but delay the reporting until it
611     // is safe to do so: Either when we leave JavaScript execution or
612     // when adding other console messages. The primary purpose of this
613     // method is to avoid calling into V8 to handle console messages
614     // when the VM is in a state that does not support GCs or allocations.
615     // Delayed messages are always reported in the page corresponding
616     // to the active context.
617     static void addDelayedMessage(const JavaScriptConsoleMessage&);
618
619     // Process any delayed messages. May end up calling JavaScript code
620     // indirectly through the inspector so only call this function when
621     // it is safe to do allocations.
622     static void processDelayedMessages();
623
624 private:
625     // All delayed messages are stored in this vector. If the vector
626     // is NULL, there are no delayed messages.
627     static Vector<JavaScriptConsoleMessage>* m_delayed;
628 };
629
630 Vector<JavaScriptConsoleMessage>* ConsoleMessageManager::m_delayed = 0;
631
632 void ConsoleMessageManager::addMessage(Page* page, const JavaScriptConsoleMessage& message)
633 {
634     // Process any delayed messages to make sure that messages
635     // appear in the right order in the console.
636     processDelayedMessages();
637     message.addToPage(page);
638 }
639
640 void ConsoleMessageManager::addDelayedMessage(const JavaScriptConsoleMessage& message)
641 {
642     if (!m_delayed) {
643         // Allocate a vector for the delayed messages. Will be
644         // deallocated when the delayed messages are processed
645         // in processDelayedMessages().
646         m_delayed = new Vector<JavaScriptConsoleMessage>();
647     }
648     m_delayed->append(message);
649 }
650
651 void ConsoleMessageManager::processDelayedMessages()
652 {
653     // If we have a delayed vector it cannot be empty.
654     if (!m_delayed)
655         return;
656     ASSERT(!m_delayed->isEmpty());
657
658     // Add the delayed messages to the page of the active
659     // context. If that for some bizarre reason does not
660     // exist, we clear the list of delayed messages to avoid
661     // posting messages. We still deallocate the vector.
662     Frame* frame = V8Proxy::retrieveFrameForEnteredContext();
663     Page* page = 0;
664     if (frame)
665         page = frame->page();
666     if (!page)
667         m_delayed->clear();
668
669     // Iterate through all the delayed messages and add them
670     // to the console.
671     const int size = m_delayed->size();
672     for (int i = 0; i < size; i++)
673         m_delayed->at(i).addToPage(page);
674
675     // Deallocate the delayed vector.
676     delete m_delayed;
677     m_delayed = 0;
678 }
679
680 // Convenience class for ensuring that delayed messages in the
681 // ConsoleMessageManager are processed quickly.
682 class ConsoleMessageScope {
683 public:
684     ConsoleMessageScope() { ConsoleMessageManager::processDelayedMessages(); }
685     ~ConsoleMessageScope() { ConsoleMessageManager::processDelayedMessages(); }
686 };
687
688 void logInfo(Frame* frame, const String& message, const String& url)
689 {
690     Page* page = frame->page();
691     if (!page)
692         return;
693     JavaScriptConsoleMessage consoleMessage(message, url, 0);
694     ConsoleMessageManager::addMessage(page, consoleMessage);
695 }
696
697 static void handleConsoleMessage(v8::Handle<v8::Message> message, v8::Handle<v8::Value> data)
698 {
699     // Use the frame where JavaScript is called from.
700     Frame* frame = V8Proxy::retrieveFrameForEnteredContext();
701     if (!frame)
702         return;
703
704     Page* page = frame->page();
705     if (!page)
706         return;
707
708     v8::Handle<v8::String> errorMessageString = message->Get();
709     ASSERT(!errorMessageString.IsEmpty());
710     String errorMessage = ToWebCoreString(errorMessageString);
711
712     v8::Handle<v8::Value> resourceName = message->GetScriptResourceName();
713     bool useURL = resourceName.IsEmpty() || !resourceName->IsString();
714     String resourceNameString = useURL ? frame->document()->url() : ToWebCoreString(resourceName);
715     JavaScriptConsoleMessage consoleMessage(errorMessage, resourceNameString, message->GetLineNumber());
716     ConsoleMessageManager::addMessage(page, consoleMessage);
717 }
718
719 enum DelayReporting {
720     ReportLater,
721     ReportNow
722 };
723
724 static void reportUnsafeAccessTo(Frame* target, DelayReporting delay)
725 {
726     ASSERT(target);
727     Document* targetDocument = target->document();
728     if (!targetDocument)
729         return;
730
731     Frame* source = V8Proxy::retrieveFrameForEnteredContext();
732     if (!source || !source->document())
733         return; // Ignore error if the source document is gone.
734
735     Document* sourceDocument = source->document();
736
737     // FIXME: This error message should contain more specifics of why the same
738     // origin check has failed.
739     String str = String::format("Unsafe JavaScript attempt to access frame "
740                                 "with URL %s from frame with URL %s. "
741                                 "Domains, protocols and ports must match.\n",
742                                 targetDocument->url().string().utf8().data(),
743                                 sourceDocument->url().string().utf8().data());
744
745     // Build a console message with fake source ID and line number.
746     const String kSourceID = "";
747     const int kLineNumber = 1;
748     JavaScriptConsoleMessage message(str, kSourceID, kLineNumber);
749
750     if (delay == ReportNow) {
751         // NOTE: Safari prints the message in the target page, but it seems like
752         // it should be in the source page. Even for delayed messages, we put it in
753         // the source page; see ConsoleMessageManager::processDelayedMessages().
754         ConsoleMessageManager::addMessage(source->page(), message);
755
756     } else {
757         ASSERT(delay == ReportLater);
758         // We cannot safely report the message eagerly, because this may cause
759         // allocations and GCs internally in V8 and we cannot handle that at this
760         // point. Therefore we delay the reporting.
761         ConsoleMessageManager::addDelayedMessage(message);
762     }
763 }
764
765 static void reportUnsafeJavaScriptAccess(v8::Local<v8::Object> host, v8::AccessType type, v8::Local<v8::Value> data)
766 {
767     Frame* target = V8Custom::GetTargetFrame(host, data);
768     if (target)
769         reportUnsafeAccessTo(target, ReportLater);
770 }
771
772 static void handleFatalErrorInV8()
773 {
774     // FIXME: We temporarily deal with V8 internal error situations
775     // such as out-of-memory by crashing the renderer.
776     CRASH();
777 }
778
779 static void reportFatalErrorInV8(const char* location, const char* message)
780 {
781     // V8 is shutdown, we cannot use V8 api.
782     // The only thing we can do is to disable JavaScript.
783     // FIXME: clean up V8Proxy and disable JavaScript.
784     printf("V8 error: %s (%s)\n", message, location);
785     handleFatalErrorInV8();
786 }
787
788 V8Proxy::~V8Proxy()
789 {
790     clearForClose();
791     destroyGlobal();
792 }
793
794 void V8Proxy::destroyGlobal()
795 {
796     if (!m_global.IsEmpty()) {
797 #ifndef NDEBUG
798         unregisterGlobalHandle(this, m_global);
799 #endif
800         m_global.Dispose();
801         m_global.Clear();
802     }
803 }
804
805
806 bool V8Proxy::domObjectHasJSWrapper(void* object)
807 {
808     return getDOMObjectMap().contains(object) || getActiveDOMObjectMap().contains(object);
809 }
810
811 // The caller must have increased obj's ref count.
812 void V8Proxy::setJSWrapperForDOMObject(void* object, v8::Persistent<v8::Object> wrapper)
813 {
814     ASSERT(maybeDOMWrapper(wrapper));
815 #ifndef NDEBUG
816     V8ClassIndex::V8WrapperType type = V8Proxy::domWrapperType(wrapper);
817     switch (type) {
818 #define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE:
819         ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
820         ASSERT_NOT_REACHED();
821 #undef MAKE_CASE
822     default:
823         break;
824     }
825 #endif
826     getDOMObjectMap().set(object, wrapper);
827 }
828
829 // The caller must have increased obj's ref count.
830 void V8Proxy::setJSWrapperForActiveDOMObject(void* object, v8::Persistent<v8::Object> wrapper)
831 {
832     ASSERT(maybeDOMWrapper(wrapper));
833 #ifndef NDEBUG
834     V8ClassIndex::V8WrapperType type = V8Proxy::domWrapperType(wrapper);
835     switch (type) {
836 #define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE: break;
837         ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
838     default: 
839         ASSERT_NOT_REACHED();
840 #undef MAKE_CASE
841     }
842 #endif
843     getActiveDOMObjectMap().set(object, wrapper);
844 }
845
846 // The caller must have increased node's ref count.
847 void V8Proxy::setJSWrapperForDOMNode(Node* node, v8::Persistent<v8::Object> wrapper)
848 {
849     ASSERT(maybeDOMWrapper(wrapper));
850     getDOMNodeMap().set(node, wrapper);
851 }
852
853 // Event listeners
854
855 static V8EventListener* findEventListenerInList(V8EventListenerList& list, v8::Local<v8::Value> listener, bool isInline)
856 {
857     ASSERT(v8::Context::InContext());
858
859     if (!listener->IsObject())
860         return 0;
861
862     return list.find(listener->ToObject(), isInline);
863 }
864
865 // Find an existing wrapper for a JS event listener in the map.
866 PassRefPtr<V8EventListener> V8Proxy::findV8EventListener(v8::Local<v8::Value> listener, bool isInline)
867 {
868     return findEventListenerInList(m_eventListeners, listener, isInline);
869 }
870
871 PassRefPtr<V8EventListener> V8Proxy::findOrCreateV8EventListener(v8::Local<v8::Value> object, bool isInline)
872 {
873     ASSERT(v8::Context::InContext());
874
875     if (!object->IsObject())
876         return 0;
877
878     V8EventListener* wrapper = findEventListenerInList(m_eventListeners, object, isInline);
879     if (wrapper)
880         return wrapper;
881
882     // Create a new one, and add to cache.
883     RefPtr<V8EventListener> newListener = V8EventListener::create(m_frame, v8::Local<v8::Object>::Cast(object), isInline);
884     m_eventListeners.add(newListener.get());
885
886     return newListener;
887 }
888
889 // Object event listeners (such as XmlHttpRequest and MessagePort) are
890 // different from listeners on DOM nodes. An object event listener wrapper
891 // only holds a weak reference to the JS function. A strong reference can
892 // create a cycle.
893 //
894 // The lifetime of these objects is bounded by the life time of its JS
895 // wrapper. So we can create a hidden reference from the JS wrapper to
896 // to its JS function.
897 //
898 //                          (map)
899 //              XHR      <----------  JS_wrapper
900 //               |             (hidden) :  ^
901 //               V                      V  : (may reachable by closure)
902 //           V8_listener  --------> JS_function
903 //                         (weak)  <-- may create a cycle if it is strong
904 //
905 // The persistent reference is made weak in the constructor
906 // of V8ObjectEventListener.
907
908 PassRefPtr<V8EventListener> V8Proxy::findObjectEventListener( v8::Local<v8::Value> listener, bool isInline)
909 {
910     return findEventListenerInList(m_xhrListeners, listener, isInline);
911 }
912
913 PassRefPtr<V8EventListener> V8Proxy::findOrCreateObjectEventListener(v8::Local<v8::Value> object, bool isInline)
914 {
915     ASSERT(v8::Context::InContext());
916
917     if (!object->IsObject())
918         return 0;
919
920     V8EventListener* wrapper = findEventListenerInList(m_xhrListeners, object, isInline);
921     if (wrapper)
922         return wrapper;
923
924     // Create a new one, and add to cache.
925     RefPtr<V8EventListener> newListener = V8ObjectEventListener::create(m_frame, v8::Local<v8::Object>::Cast(object), isInline);
926     m_xhrListeners.add(newListener.get());
927
928     return newListener.release();
929 }
930
931
932 static void removeEventListenerFromList(V8EventListenerList& list, V8EventListener* listener)
933 {
934     list.remove(listener);
935 }
936
937 void V8Proxy::removeV8EventListener(V8EventListener* listener)
938 {
939     removeEventListenerFromList(m_eventListeners, listener);
940 }
941
942
943 void V8Proxy::removeObjectEventListener(V8ObjectEventListener* listener)
944 {
945     removeEventListenerFromList(m_xhrListeners, listener);
946 }
947
948 static void disconnectEventListenersInList(V8EventListenerList& list)
949 {
950     V8EventListenerList::iterator it = list.begin();
951     while (it != list.end()) {
952         (*it)->disconnectFrame();
953         ++it;
954     }
955     list.clear();
956 }
957
958
959 void V8Proxy::disconnectEventListeners()
960 {
961     disconnectEventListenersInList(m_eventListeners);
962     disconnectEventListenersInList(m_xhrListeners);
963 }
964
965
966 v8::Handle<v8::Script> V8Proxy::compileScript(v8::Handle<v8::String> code, const String& fileName, int baseLine)
967 {
968     const uint16_t* fileNameString = FromWebCoreString(fileName);
969     v8::Handle<v8::String> name = v8::String::New(fileNameString, fileName.length());
970     v8::Handle<v8::Integer> line = v8::Integer::New(baseLine);
971     v8::ScriptOrigin origin(name, line);
972     v8::Handle<v8::Script> script = v8::Script::Compile(code, &origin);
973     return script;
974 }
975
976 bool V8Proxy::handleOutOfMemory()
977 {
978     v8::Local<v8::Context> context = v8::Context::GetCurrent();
979
980     if (!context->HasOutOfMemoryException())
981         return false;
982
983     // Warning, error, disable JS for this frame?
984     Frame* frame = V8Proxy::retrieveFrame(context);
985
986     V8Proxy* proxy = V8Proxy::retrieve(frame);
987     if (proxy) {
988         // Clean m_context, and event handlers.
989         proxy->clearForClose();
990
991         proxy->destroyGlobal();
992     }
993
994     ChromiumBridge::notifyJSOutOfMemory(frame);
995
996     // Disable JS.
997     Settings* settings = frame->settings();
998     ASSERT(settings);
999     settings->setJavaScriptEnabled(false);
1000
1001     return true;
1002 }
1003
1004 void V8Proxy::evaluateInNewWorld(const Vector<ScriptSourceCode>& sources)
1005 {
1006     initContextIfNeeded();
1007     V8IsolatedWorld::evaluate(sources, this);
1008 }
1009
1010 void V8Proxy::evaluateInNewContext(const Vector<ScriptSourceCode>& sources)
1011 {
1012     initContextIfNeeded();
1013
1014     v8::HandleScope handleScope;
1015
1016     // Set up the DOM window as the prototype of the new global object.
1017     v8::Handle<v8::Context> windowContext = m_context;
1018     v8::Handle<v8::Object> windowGlobal = windowContext->Global();
1019     v8::Handle<v8::Value> windowWrapper = V8Proxy::lookupDOMWrapper(V8ClassIndex::DOMWINDOW, windowGlobal);
1020
1021     ASSERT(V8Proxy::convertDOMWrapperToNative<DOMWindow>(windowWrapper) == m_frame->domWindow());
1022
1023     v8::Persistent<v8::Context> context = createNewContext(v8::Handle<v8::Object>());
1024     v8::Context::Scope contextScope(context);
1025
1026     // Setup context id for JS debugger.
1027     v8::Handle<v8::Object> contextData = v8::Object::New();
1028     v8::Handle<v8::Value> windowContextData = windowContext->GetData();
1029     if (windowContextData->IsObject()) {
1030         v8::Handle<v8::String> propertyName = v8::String::New(kContextDebugDataValue);
1031         contextData->Set(propertyName, v8::Object::Cast(*windowContextData)->Get(propertyName));
1032     }
1033     contextData->Set(v8::String::New(kContextDebugDataType), v8::String::New("injected"));
1034     context->SetData(contextData);
1035
1036     v8::Handle<v8::Object> global = context->Global();
1037
1038     v8::Handle<v8::String> implicitProtoString = v8::String::New("__proto__");
1039     global->Set(implicitProtoString, windowWrapper);
1040
1041     // Give the code running in the new context a way to get access to the
1042     // original context.
1043     global->Set(v8::String::New("contentWindow"), windowGlobal);
1044
1045     // Run code in the new context.
1046     for (size_t i = 0; i < sources.size(); ++i)
1047         evaluate(sources[i], 0);
1048
1049     // Using the default security token means that the canAccess is always
1050     // called, which is slow.
1051     // FIXME: Use tokens where possible. This will mean keeping track of all
1052     // created contexts so that they can all be updated when the document domain
1053     // changes.
1054     context->UseDefaultSecurityToken();
1055     context.Dispose();
1056 }
1057
1058 v8::Local<v8::Value> V8Proxy::evaluate(const ScriptSourceCode& source, Node* node)
1059 {
1060     ASSERT(v8::Context::InContext());
1061
1062     // Compile the script.
1063     v8::Local<v8::String> code = v8ExternalString(source.source());
1064     ChromiumBridge::traceEventBegin("v8.compile", node, "");
1065
1066     // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at
1067     // 1, whereas v8 starts at 0.
1068     v8::Handle<v8::Script> script = compileScript(code, source.url(), source.startLine() - 1);
1069     ChromiumBridge::traceEventEnd("v8.compile", node, "");
1070
1071     ChromiumBridge::traceEventBegin("v8.run", node, "");
1072     v8::Local<v8::Value> result;
1073     {
1074         // Isolate exceptions that occur when executing the code. These
1075         // exceptions should not interfere with javascript code we might
1076         // evaluate from C++ when returning from here.
1077         v8::TryCatch tryCatch;
1078         tryCatch.SetVerbose(true);
1079
1080         // Set inlineCode to true for <a href="javascript:doSomething()">
1081         // and false for <script>doSomething</script>. We make a rough guess at
1082         // this based on whether the script source has a URL.
1083         result = runScript(script, source.url().string().isNull());
1084     }
1085     ChromiumBridge::traceEventEnd("v8.run", node, "");
1086     return result;
1087 }
1088
1089 v8::Local<v8::Value> V8Proxy::runScript(v8::Handle<v8::Script> script, bool isInlineCode)
1090 {
1091     if (script.IsEmpty())
1092         return notHandledByInterceptor();
1093
1094     // Compute the source string and prevent against infinite recursion.
1095     if (m_recursion >= kMaxRecursionDepth) {
1096         v8::Local<v8::String> code = v8ExternalString("throw RangeError('Recursion too deep')");
1097         // FIXME: Ideally, we should be able to re-use the origin of the
1098         // script passed to us as the argument instead of using an empty string
1099         // and 0 baseLine.
1100         script = compileScript(code, "", 0);
1101     }
1102
1103     if (handleOutOfMemory())
1104         ASSERT(script.IsEmpty());
1105
1106     if (script.IsEmpty())
1107         return notHandledByInterceptor();
1108
1109     // Save the previous value of the inlineCode flag and update the flag for
1110     // the duration of the script invocation.
1111     bool previousInlineCode = inlineCode();
1112     setInlineCode(isInlineCode);
1113
1114     // Run the script and keep track of the current recursion depth.
1115     v8::Local<v8::Value> result;
1116     {
1117         ConsoleMessageScope scope;
1118         m_recursion++;
1119
1120         // See comment in V8Proxy::callFunction.
1121         m_frame->keepAlive();
1122
1123         result = script->Run();
1124         m_recursion--;
1125     }
1126
1127     if (handleOutOfMemory())
1128         ASSERT(result.IsEmpty());
1129
1130     // Handle V8 internal error situation (Out-of-memory).
1131     if (result.IsEmpty())
1132         return notHandledByInterceptor();
1133
1134     // Restore inlineCode flag.
1135     setInlineCode(previousInlineCode);
1136
1137     if (v8::V8::IsDead())
1138         handleFatalErrorInV8();
1139
1140     return result;
1141 }
1142
1143 v8::Local<v8::Value> V8Proxy::callFunction(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[])
1144 {
1145     // For now, we don't put any artificial limitations on the depth
1146     // of recursion that stems from calling functions. This is in
1147     // contrast to the script evaluations.
1148     v8::Local<v8::Value> result;
1149     {
1150         ConsoleMessageScope scope;
1151
1152         // Evaluating the JavaScript could cause the frame to be deallocated,
1153         // so we start the keep alive timer here.
1154         // Frame::keepAlive method adds the ref count of the frame and sets a
1155         // timer to decrease the ref count. It assumes that the current JavaScript
1156         // execution finishs before firing the timer.
1157         m_frame->keepAlive();
1158
1159         result = function->Call(receiver, argc, args);
1160     }
1161
1162     if (v8::V8::IsDead())
1163         handleFatalErrorInV8();
1164
1165     return result;
1166 }
1167
1168 v8::Local<v8::Value> V8Proxy::newInstance(v8::Handle<v8::Function> constructor, int argc, v8::Handle<v8::Value> args[])
1169 {
1170     // No artificial limitations on the depth of recursion, see comment in
1171     // V8Proxy::callFunction.
1172     v8::Local<v8::Value> result;
1173     {
1174         ConsoleMessageScope scope;
1175
1176         // See comment in V8Proxy::callFunction.
1177         m_frame->keepAlive();
1178
1179         result = constructor->NewInstance(argc, args);
1180     }
1181
1182     if (v8::V8::IsDead())
1183         handleFatalErrorInV8();
1184
1185     return result;
1186 }
1187
1188 v8::Local<v8::Function> V8Proxy::getConstructor(V8ClassIndex::V8WrapperType type)
1189 {
1190     // A DOM constructor is a function instance created from a DOM constructor
1191     // template. There is one instance per context. A DOM constructor is
1192     // different from a normal function in two ways:
1193     //   1) it cannot be called as constructor (aka, used to create a DOM object)
1194     //   2) its __proto__ points to Object.prototype rather than
1195     //      Function.prototype.
1196     // The reason for 2) is that, in Safari, a DOM constructor is a normal JS
1197     // object, but not a function. Hotmail relies on the fact that, in Safari,
1198     // HTMLElement.__proto__ == Object.prototype.
1199     //
1200     // m_objectPrototype is a cache of the original Object.prototype.
1201
1202     ASSERT(isContextInitialized());
1203     // Enter the context of the proxy to make sure that the
1204     // function is constructed in the context corresponding to
1205     // this proxy.
1206     v8::Context::Scope scope(m_context);
1207     v8::Handle<v8::FunctionTemplate> functionTemplate = getTemplate(type);
1208     // Getting the function might fail if we're running out of
1209     // stack or memory.
1210     v8::TryCatch tryCatch;
1211     v8::Local<v8::Function> value = functionTemplate->GetFunction();
1212     if (value.IsEmpty())
1213       return v8::Local<v8::Function>();
1214     // Hotmail fix, see comments above.
1215     value->Set(v8::String::New("__proto__"), m_objectPrototype);
1216     return value;
1217 }
1218
1219 v8::Local<v8::Object> V8Proxy::createWrapperFromCache(V8ClassIndex::V8WrapperType type)
1220 {
1221     int classIndex = V8ClassIndex::ToInt(type);
1222     v8::Local<v8::Object> clone(m_wrapperBoilerplates->CloneElementAt(classIndex));
1223     if (!clone.IsEmpty())
1224         return clone;
1225
1226     // Not in cache.
1227     initContextIfNeeded();
1228     v8::Context::Scope scope(m_context);
1229     v8::Local<v8::Function> function = getConstructor(type);
1230     v8::Local<v8::Object> instance = SafeAllocation::newInstance(function);
1231     if (!instance.IsEmpty()) {
1232         m_wrapperBoilerplates->Set(v8::Integer::New(classIndex), instance);
1233         return instance->Clone();
1234     }
1235     return notHandledByInterceptor();
1236 }
1237
1238 // Get the string 'toString'.
1239 static v8::Persistent<v8::String> GetToStringName()
1240 {
1241     DEFINE_STATIC_LOCAL(v8::Persistent<v8::String>, value, ());
1242     if (value.IsEmpty())
1243         value = v8::Persistent<v8::String>::New(v8::String::New("toString"));
1244     return value;
1245 }
1246
1247 static v8::Handle<v8::Value> ConstructorToString(const v8::Arguments& args)
1248 {
1249     // The DOM constructors' toString functions grab the current toString
1250     // for Functions by taking the toString function of itself and then
1251     // calling it with the constructor as its receiver. This means that
1252     // changes to the Function prototype chain or toString function are
1253     // reflected when printing DOM constructors. The only wart is that
1254     // changes to a DOM constructor's toString's toString will cause the
1255     // toString of the DOM constructor itself to change. This is extremely
1256     // obscure and unlikely to be a problem.
1257     v8::Handle<v8::Value> value = args.Callee()->Get(GetToStringName());
1258     if (!value->IsFunction()) 
1259         return v8::String::New("");
1260     return v8::Handle<v8::Function>::Cast(value)->Call(args.This(), 0, 0);
1261 }
1262
1263 v8::Persistent<v8::FunctionTemplate> V8Proxy::getTemplate(V8ClassIndex::V8WrapperType type)
1264 {
1265     v8::Persistent<v8::FunctionTemplate>* cacheCell = V8ClassIndex::GetCache(type);
1266     if (!cacheCell->IsEmpty())
1267         return *cacheCell;
1268
1269     // Not in the cache.
1270     FunctionTemplateFactory factory = V8ClassIndex::GetFactory(type);
1271     v8::Persistent<v8::FunctionTemplate> descriptor = factory();
1272     // DOM constructors are functions and should print themselves as such.
1273     // However, we will later replace their prototypes with Object
1274     // prototypes so we need to explicitly override toString on the
1275     // instance itself. If we later make DOM constructors full objects
1276     // we can give them class names instead and Object.prototype.toString
1277     // will work so we can remove this code.
1278     DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, toStringTemplate, ());
1279     if (toStringTemplate.IsEmpty())
1280         toStringTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(ConstructorToString));
1281     descriptor->Set(GetToStringName(), toStringTemplate);
1282     switch (type) {
1283     case V8ClassIndex::CSSSTYLEDECLARATION:
1284         // The named property handler for style declarations has a
1285         // setter. Therefore, the interceptor has to be on the object
1286         // itself and not on the prototype object.
1287         descriptor->InstanceTemplate()->SetNamedPropertyHandler( USE_NAMED_PROPERTY_GETTER(CSSStyleDeclaration), USE_NAMED_PROPERTY_SETTER(CSSStyleDeclaration));
1288         setCollectionStringOrNullIndexedGetter<CSSStyleDeclaration>(descriptor);
1289         break;
1290     case V8ClassIndex::CSSRULELIST:
1291         setCollectionIndexedGetter<CSSRuleList, CSSRule>(descriptor,  V8ClassIndex::CSSRULE);
1292         break;
1293     case V8ClassIndex::CSSVALUELIST:
1294         setCollectionIndexedGetter<CSSValueList, CSSValue>(descriptor, V8ClassIndex::CSSVALUE);
1295         break;
1296     case V8ClassIndex::CSSVARIABLESDECLARATION:
1297         setCollectionStringOrNullIndexedGetter<CSSVariablesDeclaration>(descriptor);
1298         break;
1299     case V8ClassIndex::WEBKITCSSTRANSFORMVALUE:
1300         setCollectionIndexedGetter<WebKitCSSTransformValue, CSSValue>(descriptor, V8ClassIndex::CSSVALUE);
1301         break;
1302     case V8ClassIndex::UNDETECTABLEHTMLCOLLECTION:
1303         descriptor->InstanceTemplate()->MarkAsUndetectable(); // fall through
1304     case V8ClassIndex::HTMLCOLLECTION:
1305         descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(HTMLCollection));
1306         descriptor->InstanceTemplate()->SetCallAsFunctionHandler(USE_CALLBACK(HTMLCollectionCallAsFunction));
1307         setCollectionIndexedGetter<HTMLCollection, Node>(descriptor, V8ClassIndex::NODE);
1308         break;
1309     case V8ClassIndex::HTMLOPTIONSCOLLECTION:
1310         descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(HTMLCollection));
1311         descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(HTMLOptionsCollection), USE_INDEXED_PROPERTY_SETTER(HTMLOptionsCollection));
1312         descriptor->InstanceTemplate()->SetCallAsFunctionHandler(USE_CALLBACK(HTMLCollectionCallAsFunction));
1313         break;
1314     case V8ClassIndex::HTMLSELECTELEMENT:
1315         descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(HTMLSelectElementCollection));
1316         descriptor->InstanceTemplate()->SetIndexedPropertyHandler(nodeCollectionIndexedPropertyGetter<HTMLSelectElement>, USE_INDEXED_PROPERTY_SETTER(HTMLSelectElementCollection),
1317             0, 0, nodeCollectionIndexedPropertyEnumerator<HTMLSelectElement>, v8::Integer::New(V8ClassIndex::NODE));
1318         break;
1319     case V8ClassIndex::HTMLDOCUMENT: {
1320         descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(HTMLDocument), 0, 0, USE_NAMED_PROPERTY_DELETER(HTMLDocument));
1321
1322         // We add an extra internal field to all Document wrappers for
1323         // storing a per document DOMImplementation wrapper.
1324         //
1325         // Additionally, we add two extra internal fields for
1326         // HTMLDocuments to implement temporary shadowing of
1327         // document.all. One field holds an object that is used as a
1328         // marker. The other field holds the marker object if
1329         // document.all is not shadowed and some other value if
1330         // document.all is shadowed.
1331         v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
1332         ASSERT(instanceTemplate->InternalFieldCount() == V8Custom::kDefaultWrapperInternalFieldCount);
1333         instanceTemplate->SetInternalFieldCount(V8Custom::kHTMLDocumentInternalFieldCount);
1334         break;
1335     }
1336 #if ENABLE(SVG)
1337     case V8ClassIndex::SVGDOCUMENT:  // fall through
1338 #endif
1339     case V8ClassIndex::DOCUMENT: {
1340         // We add an extra internal field to all Document wrappers for
1341         // storing a per document DOMImplementation wrapper.
1342         v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
1343         ASSERT(instanceTemplate->InternalFieldCount() == V8Custom::kDefaultWrapperInternalFieldCount);
1344         instanceTemplate->SetInternalFieldCount( V8Custom::kDocumentMinimumInternalFieldCount);
1345         break;
1346     }
1347     case V8ClassIndex::HTMLAPPLETELEMENT:  // fall through
1348     case V8ClassIndex::HTMLEMBEDELEMENT:  // fall through
1349     case V8ClassIndex::HTMLOBJECTELEMENT:
1350         // HTMLAppletElement, HTMLEmbedElement and HTMLObjectElement are
1351         // inherited from HTMLPlugInElement, and they share the same property
1352         // handling code.
1353         descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(HTMLPlugInElement), USE_NAMED_PROPERTY_SETTER(HTMLPlugInElement));
1354         descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(HTMLPlugInElement), USE_INDEXED_PROPERTY_SETTER(HTMLPlugInElement));
1355         descriptor->InstanceTemplate()->SetCallAsFunctionHandler(USE_CALLBACK(HTMLPlugInElement));
1356         break;
1357     case V8ClassIndex::HTMLFRAMESETELEMENT:
1358         descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(HTMLFrameSetElement));
1359         break;
1360     case V8ClassIndex::HTMLFORMELEMENT:
1361         descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(HTMLFormElement));
1362         descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(HTMLFormElement), 0, 0, 0, nodeCollectionIndexedPropertyEnumerator<HTMLFormElement>, v8::Integer::New(V8ClassIndex::NODE));
1363         break;
1364     case V8ClassIndex::CANVASPIXELARRAY:
1365         descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(CanvasPixelArray), USE_INDEXED_PROPERTY_SETTER(CanvasPixelArray));
1366         break;
1367     case V8ClassIndex::STYLESHEET:  // fall through
1368     case V8ClassIndex::CSSSTYLESHEET: {
1369         // We add an extra internal field to hold a reference to
1370         // the owner node.
1371         v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
1372         ASSERT(instanceTemplate->InternalFieldCount() == V8Custom::kDefaultWrapperInternalFieldCount);
1373         instanceTemplate->SetInternalFieldCount(V8Custom::kStyleSheetInternalFieldCount);
1374         break;
1375     }
1376     case V8ClassIndex::MEDIALIST:
1377         setCollectionStringOrNullIndexedGetter<MediaList>(descriptor);
1378         break;
1379     case V8ClassIndex::MIMETYPEARRAY:
1380         setCollectionIndexedAndNamedGetters<MimeTypeArray, MimeType>(descriptor, V8ClassIndex::MIMETYPE);
1381         break;
1382     case V8ClassIndex::NAMEDNODEMAP:
1383         descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(NamedNodeMap));
1384         descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(NamedNodeMap), 0, 0, 0, collectionIndexedPropertyEnumerator<NamedNodeMap>, v8::Integer::New(V8ClassIndex::NODE));
1385         break;
1386 #if ENABLE(DOM_STORAGE)
1387     case V8ClassIndex::STORAGE:
1388         descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(Storage), USE_NAMED_PROPERTY_SETTER(Storage), 0, USE_NAMED_PROPERTY_DELETER(Storage), V8Custom::v8StorageNamedPropertyEnumerator);
1389         descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(Storage), USE_INDEXED_PROPERTY_SETTER(Storage), 0, USE_INDEXED_PROPERTY_DELETER(Storage));
1390         break;
1391 #endif
1392     case V8ClassIndex::NODELIST:
1393         setCollectionIndexedGetter<NodeList, Node>(descriptor, V8ClassIndex::NODE);
1394         descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(NodeList));
1395         break;
1396     case V8ClassIndex::PLUGIN:
1397         setCollectionIndexedAndNamedGetters<Plugin, MimeType>(descriptor, V8ClassIndex::MIMETYPE);
1398         break;
1399     case V8ClassIndex::PLUGINARRAY:
1400         setCollectionIndexedAndNamedGetters<PluginArray, Plugin>(descriptor, V8ClassIndex::PLUGIN);
1401         break;
1402     case V8ClassIndex::STYLESHEETLIST:
1403         descriptor->InstanceTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(StyleSheetList));
1404         setCollectionIndexedGetter<StyleSheetList, StyleSheet>(descriptor, V8ClassIndex::STYLESHEET);
1405         break;
1406     case V8ClassIndex::DOMWINDOW: {
1407         v8::Local<v8::Signature> defaultSignature = v8::Signature::New(descriptor);
1408
1409         descriptor->PrototypeTemplate()->SetNamedPropertyHandler(USE_NAMED_PROPERTY_GETTER(DOMWindow));
1410         descriptor->PrototypeTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(DOMWindow));
1411
1412         descriptor->SetHiddenPrototype(true);
1413
1414         // Reserve spaces for references to location, history and
1415         // navigator objects.
1416         v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
1417         instanceTemplate->SetInternalFieldCount(V8Custom::kDOMWindowInternalFieldCount);
1418
1419         // Set access check callbacks, but turned off initially.
1420         // When a context is detached from a frame, turn on the access check.
1421         // Turning on checks also invalidates inline caches of the object.
1422         instanceTemplate->SetAccessCheckCallbacks(V8Custom::v8DOMWindowNamedSecurityCheck, V8Custom::v8DOMWindowIndexedSecurityCheck, v8::Integer::New(V8ClassIndex::DOMWINDOW), false);
1423         break;
1424     }
1425     case V8ClassIndex::LOCATION: {
1426         // For security reasons, these functions are on the instance
1427         // instead of on the prototype object to insure that they cannot
1428         // be overwritten.
1429         v8::Local<v8::ObjectTemplate> instance = descriptor->InstanceTemplate();
1430         instance->SetAccessor(v8::String::New("reload"), V8Custom::v8LocationReloadAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly));
1431         instance->SetAccessor(v8::String::New("replace"), V8Custom::v8LocationReplaceAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly));
1432         instance->SetAccessor(v8::String::New("assign"), V8Custom::v8LocationAssignAccessorGetter, 0, v8::Handle<v8::Value>(), v8::ALL_CAN_READ, static_cast<v8::PropertyAttribute>(v8::DontDelete | v8::ReadOnly));
1433         break;
1434     }
1435     case V8ClassIndex::HISTORY:
1436         break;
1437
1438     case V8ClassIndex::MESSAGECHANNEL: {
1439         // Reserve two more internal fields for referencing the port1
1440         // and port2 wrappers. This ensures that the port wrappers are
1441         // kept alive when the channel wrapper is.
1442         descriptor->SetCallHandler(USE_CALLBACK(MessageChannelConstructor));
1443         v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
1444         instanceTemplate->SetInternalFieldCount(V8Custom::kMessageChannelInternalFieldCount);
1445         break;
1446     }
1447
1448     case V8ClassIndex::MESSAGEPORT: {
1449         // Reserve one more internal field for keeping event listeners.
1450         v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
1451         instanceTemplate->SetInternalFieldCount(V8Custom::kMessagePortInternalFieldCount);
1452         break;
1453     }
1454
1455 #if ENABLE(WORKERS)
1456     case V8ClassIndex::WORKER: {
1457         // Reserve one more internal field for keeping event listeners.
1458         v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
1459         instanceTemplate->SetInternalFieldCount(V8Custom::kWorkerInternalFieldCount);
1460         descriptor->SetCallHandler(USE_CALLBACK(WorkerConstructor));
1461         break;
1462     }
1463
1464     case V8ClassIndex::WORKERCONTEXT: {
1465         // Reserve one more internal field for keeping event listeners.
1466         v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
1467         instanceTemplate->SetInternalFieldCount(V8Custom::kWorkerContextInternalFieldCount);
1468         break;
1469     }
1470 #endif // WORKERS
1471
1472     // The following objects are created from JavaScript.
1473     case V8ClassIndex::DOMPARSER:
1474         descriptor->SetCallHandler(USE_CALLBACK(DOMParserConstructor));
1475         break;
1476 #if ENABLE(VIDEO)
1477     case V8ClassIndex::HTMLAUDIOELEMENT:
1478         descriptor->SetCallHandler(USE_CALLBACK(HTMLAudioElementConstructor));
1479         break;
1480 #endif
1481     case V8ClassIndex::HTMLIMAGEELEMENT:
1482         descriptor->SetCallHandler(USE_CALLBACK(HTMLImageElementConstructor));
1483         break;
1484     case V8ClassIndex::HTMLOPTIONELEMENT:
1485         descriptor->SetCallHandler(USE_CALLBACK(HTMLOptionElementConstructor));
1486         break;
1487     case V8ClassIndex::WEBKITCSSMATRIX:
1488         descriptor->SetCallHandler(USE_CALLBACK(WebKitCSSMatrixConstructor));
1489         break;
1490     case V8ClassIndex::WEBKITPOINT:
1491         descriptor->SetCallHandler(USE_CALLBACK(WebKitPointConstructor));
1492         break;
1493     case V8ClassIndex::XMLSERIALIZER:
1494         descriptor->SetCallHandler(USE_CALLBACK(XMLSerializerConstructor));
1495         break;
1496     case V8ClassIndex::XMLHTTPREQUEST: {
1497         // Reserve one more internal field for keeping event listeners.
1498         v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
1499         instanceTemplate->SetInternalFieldCount(V8Custom::kXMLHttpRequestInternalFieldCount);
1500         descriptor->SetCallHandler(USE_CALLBACK(XMLHttpRequestConstructor));
1501         break;
1502     }
1503     case V8ClassIndex::XMLHTTPREQUESTUPLOAD: {
1504         // Reserve one more internal field for keeping event listeners.
1505         v8::Local<v8::ObjectTemplate> instanceTemplate = descriptor->InstanceTemplate();
1506         instanceTemplate->SetInternalFieldCount(V8Custom::kXMLHttpRequestInternalFieldCount);
1507         break;
1508     }
1509     case V8ClassIndex::XPATHEVALUATOR:
1510         descriptor->SetCallHandler(USE_CALLBACK(XPathEvaluatorConstructor));
1511         break;
1512     case V8ClassIndex::XSLTPROCESSOR:
1513         descriptor->SetCallHandler(USE_CALLBACK(XSLTProcessorConstructor));
1514         break;
1515     case V8ClassIndex::CLIENTRECTLIST:
1516         descriptor->InstanceTemplate()->SetIndexedPropertyHandler(USE_INDEXED_PROPERTY_GETTER(ClientRectList));
1517         break;
1518     default:
1519         break;
1520     }
1521
1522     *cacheCell = descriptor;
1523     return descriptor;
1524 }
1525
1526 bool V8Proxy::isContextInitialized()
1527 {
1528     // m_context, m_global, m_objectPrototype and m_wrapperBoilerplates should
1529     // all be non-empty if if m_context is non-empty.
1530     ASSERT(m_context.IsEmpty() || !m_global.IsEmpty());
1531     ASSERT(m_context.IsEmpty() || !m_objectPrototype.IsEmpty());
1532     ASSERT(m_context.IsEmpty() || !m_wrapperBoilerplates.IsEmpty());
1533     return !m_context.IsEmpty();
1534 }
1535
1536 DOMWindow* V8Proxy::retrieveWindow()
1537 {
1538     // FIXME: This seems very fragile. How do we know that the global object
1539     // from the current context is something sensible? Do we need to use the
1540     // last entered here? Who calls this?
1541     return retrieveWindow(v8::Context::GetCurrent());
1542 }
1543
1544 DOMWindow* V8Proxy::retrieveWindow(v8::Handle<v8::Context> context)
1545 {
1546     v8::Handle<v8::Object> global = context->Global();
1547     ASSERT(!global.IsEmpty());
1548     global = lookupDOMWrapper(V8ClassIndex::DOMWINDOW, global);
1549     ASSERT(!global.IsEmpty());
1550     return convertToNativeObject<DOMWindow>(V8ClassIndex::DOMWINDOW, global);
1551 }
1552
1553 Frame* V8Proxy::retrieveFrame(v8::Handle<v8::Context> context)
1554 {
1555     return retrieveWindow(context)->frame();
1556 }
1557
1558 Frame* V8Proxy::retrieveFrameForEnteredContext()
1559 {
1560     v8::Handle<v8::Context> context = v8::Context::GetEntered();
1561     if (context.IsEmpty())
1562         return 0;
1563     return retrieveFrame(context);
1564 }
1565
1566 Frame* V8Proxy::retrieveFrameForCurrentContext()
1567 {
1568     v8::Handle<v8::Context> context = v8::Context::GetCurrent();
1569     if (context.IsEmpty())
1570         return 0;
1571     return retrieveFrame(context);
1572 }
1573
1574 Frame* V8Proxy::retrieveFrameForCallingContext()
1575 {
1576     v8::Handle<v8::Context> context = v8::Context::GetCalling();
1577     if (context.IsEmpty())
1578         return 0;
1579     return retrieveFrame(context);
1580 }
1581
1582 Frame* V8Proxy::retrieveFrame()
1583 {
1584     DOMWindow* window = retrieveWindow();
1585     return window ? window->frame() : 0;
1586 }
1587
1588 V8Proxy* V8Proxy::retrieve()
1589 {
1590     DOMWindow* window = retrieveWindow();
1591     ASSERT(window);
1592     return retrieve(window->frame());
1593 }
1594
1595 V8Proxy* V8Proxy::retrieve(Frame* frame)
1596 {
1597     if (!frame)
1598         return 0;
1599     return frame->script()->isEnabled() ? frame->script()->proxy() : 0;
1600 }
1601
1602 V8Proxy* V8Proxy::retrieve(ScriptExecutionContext* context)
1603 {
1604     if (!context->isDocument())
1605         return 0;
1606     return retrieve(static_cast<Document*>(context)->frame());
1607 }
1608
1609 void V8Proxy::disconnectFrame()
1610 {
1611     disconnectEventListeners();
1612 }
1613
1614 bool V8Proxy::isEnabled()
1615 {
1616     Settings* settings = m_frame->settings();
1617     if (!settings)
1618         return false;
1619
1620     // In the common case, JavaScript is enabled and we're done.
1621     if (settings->isJavaScriptEnabled())
1622         return true;
1623
1624     // If JavaScript has been disabled, we need to look at the frame to tell
1625     // whether this script came from the web or the embedder. Scripts from the
1626     // embedder are safe to run, but scripts from the other sources are
1627     // disallowed.
1628     Document* document = m_frame->document();
1629     if (!document)
1630         return false;
1631
1632     SecurityOrigin* origin = document->securityOrigin();
1633     if (origin->protocol().isEmpty())
1634         return false; // Uninitialized document
1635
1636     if (origin->protocol() == "http" || origin->protocol() == "https")
1637         return false; // Web site
1638
1639     // FIXME: the following are application decisions, and they should
1640     // not be made at this layer. instead, we should bridge out to the
1641     // embedder to allow them to override policy here.
1642
1643     if (origin->protocol() == ChromiumBridge::uiResourceProtocol())
1644         return true;   // Embedder's scripts are ok to run
1645
1646     // If the scheme is ftp: or file:, an empty file name indicates a directory
1647     // listing, which requires JavaScript to function properly.
1648     const char* kDirProtocols[] = { "ftp", "file" };
1649     for (size_t i = 0; i < arraysize(kDirProtocols); ++i) {
1650         if (origin->protocol() == kDirProtocols[i]) {
1651             const KURL& url = document->url();
1652             return url.pathAfterLastSlash() == url.pathEnd();
1653         }
1654     }
1655
1656     return false; // Other protocols fall through to here
1657 }
1658
1659 void V8Proxy::updateDocumentWrapper(v8::Handle<v8::Value> wrapper)
1660 {
1661     clearDocumentWrapper();
1662
1663     ASSERT(m_document.IsEmpty());
1664     m_document = v8::Persistent<v8::Value>::New(wrapper);
1665 #ifndef NDEBUG
1666     registerGlobalHandle(PROXY, this, m_document);
1667 #endif
1668 }
1669
1670 void V8Proxy::clearDocumentWrapper()
1671 {
1672     if (!m_document.IsEmpty()) {
1673 #ifndef NDEBUG
1674         unregisterGlobalHandle(this, m_document);
1675 #endif
1676         m_document.Dispose();
1677         m_document.Clear();
1678     }
1679 }
1680
1681 void V8Proxy::updateDocumentWrapperCache()
1682 {
1683     v8::HandleScope handleScope;
1684     v8::Context::Scope contextScope(context());
1685
1686     // If the document has no frame, NodeToV8Object might get the
1687     // document wrapper for a document that is about to be deleted.
1688     // If the ForceSet below causes a garbage collection, the document
1689     // might get deleted and the global handle for the document
1690     // wrapper cleared. Using the cleared global handle will lead to
1691     // crashes. In this case we clear the cache and let the DOMWindow
1692     // accessor handle access to the document.
1693     if (!m_frame->document()->frame()) {
1694         clearDocumentWrapperCache();
1695         return;
1696     }
1697
1698     v8::Handle<v8::Value> documentWrapper = convertNodeToV8Object(m_frame->document());
1699
1700     // If instantiation of the document wrapper fails, clear the cache
1701     // and let the DOMWindow accessor handle access to the document.
1702     if (documentWrapper.IsEmpty()) {
1703         clearDocumentWrapperCache();
1704         return;
1705     }
1706     m_context->Global()->ForceSet(v8::String::New("document"), documentWrapper, static_cast<v8::PropertyAttribute>(v8::ReadOnly | v8::DontDelete));
1707 }
1708
1709 void V8Proxy::clearDocumentWrapperCache()
1710 {
1711     ASSERT(!m_context.IsEmpty());
1712     m_context->Global()->ForceDelete(v8::String::New("document"));
1713 }
1714
1715 void V8Proxy::disposeContextHandles()
1716 {
1717     if (!m_context.IsEmpty()) {
1718         m_frame->loader()->client()->didDestroyScriptContext();
1719         m_context.Dispose();
1720         m_context.Clear();
1721     }
1722
1723     if (!m_wrapperBoilerplates.IsEmpty()) {
1724 #ifndef NDEBUG
1725         unregisterGlobalHandle(this, m_wrapperBoilerplates);
1726 #endif
1727         m_wrapperBoilerplates.Dispose();
1728         m_wrapperBoilerplates.Clear();
1729     }
1730
1731     if (!m_objectPrototype.IsEmpty()) {
1732 #ifndef NDEBUG
1733         unregisterGlobalHandle(this, m_objectPrototype);
1734 #endif
1735         m_objectPrototype.Dispose();
1736         m_objectPrototype.Clear();
1737     }
1738 }
1739
1740 void V8Proxy::clearForClose()
1741 {
1742     if (!m_context.IsEmpty()) {
1743         v8::HandleScope handleScope;
1744
1745         clearDocumentWrapper();
1746         disposeContextHandles();
1747     }
1748 }
1749
1750 void V8Proxy::clearForNavigation()
1751 {
1752     disconnectEventListeners();
1753
1754     if (!m_context.IsEmpty()) {
1755         v8::HandleScope handle;
1756         clearDocumentWrapper();
1757
1758         v8::Context::Scope contextScope(m_context);
1759
1760         // Clear the document wrapper cache before turning on access checks on
1761         // the old DOMWindow wrapper. This way, access to the document wrapper
1762         // will be protected by the security checks on the DOMWindow wrapper.
1763         clearDocumentWrapperCache();
1764
1765         // Turn on access check on the old DOMWindow wrapper.
1766         v8::Handle<v8::Object> wrapper = lookupDOMWrapper(V8ClassIndex::DOMWINDOW, m_global);
1767         ASSERT(!wrapper.IsEmpty());
1768         wrapper->TurnOnAccessCheck();
1769
1770         // Separate the context from its global object.
1771         m_context->DetachGlobal();
1772
1773         disposeContextHandles();
1774
1775         // Reinitialize the context so the global object points to
1776         // the new DOM window.
1777         initContextIfNeeded();
1778     }
1779 }
1780
1781 void V8Proxy::setSecurityToken()
1782 {
1783     Document* document = m_frame->document();
1784     // Setup security origin and security token.
1785     if (!document) {
1786         m_context->UseDefaultSecurityToken();
1787         return;
1788     }
1789
1790     // Ask the document's SecurityOrigin to generate a security token.
1791     // If two tokens are equal, then the SecurityOrigins canAccess each other.
1792     // If two tokens are not equal, then we have to call canAccess.
1793     // Note: we can't use the HTTPOrigin if it was set from the DOM.
1794     SecurityOrigin* origin = document->securityOrigin();
1795     String token;
1796     if (!origin->domainWasSetInDOM())
1797         token = document->securityOrigin()->toString();
1798
1799     // An empty or "null" token means we always have to call
1800     // canAccess. The toString method on securityOrigins returns the
1801     // string "null" for empty security origins and for security
1802     // origins that should only allow access to themselves. In this
1803     // case, we use the global object as the security token to avoid
1804     // calling canAccess when a script accesses its own objects.
1805     if (token.isEmpty() || token == "null") {
1806         m_context->UseDefaultSecurityToken();
1807         return;
1808     }
1809
1810     CString utf8Token = token.utf8();
1811     // NOTE: V8 does identity comparison in fast path, must use a symbol
1812     // as the security token.
1813     m_context->SetSecurityToken(v8::String::NewSymbol(utf8Token.data(), utf8Token.length()));
1814 }
1815
1816 void V8Proxy::updateDocument()
1817 {
1818     if (!m_frame->document())
1819         return;
1820
1821     if (m_global.IsEmpty()) {
1822         ASSERT(m_context.IsEmpty());
1823         return;
1824     }
1825
1826     // We have a new document and we need to update the cache.
1827     updateDocumentWrapperCache();
1828
1829     updateSecurityOrigin();
1830 }
1831
1832 void V8Proxy::updateSecurityOrigin()
1833 {
1834     v8::HandleScope scope;
1835     setSecurityToken();
1836 }
1837
1838 // Same origin policy implementation:
1839 //
1840 // Same origin policy prevents JS code from domain A access JS & DOM objects
1841 // in a different domain B. There are exceptions and several objects are
1842 // accessible by cross-domain code. For example, the window.frames object is
1843 // accessible by code from a different domain, but window.document is not.
1844 //
1845 // The binding code sets security check callbacks on a function template,
1846 // and accessing instances of the template calls the callback function.
1847 // The callback function checks same origin policy.
1848 //
1849 // Callback functions are expensive. V8 uses a security token string to do
1850 // fast access checks for the common case where source and target are in the
1851 // same domain. A security token is a string object that represents
1852 // the protocol/url/port of a domain.
1853 //
1854 // There are special cases where a security token matching is not enough.
1855 // For example, JavaScript can set its domain to a super domain by calling
1856 // document.setDomain(...). In these cases, the binding code can reset
1857 // a context's security token to its global object so that the fast access
1858 // check will always fail.
1859
1860 // Check if the current execution context can access a target frame.
1861 // First it checks same domain policy using the lexical context
1862 //
1863 // This is equivalent to KJS::Window::allowsAccessFrom(ExecState*, String&).
1864 bool V8Proxy::canAccessPrivate(DOMWindow* targetWindow)
1865 {
1866     ASSERT(targetWindow);
1867
1868     String message;
1869
1870     DOMWindow* originWindow = retrieveWindow();
1871     if (originWindow == targetWindow)
1872         return true;
1873
1874     if (!originWindow)
1875         return false;
1876
1877     const SecurityOrigin* activeSecurityOrigin = originWindow->securityOrigin();
1878     const SecurityOrigin* targetSecurityOrigin = targetWindow->securityOrigin();
1879
1880     // We have seen crashes were the security origin of the target has not been
1881     // initialized. Defend against that.
1882     if (!targetSecurityOrigin)
1883         return false;
1884
1885     if (activeSecurityOrigin->canAccess(targetSecurityOrigin))
1886         return true;
1887
1888     // Allow access to a "about:blank" page if the dynamic context is a
1889     // detached context of the same frame as the blank page.
1890     if (targetSecurityOrigin->isEmpty() && originWindow->frame() == targetWindow->frame())
1891         return true;
1892
1893     return false;
1894 }
1895
1896 bool V8Proxy::canAccessFrame(Frame* target, bool reportError)
1897 {
1898     // The subject is detached from a frame, deny accesses.
1899     if (!target)
1900         return false;
1901
1902     if (!canAccessPrivate(target->domWindow())) {
1903         if (reportError)
1904             reportUnsafeAccessTo(target, ReportNow);
1905         return false;
1906     }
1907     return true;
1908 }
1909
1910 bool V8Proxy::checkNodeSecurity(Node* node)
1911 {
1912     if (!node)
1913         return false;
1914
1915     Frame* target = node->document()->frame();
1916
1917     if (!target)
1918         return false;
1919
1920     return canAccessFrame(target, true);
1921 }
1922
1923 v8::Persistent<v8::Context> V8Proxy::createNewContext(v8::Handle<v8::Object> global)
1924 {
1925     v8::Persistent<v8::Context> result;
1926
1927     // Create a new environment using an empty template for the shadow
1928     // object. Reuse the global object if one has been created earlier.
1929     v8::Persistent<v8::ObjectTemplate> globalTemplate = V8DOMWindow::GetShadowObjectTemplate();
1930     if (globalTemplate.IsEmpty())
1931         return result;
1932
1933     // Install a security handler with V8.
1934     globalTemplate->SetAccessCheckCallbacks(V8Custom::v8DOMWindowNamedSecurityCheck, V8Custom::v8DOMWindowIndexedSecurityCheck, v8::Integer::New(V8ClassIndex::DOMWINDOW));
1935
1936     // Dynamically tell v8 about our extensions now.
1937     OwnArrayPtr<const char*> extensionNames(new const char*[m_extensions.size()]);
1938     int index = 0;
1939     for (V8ExtensionList::iterator it = m_extensions.begin(); it != m_extensions.end(); ++it) {
1940         // Note: we check the loader URL here instead of the document URL
1941         // because we might be currently loading an URL into a blank page.
1942         // See http://code.google.com/p/chromium/issues/detail?id=10924
1943         if (it->scheme.length() > 0 && (it->scheme != m_frame->loader()->activeDocumentLoader()->url().protocol() || it->scheme != m_frame->page()->mainFrame()->loader()->activeDocumentLoader()->url().protocol()))
1944             continue;
1945
1946         extensionNames[index++] = it->extension->name();
1947     }
1948     v8::ExtensionConfiguration extensions(index, extensionNames.get());
1949     result = v8::Context::New(&extensions, globalTemplate, global);
1950
1951     return result;
1952 }
1953
1954 bool V8Proxy::installDOMWindow(v8::Handle<v8::Context> context, DOMWindow* window)
1955 {
1956     v8::Handle<v8::String> implicitProtoString = v8::String::New("__proto__");
1957     if (implicitProtoString.IsEmpty())
1958         return false;
1959
1960     // Create a new JS window object and use it as the prototype for the  shadow global object.
1961     v8::Handle<v8::Function> windowConstructor = getConstructor(V8ClassIndex::DOMWINDOW);
1962     v8::Local<v8::Object> jsWindow = SafeAllocation::newInstance(windowConstructor);
1963     // Bail out if allocation failed.
1964     if (jsWindow.IsEmpty())
1965         return false;
1966
1967     // Wrap the window.
1968     setDOMWrapper(jsWindow, V8ClassIndex::ToInt(V8ClassIndex::DOMWINDOW), window);
1969
1970     window->ref();
1971     V8Proxy::setJSWrapperForDOMObject(window, v8::Persistent<v8::Object>::New(jsWindow));
1972
1973     // Insert the window instance as the prototype of the shadow object.
1974     v8::Handle<v8::Object> v8Global = context->Global();
1975     v8Global->Set(implicitProtoString, jsWindow);
1976     return true;
1977 }
1978
1979 // Create a new environment and setup the global object.
1980 //
1981 // The global object corresponds to a DOMWindow instance. However, to
1982 // allow properties of the JS DOMWindow instance to be shadowed, we
1983 // use a shadow object as the global object and use the JS DOMWindow
1984 // instance as the prototype for that shadow object. The JS DOMWindow
1985 // instance is undetectable from javascript code because the __proto__
1986 // accessors skip that object.
1987 //
1988 // The shadow object and the DOMWindow instance are seen as one object
1989 // from javascript. The javascript object that corresponds to a
1990 // DOMWindow instance is the shadow object. When mapping a DOMWindow
1991 // instance to a V8 object, we return the shadow object.
1992 //
1993 // To implement split-window, see
1994 //   1) https://bugs.webkit.org/show_bug.cgi?id=17249
1995 //   2) https://wiki.mozilla.org/Gecko:SplitWindow
1996 //   3) https://bugzilla.mozilla.org/show_bug.cgi?id=296639
1997 // we need to split the shadow object further into two objects:
1998 // an outer window and an inner window. The inner window is the hidden
1999 // prototype of the outer window. The inner window is the default
2000 // global object of the context. A variable declared in the global
2001 // scope is a property of the inner window.
2002 //
2003 // The outer window sticks to a Frame, it is exposed to JavaScript
2004 // via window.window, window.self, window.parent, etc. The outer window
2005 // has a security token which is the domain. The outer window cannot
2006 // have its own properties. window.foo = 'x' is delegated to the
2007 // inner window.
2008 //
2009 // When a frame navigates to a new page, the inner window is cut off
2010 // the outer window, and the outer window identify is preserved for
2011 // the frame. However, a new inner window is created for the new page.
2012 // If there are JS code holds a closure to the old inner window,
2013 // it won't be able to reach the outer window via its global object.
2014 void V8Proxy::initContextIfNeeded()
2015 {
2016     // Bail out if the context has already been initialized.
2017     if (!m_context.IsEmpty())
2018         return;
2019
2020     // Create a handle scope for all local handles.
2021     v8::HandleScope handleScope;
2022
2023     // Setup the security handlers and message listener. This only has
2024     // to be done once.
2025     static bool isV8Initialized = false;
2026     if (!isV8Initialized) {
2027         // Tells V8 not to call the default OOM handler, binding code
2028         // will handle it.
2029         v8::V8::IgnoreOutOfMemoryException();
2030         v8::V8::SetFatalErrorHandler(reportFatalErrorInV8);
2031
2032         v8::V8::SetGlobalGCPrologueCallback(&gcPrologue);
2033         v8::V8::SetGlobalGCEpilogueCallback(&gcEpilogue);
2034
2035         v8::V8::AddMessageListener(handleConsoleMessage);
2036
2037         v8::V8::SetFailedAccessCheckCallbackFunction(reportUnsafeJavaScriptAccess);
2038
2039         isV8Initialized = true;
2040     }
2041
2042     m_context = createNewContext(m_global);
2043     if (m_context.IsEmpty())
2044         return;
2045
2046     // Starting from now, use local context only.
2047     v8::Local<v8::Context> v8Context = context();
2048     v8::Context::Scope contextScope(v8Context);
2049
2050     // Store the first global object created so we can reuse it.
2051     if (m_global.IsEmpty()) {
2052         m_global = v8::Persistent<v8::Object>::New(v8Context->Global());
2053         // Bail out if allocation of the first global objects fails.
2054         if (m_global.IsEmpty()) {
2055             disposeContextHandles();
2056             return;
2057         }
2058 #ifndef NDEBUG
2059         registerGlobalHandle(PROXY, this, m_global);
2060 #endif
2061     }
2062
2063     // Allocate strings used during initialization.
2064     v8::Handle<v8::String> objectString = v8::String::New("Object");
2065     v8::Handle<v8::String> prototypeString = v8::String::New("prototype");
2066     // Bail out if allocation failed.
2067     if (objectString.IsEmpty() || prototypeString.IsEmpty()) {
2068         disposeContextHandles();
2069         return;
2070     }
2071
2072     // Allocate clone cache and pre-allocated objects
2073     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(m_global->Get(objectString));
2074     m_objectPrototype = v8::Persistent<v8::Value>::New(object->Get(prototypeString));
2075     m_wrapperBoilerplates = v8::Persistent<v8::Array>::New(v8::Array::New(V8ClassIndex::WRAPPER_TYPE_COUNT));
2076     // Bail out if allocation failed.
2077     if (m_objectPrototype.IsEmpty()) {
2078         disposeContextHandles();
2079         return;
2080     }
2081 #ifndef NDEBUG
2082     registerGlobalHandle(PROXY, this, m_objectPrototype);
2083     registerGlobalHandle(PROXY, this, m_wrapperBoilerplates);
2084 #endif
2085
2086     if (!installDOMWindow(v8Context, m_frame->domWindow()))
2087         disposeContextHandles();
2088
2089     updateDocument();
2090
2091     setSecurityToken();
2092
2093     m_frame->loader()->client()->didCreateScriptContext();
2094     m_frame->loader()->dispatchWindowObjectAvailable();
2095 }
2096
2097 template <class T>
2098 void setDOMExceptionHelper(V8ClassIndex::V8WrapperType type, PassRefPtr<T> exception)
2099 {
2100     v8::Handle<v8::Value> v8Exception;
2101     if (WorkerContextExecutionProxy::retrieve())
2102         v8Exception = WorkerContextExecutionProxy::ToV8Object(type, exception.get());
2103     else
2104         v8Exception = V8Proxy::convertToV8Object(type, exception.get());
2105
2106     v8::ThrowException(v8Exception);
2107 }
2108
2109 void V8Proxy::setDOMException(int exceptionCode)
2110 {
2111     if (exceptionCode <= 0)
2112         return;
2113
2114     ExceptionCodeDescription description;
2115     getExceptionCodeDescription(exceptionCode, description);
2116
2117     v8::Handle<v8::Value> exception;
2118     switch (description.type) {
2119     case DOMExceptionType:
2120         setDOMExceptionHelper(V8ClassIndex::DOMCOREEXCEPTION, DOMCoreException::create(description));
2121         break;
2122     case RangeExceptionType:
2123         setDOMExceptionHelper(V8ClassIndex::RANGEEXCEPTION, RangeException::create(description));
2124         break;
2125     case EventExceptionType:
2126         setDOMExceptionHelper(V8ClassIndex::EVENTEXCEPTION, EventException::create(description));
2127         break;
2128     case XMLHttpRequestExceptionType:
2129         setDOMExceptionHelper(V8ClassIndex::XMLHTTPREQUESTEXCEPTION, XMLHttpRequestException::create(description));
2130         break;
2131 #if ENABLE(SVG)
2132     case SVGExceptionType:
2133         setDOMExceptionHelper(V8ClassIndex::SVGEXCEPTION, SVGException::create(description));
2134         break;
2135 #endif
2136 #if ENABLE(XPATH)
2137     case XPathExceptionType:
2138         setDOMExceptionHelper(V8ClassIndex::XPATHEXCEPTION, XPathException::create(description));
2139         break;
2140 #endif
2141     default:
2142         ASSERT_NOT_REACHED();
2143         break;
2144     }
2145 }
2146
2147 v8::Handle<v8::Value> V8Proxy::throwError(ErrorType type, const char* message)
2148 {
2149     switch (type) {
2150     case RangeError:
2151         return v8::ThrowException(v8::Exception::RangeError(v8String(message)));
2152     case ReferenceError:
2153         return v8::ThrowException(v8::Exception::ReferenceError(v8String(message)));
2154     case SyntaxError:
2155         return v8::ThrowException(v8::Exception::SyntaxError(v8String(message)));
2156     case TypeError:
2157         return v8::ThrowException(v8::Exception::TypeError(v8String(message)));
2158     case GeneralError:
2159         return v8::ThrowException(v8::Exception::Error(v8String(message)));
2160     default:
2161         ASSERT_NOT_REACHED();
2162         return notHandledByInterceptor();
2163     }
2164 }
2165
2166 v8::Local<v8::Context> V8Proxy::context(Frame* frame)
2167 {
2168     V8Proxy* proxy = retrieve(frame);
2169     if (!proxy)
2170         return v8::Local<v8::Context>();
2171
2172     proxy->initContextIfNeeded();
2173     return proxy->context();
2174 }
2175
2176 v8::Local<v8::Context> V8Proxy::currentContext()
2177 {
2178     return v8::Context::GetCurrent();
2179 }
2180
2181 v8::Handle<v8::Value> V8Proxy::convertToV8Object(V8ClassIndex::V8WrapperType type, void* impl)
2182 {
2183     ASSERT(type != V8ClassIndex::EVENTLISTENER);
2184     ASSERT(type != V8ClassIndex::EVENTTARGET);
2185     ASSERT(type != V8ClassIndex::EVENT);
2186
2187     bool isActiveDomObject = false;
2188     switch (type) {
2189 #define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE:
2190         DOM_NODE_TYPES(MAKE_CASE)
2191 #if ENABLE(SVG)
2192         SVG_NODE_TYPES(MAKE_CASE)
2193 #endif
2194         return convertNodeToV8Object(static_cast<Node*>(impl));
2195     case V8ClassIndex::CSSVALUE:
2196         return convertCSSValueToV8Object(static_cast<CSSValue*>(impl));
2197     case V8ClassIndex::CSSRULE:
2198         return convertCSSRuleToV8Object(static_cast<CSSRule*>(impl));
2199     case V8ClassIndex::STYLESHEET:
2200         return convertStyleSheetToV8Object(static_cast<StyleSheet*>(impl));
2201     case V8ClassIndex::DOMWINDOW:
2202         return convertWindowToV8Object(static_cast<DOMWindow*>(impl));
2203 #if ENABLE(SVG)
2204         SVG_NONNODE_TYPES(MAKE_CASE)
2205         if (type == V8ClassIndex::SVGELEMENTINSTANCE)
2206             return convertSVGElementInstanceToV8Object(static_cast<SVGElementInstance*>(impl));
2207         return convertSVGObjectWithContextToV8Object(type, impl);
2208 #endif
2209
2210         ACTIVE_DOM_OBJECT_TYPES(MAKE_CASE)
2211         isActiveDomObject = true;
2212         break;
2213     default:
2214         break;
2215   }
2216
2217 #undef MAKE_CASE
2218
2219     if (!impl)
2220         return v8::Null();
2221
2222     // Non DOM node
2223     v8::Persistent<v8::Object> result = isActiveDomObject ? getActiveDOMObjectMap().get(impl) : getDOMObjectMap().get(impl);
2224     if (result.IsEmpty()) {
2225         v8::Local<v8::Object> v8Object = instantiateV8Object(type, type, impl);
2226         if (!v8Object.IsEmpty()) {
2227             // Go through big switch statement, it has some duplications
2228             // that were handled by code above (such as CSSVALUE, CSSRULE, etc).
2229             switch (type) {
2230 #define MAKE_CASE(TYPE, NAME) \
2231             case V8ClassIndex::TYPE: static_cast<NAME*>(impl)->ref(); break;
2232                 DOM_OBJECT_TYPES(MAKE_CASE)
2233 #undef MAKE_CASE
2234             default:
2235                 ASSERT_NOT_REACHED();
2236             }
2237             result = v8::Persistent<v8::Object>::New(v8Object);
2238             if (isActiveDomObject)
2239                 setJSWrapperForActiveDOMObject(impl, result);
2240             else
2241                 setJSWrapperForDOMObject(impl, result);
2242
2243             // Special case for non-node objects associated with a
2244             // DOMWindow. Both Safari and FF let the JS wrappers for these
2245             // objects survive GC. To mimic their behavior, V8 creates
2246             // hidden references from the DOMWindow to these wrapper
2247             // objects. These references get cleared when the DOMWindow is
2248             // reused by a new page.
2249             switch (type) {
2250             case V8ClassIndex::CONSOLE:
2251                 setHiddenWindowReference(static_cast<Console*>(impl)->frame(), V8Custom::kDOMWindowConsoleIndex, result);
2252                 break;
2253             case V8ClassIndex::HISTORY:
2254                 setHiddenWindowReference(static_cast<History*>(impl)->frame(), V8Custom::kDOMWindowHistoryIndex, result);
2255                 break;
2256             case V8ClassIndex::NAVIGATOR:
2257                 setHiddenWindowReference(static_cast<Navigator*>(impl)->frame(), V8Custom::kDOMWindowNavigatorIndex, result);
2258                 break;
2259             case V8ClassIndex::SCREEN:
2260                 setHiddenWindowReference(static_cast<Screen*>(impl)->frame(), V8Custom::kDOMWindowScreenIndex, result);
2261                 break;
2262             case V8ClassIndex::LOCATION:
2263                 setHiddenWindowReference(static_cast<Location*>(impl)->frame(), V8Custom::kDOMWindowLocationIndex, result);
2264                 break;
2265             case V8ClassIndex::DOMSELECTION:
2266                 setHiddenWindowReference(static_cast<DOMSelection*>(impl)->frame(), V8Custom::kDOMWindowDOMSelectionIndex, result);
2267                 break;
2268             case V8ClassIndex::BARINFO: {
2269                 BarInfo* barInfo = static_cast<BarInfo*>(impl);
2270                 Frame* frame = barInfo->frame();
2271                 switch (barInfo->type()) {
2272                 case BarInfo::Locationbar:
2273                     setHiddenWindowReference(frame, V8Custom::kDOMWindowLocationbarIndex, result);
2274                     break;
2275                 case BarInfo::Menubar:
2276                     setHiddenWindowReference(frame, V8Custom::kDOMWindowMenubarIndex, result);
2277                     break;
2278                 case BarInfo::Personalbar:
2279                     setHiddenWindowReference(frame, V8Custom::kDOMWindowPersonalbarIndex, result);
2280                     break;
2281                 case BarInfo::Scrollbars:
2282                     setHiddenWindowReference(frame, V8Custom::kDOMWindowScrollbarsIndex, result);
2283                     break;
2284                 case BarInfo::Statusbar:
2285                     setHiddenWindowReference(frame, V8Custom::kDOMWindowStatusbarIndex, result);
2286                     break;
2287                 case BarInfo::Toolbar:
2288                     setHiddenWindowReference(frame, V8Custom::kDOMWindowToolbarIndex, result);
2289                     break;
2290                 }
2291                 break;
2292             }
2293             default:
2294                 break;
2295             }
2296         }
2297     }
2298     return result;
2299 }
2300
2301 void V8Proxy::setHiddenWindowReference(Frame* frame, const int internalIndex, v8::Handle<v8::Object> jsObject)
2302 {
2303     // Get DOMWindow
2304     if (!frame)
2305         return; // Object might be detached from window
2306     v8::Handle<v8::Context> v8Context = context(frame);
2307     if (v8Context.IsEmpty())
2308         return;
2309
2310     ASSERT(internalIndex < V8Custom::kDOMWindowInternalFieldCount);
2311
2312     v8::Handle<v8::Object> global = v8Context->Global();
2313     // Look for real DOM wrapper.
2314     global = lookupDOMWrapper(V8ClassIndex::DOMWINDOW, global);
2315     ASSERT(!global.IsEmpty());
2316     ASSERT(global->GetInternalField(internalIndex)->IsUndefined());
2317     global->SetInternalField(internalIndex, jsObject);
2318 }
2319
2320 V8ClassIndex::V8WrapperType V8Proxy::domWrapperType(v8::Handle<v8::Object> object)
2321 {
2322     ASSERT(maybeDOMWrapper(object));
2323     v8::Handle<v8::Value> type = object->GetInternalField(V8Custom::kDOMWrapperTypeIndex);
2324     return V8ClassIndex::FromInt(type->Int32Value());
2325 }
2326
2327 void* V8Proxy::convertToNativeObjectImpl(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> object)
2328 {
2329     // Native event listener is per frame, it cannot be handled by this generic function.
2330     ASSERT(type != V8ClassIndex::EVENTLISTENER);
2331     ASSERT(type != V8ClassIndex::EVENTTARGET);
2332
2333     ASSERT(maybeDOMWrapper(object));
2334
2335     switch (type) {
2336 #define MAKE_CASE(TYPE, NAME) case V8ClassIndex::TYPE:
2337         DOM_NODE_TYPES(MAKE_CASE)
2338 #if ENABLE(SVG)
2339         SVG_NODE_TYPES(MAKE_CASE)
2340 #endif
2341         ASSERT_NOT_REACHED();
2342         return 0;
2343     case V8ClassIndex::XMLHTTPREQUEST:
2344         return convertDOMWrapperToNative<XMLHttpRequest>(object);
2345     case V8ClassIndex::EVENT:
2346         return convertDOMWrapperToNative<Event>(object);
2347     case V8ClassIndex::CSSRULE:
2348         return convertDOMWrapperToNative<CSSRule>(object);
2349     default:
2350         break;
2351     }
2352 #undef MAKE_CASE
2353
2354     return convertDOMWrapperToNative<void>(object);
2355 }
2356
2357
2358 void* V8Proxy::convertToSVGPODTypeImpl(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> object)
2359 {
2360     return isWrapperOfType(object, type) ? convertDOMWrapperToNative<void>(object) : 0;
2361 }
2362
2363 v8::Handle<v8::Object> V8Proxy::lookupDOMWrapper(V8ClassIndex::V8WrapperType type, v8::Handle<v8::Value> value)
2364 {
2365     if (value.IsEmpty())
2366         return notHandledByInterceptor();
2367
2368     v8::Handle<v8::FunctionTemplate> descriptor = V8Proxy::getTemplate(type);
2369     while (value->IsObject()) {
2370         v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
2371         if (descriptor->HasInstance(object))
2372             return object;
2373
2374         value = object->GetPrototype();
2375     }
2376     return notHandledByInterceptor();
2377
2378
2379 void* V8Proxy::convertDOMWrapperToNodeHelper(v8::Handle<v8::Value> value)
2380 {
2381     ASSERT(maybeDOMWrapper(value));
2382
2383     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
2384
2385     ASSERT(domWrapperType(object) == V8ClassIndex::NODE);
2386
2387     v8::Handle<v8::Value> wrapper = object->GetInternalField(V8Custom::kDOMWrapperObjectIndex);
2388     return extractCPointer<Node>(wrapper);
2389 }
2390
2391 PassRefPtr<NodeFilter> V8Proxy::wrapNativeNodeFilter(v8::Handle<v8::Value> filter)
2392 {
2393     // A NodeFilter is used when walking through a DOM tree or iterating tree
2394     // nodes.
2395     // FIXME: we may want to cache NodeFilterCondition and NodeFilter
2396     // object, but it is minor.
2397     // NodeFilter is passed to NodeIterator that has a ref counted pointer
2398     // to NodeFilter. NodeFilter has a ref counted pointer to NodeFilterCondition.
2399     // In NodeFilterCondition, filter object is persisted in its constructor,
2400     // and disposed in its destructor.
2401     if (!filter->IsFunction())
2402         return 0;
2403
2404     NodeFilterCondition* condition = new V8NodeFilterCondition(filter);
2405     return NodeFilter::create(condition);
2406 }
2407
2408 v8::Local<v8::Object> V8Proxy::instantiateV8Object(V8Proxy* proxy, V8ClassIndex::V8WrapperType descriptorType, V8ClassIndex::V8WrapperType cptrType, void* impl)
2409 {
2410     // Make a special case for document.all
2411     if (descriptorType == V8ClassIndex::HTMLCOLLECTION && static_cast<HTMLCollection*>(impl)->type() == DocAll)
2412         descriptorType = V8ClassIndex::UNDETECTABLEHTMLCOLLECTION;
2413
2414     if (!proxy)
2415         V8Proxy* proxy = V8Proxy::retrieve();
2416     v8::Local<v8::Object> instance;
2417     if (proxy)
2418         instance = proxy->createWrapperFromCache(descriptorType);
2419     else {
2420         v8::Local<v8::Function> function = getTemplate(descriptorType)->GetFunction();
2421         instance = SafeAllocation::newInstance(function);
2422     }
2423     if (!instance.IsEmpty()) {
2424         // Avoid setting the DOM wrapper for failed allocations.
2425         setDOMWrapper(instance, V8ClassIndex::ToInt(cptrType), impl);
2426     }
2427     return instance;
2428 }
2429
2430 v8::Handle<v8::Value> V8Proxy::checkNewLegal(const v8::Arguments& args)
2431 {
2432     if (!AllowAllocation::m_current)
2433         return throwError(TypeError, "Illegal constructor");
2434
2435     return args.This();
2436 }
2437
2438 void V8Proxy::setDOMWrapper(v8::Handle<v8::Object> object, int type, void* cptr)
2439 {
2440     ASSERT(object->InternalFieldCount() >= 2);
2441     object->SetInternalField(V8Custom::kDOMWrapperObjectIndex, wrapCPointer(cptr));
2442     object->SetInternalField(V8Custom::kDOMWrapperTypeIndex, v8::Integer::New(type));
2443 }
2444
2445 #ifndef NDEBUG
2446 bool V8Proxy::maybeDOMWrapper(v8::Handle<v8::Value> value)
2447 {
2448     if (value.IsEmpty() || !value->IsObject())
2449         return false;
2450
2451     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
2452     if (!object->InternalFieldCount())
2453         return false;
2454
2455     ASSERT(object->InternalFieldCount() >= V8Custom::kDefaultWrapperInternalFieldCount);
2456
2457     v8::Handle<v8::Value> type = object->GetInternalField(V8Custom::kDOMWrapperTypeIndex);
2458     ASSERT(type->IsInt32());
2459     ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && type->Int32Value() < V8ClassIndex::CLASSINDEX_END);
2460
2461     v8::Handle<v8::Value> wrapper = object->GetInternalField(V8Custom::kDOMWrapperObjectIndex);
2462     ASSERT(wrapper->IsNumber() || wrapper->IsExternal());
2463
2464     return true;
2465 }
2466 #endif
2467
2468 bool V8Proxy::isDOMEventWrapper(v8::Handle<v8::Value> value)
2469 {
2470     // All kinds of events use EVENT as dom type in JS wrappers.
2471     // See EventToV8Object
2472     return isWrapperOfType(value, V8ClassIndex::EVENT);
2473 }
2474
2475 bool V8Proxy::isWrapperOfType(v8::Handle<v8::Value> value, V8ClassIndex::V8WrapperType classType)
2476 {
2477     if (value.IsEmpty() || !value->IsObject())
2478         return false;
2479
2480     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
2481     if (!object->InternalFieldCount())
2482         return false;
2483
2484     ASSERT(object->InternalFieldCount() >= V8Custom::kDefaultWrapperInternalFieldCount);
2485
2486     v8::Handle<v8::Value> wrapper = object->GetInternalField(V8Custom::kDOMWrapperObjectIndex);
2487     ASSERT(wrapper->IsNumber() || wrapper->IsExternal());
2488
2489     v8::Handle<v8::Value> type = object->GetInternalField(V8Custom::kDOMWrapperTypeIndex);
2490     ASSERT(type->IsInt32());
2491     ASSERT(V8ClassIndex::INVALID_CLASS_INDEX < type->Int32Value() && type->Int32Value() < V8ClassIndex::CLASSINDEX_END);
2492
2493     return V8ClassIndex::FromInt(type->Int32Value()) == classType;
2494 }
2495
2496 #if ENABLE(VIDEO)
2497 #define FOR_EACH_VIDEO_TAG(macro)                  \
2498     macro(audio, AUDIO)                            \
2499     macro(source, SOURCE)                          \
2500     macro(video, VIDEO)
2501 #else
2502 #define FOR_EACH_VIDEO_TAG(macro)
2503 #endif
2504
2505 #define FOR_EACH_TAG(macro)                        \
2506     macro(a, ANCHOR)                               \
2507     macro(applet, APPLET)                          \
2508     macro(area, AREA)                              \
2509     macro(base, BASE)                              \
2510     macro(basefont, BASEFONT)                      \
2511     macro(blockquote, BLOCKQUOTE)                  \
2512     macro(body, BODY)                              \
2513     macro(br, BR)                                  \
2514     macro(button, BUTTON)                          \
2515     macro(caption, TABLECAPTION)                   \
2516     macro(col, TABLECOL)                           \
2517     macro(colgroup, TABLECOL)                      \
2518     macro(del, MOD)                                \
2519     macro(canvas, CANVAS)                          \
2520     macro(dir, DIRECTORY)                          \
2521     macro(div, DIV)                                \
2522     macro(dl, DLIST)                               \
2523     macro(embed, EMBED)                            \
2524     macro(fieldset, FIELDSET)                      \
2525     macro(font, FONT)                              \
2526     macro(form, FORM)                              \
2527     macro(frame, FRAME)                            \
2528     macro(frameset, FRAMESET)                      \
2529     macro(h1, HEADING)                             \
2530     macro(h2, HEADING)                             \
2531     macro(h3, HEADING)                             \
2532     macro(h4, HEADING)                             \
2533     macro(h5, HEADING)                             \
2534     macro(h6, HEADING)                             \
2535     macro(head, HEAD)                              \
2536     macro(hr, HR)                                  \
2537     macro(html, HTML)                              \
2538     macro(img, IMAGE)                              \
2539     macro(iframe, IFRAME)                          \
2540     macro(image, IMAGE)                            \
2541     macro(input, INPUT)                            \
2542     macro(ins, MOD)                                \
2543     macro(isindex, ISINDEX)                        \
2544     macro(keygen, SELECT)                          \
2545     macro(label, LABEL)                            \
2546     macro(legend, LEGEND)                          \
2547     macro(li, LI)                                  \
2548     macro(link, LINK)                              \
2549     macro(listing, PRE)                            \
2550     macro(map, MAP)                                \
2551     macro(marquee, MARQUEE)                        \
2552     macro(menu, MENU)                              \
2553     macro(meta, META)                              \
2554     macro(object, OBJECT)                          \
2555     macro(ol, OLIST)                               \
2556     macro(optgroup, OPTGROUP)                      \
2557     macro(option, OPTION)                          \
2558     macro(p, PARAGRAPH)                            \
2559     macro(param, PARAM)                            \
2560     macro(pre, PRE)                                \
2561     macro(q, QUOTE)                                \
2562     macro(script, SCRIPT)                          \
2563     macro(select, SELECT)                          \
2564     macro(style, STYLE)                            \
2565     macro(table, TABLE)                            \
2566     macro(thead, TABLESECTION)                     \
2567     macro(tbody, TABLESECTION)                     \
2568     macro(tfoot, TABLESECTION)                     \
2569     macro(td, TABLECELL)                           \
2570     macro(th, TABLECELL)                           \
2571     macro(tr, TABLEROW)                            \
2572     macro(textarea, TEXTAREA)                      \
2573     macro(title, TITLE)                            \
2574     macro(ul, ULIST)                               \
2575     macro(xmp, PRE)
2576
2577 V8ClassIndex::V8WrapperType V8Proxy::htmlElementType(HTMLElement* element)
2578 {
2579     typedef HashMap<String, V8ClassIndex::V8WrapperType> WrapperTypeMap;
2580     DEFINE_STATIC_LOCAL(WrapperTypeMap, wrapperTypeMap, ());
2581     if (wrapperTypeMap.isEmpty()) {
2582 #define ADD_TO_HASH_MAP(tag, name) \
2583         wrapperTypeMap.set(#tag, V8ClassIndex::HTML##name##ELEMENT);
2584         FOR_EACH_TAG(ADD_TO_HASH_MAP)
2585 #if ENABLE(VIDEO)
2586         if (MediaPlayer::isAvailable()) {
2587             FOR_EACH_VIDEO_TAG(ADD_TO_HASH_MAP)
2588         }
2589 #endif
2590 #undef ADD_TO_HASH_MAP
2591     }
2592
2593     V8ClassIndex::V8WrapperType type = wrapperTypeMap.get(element->localName().impl());
2594     if (!type)
2595         return V8ClassIndex::HTMLELEMENT;
2596     return type;
2597 }
2598 #undef FOR_EACH_TAG
2599
2600 #if ENABLE(SVG)
2601
2602 #if ENABLE(SVG_ANIMATION)
2603 #define FOR_EACH_ANIMATION_TAG(macro) \
2604     macro(animateColor, ANIMATECOLOR) \
2605     macro(animate, ANIMATE) \
2606     macro(animateTransform, ANIMATETRANSFORM) \
2607     macro(set, SET)
2608 #else
2609 #define FOR_EACH_ANIMATION_TAG(macro)
2610 #endif
2611
2612 #if ENABLE(SVG_FILTERS)
2613 #define FOR_EACH_FILTERS_TAG(macro) \
2614     macro(feBlend, FEBLEND) \
2615     macro(feColorMatrix, FECOLORMATRIX) \
2616     macro(feComponentTransfer, FECOMPONENTTRANSFER) \
2617     macro(feComposite, FECOMPOSITE) \
2618     macro(feDiffuseLighting, FEDIFFUSELIGHTING) \
2619     macro(feDisplacementMap, FEDISPLACEMENTMAP) \
2620     macro(feDistantLight, FEDISTANTLIGHT) \
2621     macro(feFlood, FEFLOOD) \
2622     macro(feFuncA, FEFUNCA) \
2623     macro(feFuncB, FEFUNCB) \
2624     macro(feFuncG, FEFUNCG) \
2625     macro(feFuncR, FEFUNCR) \
2626     macro(feGaussianBlur, FEGAUSSIANBLUR) \
2627     macro(feImage, FEIMAGE) \
2628     macro(feMerge, FEMERGE) \
2629     macro(feMergeNode, FEMERGENODE) \
2630     macro(feOffset, FEOFFSET) \
2631     macro(fePointLight, FEPOINTLIGHT) \
2632     macro(feSpecularLighting, FESPECULARLIGHTING) \
2633     macro(feSpotLight, FESPOTLIGHT) \
2634     macro(feTile, FETILE) \
2635     macro(feTurbulence, FETURBULENCE) \
2636     macro(filter, FILTER)
2637 #else
2638 #define FOR_EACH_FILTERS_TAG(macro)
2639 #endif
2640
2641 #if ENABLE(SVG_FONTS)
2642 #define FOR_EACH_FONTS_TAG(macro) \
2643     macro(definition-src, DEFINITIONSRC) \
2644     macro(font-face, FONTFACE) \
2645     macro(font-face-format, FONTFACEFORMAT) \
2646     macro(font-face-name, FONTFACENAME) \
2647     macro(font-face-src, FONTFACESRC) \
2648     macro(font-face-uri, FONTFACEURI)
2649 #else
2650 #define FOR_EACH_FONTS_TAG(marco)
2651 #endif
2652
2653 #if ENABLE(SVG_FOREIGN_OBJECT)
2654 #define FOR_EACH_FOREIGN_OBJECT_TAG(macro) \
2655     macro(foreignObject, FOREIGNOBJECT)
2656 #else
2657 #define FOR_EACH_FOREIGN_OBJECT_TAG(macro)
2658 #endif
2659
2660 #if ENABLE(SVG_USE)
2661 #define FOR_EACH_USE_TAG(macro) \
2662     macro(use, USE)
2663 #else
2664 #define FOR_EACH_USE_TAG(macro)
2665 #endif
2666
2667 #define FOR_EACH_TAG(macro) \
2668     FOR_EACH_ANIMATION_TAG(macro) \
2669     FOR_EACH_FILTERS_TAG(macro) \
2670     FOR_EACH_FONTS_TAG(macro) \
2671     FOR_EACH_FOREIGN_OBJECT_TAG(macro) \
2672     FOR_EACH_USE_TAG(macro) \
2673     macro(a, A) \
2674     macro(altGlyph, ALTGLYPH) \
2675     macro(circle, CIRCLE) \
2676     macro(clipPath, CLIPPATH) \
2677     macro(cursor, CURSOR) \
2678     macro(defs, DEFS) \
2679     macro(desc, DESC) \
2680     macro(ellipse, ELLIPSE) \
2681     macro(g, G) \
2682     macro(glyph, GLYPH) \
2683     macro(image, IMAGE) \
2684     macro(linearGradient, LINEARGRADIENT) \
2685     macro(line, LINE) \
2686     macro(marker, MARKER) \
2687     macro(mask, MASK) \
2688     macro(metadata, METADATA) \
2689     macro(path, PATH) \
2690     macro(pattern, PATTERN) \
2691     macro(polyline, POLYLINE) \
2692     macro(polygon, POLYGON) \
2693     macro(radialGradient, RADIALGRADIENT) \
2694     macro(rect, RECT) \
2695     macro(script, SCRIPT) \
2696     macro(stop, STOP) \
2697     macro(style, STYLE) \
2698     macro(svg, SVG) \
2699     macro(switch, SWITCH) \
2700     macro(symbol, SYMBOL) \
2701     macro(text, TEXT) \
2702     macro(textPath, TEXTPATH) \
2703     macro(title, TITLE) \
2704     macro(tref, TREF) \
2705     macro(tspan, TSPAN) \
2706     macro(view, VIEW) \
2707     // end of macro
2708
2709 V8ClassIndex::V8WrapperType V8Proxy::svgElementType(SVGElement* element)
2710 {
2711     typedef HashMap<String, V8ClassIndex::V8WrapperType> WrapperTypeMap;
2712     DEFINE_STATIC_LOCAL(WrapperTypeMap, wrapperTypeMap, ());
2713     if (wrapperTypeMap.isEmpty()) {
2714 #define ADD_TO_HASH_MAP(tag, name) \
2715         wrapperTypeMap.set(#tag, V8ClassIndex::SVG##name##ELEMENT);
2716         FOR_EACH_TAG(ADD_TO_HASH_MAP)
2717 #undef ADD_TO_HASH_MAP
2718     }
2719
2720     V8ClassIndex::V8WrapperType type = wrapperTypeMap.get(element->localName().impl());
2721     if (!type)
2722         return V8ClassIndex::SVGELEMENT;
2723     return type;
2724 }
2725 #undef FOR_EACH_TAG
2726
2727 #endif // ENABLE(SVG)
2728
2729 v8::Handle<v8::Value> V8Proxy::convertEventToV8Object(Event* event)
2730 {
2731     if (!event)
2732         return v8::Null();
2733
2734     v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(event);
2735     if (!wrapper.IsEmpty())
2736         return wrapper;
2737
2738     V8ClassIndex::V8WrapperType type = V8ClassIndex::EVENT;
2739
2740     if (event->isUIEvent()) {
2741         if (event->isKeyboardEvent())
2742             type = V8ClassIndex::KEYBOARDEVENT;
2743         else if (event->isTextEvent())
2744             type = V8ClassIndex::TEXTEVENT;
2745         else if (event->isMouseEvent())
2746             type = V8ClassIndex::MOUSEEVENT;
2747         else if (event->isWheelEvent())
2748             type = V8ClassIndex::WHEELEVENT;
2749 #if ENABLE(SVG)
2750         else if (event->isSVGZoomEvent())
2751             type = V8ClassIndex::SVGZOOMEVENT;
2752 #endif
2753         else
2754             type = V8ClassIndex::UIEVENT;
2755     } else if (event->isMutationEvent())
2756         type = V8ClassIndex::MUTATIONEVENT;
2757     else if (event->isOverflowEvent())
2758         type = V8ClassIndex::OVERFLOWEVENT;
2759     else if (event->isMessageEvent())
2760         type = V8ClassIndex::MESSAGEEVENT;
2761     else if (event->isProgressEvent()) {
2762         if (event->isXMLHttpRequestProgressEvent())
2763             type = V8ClassIndex::XMLHTTPREQUESTPROGRESSEVENT;
2764         else
2765             type = V8ClassIndex::PROGRESSEVENT;
2766     } else if (event->isWebKitAnimationEvent())
2767         type = V8ClassIndex::WEBKITANIMATIONEVENT;
2768     else if (event->isWebKitTransitionEvent())
2769         type = V8ClassIndex::WEBKITTRANSITIONEVENT;
2770
2771
2772     v8::Handle<v8::Object> result = instantiateV8Object(type, V8ClassIndex::EVENT, event);
2773     if (result.IsEmpty()) {
2774         // Instantiation failed. Avoid updating the DOM object map and
2775         // return null which is already handled by callers of this function
2776         // in case the event is NULL.
2777         return v8::Null();
2778     }
2779
2780     event->ref(); // fast ref
2781     setJSWrapperForDOMObject(event, v8::Persistent<v8::Object>::New(result));
2782
2783     return result;
2784 }
2785
2786
2787 static const V8ClassIndex::V8WrapperType mapping[] = {
2788     V8ClassIndex::INVALID_CLASS_INDEX,    // NONE
2789     V8ClassIndex::INVALID_CLASS_INDEX,    // ELEMENT_NODE needs special treatment
2790     V8ClassIndex::ATTR,                   // ATTRIBUTE_NODE
2791     V8ClassIndex::TEXT,                   // TEXT_NODE
2792     V8ClassIndex::CDATASECTION,           // CDATA_SECTION_NODE
2793     V8ClassIndex::ENTITYREFERENCE,        // ENTITY_REFERENCE_NODE
2794     V8ClassIndex::ENTITY,                 // ENTITY_NODE
2795     V8ClassIndex::PROCESSINGINSTRUCTION,  // PROCESSING_INSTRUCTION_NODE
2796     V8ClassIndex::COMMENT,                // COMMENT_NODE
2797     V8ClassIndex::INVALID_CLASS_INDEX,    // DOCUMENT_NODE needs special treatment
2798     V8ClassIndex::DOCUMENTTYPE,           // DOCUMENT_TYPE_NODE
2799     V8ClassIndex::DOCUMENTFRAGMENT,       // DOCUMENT_FRAGMENT_NODE
2800     V8ClassIndex::NOTATION,               // NOTATION_NODE
2801     V8ClassIndex::NODE,                   // XPATH_NAMESPACE_NODE
2802 };
2803
2804 // Caller checks node is not null.
2805 v8::Handle<v8::Value> V8Proxy::convertNodeToV8Object(Node* node)
2806 {
2807     if (!node)
2808         return v8::Null();
2809
2810     // Find a proxy for this node.
2811     //
2812     // Note that if proxy is found, we might initialize the context which can
2813     // instantiate a document wrapper.  Therefore, we get the proxy before
2814     // checking if the node already has a wrapper.
2815     V8Proxy* proxy = 0;
2816     Document* document = node->document();
2817     if (document) {
2818         Frame* frame = document->frame();
2819         proxy = retrieve(frame);
2820         if (proxy)
2821             proxy->initContextIfNeeded();
2822     }
2823
2824     DOMWrapperMap<Node>& domNodeMap = proxy ? proxy->m_domNodeMap : getDOMNodeMap();
2825     v8::Handle<v8::Object> wrapper = domNodeMap.get(node);
2826     if (!wrapper.IsEmpty())
2827         return wrapper;
2828
2829     bool isDocument = false; // document type node has special handling
2830     V8ClassIndex::V8WrapperType type;
2831
2832     Node::NodeType nodeType = node->nodeType();
2833     if (nodeType == Node::ELEMENT_NODE) {
2834         if (node->isHTMLElement())
2835             type = htmlElementType(static_cast<HTMLElement*>(node));
2836 #if ENABLE(SVG)
2837         else if (node->isSVGElement())
2838             type = svgElementType(static_cast<SVGElement*>(node));
2839 #endif
2840         else
2841             type = V8ClassIndex::ELEMENT;
2842     } else if (nodeType == Node::DOCUMENT_NODE) {
2843         isDocument = true;
2844         Document* document = static_cast<Document*>(node);
2845         if (document->isHTMLDocument())
2846             type = V8ClassIndex::HTMLDOCUMENT;
2847 #if ENABLE(SVG)
2848         else if (document->isSVGDocument())
2849             type = V8ClassIndex::SVGDOCUMENT;
2850 #endif
2851         else
2852             type = V8ClassIndex::DOCUMENT;
2853     } else {
2854         ASSERT(nodeType < sizeof(mapping)/sizeof(mapping[0]));
2855         type = mapping[nodeType];
2856         ASSERT(type != V8ClassIndex::INVALID_CLASS_INDEX);
2857     }
2858
2859     v8::Local<v8::Context> v8Context;
2860     if (proxy)
2861         v8Context = proxy->context();
2862
2863     // Enter the node's context and create the wrapper in that context.
2864     if (!v8Context.IsEmpty())
2865         v8Context->Enter();
2866
2867     v8::Local<v8::Object> result = instantiateV8Object(proxy, type, V8ClassIndex::NODE, node);
2868
2869     // Exit the node's context if it was entered.
2870     if (!v8Context.IsEmpty())
2871         v8Context->Exit();
2872
2873     if (result.IsEmpty()) {
2874         // If instantiation failed it's important not to add the result
2875         // to the DOM node map. Instead we return an empty handle, which
2876         // should already be handled by callers of this function in case
2877         // the node is NULL.
2878         return result;
2879     }
2880
2881     node->ref();
2882     domNodeMap.set(node, v8::Persistent<v8::Object>::New(result));
2883
2884     if (isDocument) {
2885         if (proxy)
2886             proxy->updateDocumentWrapper(result);
2887
2888         if (type == V8ClassIndex::HTMLDOCUMENT) {
2889             // Create marker object and insert it in two internal fields.
2890             // This is used to implement temporary shadowing of
2891             // document.all.
2892             ASSERT(result->InternalFieldCount() == V8Custom::kHTMLDocumentInternalFieldCount);
2893             v8::Local<v8::Object> marker = v8::Object::New();
2894             result->SetInternalField(V8Custom::kHTMLDocumentMarkerIndex, marker);
2895             result->SetInternalField(V8Custom::kHTMLDocumentShadowIndex, marker);
2896         }
2897     }
2898
2899     return result;
2900 }
2901
2902 // A JS object of type EventTarget can only be the following possible types:
2903 // 1) EventTargetNode; 2) DOMWindow 3) XMLHttpRequest; 4) MessagePort;
2904 // 5) XMLHttpRequestUpload
2905 // check EventTarget.h for new type conversion methods
2906 v8::Handle<v8::Value> V8Proxy::convertEventTargetToV8Object(EventTarget* target)
2907 {
2908     if (!target)
2909         return v8::Null();
2910
2911 #if ENABLE(SVG)
2912     SVGElementInstance* instance = target->toSVGElementInstance();
2913     if (instance)
2914         return convertToV8Object(V8ClassIndex::SVGELEMENTINSTANCE, instance);
2915 #endif
2916
2917 #if ENABLE(WORKERS)
2918     Worker* worker = target->toWorker();
2919     if (worker)
2920         return convertToV8Object(V8ClassIndex::WORKER, worker);
2921 #endif // WORKERS
2922
2923     Node* node = target->toNode();
2924     if (node)
2925         return convertNodeToV8Object(node);
2926
2927     if (DOMWindow* domWindow = target->toDOMWindow())
2928         return convertToV8Object(V8ClassIndex::DOMWINDOW, domWindow);
2929
2930     // XMLHttpRequest is created within its JS counterpart.
2931     XMLHttpRequest* xmlHttpRequest = target->toXMLHttpRequest();
2932     if (xmlHttpRequest) {
2933         v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(xmlHttpRequest);
2934         ASSERT(!wrapper.IsEmpty());
2935         return wrapper;
2936     }
2937
2938     // MessagePort is created within its JS counterpart
2939     MessagePort* port = target->toMessagePort();
2940     if (port) {
2941         v8::Handle<v8::Object> wrapper = getActiveDOMObjectMap().get(port);
2942         ASSERT(!wrapper.IsEmpty());
2943         return wrapper;
2944     }
2945
2946     XMLHttpRequestUpload* upload = target->toXMLHttpRequestUpload();
2947     if (upload) {
2948         v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(upload);
2949         ASSERT(!wrapper.IsEmpty());
2950         return wrapper;
2951     }
2952
2953     ASSERT(0);
2954     return notHandledByInterceptor();
2955 }
2956
2957 v8::Handle<v8::Value> V8Proxy::convertEventListenerToV8Object(EventListener* listener)
2958 {
2959     if (!listener)
2960         return v8::Null();
2961
2962     // FIXME: can a user take a lazy event listener and set to other places?
2963     V8AbstractEventListener* v8listener = static_cast<V8AbstractEventListener*>(listener);
2964     return v8listener->getListenerObject();
2965 }
2966
2967 v8::Handle<v8::Value> V8Proxy::convertDOMImplementationToV8Object(DOMImplementation* impl)
2968 {
2969     v8::Handle<v8::Object> result = instantiateV8Object(V8ClassIndex::DOMIMPLEMENTATION, V8ClassIndex::DOMIMPLEMENTATION, impl);
2970     if (result.IsEmpty()) {
2971         // If the instantiation failed, we ignore it and return null instead
2972         // of returning an empty handle.
2973         return v8::Null();
2974     }
2975     return result;
2976 }
2977
2978 v8::Handle<v8::Value> V8Proxy::convertStyleSheetToV8Object(StyleSheet* sheet)
2979 {
2980     if (!sheet)
2981         return v8::Null();
2982
2983     v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(sheet);
2984     if (!wrapper.IsEmpty())
2985         return wrapper;
2986
2987     V8ClassIndex::V8WrapperType type = V8ClassIndex::STYLESHEET;
2988     if (sheet->isCSSStyleSheet())
2989         type = V8ClassIndex::CSSSTYLESHEET;
2990
2991     v8::Handle<v8::Object> result = instantiateV8Object(type, V8ClassIndex::STYLESHEET, sheet);
2992     if (!result.IsEmpty()) {
2993         // Only update the DOM object map if the result is non-empty.
2994         sheet->ref();
2995         setJSWrapperForDOMObject(sheet, v8::Persistent<v8::Object>::New(result));
2996     }
2997
2998     // Add a hidden reference from stylesheet object to its owner node.
2999     Node* ownerNode = sheet->ownerNode();
3000     if (ownerNode) {
3001         v8::Handle<v8::Object> owner = v8::Handle<v8::Object>::Cast(convertNodeToV8Object(ownerNode));
3002         result->SetInternalField(V8Custom::kStyleSheetOwnerNodeIndex, owner);
3003     }
3004
3005     return result;
3006 }
3007
3008 v8::Handle<v8::Value> V8Proxy::convertCSSValueToV8Object(CSSValue* value)
3009 {
3010     if (!value)
3011         return v8::Null();
3012
3013     v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(value);
3014     if (!wrapper.IsEmpty())
3015         return wrapper;
3016
3017     V8ClassIndex::V8WrapperType type;
3018
3019     if (value->isWebKitCSSTransformValue())
3020         type = V8ClassIndex::WEBKITCSSTRANSFORMVALUE;
3021     else if (value->isValueList())
3022         type = V8ClassIndex::CSSVALUELIST;
3023     else if (value->isPrimitiveValue())
3024         type = V8ClassIndex::CSSPRIMITIVEVALUE;
3025 #if ENABLE(SVG)
3026     else if (value->isSVGPaint())
3027         type = V8ClassIndex::SVGPAINT;
3028     else if (value->isSVGColor())
3029         type = V8ClassIndex::SVGCOLOR;
3030 #endif
3031     else
3032         type = V8ClassIndex::CSSVALUE;
3033
3034     v8::Handle<v8::Object> result = instantiateV8Object(type, V8ClassIndex::CSSVALUE, value);
3035     if (!result.IsEmpty()) {
3036         // Only update the DOM object map if the result is non-empty.
3037         value->ref();
3038         setJSWrapperForDOMObject(value, v8::Persistent<v8::Object>::New(result));
3039     }
3040
3041     return result;
3042 }
3043
3044 v8::Handle<v8::Value> V8Proxy::convertCSSRuleToV8Object(CSSRule* rule)
3045 {
3046     if (!rule) 
3047         return v8::Null();
3048
3049     v8::Handle<v8::Object> wrapper = getDOMObjectMap().get(rule);
3050     if (!wrapper.IsEmpty())
3051         return wrapper;
3052
3053     V8ClassIndex::V8WrapperType type;
3054
3055     switch (rule->type()) {
3056     case CSSRule::STYLE_RULE:
3057         type = V8ClassIndex::CSSSTYLERULE;
3058         break;
3059     case CSSRule::CHARSET_RULE:
3060         type = V8ClassIndex::CSSCHARSETRULE;
3061         break;
3062     case CSSRule::IMPORT_RULE:
3063         type = V8ClassIndex::CSSIMPORTRULE;
3064         break;
3065     case CSSRule::MEDIA_RULE:
3066         type = V8ClassIndex::CSSMEDIARULE;
3067         break;
3068     case CSSRule::FONT_FACE_RULE:
3069         type = V8ClassIndex::CSSFONTFACERULE;
3070         break;
3071     case CSSRule::PAGE_RULE:
3072         type = V8ClassIndex::CSSPAGERULE;
3073         break;
3074     case CSSRule::VARIABLES_RULE:
3075         type = V8ClassIndex::CSSVARIABLESRULE;
3076         break;
3077     case CSSRule::WEBKIT_KEYFRAME_RULE:
3078         type = V8ClassIndex::WEBKITCSSKEYFRAMERULE;
3079         break;
3080     case CSSRule::WEBKIT_KEYFRAMES_RULE:
3081         type = V8ClassIndex::WEBKITCSSKEYFRAMESRULE;
3082         break;
3083     default:  // CSSRule::UNKNOWN_RULE
3084         type = V8ClassIndex::CSSRULE;
3085         break;
3086     }
3087
3088     v8::Handle<v8::Object> result = instantiateV8Object(type, V8ClassIndex::CSSRULE, rule);
3089     if (!result.IsEmpty()) {
3090         // Only update the DOM object map if the result is non-empty.
3091         rule->ref();
3092         setJSWrapperForDOMObject(rule, v8::Persistent<v8::Object>::New(result));
3093     }
3094     return result;
3095 }
3096
3097 v8::Handle<v8::Value> V8Proxy::convertWindowToV8Object(DOMWindow* window)
3098 {
3099     if (!window)
3100         return v8::Null();
3101     // Initializes environment of a frame, and return the global object
3102     // of the frame.
3103     Frame* frame = window->frame();
3104     if (!frame)
3105         return v8::Handle<v8::Object>();
3106
3107     // Special case: Because of evaluateInNewContext() one DOMWindow can have
3108     // multiple contexts and multiple global objects associated with it. When
3109     // code running in one of those contexts accesses the window object, we
3110     // want to return the global object associated with that context, not
3111     // necessarily the first global object associated with that DOMWindow.
3112     v8::Handle<v8::Context> currentContext = v8::Context::GetCurrent();
3113     v8::Handle<v8::Object> currentGlobal = currentContext->Global();
3114     v8::Handle<v8::Object> windowWrapper = lookupDOMWrapper(V8ClassIndex::DOMWINDOW, currentGlobal);
3115     if (!windowWrapper.IsEmpty()) {
3116         if (convertDOMWrapperToNative<DOMWindow>(windowWrapper) == window)
3117             return currentGlobal;
3118     }
3119
3120     // Otherwise, return the global object associated with this frame.
3121     v8::Handle<v8::Context> v8Context = context(frame);
3122     if (v8Context.IsEmpty())
3123         return v8::Handle<v8::Object>();
3124
3125     v8::Handle<v8::Object> global = v8Context->Global();
3126     ASSERT(!global.IsEmpty());
3127     return global;
3128 }
3129
3130 void V8Proxy::bindJsObjectToWindow(Frame* frame, const char* name, int type, v8::Handle<v8::FunctionTemplate> descriptor, void* impl)
3131 {
3132     // Get environment.
3133     v8::Handle<v8::Context> v8Context = V8Proxy::context(frame);
3134     if (v8Context.IsEmpty())
3135         return; // JS not enabled.
3136
3137     v8::Context::Scope scope(v8Context);
3138     v8::Handle<v8::Object> instance = descriptor->GetFunction();
3139     setDOMWrapper(instance, type, impl);
3140
3141     v8::Handle<v8::Object> global = v8Context->Global();
3142     global->Set(v8::String::New(name), instance);
3143 }
3144
3145 void V8Proxy::processConsoleMessages()
3146 {
3147     ConsoleMessageManager::processDelayedMessages();
3148 }
3149
3150 // Create the utility context for holding JavaScript functions used internally
3151 // which are not visible to JavaScript executing on the page.
3152 void V8Proxy::createUtilityContext()
3153 {
3154     ASSERT(m_utilityContext.IsEmpty());
3155
3156     v8::HandleScope scope;
3157     v8::Handle<v8::ObjectTemplate> globalTemplate = v8::ObjectTemplate::New();
3158     m_utilityContext = v8::Context::New(0, globalTemplate);
3159     v8::Context::Scope contextScope(m_utilityContext);
3160
3161     // Compile JavaScript function for retrieving the source line of the top
3162     // JavaScript stack frame.
3163     DEFINE_STATIC_LOCAL(const char*, frameSourceLineSource,
3164         ("function frameSourceLine(exec_state) {"
3165         "  return exec_state.frame(0).sourceLine();"
3166         "}"));
3167     v8::Script::Compile(v8::String::New(frameSourceLineSource))->Run();
3168
3169     // Compile JavaScript function for retrieving the source name of the top
3170     // JavaScript stack frame.
3171     DEFINE_STATIC_LOCAL(const char*, frameSourceNameSource,
3172         ("function frameSourceName(exec_state) {"
3173         "  var frame = exec_state.frame(0);"
3174         "  if (frame.func().resolved() && "
3175         "      frame.func().script() && "
3176         "      frame.func().script().name()) {"
3177         "    return frame.func().script().name();"
3178         "  }"
3179         "}"));
3180     v8::Script::Compile(v8::String::New(frameSourceNameSource))->Run();
3181 }
3182
3183 int V8Proxy::sourceLineNumber()
3184 {
3185     v8::HandleScope scope;
3186     v8::Handle<v8::Context> v8UtilityContext = V8Proxy::utilityContext();
3187     if (v8UtilityContext.IsEmpty())
3188         return 0;
3189     v8::Context::Scope contextScope(v8UtilityContext);
3190     v8::Handle<v8::Function> frameSourceLine;
3191     frameSourceLine = v8::Local<v8::Function>::Cast(v8UtilityContext->Global()->Get(v8::String::New("frameSourceLine")));
3192     if (frameSourceLine.IsEmpty())
3193         return 0;
3194     v8::Handle<v8::Value> result = v8::Debug::Call(frameSourceLine);
3195     if (result.IsEmpty())
3196         return 0;
3197     return result->Int32Value();
3198 }
3199
3200 String V8Proxy::sourceName()
3201 {
3202     v8::HandleScope scope;
3203     v8::Handle<v8::Context> v8UtilityContext = utilityContext();
3204     if (v8UtilityContext.IsEmpty())
3205         return String();
3206     v8::Context::Scope contextScope(v8UtilityContext);
3207     v8::Handle<v8::Function> frameSourceName;
3208     frameSourceName = v8::Local<v8::Function>::Cast(v8UtilityContext->Global()->Get(v8::String::New("frameSourceName")));
3209     if (frameSourceName.IsEmpty())
3210         return String();
3211     return ToWebCoreString(v8::Debug::Call(frameSourceName));
3212 }
3213
3214 void V8Proxy::registerExtension(v8::Extension* extension, const String& schemeRestriction)
3215 {
3216     v8::RegisterExtension(extension);
3217     V8ExtensionInfo info = {schemeRestriction, extension};
3218     m_extensions.push_back(info);
3219 }
3220
3221 bool V8Proxy::setContextDebugId(int debugId)
3222 {
3223     ASSERT(debugId > 0);
3224     if (m_context.IsEmpty())
3225         return false;
3226     v8::HandleScope scope;
3227     if (!m_context->GetData()->IsUndefined())
3228         return false;
3229
3230     v8::Handle<v8::Object> contextData = v8::Object::New();
3231     contextData->Set(v8::String::New(kContextDebugDataType), v8::String::New("page"));
3232     contextData->Set(v8::String::New(kContextDebugDataValue), v8::Integer::New(debugId));
3233     m_context->SetData(contextData);
3234     return true;
3235 }
3236
3237 int V8Proxy::contextDebugId(v8::Handle<v8::Context> context)
3238 {
3239     v8::HandleScope scope;
3240     if (!context->GetData()->IsObject())
3241         return -1;
3242     v8::Handle<v8::Value> data = context->GetData()->ToObject()->Get( v8::String::New(kContextDebugDataValue));
3243     return data->IsInt32() ? data->Int32Value() : -1;
3244 }
3245
3246 }  // namespace WebCore