/*
 *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
 *  Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Apple Inc. All rights reserved.
 *  Copyright (C) 2007 Samuel Weinig <sam@webkit.org>
 *  Copyright (C) 2009 Google, Inc. All rights reserved.
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#pragma once

#include "CanvasWindingRule.h"
#include "BindingState.h"
#include "BufferSource.h"
#include "CSSImportRule.h"
#include "CSSStyleDeclaration.h"
#include "CSSStyleSheet.h"
#include "CSSUnits.h"
#include "JSDOMGlobalObject.h"
#include "JSDOMWrapper.h"
#include "Exception.h"
#include "DOMWrapperWorld.h"
#include "Document.h"
#include "Element.h"
#include "Exception.h"
#include "MediaKeySessionType.h"
#include "MediaKeysRequirement.h"
#include "MediaKeySystemConfiguration.h"
#include "MediaKeySystemMediaCapability.h"
#include "MediaList.h"
#include "RTCIceServer.h"
#include "RTCRtpParameters.h"
#include "ScriptValue.h"
#include "ScriptWrappable.h"
#include "ShadowRoot.h"
#include "StylePropertySet.h"
#include "StyledElement.h"
#include "WebCoreTypedArrayController.h"
#include <heap/SlotVisitor.h>
#include <heap/Weak.h>
#include <runtime/Error.h>
#include <runtime/InternalFunction.h>
#include <runtime/IteratorOperations.h>
#include <runtime/ExceptionScope.h>
#include <runtime/FunctionPrototype.h>
#include <runtime/JSArray.h>
#include <runtime/JSArrayBuffer.h>
#include <runtime/JSDataView.h>
#include <runtime/JSTypedArrays.h>
#include <runtime/Lookup.h>
#include <runtime/ObjectPrototype.h>
#include <runtime/Operations.h>
#include <runtime/TypedArrays.h>
#include <runtime/WriteBarrier.h>
#include <wtf/Forward.h>
#include <wtf/GetPtr.h>
#include <wtf/Noncopyable.h>
#include <wtf/NullPtr.h>
#include <wtf/Ref.h>
#include <wtf/Vector.h>

// FIXME: We could make this file a lot easier to read by putting all function declarations at the top,
// and function definitions below, even for template and inline functions.

namespace JSC {
class JSFunction;
class JSObject;

ALWAYS_INLINE JSValue jsNumber(WebCore::CSSUnitType type)
{
	return jsNumber(static_cast<unsigned short>(type));
}

}

namespace WebCore {

class CachedScript;
class DOMStringList;
class HTMLFrameElementBase;
class Frame;
class JSDocument;
class JSElement;
class JSNode;
class KURL;
class WebAnimation;

typedef int ExceptionCode;

template<typename Class>
class DOMPromiseProxyWithResolveCallback;

ALWAYS_INLINE JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, JSC::JSValue jsValue) { return jsValue; }

JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, WebAnimation*);

template<typename Class>
JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, DOMPromiseProxyWithResolveCallback<Class>*);
template<typename Class>
JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, DOMPromiseProxyWithResolveCallback<Class>&);

void callFunctionWithCurrentArguments(JSC::ExecState&, JSC::JSObject& thisObject, JSC::JSFunction&);

JSC::EncodedJSValue reportDeprecatedGetterError(JSC::ExecState&, const char* interfaceName, const char* attributeName);
void reportDeprecatedSetterError(JSC::ExecState&, const char* interfaceName, const char* attributeName);

void throwArrayElementTypeError(JSC::ExecState&);
void throwAttributeTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName, const char* expectedType);
void throwSequenceTypeError(JSC::ExecState&);

#if ENABLE(BINDINGS_ALL_IN_ONE)
static
#endif
JSC::EncodedJSValue throwGetterTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName);

#if ENABLE(BINDINGS_ALL_IN_ONE)
static
#endif
bool throwSetterTypeError(JSC::ExecState&, const char* interfaceName, const char* attributeName);

void throwNonFiniteTypeError(JSC::ExecState&);
void throwSecurityError(JSC::ExecState&, const String& message);

JSC::EncodedJSValue throwArgumentMustBeEnumError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedValues);
JSC::EncodedJSValue throwArgumentMustBeFunctionError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName);
JSC::EncodedJSValue throwArgumentTypeError(JSC::ExecState&, unsigned argumentIndex, const char* argumentName, const char* functionInterfaceName, const char* functionName, const char* expectedType);
JSC::EncodedJSValue throwConstructorScriptExecutionContextUnavailableError(JSC::ExecState&, const char* interfaceName);

String makeGetterTypeErrorMessage(const char* interfaceName, const char* attributeName);
String makeThisTypeErrorMessage(const char* interfaceName, const char* attributeName);
String makeUnsupportedIndexedSetterErrorMessage(const char* interfaceName);

#if ENABLE(BINDINGS_ALL_IN_ONE)
static
#endif
JSC::EncodedJSValue throwThisTypeError(JSC::ExecState&, const char* interfaceName, const char* functionName);

template<typename T> Vector<T> toNativeArray(JSC::ExecState&, JSC::JSObject*);
template<typename T> Vector<T> toNativeArray(JSC::ExecState&, JSC::JSValue);

JSC::EncodedJSValue JSC_HOST_CALL callThrowTypeErrorForJSDOMConstructor(JSC::ExecState*);
JSC::EncodedJSValue JSC_HOST_CALL callThrowTypeErrorForJSDOMConstructorNotConstructable(JSC::ExecState*);

// Base class for all callable constructor objects in the JSC bindings.
class JSDOMConstructorBase : public JSC::InternalFunction {
public:
    using Base = InternalFunction;

	static const unsigned StructureFlags = Base::StructureFlags;

    JSDOMGlobalObject* globalObject() const { return JSC::jsCast<JSDOMGlobalObject*>(Base::globalObject()); }
    ScriptExecutionContext* scriptExecutionContext() const { return globalObject()->scriptExecutionContext(); }

protected:
    JSDOMConstructorBase(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction functionForConstruct)
        : Base(vm, structure,
            functionForConstruct ? callThrowTypeErrorForJSDOMConstructor : callThrowTypeErrorForJSDOMConstructorNotConstructable,
            functionForConstruct ? functionForConstruct : callThrowTypeErrorForJSDOMConstructorNotConstructable)
    {
    }

    static String className(const JSObject*);
    static String toStringName(const JSObject*, JSC::ExecState*);
};

// Constructors using this base class depend on being in a Document and
// can never be used from a WorkerGlobalScope.
class DOMConstructorWithDocument : public JSDOMConstructorBase {
	typedef JSDOMConstructorBase Base;
public:
    static const bool needsDestruction = false;

	ALWAYS_INLINE Document* document() const
	{
		return static_cast<Document*>(scriptExecutionContext());
	}

protected:
    DOMConstructorWithDocument(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction functionForConstruct)
        : Base(vm, structure, functionForConstruct)
    {
    }

	ALWAYS_INLINE void finishCreation(JSC::JSGlobalData& vm)
	{
		Base::finishCreation(vm);
		ASSERT(globalObject()->scriptExecutionContext()->isDocument());
	}
};

class DOMConstructorJSBuiltinObject : public JSDOMConstructorBase {
public:
    typedef JSDOMConstructorBase Base;
    static const bool needsDestruction = false;

protected:
    DOMConstructorJSBuiltinObject(JSC::VM& vm, JSC::Structure* structure, JSC::NativeFunction functionForConstruct)
	: Base(vm, structure, functionForConstruct)
	{
	}

    static void visitChildren(JSC::JSCell*, JSC::SlotVisitor&);

    JSC::JSFunction* initializeFunction() { return m_initializeFunction.get(); }
    void setInitializeFunction(JSC::VM& vm, JSC::JSFunction& function) { m_initializeFunction.set(vm, this, &function); }

private:
    JSC::WriteBarrier<JSC::JSFunction> m_initializeFunction;
};

JSC::Structure* getCachedDOMStructure(JSDOMGlobalObject*, const JSC::ClassInfo*);
JSC::Structure* cacheDOMStructure(JSDOMGlobalObject*, JSC::Structure*, const JSC::ClassInfo*);

enum ShouldAllowNonFinite { ShouldAllowNonFiniteNo, ShouldAllowNonFiniteYes };

enum IntegerConversionConfiguration { NormalConversion, EnforceRange, Clamp };

template<typename T> struct Converter;

template<typename T> T convert(JSC::ExecState&, JSC::JSValue);
template<typename T> T convert(JSC::ExecState&, JSC::JSValue, IntegerConversionConfiguration);
template<typename T> T convert(JSC::ExecState&, JSC::JSValue, ShouldAllowNonFinite);

template<typename T> T convertDictionary(JSC::ExecState&, JSC::JSValue);

enum IsNullable { IsNullableNo, IsNullableYes };
template<typename T, typename JST> T* convertWrapperType(JSC::ExecState&, JSC::JSValue, IsNullable);
template<typename T, typename JST, typename VectorType> VectorType convertWrapperTypeSequence(JSC::ExecState&, JSC::JSValue);

ALWAYS_INLINE JSDOMGlobalObject* deprecatedGlobalObjectForPrototype(JSC::ExecState* exec)
{
	// FIXME: Callers to this function should be using the global object
	// from which the object is being created, instead of assuming the lexical one.
	// e.g. subframe.document.body should use the subframe's global object, not the lexical one.
	return JSC::jsCast<JSDOMGlobalObject*>(exec->lexicalGlobalObject());
}

template<typename WrapperClass> inline JSC::Structure* getDOMStructure(JSC::JSGlobalData& vm, JSDOMGlobalObject* globalObject)
{
	if (JSC::Structure* structure = getCachedDOMStructure(globalObject, WrapperClass::info()))
		return structure;
	return cacheDOMStructure(globalObject, WrapperClass::createStructure(vm, globalObject, WrapperClass::createPrototype(vm, globalObject)), WrapperClass::info());
}

template<typename WrapperClass> inline JSC::Structure* deprecatedGetDOMStructure(JSC::ExecState* exec)
{
    // FIXME: This function is wrong. It uses the wrong global object for creating the prototype structure.
    return getDOMStructure<WrapperClass>(exec->vm(), deprecatedGlobalObjectForPrototype(exec));
}

template<typename WrapperClass> ALWAYS_INLINE JSC::JSObject* getDOMPrototype(JSC::JSGlobalData& vm, JSC::JSGlobalObject* globalObject)
{
	return JSC::jsCast<JSC::JSObject*>(asObject(getDOMStructure<WrapperClass>(vm, JSC::jsCast<JSDOMGlobalObject*>(globalObject))->storedPrototype()));
}

ALWAYS_INLINE JSC::WeakHandleOwner* wrapperOwner(DOMWrapperWorld* world, JSC::ArrayBuffer*)
{
    return static_cast<WebCoreTypedArrayController*>(world->vm()->m_typedArrayController.get())->wrapperOwner();
}

ALWAYS_INLINE void* wrapperContext(DOMWrapperWorld* world, JSC::ArrayBuffer*)
{
    return world;
}

template<typename DOMClass> void* wrapperKey(DOMClass* domObject)
{
	return domObject;
}

template<>
ALWAYS_INLINE void* wrapperKey(JSC::ArrayBuffer* domObject)
{
    return domObject;
}

inline JSDOMObject* getInlineCachedWrapper(JSDOMGlobalObject*, void*) { return 0; }
inline bool setInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMObject*, JSC::WeakHandleOwner*, void*) { return false; }
inline bool clearInlineCachedWrapper(DOMWrapperWorld*, void*, JSDOMObject*) { return false; }

inline JSDOMObject* getInlineCachedWrapper(JSDOMGlobalObject* globalObject, ScriptWrappable* domObject)
{
    if (UNLIKELY(!globalObject->worldIsNormal()))
        return 0;
    return domObject->wrapper();
}

inline bool setInlineCachedWrapper(DOMWrapperWorld* world, ScriptWrappable* domObject, JSDOMObject* wrapper, JSC::WeakHandleOwner* wrapperOwner, void* context)
{
    if (UNLIKELY(!world->isNormal()))
        return false;
    domObject->setWrapper(wrapper, wrapperOwner, context);
    return true;
}

inline bool clearInlineCachedWrapper(DOMWrapperWorld* world, ScriptWrappable* domObject, JSDOMObject* wrapper)
{
    if (UNLIKELY(!world->isNormal()))
        return false;
    domObject->clearWrapper(wrapper);
    return true;
}

ALWAYS_INLINE JSC::JSArrayBuffer* getInlineCachedWrapper(JSDOMGlobalObject* globalObject, JSC::ArrayBuffer* buffer)
{
    if (LIKELY(globalObject->worldIsNormal()))
    	return buffer->m_wrapper.get();
    return 0;
}

ALWAYS_INLINE bool setInlineCachedWrapper(DOMWrapperWorld* world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper, JSC::WeakHandleOwner*, void*)
{
    if (LIKELY(world->isNormal())){
		domObject->m_wrapper = JSC::PassWeak<JSC::JSArrayBuffer>(wrapper, wrapperOwner(world, domObject), wrapperContext(world, domObject));
		return true;
    }
    return false;
}

ALWAYS_INLINE bool clearInlineCachedWrapper(DOMWrapperWorld* world, JSC::ArrayBuffer* domObject, JSC::JSArrayBuffer* wrapper)
{
    if (LIKELY(world->isNormal())){
    	weakClear(domObject->m_wrapper, wrapper);
    	return true;
    }
    return false;
}

template <typename DOMClass> inline JSC::JSObject* getCachedWrapper(JSDOMGlobalObject* globalObject, DOMClass* domObject)
{
    if (JSC::JSObject* wrapper = getInlineCachedWrapper(globalObject, domObject))
        return wrapper;
    return globalObject->world()->wrappers().get(wrapperKey(domObject));
}

template <typename DOMClass> inline JSC::JSObject* getCachedWrapper(JSDOMGlobalObject* globalObject, DOMClass& domObject)
{
    if (JSC::JSObject* wrapper = getInlineCachedWrapper(globalObject, domObject))
        return wrapper;
    return globalObject->world()->wrappers().get(wrapperKey(domObject));
}

template <typename DOMClass, typename WrapperClass> inline void cacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, WrapperClass* wrapper)
{
    JSC::WeakHandleOwner* owner = wrapperOwner(world, domObject);
    void* context = wrapperContext(world, domObject);
    if (setInlineCachedWrapper(world, domObject, wrapper, owner, context))
        return;
    JSC::PassWeak<JSC::JSObject> passWeak(wrapper, owner, context);
	weakAdd(world->wrappers(), wrapperKey(domObject), passWeak);
}

template <typename DOMClass, typename WrapperClass> inline void uncacheWrapper(DOMWrapperWorld* world, DOMClass* domObject, WrapperClass* wrapper)
{
	if (clearInlineCachedWrapper(world, domObject, wrapper))
		return;
	weakRemove(world->wrappers(), wrapperKey(domObject), wrapper);
}

#define CREATE_DOM_WRAPPER(globalObject, className, object) createWrapper<JS##className>(globalObject, static_cast<className*>(object))
template<typename WrapperClass, typename DOMClass> inline JSDOMObject* createWrapper(JSDOMGlobalObject* globalObject, DOMClass* node)
{
	ASSERT(node);
    ASSERT(!getCachedWrapper(globalObject, node));
	WrapperClass* wrapper = WrapperClass::create(getDOMStructure<WrapperClass>(globalObject->vm(), globalObject), globalObject, node);
	cacheWrapper(globalObject->world(), node, wrapper);
	return wrapper;
}

template<typename WrapperClass, typename DOMClass> inline JSC::JSValue wrap(JSDOMGlobalObject* globalObject, DOMClass* domObject)
{
	if (!domObject)
		return JSC::jsNull();
	if (JSC::JSObject* wrapper = getCachedWrapper(globalObject, domObject))
		return wrapper;
	return createWrapper<WrapperClass>(globalObject, domObject);
}

template<typename WrapperClass, typename DOMClass> inline JSC::JSValue wrap(JSDOMGlobalObject* globalObject, DOMClass& domObject)
{
	if (JSC::JSObject* wrapper = getCachedWrapper(globalObject, domObject))
		return wrapper;
	return createWrapper<WrapperClass>(globalObject, domObject);
}

template<typename WrapperClass, typename DOMClass> ALWAYS_INLINE JSC::JSObject* getExistingWrapper(JSDOMGlobalObject* globalObject, DOMClass* domObject)
{
    ASSERT(domObject);
    return getCachedWrapper(globalObject, domObject);
}

template<class WrapperClass, class DOMClass> inline JSC::JSValue createNewWrapper(JSDOMGlobalObject* globalObject, DOMClass* domObject)
{
    ASSERT(domObject);
    ASSERT(!getCachedWrapper(globalObject, domObject));
    return createWrapper<WrapperClass>(globalObject, domObject);
}

ALWAYS_INLINE void* root(Node& node)
{
    return node.opaqueRoot();
}

ALWAYS_INLINE void* root(Node* node)
{
    return node ? root(*node) : nullptr;
}

inline void* root(CSSRule*);
inline void* root(StyleSheet*);

inline void* root(CSSRule& rule)
{
	if (rule.parentRule())
		return root(rule.parentRule());
	if (rule.parentStyleSheet())
		return root(rule.parentStyleSheet());
	return &rule;
}

inline void* root(CSSRule* rule)
{
	return rule ? root(*rule) : nullptr;
}

inline void* root(StyleSheet& styleSheet)
{
	if (styleSheet.ownerRule())
		return root(styleSheet.ownerRule());
	if (styleSheet.ownerNode())
		return root(styleSheet.ownerNode());
	return &styleSheet;
}

inline void* root(StyleSheet* styleSheet)
{
	return styleSheet ? root(*styleSheet) : nullptr;
}

void* root(CSSStyleDeclaration&);
inline void* root(CSSStyleDeclaration* style)
{
	return style ? root(*style) : nullptr;
}

inline void* root(MediaList& mediaList)
{
	if (CSSRule* parentRule = mediaList.parentRule())
		return root(parentRule);
	if (CSSStyleSheet* parentStyleSheet = mediaList.parentStyleSheet())
		return root(parentStyleSheet);
	return &mediaList;
}

inline void* root(MediaList* mediaList)
{
	return mediaList ? root(*mediaList) : nullptr;
}

template<typename JSClass> JSClass& castThisValue(JSC::ExecState&);

void addImpureProperty(const AtomicString&);

const JSC::HashTable& getHashTableForGlobalData(JSC::JSGlobalData&, const JSC::HashTable& staticTable);

String retrieveErrorMessage(JSC::ExecState&, JSC::VM&, JSC::JSValue exception, JSC::JSGlobalData&);
void reportException(JSC::ExecState*, JSC::JSValue exception, CachedScript* = 0);
void reportException(JSC::ExecState*, JSC::Exception*, CachedScript* cachedScript = 0);
void reportCurrentException(JSC::ExecState*);

JSC::JSValue createDOMException(JSC::ExecState*, ExceptionCode);
JSC::JSValue createDOMException(JSC::ExecState*, ExceptionCode, const String& message);
// Convert a DOM implementation exception code into a JavaScript exception in the execution state.
void setDOMException(JSC::ExecState* exec, ExceptionCode ec);
void setDOMException(JSC::ExecState*, ExceptionCode, const ASCIILiteral&);
void setDOMException(JSC::ExecState*, ExceptionCode, const String&);

inline void setDOMException(JSC::ExecState* exec, const Exception& exception)
{
	setDOMException(exec, exception.code(), exception.message());
}

JSC::JSValue jsString(JSC::ExecState*, const KURL&); // empty if the URL is null

ALWAYS_INLINE JSC::JSValue jsStringOrNull(JSC::VM& vm, const String& s) // null if the string is null
{
    if (UNLIKELY(s.isNull()))
        return JSC::jsNull();
    return JSC::jsStringWithCache(vm, s);
}

ALWAYS_INLINE JSC::JSValue jsStringOrNull(JSC::VM& vm, const KURL& url) // null if the URL is null
{
	return jsStringOrNull(vm, url.string());
}

JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const String&); // undefined if the string is null
JSC::JSValue jsStringOrUndefined(JSC::ExecState*, const KURL&); // undefined if the URL is null

// See JavaScriptCore for explanation: Should be used for any string that is already owned by another
// object, to let the engine know that collecting the JSString wrapper is unlikely to save memory.
JSC::JSValue jsOwnedStringOrNull(JSC::ExecState*, const String&);

String propertyNameToString(JSC::PropertyName);
AtomicString propertyNameToAtomicString(JSC::PropertyName);

template<JSC::NativeFunction, int length> JSC::EncodedJSValue nonCachingStaticFunctionGetter(JSC::ExecState*, JSC::EncodedJSValue, JSC::PropertyName);

// FIXME: This is only used by legacy code and should go away. Use valueToStringTreatingNullAsEmptyString() instead.
String valueToStringWithNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null

String valueToStringTreatingNullAsEmptyString(JSC::ExecState*, JSC::JSValue);
String valueToStringWithUndefinedOrNullCheck(JSC::ExecState*, JSC::JSValue); // null if the value is null or undefined

String identifierToByteString(JSC::ExecState&, const JSC::Identifier&);
String valueToByteString(JSC::ExecState&, JSC::JSValue);
inline String valueToByteString(JSC::ExecState* exec, JSC::JSValue value) { return valueToByteString(*exec, value); }
String valueToByteStringTreatingNullAsEmptyString(JSC::ExecState*, JSC::JSValue);
String valueToByteStringWithUndefinedOrNullCheck(JSC::ExecState*, JSC::JSValue);

String identifierToUSVString(JSC::ExecState&, const JSC::Identifier&);
String valueToUSVString(JSC::ExecState&, JSC::JSValue);
inline String valueToUSVString(JSC::ExecState* exec, JSC::JSValue value) { return valueToUSVString(*exec, value); }
String valueToUSVStringTreatingNullAsEmptyString(JSC::ExecState*, JSC::JSValue);
String valueToUSVStringWithUndefinedOrNullCheck(JSC::ExecState*, JSC::JSValue);

template<typename T> JSC::JSValue toNullableJSNumber(Optional<T>); // null if the optional is null

template<typename JSClass> inline JSClass& castThisValue(JSC::ExecState& state)
{
	JSC::JSValue thisValue = state.thisValue();
	JSClass* castedThis = JSC::jsDynamicCast<JSClass*>(thisValue);
    ASSERT(castedThis);
    return *castedThis;
}

inline int32_t finiteInt32Value(JSC::JSValue value, JSC::ExecState* exec, bool& okay)
{
	double number = value.toNumber(exec);
	okay = isfinite(number);
	return JSC::toInt32(number);
}

int8_t toInt8EnforceRange(JSC::ExecState&, JSC::JSValue);
uint8_t toUInt8EnforceRange(JSC::ExecState&, JSC::JSValue);
int16_t toInt16EnforceRange(JSC::ExecState&, JSC::JSValue);
uint16_t toUInt16EnforceRange(JSC::ExecState&, JSC::JSValue);
int32_t toInt32EnforceRange(JSC::ExecState&, JSC::JSValue);
uint32_t toUInt32EnforceRange(JSC::ExecState&, JSC::JSValue);
int64_t toInt64EnforceRange(JSC::ExecState&, JSC::JSValue);
uint64_t toUInt64EnforceRange(JSC::ExecState&, JSC::JSValue);

int8_t toInt8Clamp(JSC::ExecState&, JSC::JSValue);
uint8_t toUInt8Clamp(JSC::ExecState&, JSC::JSValue);
int16_t toInt16Clamp(JSC::ExecState&, JSC::JSValue);
uint16_t toUInt16Clamp(JSC::ExecState&, JSC::JSValue);
int32_t toInt32Clamp(JSC::ExecState&, JSC::JSValue);
uint32_t toUInt32Clamp(JSC::ExecState&, JSC::JSValue);
int64_t toInt64Clamp(JSC::ExecState&, JSC::JSValue);
uint64_t toUInt64Clamp(JSC::ExecState&, JSC::JSValue);

int8_t toInt8(JSC::ExecState&, JSC::JSValue);
uint8_t toUInt8(JSC::ExecState&, JSC::JSValue);
int16_t toInt16(JSC::ExecState&, JSC::JSValue);
uint16_t toUInt16(JSC::ExecState&, JSC::JSValue);
int64_t toInt64(JSC::ExecState&, JSC::JSValue);
uint64_t toUInt64(JSC::ExecState&, JSC::JSValue);

JSC::JSValue jsDate(JSC::ExecState*, double value);
JSC::JSValue jsDateOrNull(JSC::ExecState*, double value);

// NaN if the value can't be converted to a date.
double valueToDate(JSC::ExecState*, JSC::JSValue);

// Validates that the passed object is a sequence type per section 4.1.13 of the WebIDL spec.
inline JSC::JSObject* toJSSequence(JSC::ExecState* exec, JSC::VM& vm, JSC::JSObject* object, unsigned& length)
{
	JSC::JSValue lengthValue = object->get(vm, exec, vm.propertyNames->length);
    RETURN_IF_EXCEPTION(vm, static_cast<JSC::JSObject*>(0));

	if (lengthValue.isUndefinedOrNull()) {
        throwVMError(exec, vm, createTypeError(exec, "Value is not a sequence"));
		return 0;
	}

	length = lengthValue.toUInt32(exec);
    RETURN_IF_EXCEPTION(vm, static_cast<JSC::JSObject*>(0));

	return object;
}

inline JSC::JSObject* toJSSequence(JSC::ExecState* exec, JSC::VM& vm, JSC::JSValue value, unsigned& length)
{
	JSC::JSObject* object = value.getObject();
	if (!object) {
        throwVMError(exec, vm, createTypeError(exec, "Value is not a sequence"));
		return 0;
	}

	return toJSSequence(exec, vm, object, length);
}

inline JSC::JSValue toJS(JSC::ExecState*, JSC::JSGlobalObject*, double value)
{
	return JSC::JSValue(value);
}

inline JSC::JSValue toJS(JSC::ExecState*, JSC::JSGlobalObject*, Optional<double> optionalValue)
{
	return optionalValue ? JSC::JSValue(optionalValue.value()) : JSC::jsNull();
}

inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, Optional<CompositeOperation> optionalValue)
{
	return optionalValue ? toJS(exec, globalObject, optionalValue.value()) : JSC::jsNull();
}

inline JSC::JSValue toJS(JSC::ExecState*, JSC::JSGlobalObject*, ScriptValue scriptValue)
{
	return scriptValue.jsValue();
}

ALWAYS_INLINE JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::ArrayBuffer* buffer)
{
    if (!buffer)
        return JSC::jsNull();
    if (auto* result = getExistingWrapper<JSC::JSArrayBuffer>(globalObject, buffer))
        return result;
    // The JSArrayBuffer::create function will register the wrapper in finishCreation.
    JSC::JSArrayBuffer* wrapper = JSC::JSArrayBuffer::create(globalObject->vm(), globalObject->arrayBufferStructure(), buffer);
    return wrapper;
}

ALWAYS_INLINE JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::ArrayBufferView* view)
{
    if (!view)
        return JSC::jsNull();
    return view->wrap(exec, globalObject);
}

inline JSC::JSValue toJS(JSC::ExecState* exec, JSC::JSGlobalObject* globalObject, JSC::ArrayBufferView* view)
{
    if (!view)
        return JSC::jsNull();
    return view->wrap(exec, globalObject);
}

inline JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const BufferSource& bufferSource)
{
	return toJS(exec, globalObject, bufferSource.buffer().get());
}

template <typename T>
ALWAYS_INLINE JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, RefPtr<T> ptr)
{
	return toJS(exec, globalObject, ptr.get());
}

template <typename T>
ALWAYS_INLINE JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, PassRefPtr<T> ptr)
{
	return toJS(exec, globalObject, ptr.get());
}

ALWAYS_INLINE JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject* globalObject, const String& s)
{
	return JSC::jsStringWithCache(globalObject->vm(), s);
}

ALWAYS_INLINE JSC::JSValue toJS(JSC::ExecState*, JSC::VM& vm, const String& s)
{
	return JSC::jsStringWithCache(vm, s);
}

inline JSC::JSValue toJSIterator(JSC::ExecState& state, JSDOMGlobalObject& globalObject, JSC::JSValue value)
{
    return JSC::createIteratorResultObject(globalObject.vm(), &state, value, false);
}

template<typename T> inline JSC::JSValue toJSIterator(JSC::ExecState& state, JSDOMGlobalObject& globalObject, const T& value)
{
    return JSC::createIteratorResultObject(globalObject.vm(), &state, toJS(&state, &globalObject, value), false);
}

inline JSC::JSValue toJSIteratorEnd(JSC::ExecState& state)
{
    return JSC::createIteratorResultObject(state.vm(), &state, JSC::jsUndefined(), true);
}

template <typename T>
struct JSValueTraits {
	static ALWAYS_INLINE JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const T& value)
	{
		return toJS(exec, globalObject, WTF::getPtr(value));
	}
};

template<>
struct JSValueTraits<String> {
	static ALWAYS_INLINE JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject* globalObject, const String& value)
	{
		return JSC::jsStringWithCache(globalObject->vm(), value);
	}
};

template<>
struct JSValueTraits<double> {
	static ALWAYS_INLINE JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const float& value)
	{
		return JSC::jsNumber(value);
	}
};

template<>
struct JSValueTraits<float> {
	static ALWAYS_INLINE JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const float& value)
	{
		return JSC::jsNumber(value);
	}
};

template<>
struct JSValueTraits<unsigned long> {
	static ALWAYS_INLINE JSC::JSValue arrayJSValue(JSC::ExecState*, JSDOMGlobalObject*, const unsigned long& value)
	{
		return JSC::jsNumber(value);
	}
};

#if ENABLE(ENCRYPTED_MEDIA)
JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, const MediaKeySystemMediaCapability&);
template<>
struct JSValueTraits<MediaKeySystemMediaCapability> {
	static ALWAYS_INLINE JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const MediaKeySystemMediaCapability& value)
	{
		return toJS(exec, globalObject, value);
	}
};

JSC::JSValue toJS(JSC::ExecState*, JSDOMGlobalObject*, MediaKeySessionType);
template<>
struct JSValueTraits<MediaKeySessionType> {
	static ALWAYS_INLINE JSC::JSValue arrayJSValue(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, MediaKeySessionType value)
	{
		return toJS(exec, globalObject, value);
	}
};
#endif

template <typename T, size_t inlineCapacity>
JSC::JSValue jsArrayOrNull(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T, inlineCapacity>& vector)
{
	JSC::MarkedArgumentBuffer list;
	typename Vector<T, inlineCapacity>::const_iterator end = vector.end();
	typedef JSValueTraits<T> TraitsType;

	for (typename Vector<T, inlineCapacity>::const_iterator iter = vector.begin(); iter != end; ++iter)
		list.append(TraitsType::arrayJSValue(exec, globalObject, *iter));

	if (auto* result = JSC::constructArray(exec, nullptr, globalObject, list))
		return result;
	return JSC::jsNull();
}

template <typename T, size_t inlineCapacity>
JSC::JSValue jsArrayOrNull(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T, inlineCapacity>* vector)
{
    if (!vector) {
        if (auto* result = JSC::constructEmptyArray(exec, nullptr, globalObject, 0))
        	return result;
        return JSC::jsNull();
    }
    return jsArrayOrNull(exec, globalObject, *vector);
}

JSC::JSValue jsArrayOrNull(JSC::ExecState*, JSDOMGlobalObject*, PassRefPtr<DOMStringList>);

template <typename T, size_t inlineCapacity>
ALWAYS_INLINE JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T, inlineCapacity>& iterator)
{
	return jsArrayOrNull(exec, globalObject, iterator);
}

template <typename T, size_t inlineCapacity>
ALWAYS_INLINE JSC::JSValue toJS(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const Vector<T, inlineCapacity>* iterator)
{
	return jsArrayOrNull(exec, globalObject, iterator);
}

template<typename FirstType, typename SecondType> JSC::JSValue jsPairOrNull(JSC::ExecState&, JSDOMGlobalObject*, const FirstType&, const SecondType&);

inline JSC::JSValue jsPairOrNull(JSC::ExecState& state, JSDOMGlobalObject* globalObject, JSC::JSValue value1, JSC::JSValue value2)
{
    JSC::MarkedArgumentBuffer args;
    args.append(value1);
    args.append(value2);
    if (auto* jsArray = constructArray(&state, nullptr, globalObject, args))
    	return jsArray;
    return JSC::jsNull();
}

inline JSC::JSValue jsPairOrNull(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, JSC::JSValue value1, JSC::JSValue value2)
{
	return jsPairOrNull(*exec, globalObject, value1, value2);
}

template<typename FirstType, typename SecondType> inline JSC::JSValue jsPairOrNull(JSC::ExecState& state, JSDOMGlobalObject* globalObject, const FirstType& value1, const SecondType& value2)
{
	return jsPairOrNull(state, globalObject, toJS(&state, globalObject, value1), toJS(&state, globalObject, value2));
}

template<typename FirstType, typename SecondType> inline JSC::JSValue jsPairOrNull(JSC::ExecState* exec, JSDOMGlobalObject* globalObject, const FirstType& value1, const SecondType& value2)
{
	return jsPairOrNull(*exec, globalObject, value1, value2);
}

ALWAYS_INLINE PassRefPtr<JSC::ArrayBufferView> toArrayBufferView(JSC::JSValue value)
{
    JSC::JSArrayBufferView* wrapper = JSC::jsDynamicCast<JSC::JSArrayBufferView*>(value);
    if (!wrapper)
        return nullptr;
    return wrapper->impl();
}

ALWAYS_INLINE PassRefPtr<JSC::Int8Array> toInt8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int8Adaptor>(value); }
ALWAYS_INLINE PassRefPtr<JSC::Int16Array> toInt16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int16Adaptor>(value); }
ALWAYS_INLINE PassRefPtr<JSC::Int32Array> toInt32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Int32Adaptor>(value); }
ALWAYS_INLINE PassRefPtr<JSC::Uint8Array> toUint8Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8Adaptor>(value); }
ALWAYS_INLINE PassRefPtr<JSC::Uint8ClampedArray> toUint8ClampedArray(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint8ClampedAdaptor>(value); }
ALWAYS_INLINE PassRefPtr<JSC::Uint16Array> toUint16Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint16Adaptor>(value); }
ALWAYS_INLINE PassRefPtr<JSC::Uint32Array> toUint32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Uint32Adaptor>(value); }
ALWAYS_INLINE PassRefPtr<JSC::Float32Array> toFloat32Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float32Adaptor>(value); }
ALWAYS_INLINE PassRefPtr<JSC::Float64Array> toFloat64Array(JSC::JSValue value) { return JSC::toNativeTypedView<JSC::Float64Adaptor>(value); }

inline BufferSource toBufferSource(JSC::ExecState* exec, JSC::JSValue value)
{
    if (JSC::ArrayBuffer* buffer = JSC::toArrayBuffer(value))
        return BufferSource(buffer);
    if (RefPtr<JSC::ArrayBufferView> bufferView = toArrayBufferView(value))
        return BufferSource(ArrayBuffer::tryCreate(static_cast<uint8_t*>(bufferView->baseAddress()), bufferView->byteLength()));

    JSC::VM& vm = exec->vm();
    throwTypeError(exec, vm, ASCIILiteral("Only ArrayBuffer and ArrayBufferView objects can be passed as BufferSource arguments"));
    return BufferSource();
}

inline PassRefPtr<JSC::DataView> toDataView(JSC::JSValue value)
{
    JSC::JSDataView* wrapper = JSC::jsDynamicCast<JSC::JSDataView*>(value);
    if (!wrapper)
        return nullptr;
    return wrapper->typedImpl();
}

template<typename T> struct NativeValueTraits;

template<>
struct NativeValueTraits<String> {
	static ALWAYS_INLINE void nativeValue(JSC::VM&, JSC::ExecState* exec, JSC::JSValue jsValue, String& indexedValue)
	{
		indexedValue = jsValue.toWTFString(exec);
	}
};

template<>
struct NativeValueTraits<CString> {
	static ALWAYS_INLINE void nativeValue(JSC::VM&, JSC::ExecState* exec, JSC::JSValue jsValue, CString& indexedValue)
	{
		indexedValue = jsValue.toWTFString(exec).utf8();
	}
};

template<>
struct NativeValueTraits<unsigned short> {
	static inline void nativeValue(JSC::VM& vm, JSC::ExecState* exec, JSC::JSValue jsValue, unsigned short& indexedValue)
	{
		indexedValue = jsValue.toUInt32(exec);
	}
};

template<> struct NativeValueTraits<unsigned> {
    static inline void nativeValue(JSC::VM& vm, JSC::ExecState* exec, JSC::JSValue jsValue, unsigned& indexedValue)
    {
        indexedValue = jsValue.toUInt32(exec);
    }
};

template<>
struct NativeValueTraits<unsigned long> {
	static inline void nativeValue(JSC::VM& vm, JSC::ExecState* exec, JSC::JSValue jsValue, unsigned long& indexedValue)
	{
		indexedValue = jsValue.toUInt32(exec);
	}
};

template<>
struct NativeValueTraits<float> {
    static inline void nativeValue(JSC::VM& vm, JSC::ExecState* exec, JSC::JSValue jsValue, float& indexedValue)
    {
        indexedValue = jsValue.toFloat(exec);
    }
};

template<>
struct NativeValueTraits<double> {
    static inline void nativeValue(JSC::VM& vm, JSC::ExecState* exec, JSC::JSValue jsValue, double& indexedValue)
    {
        indexedValue = jsValue.toNumber(exec);
    }
};

template<>
struct NativeValueTraits<Vector<String>> {
	static ALWAYS_INLINE void nativeValue(JSC::VM& vm, JSC::ExecState* exec, JSC::JSValue jsValue, Vector<String>& indexedValue)
	{
		indexedValue = toNativeArray<String>(*exec, jsValue);
	}
};

#if ENABLE(ENCRYPTED_MEDIA)

template<> MediaKeySystemConfiguration convertDictionary<MediaKeySystemConfiguration>(JSC::ExecState&, JSC::JSValue);
template<> MediaKeySystemMediaCapability convertDictionary<MediaKeySystemMediaCapability>(JSC::ExecState&, JSC::JSValue);

template<>
struct NativeValueTraits<MediaKeySystemConfiguration> {
    static inline void nativeValue(JSC::VM&, JSC::ExecState* exec, JSC::JSValue jsValue, MediaKeySystemConfiguration& indexedValue)
    {
    	indexedValue = convertDictionary<MediaKeySystemConfiguration>(*exec, jsValue);
    }
};

template<>
struct NativeValueTraits<MediaKeySystemMediaCapability> {
    static inline void nativeValue(JSC::VM&, JSC::ExecState* exec, JSC::JSValue jsValue, MediaKeySystemMediaCapability& indexedValue)
    {
    	indexedValue = convertDictionary<MediaKeySystemMediaCapability>(*exec, jsValue);
    }
};

#endif

#if ENABLE(WEB_RTC)
template<> RTCIceServer convertDictionary<RTCIceServer>(JSC::ExecState&, JSC::JSValue);
template<>
struct NativeValueTraits<RTCIceServer> {
    static inline void nativeValue(JSC::VM&, JSC::ExecState* exec, JSC::JSValue jsValue, RTCIceServer& indexedValue)
    {
    	indexedValue = convertDictionary<RTCIceServer>(*exec, jsValue);
    }
};

template<> RTCRtpEncodingParameters convertDictionary<RTCRtpEncodingParameters>(JSC::ExecState&, JSC::JSValue);
template<>
struct NativeValueTraits<RTCRtpEncodingParameters> {
    static inline void nativeValue(JSC::VM&, JSC::ExecState* exec, JSC::JSValue jsValue, RTCRtpEncodingParameters& indexedValue)
    {
    	indexedValue = convertDictionary<RTCRtpEncodingParameters>(*exec, jsValue);
    }
};

template<> RTCRtpHeaderExtensionParameters convertDictionary<RTCRtpHeaderExtensionParameters>(JSC::ExecState&, JSC::JSValue);
template<>
struct NativeValueTraits<RTCRtpHeaderExtensionParameters> {
    static inline void nativeValue(JSC::VM&, JSC::ExecState* exec, JSC::JSValue jsValue, RTCRtpHeaderExtensionParameters& indexedValue)
    {
    	indexedValue = convertDictionary<RTCRtpHeaderExtensionParameters>(*exec, jsValue);
    }
};

template<> RTCRtpCodecParameters convertDictionary<RTCRtpCodecParameters>(JSC::ExecState&, JSC::JSValue);
template<>
struct NativeValueTraits<RTCRtpCodecParameters> {
    static inline void nativeValue(JSC::VM&, JSC::ExecState* exec, JSC::JSValue jsValue, RTCRtpCodecParameters& indexedValue)
    {
    	indexedValue = convertDictionary<RTCRtpCodecParameters>(*exec, jsValue);
    }
};
#endif

template <typename T, typename JST, typename VectorType = Vector<RefPtr<T>>>
	VectorType toRefPtrNativeArray(JSC::ExecState& exec, JSC::JSValue value)
{
    if (!value.isObject()) {
        throwSequenceTypeError(exec);
        return Vector<RefPtr<T>>();
    }

    auto& vm = exec.vm();

    VectorType result;
    struct Functor
    {
    	Functor(Vector<RefPtr<T>>& result)
    		: result(result)
    	{
    	}
    	void operator()(JSC::VM&, JSC::ExecState* state, JSC::JSValue jsValue) {
			if (jsValue.inherits(JST::info()))
				result.append(JST::toWrapped(jsValue));
			else
				throwArrayElementTypeError(*state);
		}
    	VectorType& result;
    };
    Functor functor(result);
    forEachInIterable(vm, exec, value, functor);
    return result;
}

template<typename T> Vector<T> toNativeArray(JSC::ExecState& exec, JSC::JSObject* object)
{
    auto& vm = exec.vm();

    Vector<T> result;
    struct Functor
    {
    	Functor(Vector<T>& result)
    		: result(result)
    	{
    	}
    	void operator()(JSC::VM& vm, JSC::ExecState* state, JSC::JSValue jsValue) {
            T convertedValue;
            NativeValueTraits<T>::nativeValue(vm, state, jsValue, convertedValue);
            RETURN_IF_EXCEPTION(vm, void());
            result.append(convertedValue);
        }
        Vector<T>& result;
    };
    Functor functor(result);
    forEachInIterable(vm, exec, object, functor);
    return result;
}

template<typename T> Vector<T> toNativeArray(JSC::ExecState& exec, JSC::JSValue value)
{
    if (!value.isObject()) {
        throwSequenceTypeError(exec);
        return Vector<T>();
    }

    return toNativeArray<T>(exec, JSC::asObject(value));
}

template <typename T>
Vector<T> toNativeArguments(JSC::VM& vm, JSC::ExecState* exec, size_t startIndex)
{
    size_t length = exec->argumentCount();
    ASSERT(startIndex <= length);

    Vector<T> result;
    result.reserveInitialCapacity(length - startIndex);

    for (size_t i = startIndex; i < length; ++i) {
        T indexValue;
        NativeValueTraits<T>::nativeValue(vm, exec, exec->argument(i), indexValue);
        RETURN_IF_EXCEPTION(vm, Vector<T>());
        result.append(indexValue);
    }
    return result;
}

bool hasIteratorMethod(JSC::ExecState&, JSC::JSObject*);
bool hasIteratorMethod(JSC::ExecState&, JSC::JSValue);

enum SecurityReportingOption {
    DoNotReportSecurityError,
    ReportSecurityError,
	ThrowSecurityError
};

class BindingSecurity {
public:
    static bool shouldAllowAccessToNode(BindingState*, Node*);
    static bool shouldAllowAccessToNode(BindingState*, Node&);
    static bool shouldAllowAccessToDOMWindow(BindingState*, DOMWindow&, SecurityReportingOption = ReportSecurityError);
    static bool shouldAllowAccessToDOMWindow(BindingState*, DOMWindow*, SecurityReportingOption = ReportSecurityError);
    static bool shouldAllowAccessToFrame(BindingState*, Frame*, SecurityReportingOption = ReportSecurityError);
    static bool allowSettingFrameSrcToJavascriptUrl(BindingState*, HTMLFrameElementBase*, const String& value);
};

bool shouldAllowAccessToNode(JSC::ExecState*, Node*);
bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*, SecurityReportingOption = ReportSecurityError);
bool shouldAllowAccessToFrame(JSC::ExecState*, Frame*, String& message);
bool shouldAllowAccessToDOMWindow(JSC::ExecState* exec, DOMWindow& target, String& message);
bool shouldAllowAccessToDOMWindow(JSC::ExecState* exec, DOMWindow* target, String& message);

void printErrorMessageForFrame(Frame*, const String& message);

ALWAYS_INLINE String propertyNameToString(JSC::PropertyName propertyName)
{
    ASSERT(!propertyName.isSymbol());
    return propertyName.uid() ? propertyName.uid() : propertyName.publicName();
}

ALWAYS_INLINE AtomicString propertyNameToAtomicString(JSC::PropertyName propertyName)
{
    return AtomicString(propertyName.uid() ? propertyName.uid() : propertyName.publicName());
}

template<JSC::NativeFunction nativeFunction, int length>
JSC::EncodedJSValue nonCachingStaticFunctionGetter(JSC::ExecState* exec, JSC::EncodedJSValue, JSC::PropertyName propertyName)
{
    return JSC::JSValue::encode(JSC::JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), length, propertyName.publicName(), nativeFunction));
}

template<typename T> inline JSC::JSValue toNullableJSNumber(Optional<T> optionalNumber)
{
    return optionalNumber ? JSC::jsNumber(optionalNumber.value()) : JSC::jsNull();
}

JSElement* jsElementCast(JSC::JSValue value);
JSNode* jsNodeCast(JSC::JSValue value);
JSDocument* jsDocumentCast(JSC::JSValue value);

#if 0
template<typename DOMClass> inline void setSubclassStructureIfNeeded(JSC::JSGlobalObject* lexicalGlobalObject, JSC::CallFrame* callFrame, JSC::JSObject* jsObject)
{
    JSC::JSObject* newTarget = callFrame->newTarget().getObject();
    JSC::JSObject* constructor = callFrame->jsCallee();
    if (!newTarget || newTarget == constructor)
        return;

    using WrapperClass = typename JSDOMWrapperConverterTraits<DOMClass>::WrapperClass;

    JSC::VM& vm = lexicalGlobalObject->vm();
    auto scope = DECLARE_THROW_SCOPE(vm);

    auto* functionGlobalObject = JSC::getFunctionRealm(lexicalGlobalObject, newTarget);
	RETURN_IF_EXCEPTION(scope, void());
	auto* newTargetGlobalObject = JSC::jsCast<JSDOMGlobalObject*>(functionGlobalObject);
	auto* baseStructure = getDOMStructure<WrapperClass>(vm, *newTargetGlobalObject);
    auto* subclassStructure = JSC::InternalFunction::createSubclassStructure(callFrame, lexicalGlobalObject, newTarget, baseStructure);
    RETURN_IF_EXCEPTION(scope, void());
    jsObject->setStructure(vm, subclassStructure);
}
#endif

} // namespace WebCore

#include "JSCompositeOperation.h"
#include "JSMediaKeySessionType.h"
#include "JSMediaKeysRequirement.h"
#include "JSMediaKeySystemConfiguration.h"
#include "JSMediaKeySystemMediaCapability.h"
#include "JSFillMode.h"
#include "JSPlaybackDirection.h"
#include "JSRTCIceServer.h"
#include "JSPredefinedColorSpace.h"

