Next step on dictionary bindings, along with other bindings refinements
[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 #pragma once
25
26 #include "JSDOMGlobalObject.h"
27 #include "JSDOMWrapper.h"
28 #include "DOMWrapperWorld.h"
29 #include "ScriptWrappable.h"
30 #include "ScriptWrappableInlines.h"
31 #include "WebCoreTypedArrayController.h"
32 #include <cstddef>
33 #include <heap/SlotVisitorInlines.h>
34 #include <heap/Weak.h>
35 #include <heap/WeakInlines.h>
36 #include <runtime/Error.h>
37 #include <runtime/IteratorOperations.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 <runtime/WriteBarrier.h>
48 #include <wtf/Forward.h>
49 #include <wtf/GetPtr.h>
50 #include <wtf/Noncopyable.h>
51 #include <wtf/Vector.h>
52
53 // FIXME: We could make this file a lot easier to read by putting all function declarations at the top,
54 // and function definitions below, even for template and inline functions.
55
56 namespace JSC {
57 class JSFunction;
58 }
59
60 namespace WebCore {
61
62 class CachedScript;
63 class DOMStringList;
64 class DOMWindow;
65 class Frame;
66 class URL;
67 class Node;
68
69 struct ExceptionCodeWithMessage;
70
71 typedef int ExceptionCode;
72
73 struct ExceptionDetails {
74     String message;
75     int lineNumber { 0 };
76     int columnNumber { 0 };
77     String sourceURL;
78 };
79
80 // Base class for all constructor objects in the JSC bindings.
81 class DOMConstructorObject : public JSDOMObject {
82 public:
83     typedef JSDOMObject Base;
84     static const unsigned StructureFlags = Base::StructureFlags | JSC::ImplementsHasInstance | JSC::ImplementsDefaultHasInstance | JSC::TypeOfShouldCallGetCallData;
85     static JSC::Structure* createStructure(JSC::VM&, JSC::JSGlobalObject*, JSC::JSValue);
86
87 protected:
88     DOMConstructorObject(JSC::Structure*, JSDOMGlobalObject&);
89
90     static String className(const JSObject*);
91     static JSC::CallType getCallData(JSCell*, JSC::CallData&);
92 };
93
94 class DOMConstructorJSBuiltinObject : public DOMConstructorObject {
95 public:
96     typedef DOMConstructorObject Base;
97
98 protected:
99     DOMConstructorJSBuiltinObject(JSC::Structure*, JSDOMGlobalObject&);
100     static void visitChildren(JSC::JSCell*, JSC::SlotVisitor&);
101
102     JSC::JSFunction* initializeFunction();
103     void setInitializeFunction(JSC::VM&, JSC::JSFunction&);
104
105 private:
106     JSC::WriteBarrier<JSC::JSFunction> m_initializeFunction;
107 };
108
109 DOMWindow& callerDOMWindow(JSC::ExecState*);
110 DOMWindow& activeDOMWindow(JSC::ExecState*);
111 DOMWindow& firstDOMWindow(JSC::ExecState*);
112
113 WEBCORE_EXPORT JSC::EncodedJSValue reportDeprecatedGetterError(JSC::ExecState&, const char* interfaceName, const char* attributeName);
114 WEBCORE_EXPORT void reportDeprecatedSetterError(JSC::ExecState&, const char* interfaceName, const char* attributeName);
115
116 void throwNotSupportedError(JSC::ExecState&, const char* message);
117 void throwInvalidStateError(JSC::ExecState&, const char* message);
118 void throwArrayElementTypeError(JSC::ExecState&);
119 void throwAttributeTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName, const char* expectedType);
120 WEBCORE_EXPORT void throwSequenceTypeError(JSC::ExecState&);
121 WEBCORE_EXPORT bool throwSetterTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName);
122 WEBCORE_EXPORT void throwNonFiniteTypeError(JSC::ExecState&);
123
124 WEBCORE_EXPORT JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedValues);
125 JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName);
126 JSC::EncodedJSValue throwArgumentTypeError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedType);
127 JSC::EncodedJSValue throwConstructorDocumentUnavailableError(JSC::ExecState&, const char* interfaceName);
128 WEBCORE_EXPORT JSC::EncodedJSValue throwGetterTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName);
129 WEBCORE_EXPORT JSC::EncodedJSValue throwThisTypeError(JSC::ExecState&, const char* interfaceName, const char* functionName);
130
131 WEBCORE_EXPORT JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject&, const JSC::ClassInfo*);
132 WEBCORE_EXPORT JSC::Structure* cacheDOMStructure(JSDOMGlobalObject&, JSC::Structure*, const JSC::ClassInfo*);
133
134 template<typename WrapperClass> JSC::Structure* getDOMStructure(JSC::VM&, JSDOMGlobalObject&);
135 template<typename WrapperClass> JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState*);
136 template<typename WrapperClass> JSC::JSObject* getDOMPrototype(JSC::VM&, JSC::JSGlobalObject*);
137
138 void callFunctionWithCurrentArguments(JSC::ExecState&, JSC::JSObject& thisObject, JSC::JSFunction&);
139
140 template<typename JSClass> JSC::EncodedJSValue createJSBuiltin(JSC::ExecState&, JSC::JSFunction& initializeFunction, JSDOMGlobalObject&);
141
142 JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld&, JSC::ArrayBuffer*);
143 void* wrapperKey(JSC::ArrayBuffer*);
144
145 JSDOMObject* getInlineCachedWrapper(DOMWrapperWorld&, void*);
146 JSDOMObject* getInlineCachedWrapper(DOMWrapperWorld&, ScriptWrappable*);
147 JSC::JSArrayBuffer* getInlineCachedWrapper(DOMWrapperWorld&, JSC::ArrayBuffer*);
148
149 bool setInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMObject*, JSC::WeakHandleOwner*);
150 bool setInlineCachedWrapper(DOMWrapperWorld&, ScriptWrappable*, JSDOMObject* wrapper, JSC::WeakHandleOwner* wrapperOwner);
151 bool setInlineCachedWrapper(DOMWrapperWorld&, JSC::ArrayBuffer*, JSC::JSArrayBuffer* wrapper, JSC::WeakHandleOwner* wrapperOwner);
152
153 bool clearInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMObject*);
154 bool clearInlineCachedWrapper(DOMWrapperWorld&, ScriptWrappable*, JSDOMObject* wrapper);
155 bool clearInlineCachedWrapper(DOMWrapperWorld&, JSC::ArrayBuffer*, JSC::JSArrayBuffer* wrapper);
156
157 #define CREATE_DOM_WRAPPER(globalObject, className, object) createWrapper<JS##className>(globalObject, static_cast<className*>(object))
158
159 template<typename DOMClass> JSC::JSObject* getCachedWrapper(DOMWrapperWorld&, DOMClass*);
160 template<typename DOMClass, typename WrapperClass> void cacheWrapper(DOMWrapperWorld&, DOMClass*, WrapperClass*);
161 template<typename DOMClass, typename WrapperClass> void uncacheWrapper(DOMWrapperWorld&, DOMClass*, WrapperClass*);
162
163 template<typename WrapperClass, typename DOMClass> JSDOMObject* createWrapper(JSDOMGlobalObject*, DOMClass*);
164 template<typename WrapperClass, typename DOMClass> JSC::JSValue wrap(JSDOMGlobalObject*, DOMClass&);
165 template<typename WrapperClass, typename DOMClass> JSC::JSValue getExistingWrapper(JSDOMGlobalObject*, DOMClass*);
166 template<typename WrapperClass, typename DOMClass> JSC::JSValue createNewWrapper(JSDOMGlobalObject*, DOMClass*);
167
168 void addImpureProperty(const AtomicString&);
169
170 const JSC::HashTable& getHashTableForGlobalData(JSC::VM&, const JSC::HashTable& staticTable);
171
172 WEBCORE_EXPORT void reportException(JSC::ExecState*, JSC::JSValue exception, CachedScript* = nullptr);
173 WEBCORE_EXPORT void reportException(JSC::ExecState*, JSC::Exception*, CachedScript* = nullptr, ExceptionDetails* = nullptr);
174 void reportCurrentException(JSC::ExecState*);
175
176 JSC::JSValue createDOMException(JSC::ExecState*, ExceptionCode);
177
178 // Convert a DOM implementation exception code into a JavaScript exception in the execution state.
179 WEBCORE_EXPORT void setDOMException(JSC::ExecState*, ExceptionCode);
180 void setDOMException(JSC::ExecState*, const ExceptionCodeWithMessage&);
181
182 JSC::JSValue jsString(JSC::ExecState*, const URL&); // empty if the URL is null
183
184 JSC::JSValue jsStringOrNull(JSC::ExecState*, const String&); // null if the string is null
185 JSC::JSValue jsStringOrNull(JSC::ExecState*, const URL&); // null if the URL is null
186
187 JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const String&); // undefined if the string is null
188 JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const URL&); // undefined if the URL is null
189
190 // See JavaScriptCore for explanation: Should be used for any string that is already owned by another
191 // object, to let the engine know that collecting the JSString wrapper is unlikely to save memory.
192 JSC::JSValue jsOwnedStringOrNull(JSC::ExecState*, const String&);
193
194 String propertyNameToString(JSC::PropertyName);
195
196 AtomicString propertyNameToAtomicString(JSC::PropertyName);
197
198 // FIXME: This is only used by legacy code and should go away. Use valueToStringTreatingNullAsEmptyString() instead.
199 String valueToStringWithNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null
200
201 String valueToStringTreatingNullAsEmptyString(JSC::ExecState*, JSC::JSValue);
202 String valueToStringWithUndefinedOrNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null or undefined
203
204 template<typename T> JSC::JSValue toNullableJSNumber(Optional<T>); // null if the optional is null
205
206 int32_t finiteInt32Value(JSC::JSValue, JSC::ExecState*, bool& okay);
207
208 // The following functions convert values to integers as per the WebIDL specification.
209 // The conversion fails if the value cannot be converted to a number or, if EnforceRange is specified,
210 // the value is outside the range of the destination integer type.
211
212 enum IntegerConversionConfiguration { NormalConversion, EnforceRange, Clamp };
213
214 WEBCORE_EXPORT int32_t toInt32EnforceRange(JSC::ExecState*, JSC::JSValue);
215 WEBCORE_EXPORT uint32_t toUInt32EnforceRange(JSC::ExecState*, JSC::JSValue);
216
217 WEBCORE_EXPORT int32_t toInt32Clamp(JSC::ExecState*, JSC::JSValue);
218 WEBCORE_EXPORT uint32_t toUInt32Clamp(JSC::ExecState*, JSC::JSValue);
219
220 WEBCORE_EXPORT int8_t toInt8(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
221 WEBCORE_EXPORT uint8_t toUInt8(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
222
223 WEBCORE_EXPORT int16_t toInt16(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
224 WEBCORE_EXPORT uint16_t toUInt16(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
225
226 int32_t toInt32(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
227 uint32_t toUInt32(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
228
229 WEBCORE_EXPORT int64_t toInt64(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
230 WEBCORE_EXPORT uint64_t toUInt64(JSC::ExecState*, JSC::JSValue, IntegerConversionConfiguration);
231
232 // Returns a Date instance for the specified value, or NaN if the date is not a number.
233 JSC::JSValue jsDateOrNaN(JSC::ExecState*, double);
234
235 // Returns a Date instance for the specified value, or null if the value is NaN or infinity.
236 JSC::JSValue jsDateOrNull(JSC::ExecState*, double);
237
238 // NaN if the value can't be converted to a date.
239 double valueToDate(JSC::ExecState*, JSC::JSValue);
240
241 // Validates that the passed object is a sequence type per section 4.1.13 of the WebIDL spec.
242 JSC::JSObject* toJSSequence(JSC::ExecState*, JSC::JSValue, unsigned& length);
243
244 JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, JSC::ArrayBuffer*);
245 JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, JSC::ArrayBufferView*);
246 JSC::JSValue toJS(JSC::ExecState*, JSC::JSGlobalObject*, JSC::ArrayBufferView*);
247 template<typename T> JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, RefPtr<T>);
248 template<typename T> JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, PassRefPtr<T>);
249 template<typename T> JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, const Vector<T>&);
250 template<typename T> JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, const Vector<RefPtr<T>>&);
251 JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, const String&);
252
253 JSC::JSValue toJSIterator(JSC::ExecState&, JSDOMGlobalObject&, JSC::JSValue);
254 template<typename T> JSC::JSValue toJSIterator(JSC::ExecState&, JSDOMGlobalObject&, const T&);
255
256 JSC::JSValue toJSIteratorEnd(JSC::ExecState&);
257
258 template<typename T, size_t inlineCapacity> JSC::JSValue jsArray(JSC::ExecState*, JSDOMGlobalObject*, const Vector<T, inlineCapacity>&);
259 template<typename T, size_t inlineCapacity> JSC::JSValue jsArray(JSC::ExecState*, JSDOMGlobalObject*, const Vector<T, inlineCapacity>*);
260 WEBCORE_EXPORT JSC::JSValue jsArray(JSC::ExecState*, JSDOMGlobalObject*, PassRefPtr<DOMStringList>);
261
262 template<typename Value1, typename Value2> JSC::JSValue jsPair(JSC::ExecState&, JSDOMGlobalObject*, const Value1&, const Value2&);
263
264 RefPtr<JSC::ArrayBufferView> toArrayBufferView(JSC::JSValue);
265 RefPtr<JSC::Int8Array> toInt8Array(JSC::JSValue);
266 RefPtr<JSC::Int16Array> toInt16Array(JSC::JSValue);
267 RefPtr<JSC::Int32Array> toInt32Array(JSC::JSValue);
268 RefPtr<JSC::Uint8Array> toUint8Array(JSC::JSValue);
269 RefPtr<JSC::Uint8ClampedArray> toUint8ClampedArray(JSC::JSValue);
270 RefPtr<JSC::Uint16Array> toUint16Array(JSC::JSValue);
271 RefPtr<JSC::Uint32Array> toUint32Array(JSC::JSValue);
272 RefPtr<JSC::Float32Array> toFloat32Array(JSC::JSValue);
273 RefPtr<JSC::Float64Array> toFloat64Array(JSC::JSValue);
274
275 template<typename T, typename JSType> Vector<RefPtr<T>> toRefPtrNativeArray(JSC::ExecState*, JSC::JSValue, T* (*)(JSC::JSValue));
276 template<typename T> Vector<T> toNativeArray(JSC::ExecState*, JSC::JSValue);
277 template<typename T> Vector<T> toNativeArguments(JSC::ExecState*, size_t startIndex = 0);
278
279 bool shouldAllowAccessToNode(JSC::ExecState*, Node*);
280 bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*);
281 bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*, String& message);
282 bool shouldAllowAccessToDOMWindow(JSC::ExecState*, DOMWindow&, String& message);
283
284 enum SecurityReportingOption { DoNotReportSecurityError, ReportSecurityError };
285
286 class BindingSecurity {
287 public:
288     static bool shouldAllowAccessToNode(JSC::ExecState*, Node*);
289     static bool shouldAllowAccessToDOMWindow(JSC::ExecState*, DOMWindow&, SecurityReportingOption = ReportSecurityError);
290     static bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*, SecurityReportingOption = ReportSecurityError);
291 };
292
293 void printErrorMessageForFrame(Frame*, const String& message);
294
295 String propertyNameToString(JSC::PropertyName);
296 AtomicString propertyNameToAtomicString(JSC::PropertyName);
297
298 template<typename DOMClass> const JSC::HashTableValue* getStaticValueSlotEntryWithoutCaching(JSC::ExecState*, JSC::PropertyName);
299 template<JSC::NativeFunction, int length> JSC::EncodedJSValue nonCachingStaticFunctionGetter(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);
300
301 JSC::JSValue propertyValue(JSC::ExecState&, JSC::JSValue, const char* propertyName);
302
303 // Inline functions and template definitions.
304
305 inline JSC::Structure* DOMConstructorObject::createStructure(JSC::VM& vm, JSC::JSGlobalObject* globalObject, JSC::JSValue prototype)
306 {
307     return JSC::Structure::create(vm, globalObject, prototype, JSC::TypeInfo(JSC::ObjectType, StructureFlags), info());
308 }
309
310 inline DOMConstructorObject::DOMConstructorObject(JSC::Structure* structure, JSDOMGlobalObject& globalObject)
311     : JSDOMObject(structure, globalObject)
312 {
313 }
314
315 inline String DOMConstructorObject::className(const JSObject*)
316 {
317     return ASCIILiteral("Function");
318 }
319
320 inline DOMConstructorJSBuiltinObject::DOMConstructorJSBuiltinObject(JSC::Structure* structure, JSDOMGlobalObject& globalObject)
321     : DOMConstructorObject(structure, globalObject)
322 {
323 }
324
325 inline JSC::JSFunction* DOMConstructorJSBuiltinObject::initializeFunction()
326 {
327     return m_initializeFunction.get();
328 }
329
330 inline void DOMConstructorJSBuiltinObject::setInitializeFunction(JSC::VM& vm, JSC::JSFunction& function)
331 {
332     m_initializeFunction.set(vm, this, &function);
333 }
334
335 inline JSDOMGlobalObject* deprecatedGlobalObjectForPrototype(JSC::ExecState* exec)
336 {
337     // FIXME: Callers to this function should be using the global object
338     // from which the object is being created, instead of assuming the lexical one.
339     // e.g. subframe.document.body should use the subframe's global object, not the lexical one.
340     return JSC::jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
341 }
342
343 template<typename WrapperClass> inline JSC::Structure* getDOMStructure(JSC::VM& vm, JSDOMGlobalObject& globalObject)
344 {
345     if (JSC::Structure* structure = getCachedDOMStructure(globalObject, WrapperClass::info()))
346         return structure;
347     return cacheDOMStructure(globalObject, WrapperClass::createStructure(vm, &globalObject, WrapperClass::createPrototype(vm, &globalObject)), WrapperClass::info());
348 }
349
350 template<typename WrapperClass> inline JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState* exec)
351 {
352     // FIXME: This function is wrong. It uses the wrong global object for creating the prototype structure.
353     return getDOMStructure<WrapperClass>(exec->vm(), *deprecatedGlobalObjectForPrototype(exec));
354 }
355
356 template<typename WrapperClass> inline JSC::JSObject* getDOMPrototype(JSC::VM& vm, JSC::JSGlobalObject* globalObject)
357 {
358     return JSC::jsCast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(vm, *JSC::jsCast<JSDOMGlobalObject*>(globalObject))->storedPrototype()));
359 }
360
361 template<typename JSClass> inline JSC::EncodedJSValue createJSBuiltin(JSC::ExecState& state, JSC::JSFunction& initializeFunction, JSDOMGlobalObject& globalObject)
362 {
363     JSC::JSObject* object = JSClass::create(getDOMStructure<JSClass>(globalObject.vm(), globalObject), &globalObject);
364     callFunctionWithCurrentArguments(state, *object, initializeFunction);
365     return JSC::JSValue::encode(object);
366 }
367
368 inline JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld& world, JSC::ArrayBuffer*)
369 {
370     return static_cast<WebCoreTypedArrayController*>(world.vm().m_typedArrayController.get())->wrapperOwner();
371 }
372
373 inline void* wrapperKey(JSC::ArrayBuffer* domObject)
374 {
375     return domObject;
376 }
377
378 inline JSDOMObject* getInlineCachedWrapper(DOMWrapperWorld&, void*) { return nullptr; }
379 inline bool setInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMObject*, JSC::WeakHandleOwner*) { return false; }
380 inline bool clearInlineCachedWrapper(DOMWrapperWorld&, void*, JSDOMObject*) { return false; }
381
382 inline JSDOMObject* getInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject)
383 {
384     if (!world.isNormal())
385         return nullptr;
386     return domObject->wrapper();
387 }
388
389 inline JSC::JSArrayBuffer* getInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* buffer)
390 {
391     if (!world.isNormal())
392         return nullptr;
393     return buffer->m_wrapper.get();
394 }
395
396 inline bool setInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject, JSDOMObject* wrapper, JSC::WeakHandleOwner* wrapperOwner)
397 {
398     if (!world.isNormal())
399         return false;
400     domObject->setWrapper(wrapper, wrapperOwner, &world);
401     return true;
402 }
403
404 inline bool setInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper, JSC::WeakHandleOwner* wrapperOwner)
405 {
406     if (!world.isNormal())
407         return false;
408     domObject->m_wrapper = JSC::Weak<JSC::JSArrayBuffer>(wrapper, wrapperOwner, &world);
409     return true;
410 }
411
412 inline bool clearInlineCachedWrapper(DOMWrapperWorld& world, ScriptWrappable* domObject, JSDOMObject* wrapper)
413 {
414     if (!world.isNormal())
415         return false;
416     domObject->clearWrapper(wrapper);
417     return true;
418 }
419
420 inline bool clearInlineCachedWrapper(DOMWrapperWorld& world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper)
421 {
422     if (!world.isNormal())
423         return false;
424     weakClear(domObject->m_wrapper, wrapper);
425     return true;
426 }
427
428 template<typename DOMClass> inline JSC::JSObject* getCachedWrapper(DOMWrapperWorld& world, DOMClass* domObject)
429 {
430     if (JSC::JSObject* wrapper = getInlineCachedWrapper(world, domObject))
431         return wrapper;
432     return world.m_wrappers.get(wrapperKey(domObject));
433 }
434
435 template<typename DOMClass, typename WrapperClass> inline void cacheWrapper(DOMWrapperWorld& world, DOMClass* domObject, WrapperClass* wrapper)
436 {
437     JSC::WeakHandleOwner* owner = wrapperOwner(world, domObject);
438     if (setInlineCachedWrapper(world, domObject, wrapper, owner))
439         return;
440     weakAdd(world.m_wrappers, wrapperKey(domObject), JSC::Weak<JSC::JSObject>(wrapper, owner, &world));
441 }
442
443 template<typename DOMClass, typename WrapperClass> inline void uncacheWrapper(DOMWrapperWorld& world, DOMClass* domObject, WrapperClass* wrapper)
444 {
445     if (clearInlineCachedWrapper(world, domObject, wrapper))
446         return;
447     weakRemove(world.m_wrappers, wrapperKey(domObject), wrapper);
448 }
449
450 template<typename WrapperClass, typename DOMClass> inline JSDOMObject* createWrapper(JSDOMGlobalObject* globalObject, DOMClass* node)
451 {
452     ASSERT(node);
453     ASSERT(!getCachedWrapper(globalObject->world(), node));
454     WrapperClass* wrapper = WrapperClass::create(getDOMStructure<WrapperClass>(globalObject->vm(), *globalObject), globalObject, Ref<DOMClass>(*node));
455     cacheWrapper(globalObject->world(), node, wrapper);
456     return wrapper;
457 }
458
459 template<typename WrapperClass, typename DOMClass> inline JSC::JSValue wrap(JSDOMGlobalObject* globalObject, DOMClass& domObject)
460 {
461     if (JSC::JSObject* wrapper = getCachedWrapper(globalObject->world(), &domObject))
462         return wrapper;
463     return createWrapper<WrapperClass>(globalObject, &domObject);
464 }
465
466 template<typename WrapperClass, typename DOMClass> inline JSC::JSValue getExistingWrapper(JSDOMGlobalObject* globalObject, DOMClass* domObject)
467 {
468     ASSERT(domObject);
469     return getCachedWrapper(globalObject->world(), domObject);
470 }
471
472 template<typename WrapperClass, typename DOMClass> inline JSC::JSValue createNewWrapper(JSDOMGlobalObject* globalObject, DOMClass* domObject)
473 {
474     ASSERT(domObject);
475     ASSERT(!getCachedWrapper(globalObject->world(), domObject));
476     return createWrapper<WrapperClass>(globalObject, domObject);
477 }
478
479 inline int32_t finiteInt32Value(JSC::JSValue value, JSC::ExecState* exec, bool& okay)
480 {
481     double number = value.toNumber(exec);
482     okay = std::isfinite(number);
483     return JSC::toInt32(number);
484 }
485
486 /*
487     Convert a value to an integer as per <http://www.w3.org/TR/WebIDL/>.
488     The conversion fails if the value cannot be converted to a number or,
489     if EnforceRange is specified, the value is outside the range of the
490     destination integer type.
491 */
492 inline int32_t toInt32(JSC::ExecState* exec, JSC::JSValue value, IntegerConversionConfiguration configuration)
493 {
494     switch (configuration) {
495     case NormalConversion:
496         break;
497     case EnforceRange:
498         return toInt32EnforceRange(exec, value);
499     case Clamp:
500         return toInt32Clamp(exec, value);
501     }
502     return value.toInt32(exec);
503 }
504
505 inline uint32_t toUInt32(JSC::ExecState* exec, JSC::JSValue value, IntegerConversionConfiguration configuration)
506 {
507     switch (configuration) {
508     case NormalConversion:
509         break;
510     case EnforceRange:
511         return toUInt32EnforceRange(exec, value);
512     case Clamp:
513         return toUInt32Clamp(exec, value);
514     }
515     return value.toUInt32(exec);
516 }
517
518 // Validates that the passed object is a sequence type per section 4.1.13 of the WebIDL spec.
519 inline JSC::JSObject* toJSSequence(JSC::ExecState* exec, JSC::JSValue value, unsigned& length)
520 {
521     JSC::JSObject* object = value.getObject();
522     if (!object) {
523         throwSequenceTypeError(*exec);
524         return nullptr;
525     }
526
527     JSC::JSValue lengthValue = object->get(exec, exec->propertyNames().length);
528     if (exec->hadException())
529         return nullptr;
530
531     if (lengthValue.isUndefinedOrNull()) {
532         throwSequenceTypeError(*exec);
533         return nullptr;
534     }
535
536     length = lengthValue.toUInt32(exec);
537     if (exec->hadException())
538         return nullptr;
539
540     return object;
541 }
542
543 inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::ArrayBuffer* buffer)
544 {
545     if (!buffer)
546         return JSC::jsNull();
547     if (JSC::JSValue result = getExistingWrapper<JSC::JSArrayBuffer>(globalObject, buffer))
548         return result;
549
550     // The JSArrayBuffer::create function will register the wrapper in finishCreation.
551     JSC::JSArrayBuffer* wrapper = JSC::JSArrayBuffer::create(exec->vm(), globalObject->arrayBufferStructure(), buffer);
552     return wrapper;
553 }
554
555 inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::ArrayBufferView* view)
556 {
557     if (!view)
558         return JSC::jsNull();
559     return view->wrap(exec, globalObject);
560 }
561
562 inline JSC::JSValue toJS(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject, JSC::ArrayBufferView* view)
563 {
564     if (!view)
565         return JSC::jsNull();
566     return view->wrap(exec, globalObject);
567 }
568
569 template<typename T> inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, RefPtr<T> ptr)
570 {
571     return toJS(exec, globalObject, ptr.get());
572 }
573
574 template<typename T> inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<T> ptr)
575 {
576     return toJS(exec, globalObject, ptr.get());
577 }
578
579 template<typename T> inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T>& vector)
580 {
581     JSC::JSArray* array = constructEmptyArray(exec, nullptr, vector.size());
582     for (size_t i = 0; i < vector.size(); ++i)
583         array->putDirectIndex(exec, i, toJS(exec, globalObject, vector[i]));
584     return array;
585 }
586
587 template<typename T> inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<RefPtr<T>>& vector)
588 {
589     JSC::JSArray* array = constructEmptyArray(exec, nullptr, vector.size());
590     for (size_t i = 0; i < vector.size(); ++i)
591         array->putDirectIndex(exec, i, toJS(exec, globalObject, vector[i].get()));
592     return array;
593 }
594
595 inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject*, const String& value)
596 {
597     return jsStringOrNull(exec, value);
598 }
599
600 inline JSC::JSValue toJSIterator(JSC::ExecState& state, JSDOMGlobalObject&, JSC::JSValue value)
601 {
602     return createIteratorResultObject(&state, value, false);
603 }
604
605 template<typename T> inline JSC::JSValue toJSIterator(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const T& value)
606 {
607     return createIteratorResultObject(&state, toJS(&state, &globalObject, value), false);
608 }
609
610 inline JSC::JSValue toJSIteratorEnd(JSC::ExecState& state)
611 {
612     return createIteratorResultObject(&state, JSC::jsUndefined(), true);
613 }
614
615 template<typename T> struct JSValueTraits {
616     static JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const T& value)
617     {
618         return toJS(exec, globalObject, WTF::getPtr(value));
619     }
620 };
621
622 template<> struct JSValueTraits<String> {
623     static JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject*, const String& value)
624     {
625         return JSC::jsStringWithCache(exec, value);
626     }
627 };
628
629 template<> struct JSValueTraits<double> {
630     static JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const double& value)
631     {
632         return JSC::jsNumber(value);
633     }
634 };
635
636 template<> struct JSValueTraits<float> {
637     static JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const float& value)
638     {
639         return JSC::jsNumber(value);
640     }
641 };
642
643 template<> struct JSValueTraits<unsigned long> {
644     static JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const unsigned long& value)
645     {
646         return JSC::jsNumber(value);
647     }
648 };
649
650 template<typename T, size_t inlineCapacity> JSC::JSValue jsArray(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T, inlineCapacity>& vector)
651 {
652     JSC::MarkedArgumentBuffer list;
653     for (auto& element : vector)
654         list.append(JSValueTraits<T>::arrayJSValue(exec, globalObject, element));
655     return JSC::constructArray(exec, nullptr, globalObject, list);
656 }
657
658 template<typename T, size_t inlineCapacity> inline JSC::JSValue jsArray(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T, inlineCapacity>* vector)
659 {
660     if (!vector)
661         return JSC::constructEmptyArray(exec, nullptr, globalObject, 0);
662     return jsArray(exec, globalObject, *vector);
663 }
664
665 template<typename Value1, typename Value2> inline JSC::JSValue jsPair(JSC::ExecState& state, JSDOMGlobalObject* globalObject, const Value1& value1, const Value2& value2)
666 {
667     JSC::MarkedArgumentBuffer args;
668     args.append(toJS(&state, globalObject, value1));
669     args.append(toJS(&state, globalObject, value2));
670     return constructArray(&state, 0, globalObject, args);
671 }
672
673 inline RefPtr<JSC::ArrayBufferView> toArrayBufferView(JSC::JSValue value)
674 {
675     auto* wrapper = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(value);
676     if (!wrapper)
677         return nullptr;
678     return wrapper->impl();
679 }
680
681 inline RefPtr<JSC::Int8Array> toInt8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int8Adaptor>(value); }
682 inline RefPtr<JSC::Int16Array> toInt16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int16Adaptor>(value); }
683 inline RefPtr<JSC::Int32Array> toInt32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int32Adaptor>(value); }
684 inline RefPtr<JSC::Uint8Array> toUint8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8Adaptor>(value); }
685 inline RefPtr<JSC::Uint8ClampedArray> toUint8ClampedArray(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8ClampedAdaptor>(value); }
686 inline RefPtr<JSC::Uint16Array> toUint16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint16Adaptor>(value); }
687 inline RefPtr<JSC::Uint32Array> toUint32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint32Adaptor>(value); }
688 inline RefPtr<JSC::Float32Array> toFloat32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float32Adaptor>(value); }
689 inline RefPtr<JSC::Float64Array> toFloat64Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float64Adaptor>(value); }
690
691 template<typename T> struct NativeValueTraits;
692
693 template<> struct NativeValueTraits<String> {
694     static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, String& indexedValue)
695     {
696         indexedValue = jsValue.toWTFString(exec);
697         return true;
698     }
699 };
700
701 template<> struct NativeValueTraits<unsigned> {
702     static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, unsigned& indexedValue)
703     {
704         if (!jsValue.isNumber())
705             return false;
706
707         indexedValue = jsValue.toUInt32(exec);
708         if (exec->hadException())
709             return false;
710
711         return true;
712     }
713 };
714
715 template<> struct NativeValueTraits<float> {
716     static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, float& indexedValue)
717     {
718         indexedValue = jsValue.toFloat(exec);
719         return !exec->hadException();
720     }
721 };
722
723 template<> struct NativeValueTraits<double> {
724     static inline bool nativeValue(JSC::ExecState* exec, JSC::JSValue jsValue, double& indexedValue)
725     {
726         indexedValue = jsValue.toNumber(exec);
727         return !exec->hadException();
728     }
729 };
730
731 template<typename T, typename JST> Vector<RefPtr<T>> toRefPtrNativeArray(JSC::ExecState* exec, JSC::JSValue value, T* (*toT)(JSC::JSValue value))
732 {
733     if (!isJSArray(value))
734         return Vector<RefPtr<T>>();
735
736     Vector<RefPtr<T>> result;
737     JSC::JSArray* array = asArray(value);
738     size_t size = array->length();
739     result.reserveInitialCapacity(size);
740     for (size_t i = 0; i < size; ++i) {
741         JSC::JSValue element = array->getIndex(exec, i);
742         if (element.inherits(JST::info()))
743             result.uncheckedAppend((*toT)(element));
744         else {
745             throwArrayElementTypeError(*exec);
746             return Vector<RefPtr<T>>();
747         }
748     }
749     return result;
750 }
751
752 template<typename T> Vector<T> toNativeArray(JSC::ExecState* exec, JSC::JSValue value)
753 {
754     JSC::JSObject* object = value.getObject();
755     if (!object)
756         return Vector<T>();
757
758     unsigned length = 0;
759     if (isJSArray(value)) {
760         JSC::JSArray* array = asArray(value);
761         length = array->length();
762     } else
763         toJSSequence(exec, value, length);
764
765     Vector<T> result;
766     result.reserveInitialCapacity(length);
767     typedef NativeValueTraits<T> TraitsType;
768
769     for (unsigned i = 0; i < length; ++i) {
770         T indexValue;
771         if (!TraitsType::nativeValue(exec, object->get(exec, i), indexValue))
772             return Vector<T>();
773         result.uncheckedAppend(indexValue);
774     }
775     return result;
776 }
777
778 template<typename T> Vector<T> toNativeArguments(JSC::ExecState* exec, size_t startIndex)
779 {
780     size_t length = exec->argumentCount();
781     ASSERT(startIndex <= length);
782
783     Vector<T> result;
784     result.reserveInitialCapacity(length - startIndex);
785     typedef NativeValueTraits<T> TraitsType;
786
787     for (size_t i = startIndex; i < length; ++i) {
788         T indexValue;
789         if (!TraitsType::nativeValue(exec, exec->argument(i), indexValue))
790             return Vector<T>();
791         result.uncheckedAppend(indexValue);
792     }
793     return result;
794 }
795
796 inline String propertyNameToString(JSC::PropertyName propertyName)
797 {
798     ASSERT(!propertyName.isSymbol());
799     return propertyName.uid() ? propertyName.uid() : propertyName.publicName();
800 }
801
802 inline AtomicString propertyNameToAtomicString(JSC::PropertyName propertyName)
803 {
804     return AtomicString(propertyName.uid() ? propertyName.uid() : propertyName.publicName());
805 }
806
807 template<typename DOMClass> inline const JSC::HashTableValue* getStaticValueSlotEntryWithoutCaching(JSC::ExecState* exec, JSC::PropertyName propertyName)
808 {
809     if (DOMClass::hasStaticPropertyTable) {
810         if (auto* entry = DOMClass::info()->staticPropHashTable->entry(propertyName))
811             return entry;
812     }
813     return getStaticValueSlotEntryWithoutCaching<typename DOMClass::Base>(exec, propertyName);
814 }
815
816 template<> inline const JSC::HashTableValue* getStaticValueSlotEntryWithoutCaching<JSDOMObject>(JSC::ExecState*, JSC::PropertyName)
817 {
818     return nullptr;
819 }
820
821 template<JSC::NativeFunction nativeFunction, int length> JSC::EncodedJSValue nonCachingStaticFunctionGetter(JSC::ExecState* exec, JSC::EncodedJSValue, JSC::PropertyName propertyName)
822 {
823     return JSC::JSValue::encode(JSC::JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), length, propertyName.publicName(), nativeFunction));
824 }
825
826 template<typename T> inline JSC::JSValue toNullableJSNumber(Optional<T> optionalNumber)
827 {
828     return optionalNumber ? JSC::jsNumber(optionalNumber.value()) : JSC::jsNull();
829 }
830
831 } // namespace WebCore