Fast path for jsStringWithCache() when asked for the same string repeatedly.
[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/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
51 namespace JSC {
52 class HashEntry;
53 }
54
55 #if ENABLE(GAMEPAD)
56 namespace WTF {
57
58 template<typename T> inline T* getPtr(const Ref<T>& p)
59 {
60     return const_cast<T*>(&p.get());
61 }
62
63 }
64 #endif
65
66 namespace WebCore {
67
68 class CachedScript;
69 class DOMStringList;
70 class DOMWindow;
71 class Frame;
72 class URL;
73 class Node;
74
75 typedef int ExceptionCode;
76
77 DOMWindow& activeDOMWindow(JSC::ExecState*);
78 DOMWindow& firstDOMWindow(JSC::ExecState*);
79
80 JSC::EncodedJSValue reportDeprecatedGetterError(JSC::ExecState&, const char* interfaceName, const char* attributeName);
81 void reportDeprecatedSetterError(JSC::ExecState&, const char* interfaceName, const char* attributeName);
82
83 void throwArrayElementTypeError(JSC::ExecState&);
84 void throwAttributeTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName, const char* expectedType);
85 void throwSequenceTypeError(JSC::ExecState&);
86 void throwSetterTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName);
87
88 JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedValues);
89 JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName);
90 JSC::EncodedJSValue throwArgumentTypeError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedType);
91 JSC::EncodedJSValue throwConstructorDocumentUnavailableError(JSC::ExecState&, const char* interfaceName);
92 JSC::EncodedJSValue throwGetterTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName);
93 JSC::EncodedJSValue throwThisTypeError(JSC::ExecState&, const char* interfaceName, const char* functionName);
94
95 // Base class for all constructor objects in the JSC bindings.
96 class DOMConstructorObject : public JSDOMWrapper {
97     typedef JSDOMWrapper Base;
98 public:
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
104 protected:
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
112 JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*);
113 JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, JSC::Structure*, const JSC::ClassInfo*);
114
115 inline 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
123 template<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
130 template<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
136 template<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
141 inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld& world, JSC::ArrayBuffer*)
142 {
143     return static_cast<WebCoreTypedArrayController*>(world.vm().m_typedArrayController.get())->wrapperOwner();
144 }
145
146 inline void* wrapperContext(DOMWrapperWorld& world, JSC::ArrayBuffer*)
147 {
148     return &world;
149 }
150
151 inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld&, void*) { return nullptr; }
152 inline bool setInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMWrapper*, JSC::WeakHandleOwner*, void*) { return false; }
153 inline bool clearInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMWrapper*) { return false; }
154
155 inline JSDOMWrapper* getInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject)
156 {
157     if (!world.isNormal())
158         return nullptr;
159     return domObject->wrapper();
160 }
161
162 inline JSC::JSArrayBuffer* getInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* buffer)
163 {
164     if (!world.isNormal())
165         return nullptr;
166     return buffer->m_wrapper.get();
167 }
168
169 inline 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
177 inline 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
185 inline 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
193 inline 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
201 template<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
208 template<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
217 template<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))
225 template<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
234 template<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
243 template<typename WrapperClass, typename DOMClass> inline JSC::JSValue getExistingWrapper(JSDOMGlobalObject* globalObject, DOMClass* domObject)
244 {
245     ASSERT(domObject);
246     return getCachedWrapper(globalObject->world(), domObject);
247 }
248
249 template<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
256 inline JSC::JSValue argumentOrNull(JSC::ExecState* exec, unsigned index)
257 {
258     return index >= exec->argumentCount() ? JSC::JSValue() : exec->argument(index);
259 }
260
261 void addImpureProperty(const AtomicString&);
262
263 const JSC::HashTable& getHashTableForGlobalData(JSC::VM&, const JSC::HashTable& staticTable);
264
265 void reportException(JSC::ExecState*, JSC::JSValue exception, CachedScript* = nullptr);
266 void reportCurrentException(JSC::ExecState*);
267
268 // Convert a DOM implementation exception code into a JavaScript exception in the execution state.
269 void setDOMException(JSC::ExecState*, ExceptionCode);
270
271 JSC::JSValue jsString(JSC::ExecState*, const URL&); // empty if the URL is null
272
273 JSC::JSValue jsStringOrNull(JSC::ExecState*, const String&); // null if the string is null
274 JSC::JSValue jsStringOrNull(JSC::ExecState*, const URL&); // null if the URL is null
275
276 JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const String&); // undefined if the string is null
277 JSC::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.
281 JSC::JSValue jsOwnedStringOrNull(JSC::ExecState*, const String&);
282
283 String propertyNameToString(JSC::PropertyName);
284
285 AtomicString propertyNameToAtomicString(JSC::PropertyName);
286 AtomicStringImpl* findAtomicString(JSC::PropertyName);
287
288 String valueToStringWithNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null
289 String valueToStringWithUndefinedOrNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null or undefined
290
291 inline 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
298 enum IntegerConversionConfiguration {
299     NormalConversion,
300     EnforceRange,
301     // FIXME: Implement Clamp
302 };
303
304 int32_t toInt32EnforceRange(JSC::ExecState*, JSC::JSValue);
305 uint32_t toUInt32EnforceRange(JSC::ExecState*, JSC::JSValue);
306
307 int8_t toInt8(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
308 uint8_t toUInt8(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
309
310 int16_t toInt16(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
311 uint16_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 */
319 inline 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
326 inline 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
333 int64_t toInt64(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
334 uint64_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.
337 JSC::JSValue jsDateOrNull(JSC::ExecState*, double);
338 // NaN if the value can't be converted to a date.
339 double 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.
342 inline 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
366 inline 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
378 inline 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
385 template<typename T> inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<T> ptr)
386 {
387     return toJS(exec, globalObject, ptr.get());
388 }
389
390 template<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
398 template<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
406 inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject*, const String& value)
407 {
408     return jsStringOrNull(exec, value);
409 }
410
411 template<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
418 template<> 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
425 template<> struct JSValueTraits<double> {
426     static JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const double& value)
427     {
428         return JSC::jsNumber(value);
429     }
430 };
431
432 template<> struct JSValueTraits<float> {
433     static JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const float& value)
434     {
435         return JSC::jsNumber(value);
436     }
437 };
438
439 template<> 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
446 template<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
454 JSC::JSValue jsArray(JSC::ExecState*, JSDOMGlobalObject*, PassRefPtr<DOMStringList>);
455
456 inline 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
464 inline PassRefPtr<JSC::Int8Array> toInt8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int8Adaptor>(value); }
465 inline PassRefPtr<JSC::Int16Array> toInt16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int16Adaptor>(value); }
466 inline PassRefPtr<JSC::Int32Array> toInt32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int32Adaptor>(value); }
467 inline PassRefPtr<JSC::Uint8Array> toUint8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8Adaptor>(value); }
468 inline PassRefPtr<JSC::Uint8ClampedArray> toUint8ClampedArray(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8ClampedAdaptor>(value); }
469 inline PassRefPtr<JSC::Uint16Array> toUint16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint16Adaptor>(value); }
470 inline PassRefPtr<JSC::Uint32Array> toUint32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint32Adaptor>(value); }
471 inline PassRefPtr<JSC::Float32Array> toFloat32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float32Adaptor>(value); }
472 inline PassRefPtr<JSC::Float64Array> toFloat64Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float64Adaptor>(value); }
473
474 template<typename T> struct NativeValueTraits;
475
476 template<> 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
484 template<> 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
498 template<> 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
506 template<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
527 template<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
553 template<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
571 bool shouldAllowAccessToNode(JSC::ExecState*, Node*);
572 bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*);
573 bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*, String& message);
574 bool shouldAllowAccessToDOMWindow(JSC::ExecState*, DOMWindow&, String& message);
575
576 void printErrorMessageForFrame(Frame*, const String& message);
577 JSC::EncodedJSValue objectToStringFunctionGetter(JSC::ExecState*, JSC::JSObject*, JSC::EncodedJSValue, JSC::PropertyName);
578
579 inline String propertyNameToString(JSC::PropertyName propertyName)
580 {
581     return propertyName.publicName();
582 }
583
584 inline AtomicString propertyNameToAtomicString(JSC::PropertyName propertyName)
585 {
586     return AtomicString(propertyName.publicName());
587 }
588
589 template<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
600 template<> inline const JSC::HashTableValue* getStaticValueSlotEntryWithoutCaching<JSDOMWrapper>(JSC::ExecState*, JSC::PropertyName)
601 {
602     return nullptr;
603 }
604
605 template<JSC::NativeFunction nativeFunction, int length>
606 JSC::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
611 enum SecurityReportingOption {
612     DoNotReportSecurityError,
613     ReportSecurityError,
614 };
615
616 class BindingSecurity {
617 public:
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