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