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