• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Apple Inc. All rights reserved.
4  *  Copyright (C) 2007 Samuel Weinig <sam@webkit.org>
5  *  Copyright (C) 2009 Google, Inc. All rights reserved.
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Lesser General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public
18  *  License along with this library; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
20  */
21 
22 #ifndef JSDOMBinding_h
23 #define JSDOMBinding_h
24 
25 #include "JSDOMGlobalObject.h"
26 #include "JSSVGContextCache.h"
27 #include "Document.h"
28 #include <runtime/Completion.h>
29 #include <runtime/Lookup.h>
30 #include <runtime/WeakGCMap.h>
31 #include <wtf/Noncopyable.h>
32 
33 namespace JSC {
34     class JSGlobalData;
35     class DebuggerCallFrame;
36 }
37 
38 namespace WebCore {
39 
40     class Document;
41     class Frame;
42     class JSNode;
43     class KURL;
44     class Node;
45     class String;
46     class ScriptController;
47     class ScriptCachedFrameData;
48 
49     typedef int ExceptionCode;
50 
51 #if ENABLE(SVG)
52     class SVGElement;
53 #endif
54 
55     // Base class for all objects in this binding except Window.
56     class DOMObject : public JSC::JSObject {
57     protected:
DOMObject(NonNullPassRefPtr<JSC::Structure> structure)58         explicit DOMObject(NonNullPassRefPtr<JSC::Structure> structure)
59             : JSObject(structure)
60         {
61         }
62 
63         virtual bool defineOwnProperty(JSC::ExecState*, const JSC::Identifier&, JSC::PropertyDescriptor&, bool);
64 
65 #ifndef NDEBUG
66         virtual ~DOMObject();
67 #endif
68     };
69 
70     // FIXME: This class should collapse into DOMObject once all DOMObjects are
71     // updated to store a globalObject pointer.
72     class DOMObjectWithGlobalPointer : public DOMObject {
73     public:
globalObject()74         JSDOMGlobalObject* globalObject() const { return static_cast<JSDOMGlobalObject*>(getAnonymousValue(GlobalObjectSlot).asCell()); }
75 
scriptExecutionContext()76         ScriptExecutionContext* scriptExecutionContext() const
77         {
78             // FIXME: Should never be 0, but can be due to bug 27640.
79             return globalObject()->scriptExecutionContext();
80         }
81 
createStructure(JSC::JSValue prototype)82         static PassRefPtr<JSC::Structure> createStructure(JSC::JSValue prototype)
83         {
84             return JSC::Structure::create(prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount);
85         }
86 
87     protected:
88         static const unsigned AnonymousSlotCount = 1 + DOMObject::AnonymousSlotCount;
89         static const unsigned GlobalObjectSlot = AnonymousSlotCount - 1;
90 
DOMObjectWithGlobalPointer(NonNullPassRefPtr<JSC::Structure> structure,JSDOMGlobalObject * globalObject)91         DOMObjectWithGlobalPointer(NonNullPassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject)
92             : DOMObject(structure)
93         {
94             // FIXME: This ASSERT is valid, but fires in fast/dom/gc-6.html when trying to create
95             // new JavaScript objects on detached windows due to DOMWindow::document()
96             // needing to reach through the frame to get to the Document*.  See bug 27640.
97             // ASSERT(globalObject->scriptExecutionContext());
98             putAnonymousValue(GlobalObjectSlot, globalObject);
99         }
~DOMObjectWithGlobalPointer()100         virtual ~DOMObjectWithGlobalPointer() { }
101     };
102 
103     // Base class for all constructor objects in the JSC bindings.
104     class DOMConstructorObject : public DOMObjectWithGlobalPointer {
105     public:
createStructure(JSC::JSValue prototype)106         static PassRefPtr<JSC::Structure> createStructure(JSC::JSValue prototype)
107         {
108             return JSC::Structure::create(prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), AnonymousSlotCount);
109         }
110 
111     protected:
112         static const unsigned StructureFlags = JSC::ImplementsHasInstance | JSC::OverridesMarkChildren | DOMObjectWithGlobalPointer::StructureFlags;
DOMConstructorObject(NonNullPassRefPtr<JSC::Structure> structure,JSDOMGlobalObject * globalObject)113         DOMConstructorObject(NonNullPassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject)
114             : DOMObjectWithGlobalPointer(structure, globalObject)
115         {
116         }
117     };
118 
119     // Constructors using this base class depend on being in a Document and
120     // can never be used from a WorkerContext.
121     class DOMConstructorWithDocument : public DOMConstructorObject {
122     public:
document()123         Document* document() const
124         {
125             return static_cast<Document*>(scriptExecutionContext());
126         }
127 
128     protected:
DOMConstructorWithDocument(NonNullPassRefPtr<JSC::Structure> structure,JSDOMGlobalObject * globalObject)129         DOMConstructorWithDocument(NonNullPassRefPtr<JSC::Structure> structure, JSDOMGlobalObject* globalObject)
130             : DOMConstructorObject(structure, globalObject)
131         {
132             ASSERT(globalObject->scriptExecutionContext()->isDocument());
133         }
134     };
135 
136     typedef JSC::WeakGCMap<void*, DOMObject*> DOMObjectWrapperMap;
137     typedef JSC::WeakGCMap<StringImpl*, JSC::JSString*> JSStringCache;
138 
139     class DOMWrapperWorld : public RefCounted<DOMWrapperWorld> {
140     public:
create(JSC::JSGlobalData * globalData,bool isNormal)141         static PassRefPtr<DOMWrapperWorld> create(JSC::JSGlobalData* globalData, bool isNormal)
142         {
143             return adoptRef(new DOMWrapperWorld(globalData, isNormal));
144         }
145         ~DOMWrapperWorld();
146 
detachFromGlobalData()147         void detachFromGlobalData() { m_globalData = 0; }
rememberDocument(Document * document)148         void rememberDocument(Document* document) { documentsWithWrappers.add(document); }
forgetDocument(Document * document)149         void forgetDocument(Document* document) { documentsWithWrappers.remove(document); }
150 
151         // FIXME: can we make this private?
152         DOMObjectWrapperMap m_wrappers;
153         JSStringCache m_stringCache;
154 
isNormal()155         bool isNormal() const { return m_isNormal; }
156 
157     protected:
158         DOMWrapperWorld(JSC::JSGlobalData*, bool isNormal);
159 
160     private:
161         JSC::JSGlobalData* m_globalData;
162         HashSet<Document*> documentsWithWrappers;
163         bool m_isNormal;
164     };
165 
166     // Map from static HashTable instances to per-GlobalData ones.
167     class DOMObjectHashTableMap {
168     public:
169         static DOMObjectHashTableMap& mapFor(JSC::JSGlobalData&);
170 
~DOMObjectHashTableMap()171         ~DOMObjectHashTableMap()
172         {
173             HashMap<const JSC::HashTable*, JSC::HashTable>::iterator mapEnd = m_map.end();
174             for (HashMap<const JSC::HashTable*, JSC::HashTable>::iterator iter = m_map.begin(); iter != m_map.end(); ++iter)
175                 iter->second.deleteTable();
176         }
177 
get(const JSC::HashTable * staticTable)178         const JSC::HashTable* get(const JSC::HashTable* staticTable)
179         {
180             HashMap<const JSC::HashTable*, JSC::HashTable>::iterator iter = m_map.find(staticTable);
181             if (iter != m_map.end())
182                 return &iter->second;
183             return &m_map.set(staticTable, JSC::HashTable(*staticTable)).first->second;
184         }
185 
186     private:
187         HashMap<const JSC::HashTable*, JSC::HashTable> m_map;
188     };
189 
190     class WebCoreJSClientData : public JSC::JSGlobalData::ClientData, public Noncopyable {
191         friend class JSGlobalDataWorldIterator;
192 
193     public:
WebCoreJSClientData(JSC::JSGlobalData * globalData)194         WebCoreJSClientData(JSC::JSGlobalData* globalData)
195             : m_normalWorld(DOMWrapperWorld::create(globalData, true))
196         {
197             m_worldSet.add(m_normalWorld.get());
198         }
199 
~WebCoreJSClientData()200         virtual ~WebCoreJSClientData()
201         {
202             ASSERT(m_worldSet.contains(m_normalWorld.get()));
203             ASSERT(m_worldSet.size() == 1);
204             m_normalWorld->detachFromGlobalData();
205         }
206 
normalWorld()207         DOMWrapperWorld* normalWorld() { return m_normalWorld.get(); }
208 
getAllWorlds(Vector<DOMWrapperWorld * > & worlds)209         void getAllWorlds(Vector<DOMWrapperWorld*>& worlds)
210         {
211             copyToVector(m_worldSet, worlds);
212         }
213 
rememberWorld(DOMWrapperWorld * world)214         void rememberWorld(DOMWrapperWorld* world)
215         {
216             ASSERT(!m_worldSet.contains(world));
217             m_worldSet.add(world);
218         }
forgetWorld(DOMWrapperWorld * world)219         void forgetWorld(DOMWrapperWorld* world)
220         {
221             ASSERT(m_worldSet.contains(world));
222             m_worldSet.remove(world);
223         }
224 
225         DOMObjectHashTableMap hashTableMap;
226     private:
227         HashSet<DOMWrapperWorld*> m_worldSet;
228         RefPtr<DOMWrapperWorld> m_normalWorld;
229     };
230 
231     DOMObject* getCachedDOMObjectWrapper(JSC::ExecState*, void* objectHandle);
232     bool hasCachedDOMObjectWrapper(JSC::JSGlobalData*, void* objectHandle);
233     void cacheDOMObjectWrapper(JSC::ExecState*, void* objectHandle, DOMObject* wrapper);
234     void forgetDOMNode(JSNode* wrapper, Node* node, Document* document);
235     void forgetDOMObject(DOMObject* wrapper, void* objectHandle);
236 
237     JSNode* getCachedDOMNodeWrapper(JSC::ExecState*, Document*, Node*);
238     void cacheDOMNodeWrapper(JSC::ExecState*, Document*, Node*, JSNode* wrapper);
239     void forgetAllDOMNodesForDocument(Document*);
240     void forgetWorldOfDOMNodesForDocument(Document*, DOMWrapperWorld*);
241     void updateDOMNodeDocument(Node*, Document* oldDocument, Document* newDocument);
242 
243     void markDOMNodesForDocument(JSC::MarkStack&, Document*);
244     void markActiveObjectsForContext(JSC::MarkStack&, JSC::JSGlobalData&, ScriptExecutionContext*);
245     void markDOMObjectWrapper(JSC::MarkStack&, JSC::JSGlobalData& globalData, void* object);
246     void markDOMNodeWrapper(JSC::MarkStack& markStack, Document* document, Node* node);
247     bool hasCachedDOMObjectWrapperUnchecked(JSC::JSGlobalData*, void* objectHandle);
248     bool hasCachedDOMNodeWrapperUnchecked(Document*, Node*);
249 
250     JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*);
251     JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, NonNullPassRefPtr<JSC::Structure>, const JSC::ClassInfo*);
252     JSC::Structure* getCachedDOMStructure(JSC::ExecState*, const JSC::ClassInfo*);
253     JSC::Structure* cacheDOMStructure(JSC::ExecState*, NonNullPassRefPtr<JSC::Structure>, const JSC::ClassInfo*);
254 
255     DOMWrapperWorld* currentWorld(JSC::ExecState*);
256     DOMWrapperWorld* normalWorld(JSC::JSGlobalData&);
257     DOMWrapperWorld* mainThreadNormalWorld();
debuggerWorld()258     inline DOMWrapperWorld* debuggerWorld() { return mainThreadNormalWorld(); }
pluginWorld()259     inline DOMWrapperWorld* pluginWorld() { return mainThreadNormalWorld(); }
260 
261     JSC::JSObject* getCachedDOMConstructor(JSC::ExecState*, const JSC::ClassInfo*);
262     void cacheDOMConstructor(JSC::ExecState*, const JSC::ClassInfo*, JSC::JSObject* constructor);
263 
deprecatedGlobalObjectForPrototype(JSC::ExecState * exec)264     inline JSDOMGlobalObject* deprecatedGlobalObjectForPrototype(JSC::ExecState* exec)
265     {
266         // FIXME: Callers to this function should be using the global object
267         // from which the object is being created, instead of assuming the lexical one.
268         // e.g. subframe.document.body should use the subframe's global object, not the lexical one.
269         return static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
270     }
271 
getDOMStructure(JSC::ExecState * exec,JSDOMGlobalObject * globalObject)272     template<class WrapperClass> inline JSC::Structure* getDOMStructure(JSC::ExecState* exec, JSDOMGlobalObject* globalObject)
273     {
274         if (JSC::Structure* structure = getCachedDOMStructure(globalObject, &WrapperClass::s_info))
275             return structure;
276         return cacheDOMStructure(globalObject, WrapperClass::createStructure(WrapperClass::createPrototype(exec, globalObject)), &WrapperClass::s_info);
277     }
deprecatedGetDOMStructure(JSC::ExecState * exec)278     template<class WrapperClass> inline JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState* exec)
279     {
280         // FIXME: This function is wrong.  It uses the wrong global object for creating the prototype structure.
281         return getDOMStructure<WrapperClass>(exec, deprecatedGlobalObjectForPrototype(exec));
282     }
getDOMPrototype(JSC::ExecState * exec,JSC::JSGlobalObject * globalObject)283     template<class WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
284     {
285         return static_cast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(exec, static_cast<JSDOMGlobalObject*>(globalObject))->storedPrototype()));
286     }
287     #define CREATE_DOM_OBJECT_WRAPPER(exec, globalObject, className, object) createDOMObjectWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))
createDOMObjectWrapper(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,DOMClass * object)288     template<class WrapperClass, class DOMClass> inline DOMObject* createDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object)
289     {
290         ASSERT(object);
291         ASSERT(!getCachedDOMObjectWrapper(exec, object));
292         // FIXME: new (exec) could use a different globalData than the globalData this wrapper is cached on.
293         WrapperClass* wrapper = new (exec) WrapperClass(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, object);
294         cacheDOMObjectWrapper(exec, object, wrapper);
295         return wrapper;
296     }
getDOMObjectWrapper(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,DOMClass * object)297     template<class WrapperClass, class DOMClass> inline JSC::JSValue getDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object)
298     {
299         if (!object)
300             return JSC::jsNull();
301         if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec, object))
302             return wrapper;
303         return createDOMObjectWrapper<WrapperClass>(exec, globalObject, object);
304     }
305 
306 #if ENABLE(SVG)
307     #define CREATE_SVG_OBJECT_WRAPPER(exec, globalObject, className, object, context) createDOMObjectWrapper<JS##className>(exec, globalObject, static_cast<className*>(object), context)
createDOMObjectWrapper(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,DOMClass * object,SVGElement * context)308     template<class WrapperClass, class DOMClass> inline DOMObject* createDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object, SVGElement* context)
309     {
310         DOMObject* wrapper = createDOMObjectWrapper<WrapperClass, DOMClass>(exec, globalObject, object);
311         ASSERT(wrapper);
312         if (context)
313             JSSVGContextCache::addWrapper(wrapper, context);
314         return wrapper;
315     }
getDOMObjectWrapper(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,DOMClass * object,SVGElement * context)316     template<class WrapperClass, class DOMClass> inline JSC::JSValue getDOMObjectWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* object, SVGElement* context)
317     {
318         if (!object)
319             return JSC::jsNull();
320         if (DOMObject* wrapper = getCachedDOMObjectWrapper(exec, object)) {
321             ASSERT(JSSVGContextCache::svgContextForDOMObject(wrapper) == context);
322             return wrapper;
323         }
324         return createDOMObjectWrapper<WrapperClass, DOMClass>(exec, globalObject, object, context);
325     }
326 #endif
327 
328     #define CREATE_DOM_NODE_WRAPPER(exec, globalObject, className, object) createDOMNodeWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))
createDOMNodeWrapper(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,DOMClass * node)329     template<class WrapperClass, class DOMClass> inline JSNode* createDOMNodeWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node)
330     {
331         ASSERT(node);
332         ASSERT(!getCachedDOMNodeWrapper(exec, node->document(), node));
333         WrapperClass* wrapper = new (exec) WrapperClass(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, node);
334         // FIXME: The entire function can be removed, once we fix caching.
335         // This function is a one-off hack to make Nodes cache in the right global object.
336         cacheDOMNodeWrapper(exec, node->document(), node, wrapper);
337         return wrapper;
338     }
getDOMNodeWrapper(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,DOMClass * node)339     template<class WrapperClass, class DOMClass> inline JSC::JSValue getDOMNodeWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node)
340     {
341         if (!node)
342             return JSC::jsNull();
343         if (JSNode* wrapper = getCachedDOMNodeWrapper(exec, node->document(), node))
344             return wrapper;
345         return createDOMNodeWrapper<WrapperClass>(exec, globalObject, node);
346     }
347 
348     const JSC::HashTable* getHashTableForGlobalData(JSC::JSGlobalData&, const JSC::HashTable* staticTable);
349 
350     void reportException(JSC::ExecState*, JSC::JSValue exception);
351     void reportCurrentException(JSC::ExecState*);
352 
353     // Convert a DOM implementation exception code into a JavaScript exception in the execution state.
354     void setDOMException(JSC::ExecState*, ExceptionCode);
355 
356     JSC::JSValue jsString(JSC::ExecState*, const String&); // empty if the string is null
357     JSC::JSValue jsStringSlowCase(JSC::ExecState*, JSStringCache&, StringImpl*);
358     JSC::JSValue jsString(JSC::ExecState*, const KURL&); // empty if the URL is null
jsString(JSC::ExecState * exec,const AtomicString & s)359     inline JSC::JSValue jsString(JSC::ExecState* exec, const AtomicString& s)
360     {
361         return jsString(exec, s.string());
362     }
363 
364     JSC::JSValue jsStringOrNull(JSC::ExecState*, const String&); // null if the string is null
365     JSC::JSValue jsStringOrNull(JSC::ExecState*, const KURL&); // null if the URL is null
366 
367     JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const String&); // undefined if the string is null
368     JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const KURL&); // undefined if the URL is null
369 
370     JSC::JSValue jsStringOrFalse(JSC::ExecState*, const String&); // boolean false if the string is null
371     JSC::JSValue jsStringOrFalse(JSC::ExecState*, const KURL&); // boolean false if the URL is null
372 
373     // See JavaScriptCore for explanation: Should be used for any UString that is already owned by another
374     // object, to let the engine know that collecting the JSString wrapper is unlikely to save memory.
375     JSC::JSValue jsOwnedStringOrNull(JSC::ExecState*, const JSC::UString&);
376 
377     JSC::UString valueToStringWithNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null
378     JSC::UString valueToStringWithUndefinedOrNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null or undefined
379 
380     // Returns a Date instance for the specified value, or null if the value is NaN or infinity.
381     JSC::JSValue jsDateOrNull(JSC::ExecState*, double);
382     // NaN if the value can't be converted to a date.
383     double valueToDate(JSC::ExecState*, JSC::JSValue);
384 
385     // FIXME: These are a stop-gap until all toJS calls can be converted to pass a globalObject
386     template <typename T>
toJS(JSC::ExecState * exec,T * ptr)387     inline JSC::JSValue toJS(JSC::ExecState* exec, T* ptr)
388     {
389         return toJS(exec, deprecatedGlobalObjectForPrototype(exec), ptr);
390     }
391     template <typename T>
toJS(JSC::ExecState * exec,PassRefPtr<T> ptr)392     inline JSC::JSValue toJS(JSC::ExecState* exec, PassRefPtr<T> ptr)
393     {
394         return toJS(exec, deprecatedGlobalObjectForPrototype(exec), ptr.get());
395     }
396     template <typename T>
toJSNewlyCreated(JSC::ExecState * exec,T * ptr)397     inline JSC::JSValue toJSNewlyCreated(JSC::ExecState* exec, T* ptr)
398     {
399         return toJSNewlyCreated(exec, deprecatedGlobalObjectForPrototype(exec), ptr);
400     }
401 
402     template <typename T>
toJS(JSC::ExecState * exec,JSDOMGlobalObject * globalObject,PassRefPtr<T> ptr)403     inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<T> ptr)
404     {
405         return toJS(exec, globalObject, ptr.get());
406     }
407 
408     // Validates that the passed object is a sequence type per section 4.1.13 of the WebIDL spec.
409     JSC::JSObject* toJSSequence(JSC::ExecState*, JSC::JSValue, unsigned&);
410 
411     bool checkNodeSecurity(JSC::ExecState*, Node*);
412 
413     // Helpers for Window, History, and Location classes to implement cross-domain policy.
414     // Besides the cross-domain check, they need non-caching versions of staticFunctionGetter for
415     // because we do not want current property values involved at all.
416     bool allowsAccessFromFrame(JSC::ExecState*, Frame*);
417     bool allowsAccessFromFrame(JSC::ExecState*, Frame*, String& message);
418     bool shouldAllowNavigation(JSC::ExecState*, Frame*);
419     void printErrorMessageForFrame(Frame*, const String& message);
420     JSC::JSValue objectToStringFunctionGetter(JSC::ExecState*, const JSC::Identifier& propertyName, const JSC::PropertySlot&);
421 
422     Frame* toLexicalFrame(JSC::ExecState*);
423     Frame* toDynamicFrame(JSC::ExecState*);
424     bool processingUserGesture(JSC::ExecState*);
425     KURL completeURL(JSC::ExecState*, const String& relativeURL);
426 
currentWorld(JSC::ExecState * exec)427     inline DOMWrapperWorld* currentWorld(JSC::ExecState* exec)
428     {
429         return static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->world();
430     }
431 
jsString(JSC::ExecState * exec,const String & s)432     inline JSC::JSValue jsString(JSC::ExecState* exec, const String& s)
433     {
434         StringImpl* stringImpl = s.impl();
435         if (!stringImpl || !stringImpl->length())
436             return jsEmptyString(exec);
437 
438         if (stringImpl->length() == 1 && stringImpl->characters()[0] <= 0xFF)
439             return jsString(exec, stringImpl->ustring());
440 
441         JSStringCache& stringCache = currentWorld(exec)->m_stringCache;
442         if (JSC::JSString* wrapper = stringCache.get(stringImpl))
443             return wrapper;
444 
445         return jsStringSlowCase(exec, stringCache, stringImpl);
446     }
447 
448 } // namespace WebCore
449 
450 #endif // JSDOMBinding_h
451