Remove home-brewed nullptr
[WebKit-https.git] / Source / WebCore / bindings / js / JSDOMBinding.h
1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009, 2013 Apple Inc. All rights reserved.
4  *  Copyright (C) 2007 Samuel Weinig <sam@webkit.org>
5  *  Copyright (C) 2009 Google, Inc. All rights reserved.
6  *  Copyright (C) 2012 Ericsson AB. All rights reserved.
7  *  Copyright (C) 2013 Michael Pruett <michael@68k.org>
8  *
9  *  This library is free software; you can redistribute it and/or
10  *  modify it under the terms of the GNU Lesser General Public
11  *  License as published by the Free Software Foundation; either
12  *  version 2 of the License, or (at your option) any later version.
13  *
14  *  This library is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  *  Lesser General Public License for more details.
18  *
19  *  You should have received a copy of the GNU Lesser General Public
20  *  License along with this library; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22  */
23
24 #ifndef JSDOMBinding_h
25 #define JSDOMBinding_h
26
27 #include "BindingState.h"
28 #include "JSDOMGlobalObject.h"
29 #include "JSDOMWrapper.h"
30 #include "DOMWrapperWorld.h"
31 #include "ScriptWrappable.h"
32 #include "ScriptWrappableInlines.h"
33 #include "WebCoreTypedArrayController.h"
34 #include <cstddef>
35 #include <heap/Weak.h>
36 #include <heap/WeakInlines.h>
37 #include <runtime/Error.h>
38 #include <runtime/FunctionPrototype.h>
39 #include <runtime/JSArray.h>
40 #include <runtime/JSArrayBuffer.h>
41 #include <runtime/JSDataView.h>
42 #include <runtime/JSTypedArrays.h>
43 #include <runtime/Lookup.h>
44 #include <runtime/ObjectPrototype.h>
45 #include <runtime/Operations.h>
46 #include <runtime/TypedArrayInlines.h>
47 #include <runtime/TypedArrays.h>
48 #include <wtf/Forward.h>
49 #include <wtf/Noncopyable.h>
50 #include <wtf/Vector.h>
51
52 namespace JSC {
53 class HashEntry;
54 }
55
56 namespace WebCore {
57
58 class DOMStringList;
59
60     class CachedScript;
61     class Document;
62     class Frame;
63     class HTMLDocument;
64     class KURL;
65     class Node;
66
67     typedef int ExceptionCode;
68
69     // Base class for all constructor objects in the JSC bindings.
70     class DOMConstructorObject : public JSDOMWrapper {
71         typedef JSDOMWrapper Base;
72     public:
73         static JSC::Structure* createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
74         {
75             return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
76         }
77
78     protected:
79         static const unsigned StructureFlags = JSC::ImplementsHasInstance | JSC::OverridesVisitChildren | JSDOMWrapper::StructureFlags;
80         DOMConstructorObject(JSC::Structure* structure, JSDOMGlobalObject* globalObject)
81             : JSDOMWrapper(structure, globalObject)
82         {
83         }
84     };
85
86     JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*);
87     JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, JSC::Structure*, const JSC::ClassInfo*);
88
89     inline JSDOMGlobalObject* deprecatedGlobalObjectForPrototype(JSC::ExecState* exec)
90     {
91         // FIXME: Callers to this function should be using the global object
92         // from which the object is being created, instead of assuming the lexical one.
93         // e.g. subframe.document.body should use the subframe's global object, not the lexical one.
94         return JSC::jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
95     }
96
97     template<class WrapperClass> inline JSC::Structure* getDOMStructure(JSC::ExecState* exec, JSDOMGlobalObject* globalObject)
98     {
99         if (JSC::Structure* structure = getCachedDOMStructure(globalObject, WrapperClass::info()))
100             return structure;
101         return cacheDOMStructure(globalObject, WrapperClass::createStructure(exec->vm(), globalObject, WrapperClass::createPrototype(exec, globalObject)), WrapperClass::info());
102     }
103
104     template<class WrapperClass> inline JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState* exec)
105     {
106         // FIXME: This function is wrong.  It uses the wrong global object for creating the prototype structure.
107         return getDOMStructure<WrapperClass>(exec, deprecatedGlobalObjectForPrototype(exec));
108     }
109
110     template<class WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject)
111     {
112         return JSC::jsCast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(exec, JSC::jsCast<JSDOMGlobalObject*>(globalObject))->storedPrototype()));
113     }
114
115     inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld* world, JSC::ArrayBuffer*)
116     {
117         return static_cast<WebCoreTypedArrayController*>(world->vm()->m_typedArrayController.get())->wrapperOwner();
118     }
119     
120     inline void* wrapperContext(DOMWrapperWorld* world, JSC::ArrayBuffer*)
121     {
122         return world;
123     }
124
125     inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld*, void*) { return 0; }
126     inline bool setInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMWrapper*, JSC::WeakHandleOwner*, void*) { return false; }
127     inline bool clearInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMWrapper*) { return false; }
128
129     inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld* world, ScriptWrappable* domObject)
130     {
131         if (!world->isNormal())
132             return 0;
133         return domObject->wrapper();
134     }
135
136     inline JSC::JSArrayBuffer* getInlineCachedWrapper(DOMWrapperWorld* world, JSC::ArrayBuffer* buffer)
137     {
138         if (!world->isNormal())
139             return 0;
140         return buffer->m_wrapper.get();
141     }
142
143     inline bool setInlineCachedWrapper(DOMWrapperWorld* world, ScriptWrappable* domObject, JSDOMWrapper* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context)
144     {
145         if (!world->isNormal())
146             return false;
147         domObject->setWrapper(*world->vm(), wrapper, wrapperOwner, context);
148         return true;
149     }
150
151     inline bool setInlineCachedWrapper(DOMWrapperWorld* world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context)
152     {
153         if (!world->isNormal())
154             return false;
155         domObject->m_wrapper = JSC::PassWeak<JSC::JSArrayBuffer>(wrapper, wrapperOwner, context);
156         return true;
157     }
158
159     inline bool clearInlineCachedWrapper(DOMWrapperWorld* world, ScriptWrappable* domObject, JSDOMWrapper* wrapper)
160     {
161         if (!world->isNormal())
162             return false;
163         domObject->clearWrapper(wrapper);
164         return true;
165     }
166
167     inline bool clearInlineCachedWrapper(DOMWrapperWorld* world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper)
168     {
169         if (!world->isNormal())
170             return false;
171         weakClear(domObject->m_wrapper, wrapper);
172         return true;
173     }
174
175     template <typename DOMClass> inline JSC::JSObject* getCachedWrapper(DOMWrapperWorld* world, DOMClass* domObject)
176     {
177         if (JSC::JSObject* wrapper = getInlineCachedWrapper(world, domObject))
178             return wrapper;
179         return world->m_wrappers.get(domObject);
180     }
181
182     template <typename DOMClass, typename WrapperClass> inline void cacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, WrapperClass* wrapper)
183     {
184         JSC::WeakHandleOwner* owner = wrapperOwner(world, domObject);
185         void* context = wrapperContext(world, domObject);
186         if (setInlineCachedWrapper(world, domObject, wrapper, owner, context))
187             return;
188         JSC::PassWeak<JSC::JSObject> passWeak(wrapper, owner, context);
189         weakAdd(world->m_wrappers, (void*)domObject, passWeak);
190     }
191
192     template <typename DOMClass, typename WrapperClass> inline void uncacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, WrapperClass* wrapper)
193     {
194         if (clearInlineCachedWrapper(world, domObject, wrapper))
195             return;
196         weakRemove(world->m_wrappers, (void*)domObject, wrapper);
197     }
198     
199     #define CREATE_DOM_WRAPPER(exec, globalObject, className, object) createWrapper<JS##className>(exec, globalObject, static_cast<className*>(object))
200     template<class WrapperClass, class DOMClass> inline JSDOMWrapper* createWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* node)
201     {
202         ASSERT(node);
203         ASSERT(!getCachedWrapper(currentWorld(exec), node));
204         WrapperClass* wrapper = WrapperClass::create(getDOMStructure<WrapperClass>(exec, globalObject), globalObject, node);
205         // FIXME: The entire function can be removed, once we fix caching.
206         // This function is a one-off hack to make Nodes cache in the right global object.
207         cacheWrapper(currentWorld(exec), node, wrapper);
208         return wrapper;
209     }
210
211     template<class WrapperClass, class DOMClass> inline JSC::JSValue wrap(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* domObject)
212     {
213         if (!domObject)
214             return JSC::jsNull();
215         if (JSC::JSObject* wrapper = getCachedWrapper(currentWorld(exec), domObject))
216             return wrapper;
217         return createWrapper<WrapperClass>(exec, globalObject, domObject);
218     }
219
220     template<class WrapperClass, class DOMClass> inline JSC::JSValue getExistingWrapper(JSC::ExecState* exec, DOMClass* domObject)
221     {
222         ASSERT(domObject);
223         return getCachedWrapper(currentWorld(exec), domObject);
224     }
225
226     template<class WrapperClass, class DOMClass> inline JSC::JSValue createNewWrapper(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, DOMClass* domObject)
227     {
228         ASSERT(domObject);
229         ASSERT(!getCachedWrapper(currentWorld(exec), domObject));
230         return createWrapper<WrapperClass>(exec, globalObject, domObject);
231     }
232
233     inline JSC::JSValue argumentOrNull(JSC::ExecState* exec, unsigned index)
234     {
235         return index >= exec->argumentCount() ? JSC::JSValue() : exec->argument(index);
236     }
237
238     const JSC::HashTable& getHashTableForGlobalData(JSC::VM&, const JSC::HashTable& staticTable);
239
240     void reportException(JSC::ExecState*, JSC::JSValue exception, CachedScript* = 0);
241     void reportCurrentException(JSC::ExecState*);
242
243     // Convert a DOM implementation exception code into a JavaScript exception in the execution state.
244     void setDOMException(JSC::ExecState*, ExceptionCode);
245
246     JSC::JSValue jsStringWithCache(JSC::ExecState*, const String&);
247     JSC::JSValue jsString(JSC::ExecState*, const KURL&); // empty if the URL is null
248     inline JSC::JSValue jsStringWithCache(JSC::ExecState* exec, const AtomicString& s)
249     { 
250         return jsStringWithCache(exec, s.string());
251     }
252         
253     JSC::JSValue jsStringOrNull(JSC::ExecState*, const String&); // null if the string is null
254     JSC::JSValue jsStringOrNull(JSC::ExecState*, const KURL&); // null if the URL is null
255
256     JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const String&); // undefined if the string is null
257     JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const KURL&); // undefined if the URL is null
258
259     // See JavaScriptCore for explanation: Should be used for any string that is already owned by another
260     // object, to let the engine know that collecting the JSString wrapper is unlikely to save memory.
261     JSC::JSValue jsOwnedStringOrNull(JSC::ExecState*, const String&); 
262
263     String propertyNameToString(JSC::PropertyName);
264
265     AtomicString propertyNameToAtomicString(JSC::PropertyName);
266     AtomicStringImpl* findAtomicString(JSC::PropertyName);
267
268     String valueToStringWithNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null
269     String valueToStringWithUndefinedOrNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null or undefined
270
271     inline int32_t finiteInt32Value(JSC::JSValue value, JSC::ExecState* exec, bool& okay)
272     {
273         double number = value.toNumber(exec);
274         okay = std::isfinite(number);
275         return JSC::toInt32(number);
276     }
277
278     enum IntegerConversionConfiguration {
279         NormalConversion,
280         EnforceRange,
281         // FIXME: Implement Clamp
282     };
283
284     int32_t toInt32EnforceRange(JSC::ExecState*, JSC::JSValue);
285     uint32_t toUInt32EnforceRange(JSC::ExecState*, JSC::JSValue);
286
287     int8_t toInt8(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
288     uint8_t toUInt8(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
289
290     /*
291         Convert a value to an integer as per <http://www.w3.org/TR/WebIDL/>.
292         The conversion fails if the value cannot be converted to a number or,
293         if EnforceRange is specified, the value is outside the range of the
294         destination integer type.
295     */
296     inline int32_t toInt32(JSC::ExecState* exec, JSC::JSValue value, IntegerConversionConfiguration configuration)
297     {
298         if (configuration == EnforceRange)
299             return toInt32EnforceRange(exec, value);
300         return value.toInt32(exec);
301     }
302
303     inline uint32_t toUInt32(JSC::ExecState* exec, JSC::JSValue value, IntegerConversionConfiguration configuration)
304     {
305         if (configuration == EnforceRange)
306             return toUInt32EnforceRange(exec, value);
307         return value.toUInt32(exec);
308     }
309
310     int64_t toInt64(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
311     uint64_t toUInt64(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
312
313     // Returns a Date instance for the specified value, or null if the value is NaN or infinity.
314     JSC::JSValue jsDateOrNull(JSC::ExecState*, double);
315     // NaN if the value can't be converted to a date.
316     double valueToDate(JSC::ExecState*, JSC::JSValue);
317
318     // Validates that the passed object is a sequence type per section 4.1.13 of the WebIDL spec.
319     inline JSC::JSObject* toJSSequence(JSC::ExecState* exec, JSC::JSValue value, unsigned& length)
320     {
321         JSC::JSObject* object = value.getObject();
322         if (!object) {
323             throwTypeError(exec);
324             return 0;
325         }
326
327         JSC::JSValue lengthValue = object->get(exec, exec->propertyNames().length);
328         if (exec->hadException())
329             return 0;
330
331         if (lengthValue.isUndefinedOrNull()) {
332             throwTypeError(exec);
333             return 0;
334         }
335
336         length = lengthValue.toUInt32(exec);
337         if (exec->hadException())
338             return 0;
339
340         return object;
341     }
342
343     inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::ArrayBuffer* buffer)
344     {
345         if (!buffer)
346             return JSC::jsNull();
347         if (JSC::JSValue result = getExistingWrapper<JSC::JSArrayBuffer>(exec, buffer))
348             return result;
349         buffer->ref();
350         JSC::JSArrayBuffer* wrapper = JSC::JSArrayBuffer::create(exec->vm(), globalObject->arrayBufferStructure(), buffer);
351         cacheWrapper(currentWorld(exec), buffer, wrapper);
352         return wrapper;
353     }
354
355     inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::ArrayBufferView* view)
356     {
357         if (!view)
358             return JSC::jsNull();
359         return view->wrap(exec, globalObject);
360     }
361
362     template <typename T>
363     inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<T> ptr)
364     {
365         return toJS(exec, globalObject, ptr.get());
366     }
367
368     template <class T>
369     struct JSValueTraits {
370         static inline JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const T& value)
371         {
372             return toJS(exec, globalObject, WTF::getPtr(value));
373         }
374     };
375
376     template<>
377     struct JSValueTraits<String> {
378         static inline JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject*, const String& value)
379         {
380             return jsStringWithCache(exec, value);
381         }
382     };
383
384     template<>
385     struct JSValueTraits<float> {
386         static inline JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const float& value)
387         {
388             return JSC::jsNumber(value);
389         }
390     };
391
392     template<>
393     struct JSValueTraits<unsigned long> {
394         static inline JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const unsigned long& value)
395         {
396             return JSC::jsNumber(value);
397         }
398     };
399
400     template <typename T, size_t inlineCapacity>
401     JSC::JSValue jsArray(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T, inlineCapacity>& iterator)
402     {
403         JSC::MarkedArgumentBuffer list;
404         typename Vector<T, inlineCapacity>::const_iterator end = iterator.end();        
405         typedef JSValueTraits<T> TraitsType;
406
407         for (typename Vector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter)
408             list.append(TraitsType::arrayJSValue(exec, globalObject, *iter));
409
410         return JSC::constructArray(exec, 0, globalObject, list);
411     }
412
413     JSC::JSValue jsArray(JSC::ExecState*, JSDOMGlobalObject*, PassRefPtr<DOMStringList>);
414
415     inline PassRefPtr<JSC::ArrayBufferView> toArrayBufferView(JSC::JSValue value)
416     {
417         JSC::JSArrayBufferView* wrapper = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(value);
418         if (!wrapper)
419             return 0;
420         return wrapper->impl();
421     }
422     
423     inline PassRefPtr<JSC::Int8Array> toInt8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int8Adaptor>(value); }
424     inline PassRefPtr<JSC::Int16Array> toInt16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int16Adaptor>(value); }
425     inline PassRefPtr<JSC::Int32Array> toInt32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int32Adaptor>(value); }
426     inline PassRefPtr<JSC::Uint8Array> toUint8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8Adaptor>(value); }
427     inline PassRefPtr<JSC::Uint8ClampedArray> toUint8ClampedArray(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8ClampedAdaptor>(value); }
428     inline PassRefPtr<JSC::Uint16Array> toUint16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint16Adaptor>(value); }
429     inline PassRefPtr<JSC::Uint32Array> toUint32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint32Adaptor>(value); }
430     inline PassRefPtr<JSC::Float32Array> toFloat32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float32Adaptor>(value); }
431     inline PassRefPtr<JSC::Float64Array> toFloat64Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float64Adaptor>(value); }
432     
433     inline PassRefPtr<JSC::DataView> toDataView(JSC::JSValue value)
434     {
435         JSC::JSDataView* wrapper = JSC::jsDynamicCast<JSC::JSDataView*>(value);
436         if (!wrapper)
437             return 0;
438         return wrapper->typedImpl();
439     }
440
441     template<class T> struct NativeValueTraits;
442
443     template<>
444     struct NativeValueTraits<String> {
445         static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, String& indexedValue)
446         {
447             indexedValue = jsValue.toString(exec)->value(exec);
448             return true;
449         }
450     };
451
452     template<>
453     struct NativeValueTraits<unsigned> {
454         static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, unsigned& indexedValue)
455         {
456             if (!jsValue.isNumber())
457                 return false;
458
459             indexedValue = jsValue.toUInt32(exec);
460             if (exec->hadException())
461                 return false;
462
463             return true;
464         }
465     };
466
467     template<>
468     struct NativeValueTraits<float> {
469         static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, float& indexedValue)
470         {
471             indexedValue = jsValue.toFloat(exec);
472             return !exec->hadException();
473         }
474     };
475
476     template <class T, class JST>
477     Vector<RefPtr<T> > toRefPtrNativeArray(JSC::ExecState* exec, JSC::JSValue value, T* (*toT)(JSC::JSValue value))
478     {
479         if (!isJSArray(value))
480             return Vector<RefPtr<T> >();
481
482         Vector<RefPtr<T> > result;
483         JSC::JSArray* array = asArray(value);
484         for (size_t i = 0; i < array->length(); ++i) {
485             JSC::JSValue element = array->getIndex(exec, i);
486             if (element.inherits(JST::info()))
487                 result.append((*toT)(element));
488             else {
489                 throwVMError(exec, createTypeError(exec, "Invalid Array element type"));
490                 return Vector<RefPtr<T> >();
491             }
492         }
493         return result;
494     }
495
496     template <class T>
497     Vector<T> toNativeArray(JSC::ExecState* exec, JSC::JSValue value)
498     {
499         unsigned length = 0;
500         if (isJSArray(value)) {
501             JSC::JSArray* array = asArray(value);
502             length = array->length();
503         } else
504             toJSSequence(exec, value, length);
505
506         JSC::JSObject* object = value.getObject();
507         Vector<T> result;
508         typedef NativeValueTraits<T> TraitsType;
509
510         for (unsigned i = 0; i < length; ++i) {
511             T indexValue;
512             if (!TraitsType::nativeValue(exec, object->get(exec, i), indexValue))
513                 return Vector<T>();
514             result.append(indexValue);
515         }
516         return result;
517     }
518
519     template <class T>
520     Vector<T> toNativeArguments(JSC::ExecState* exec, size_t startIndex = 0)
521     {
522         size_t length = exec->argumentCount();
523         ASSERT(startIndex <= length);
524
525         Vector<T> result;
526         typedef NativeValueTraits<T> TraitsType;
527
528         for (size_t i = startIndex; i < length; ++i) {
529             T indexValue;
530             if (!TraitsType::nativeValue(exec, exec->argument(i), indexValue))
531                 return Vector<T>();
532             result.append(indexValue);
533         }
534         return result;
535     }
536
537     bool shouldAllowAccessToNode(JSC::ExecState*, Node*);
538     bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*);
539     bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*, String& message);
540     bool shouldAllowAccessToDOMWindow(BindingState*, DOMWindow*, String& message);
541
542     void printErrorMessageForFrame(Frame*, const String& message);
543     JSC::JSValue objectToStringFunctionGetter(JSC::ExecState*, JSC::JSValue, JSC::PropertyName);
544
545     inline JSC::JSValue jsStringWithCache(JSC::ExecState* exec, const String& s)
546     {
547         StringImpl* stringImpl = s.impl();
548         if (!stringImpl || !stringImpl->length())
549             return jsEmptyString(exec);
550
551         if (stringImpl->length() == 1) {
552             UChar singleCharacter = (*stringImpl)[0u];
553             if (singleCharacter <= JSC::maxSingleCharacterString) {
554                 JSC::VM* vm = &exec->vm();
555                 return vm->smallStrings.singleCharacterString(static_cast<unsigned char>(singleCharacter));
556             }
557         }
558
559         JSStringCache& stringCache = currentWorld(exec)->m_stringCache;
560         JSStringCache::AddResult addResult = stringCache.add(stringImpl, nullptr);
561         if (addResult.isNewEntry)
562             addResult.iterator->value = JSC::jsString(exec, String(stringImpl));
563         return JSC::JSValue(addResult.iterator->value.get());
564     }
565
566     inline String propertyNameToString(JSC::PropertyName propertyName)
567     {
568         return propertyName.publicName();
569     }
570
571     inline AtomicString propertyNameToAtomicString(JSC::PropertyName propertyName)
572     {
573         return AtomicString(propertyName.publicName());
574     }
575
576     template <class ThisImp>
577     inline const JSC::HashEntry* getStaticValueSlotEntryWithoutCaching(JSC::ExecState* exec, JSC::PropertyName propertyName)
578     {
579         const JSC::HashEntry* entry = ThisImp::info()->propHashTable(exec)->entry(exec, propertyName);
580         if (!entry) // not found, forward to parent
581             return getStaticValueSlotEntryWithoutCaching<typename ThisImp::Base>(exec, propertyName);
582         return entry;
583     }
584
585     template <>
586     inline const JSC::HashEntry* getStaticValueSlotEntryWithoutCaching<JSDOMWrapper>(JSC::ExecState*, JSC::PropertyName)
587     {
588         return 0;
589     }
590
591     template<typename T>
592     class HasMemoryCostMemberFunction {
593         typedef char YesType;
594         struct NoType {
595             char padding[8];
596         };
597
598         struct BaseMixin {
599             size_t memoryCost();
600         };
601
602         struct Base : public T, public BaseMixin { };
603
604         template<typename U, U> struct
605         TypeChecker { };
606
607         template<typename U>
608         static NoType dummy(U*, TypeChecker<size_t (BaseMixin::*)(), &U::memoryCost>* = 0);
609         static YesType dummy(...);
610
611     public:
612         static const bool value = sizeof(dummy(static_cast<Base*>(0))) == sizeof(YesType);
613     };
614     template <typename T, bool hasReportCostFunction = HasMemoryCostMemberFunction<T>::value > struct ReportMemoryCost;
615     template <typename T> struct ReportMemoryCost<T, true> {
616         static void reportMemoryCost(JSC::ExecState* exec, T* impl)
617         {
618             exec->heap()->reportExtraMemoryCost(impl->memoryCost());
619         }
620     };
621     template <typename T> struct ReportMemoryCost<T, false> {
622         static void reportMemoryCost(JSC::ExecState*, T*)
623         {
624         }
625     };
626
627 } // namespace WebCore
628
629 #endif // JSDOMBinding_h