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