#ifndef V8Binding_h
#define V8Binding_h
#include "bindings/v8/DOMWrapperWorld.h"
#include "bindings/v8/ExceptionMessages.h"
#include "bindings/v8/V8BindingMacros.h"
#include "bindings/v8/V8PerIsolateData.h"
#include "bindings/v8/V8StringResource.h"
#include "bindings/v8/V8ThrowException.h"
#include "bindings/v8/V8ValueCache.h"
#include "platform/heap/Heap.h"
#include "wtf/MathExtras.h"
#include "wtf/text/AtomicString.h"
#include <v8.h>
namespace WebCore {
class DOMWindow;
class Document;
class EventListener;
class ExecutionContext;
class ExceptionState;
class LocalFrame;
class NodeFilter;
class ScriptWrappable;
class XPathNSResolver;
const int kMaxRecursionDepth = 22;
v8::Handle<v8::Value> throwError(V8ErrorType, const String&, v8::Isolate*);
v8::Handle<v8::Value> throwError(v8::Handle<v8::Value>, v8::Isolate*);
v8::Handle<v8::Value> throwTypeError(const String&, v8::Isolate*);
void throwArityTypeErrorForMethod(const char* method, const char* type, unsigned expected, unsigned providedLeastNumMandatoryParams, v8::Isolate*);
void throwArityTypeErrorForConstructor(const char* type, unsigned expected, unsigned providedLeastNumMandatoryParams, v8::Isolate*);
void throwArityTypeError(ExceptionState&, unsigned expected, unsigned providedLeastNumMandatoryParams);
v8::ArrayBuffer::Allocator* v8ArrayBufferAllocator();
inline v8::Handle<v8::Value> argumentOrNull(const v8::FunctionCallbackInfo<v8::Value>& info, int index)
{
return index >= info.Length() ? v8::Local<v8::Value>() : info[index];
}
template<typename CallbackInfo, typename V>
inline void v8SetReturnValue(const CallbackInfo& info, V v)
{
info.GetReturnValue().Set(v);
}
template<typename CallbackInfo>
inline void v8SetReturnValueBool(const CallbackInfo& info, bool v)
{
info.GetReturnValue().Set(v);
}
template<typename CallbackInfo>
inline void v8SetReturnValueInt(const CallbackInfo& info, int v)
{
info.GetReturnValue().Set(v);
}
template<typename CallbackInfo>
inline void v8SetReturnValueUnsigned(const CallbackInfo& info, unsigned v)
{
info.GetReturnValue().Set(v);
}
template<typename CallbackInfo>
inline void v8SetReturnValueNull(const CallbackInfo& info)
{
info.GetReturnValue().SetNull();
}
template<typename CallbackInfo>
inline void v8SetReturnValueUndefined(const CallbackInfo& info)
{
info.GetReturnValue().SetUndefined();
}
template<typename CallbackInfo>
inline void v8SetReturnValueEmptyString(const CallbackInfo& info)
{
info.GetReturnValue().SetEmptyString();
}
template <class CallbackInfo>
inline void v8SetReturnValueString(const CallbackInfo& info, const String& string, v8::Isolate* isolate)
{
if (string.isNull()) {
v8SetReturnValueEmptyString(info);
return;
}
V8PerIsolateData::from(isolate)->stringCache()->setReturnValueFromString(info.GetReturnValue(), string.impl());
}
template <class CallbackInfo>
inline void v8SetReturnValueStringOrNull(const CallbackInfo& info, const String& string, v8::Isolate* isolate)
{
if (string.isNull()) {
v8SetReturnValueNull(info);
return;
}
V8PerIsolateData::from(isolate)->stringCache()->setReturnValueFromString(info.GetReturnValue(), string.impl());
}
template <class CallbackInfo>
inline void v8SetReturnValueStringOrUndefined(const CallbackInfo& info, const String& string, v8::Isolate* isolate)
{
if (string.isNull()) {
v8SetReturnValueUndefined(info);
return;
}
V8PerIsolateData::from(isolate)->stringCache()->setReturnValueFromString(info.GetReturnValue(), string.impl());
}
inline String toCoreString(v8::Handle<v8::String> value)
{
return v8StringToWebCoreString<String>(value, Externalize);
}
inline String toCoreStringWithNullCheck(v8::Handle<v8::String> value)
{
if (value.IsEmpty() || value->IsNull())
return String();
return toCoreString(value);
}
inline String toCoreStringWithUndefinedOrNullCheck(v8::Handle<v8::String> value)
{
if (value.IsEmpty() || value->IsNull() || value->IsUndefined())
return String();
return toCoreString(value);
}
inline AtomicString toCoreAtomicString(v8::Handle<v8::String> value)
{
return v8StringToWebCoreString<AtomicString>(value, Externalize);
}
inline String toCoreStringWithUndefinedOrNullCheck(v8::Handle<v8::Value> value)
{
if (value.IsEmpty() || !value->IsString())
return String();
return toCoreString(value.As<v8::String>());
}
inline v8::Handle<v8::String> v8String(v8::Isolate* isolate, const String& string)
{
if (string.isNull())
return v8::String::Empty(isolate);
return V8PerIsolateData::from(isolate)->stringCache()->v8ExternalString(string.impl(), isolate);
}
inline v8::Handle<v8::String> v8AtomicString(v8::Isolate* isolate, const char* str)
{
ASSERT(isolate);
return v8::String::NewFromUtf8(isolate, str, v8::String::kInternalizedString, strlen(str));
}
inline v8::Handle<v8::String> v8AtomicString(v8::Isolate* isolate, const char* str, size_t length)
{
ASSERT(isolate);
return v8::String::NewFromUtf8(isolate, str, v8::String::kInternalizedString, length);
}
inline v8::Handle<v8::Value> v8Undefined()
{
return v8::Handle<v8::Value>();
}
template <class T>
struct V8ValueTraits {
static inline v8::Handle<v8::Value> arrayV8Value(const T& value, v8::Isolate* isolate)
{
return toV8(WTF::getPtr(value), v8::Handle<v8::Object>(), isolate);
}
};
template<>
struct V8ValueTraits<String> {
static inline v8::Handle<v8::Value> arrayV8Value(const String& value, v8::Isolate* isolate)
{
return v8String(isolate, value);
}
};
template<>
struct V8ValueTraits<AtomicString> {
static inline v8::Handle<v8::Value> arrayV8Value(const AtomicString& value, v8::Isolate* isolate)
{
return v8String(isolate, value);
}
};
template<>
struct V8ValueTraits<unsigned> {
static inline v8::Handle<v8::Value> arrayV8Value(const unsigned& value, v8::Isolate* isolate)
{
return v8::Integer::NewFromUnsigned(isolate, value);
}
};
template<>
struct V8ValueTraits<unsigned long> {
static inline v8::Handle<v8::Value> arrayV8Value(const unsigned long& value, v8::Isolate* isolate)
{
return v8::Integer::NewFromUnsigned(isolate, value);
}
};
template<>
struct V8ValueTraits<float> {
static inline v8::Handle<v8::Value> arrayV8Value(const float& value, v8::Isolate* isolate)
{
return v8::Number::New(isolate, value);
}
};
template<>
struct V8ValueTraits<double> {
static inline v8::Handle<v8::Value> arrayV8Value(const double& value, v8::Isolate* isolate)
{
return v8::Number::New(isolate, value);
}
};
template<typename T, size_t inlineCapacity>
v8::Handle<v8::Value> v8Array(const Vector<T, inlineCapacity>& iterator, v8::Isolate* isolate)
{
v8::Local<v8::Array> result = v8::Array::New(isolate, iterator.size());
int index = 0;
typename Vector<T, inlineCapacity>::const_iterator end = iterator.end();
typedef V8ValueTraits<T> TraitsType;
for (typename Vector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter)
result->Set(v8::Integer::New(isolate, index++), TraitsType::arrayV8Value(*iter, isolate));
return result;
}
template<typename T, size_t inlineCapacity>
v8::Handle<v8::Value> v8Array(const HeapVector<T, inlineCapacity>& iterator, v8::Isolate* isolate)
{
v8::Local<v8::Array> result = v8::Array::New(isolate, iterator.size());
int index = 0;
typename HeapVector<T, inlineCapacity>::const_iterator end = iterator.end();
typedef V8ValueTraits<T> TraitsType;
for (typename HeapVector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter)
result->Set(v8::Integer::New(isolate, index++), TraitsType::arrayV8Value(*iter, isolate));
return result;
}
template<typename T, size_t inlineCapacity>
v8::Handle<v8::Value> v8ArrayNoInline(const Vector<T, inlineCapacity>& iterator, v8::Isolate* isolate)
{
v8::Local<v8::Array> result = v8::Array::New(isolate, iterator.size());
int index = 0;
typename Vector<T, inlineCapacity>::const_iterator end = iterator.end();
for (typename Vector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter)
result->Set(v8::Integer::New(isolate, index++), toV8NoInline(WTF::getPtr(*iter), v8::Handle<v8::Object>(), isolate));
return result;
}
enum IntegerConversionConfiguration {
NormalConversion,
EnforceRange,
Clamp
};
int8_t toInt8(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline int8_t toInt8(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toInt8(value, NormalConversion, exceptionState);
}
int8_t toInt8(v8::Handle<v8::Value>);
uint8_t toUInt8(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline uint8_t toUInt8(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toUInt8(value, NormalConversion, exceptionState);
}
uint8_t toUInt8(v8::Handle<v8::Value>);
int16_t toInt16(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline int16_t toInt16(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toInt16(value, NormalConversion, exceptionState);
}
int16_t toInt16(v8::Handle<v8::Value>);
uint16_t toUInt16(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline uint16_t toUInt16(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toUInt16(value, NormalConversion, exceptionState);
}
uint16_t toUInt16(v8::Handle<v8::Value>);
int32_t toInt32(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline int32_t toInt32(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toInt32(value, NormalConversion, exceptionState);
}
int32_t toInt32(v8::Handle<v8::Value>);
uint32_t toUInt32(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline uint32_t toUInt32(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toUInt32(value, NormalConversion, exceptionState);
}
uint32_t toUInt32(v8::Handle<v8::Value>);
int64_t toInt64(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline int64_t toInt64(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toInt64(value, NormalConversion, exceptionState);
}
int64_t toInt64(v8::Handle<v8::Value>);
uint64_t toUInt64(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
inline uint64_t toUInt64(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
return toUInt64(value, NormalConversion, exceptionState);
}
uint64_t toUInt64(v8::Handle<v8::Value>);
float toFloat(v8::Handle<v8::Value>, ExceptionState&);
inline float toFloat(v8::Local<v8::Value> value)
{
return static_cast<float>(value->NumberValue());
}
inline v8::Handle<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate)
{
return value ? v8::True(isolate) : v8::False(isolate);
}
inline double toCoreDate(v8::Handle<v8::Value> object)
{
if (object->IsDate())
return v8::Handle<v8::Date>::Cast(object)->ValueOf();
if (object->IsNumber())
return object->NumberValue();
return std::numeric_limits<double>::quiet_NaN();
}
inline v8::Handle<v8::Value> v8DateOrNaN(double value, v8::Isolate* isolate)
{
ASSERT(isolate);
return v8::Date::New(isolate, std::isfinite(value) ? value : std::numeric_limits<double>::quiet_NaN());
}
PassRefPtr<NodeFilter> toNodeFilter(v8::Handle<v8::Value>, v8::Isolate*);
PassRefPtrWillBeRawPtr<XPathNSResolver> toXPathNSResolver(v8::Handle<v8::Value>, v8::Isolate*);
template<class T> struct NativeValueTraits;
template<>
struct NativeValueTraits<String> {
static inline String nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate)
{
V8TRYCATCH_FOR_V8STRINGRESOURCE_RETURN(V8StringResource<>, stringValue, value, String());
return stringValue;
}
};
template<>
struct NativeValueTraits<unsigned> {
static inline unsigned nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate)
{
return toUInt32(value);
}
};
template<>
struct NativeValueTraits<float> {
static inline float nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate)
{
return static_cast<float>(value->NumberValue());
}
};
template<>
struct NativeValueTraits<double> {
static inline double nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate)
{
return static_cast<double>(value->NumberValue());
}
};
template<>
struct NativeValueTraits<v8::Handle<v8::Value> > {
static inline v8::Handle<v8::Value> nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate)
{
return value;
}
};
v8::Handle<v8::Value> toV8Sequence(v8::Handle<v8::Value>, uint32_t& length, v8::Isolate*);
template <class T, class V8T>
Vector<RefPtr<T> > toRefPtrNativeArrayUnchecked(v8::Local<v8::Value> v8Value, uint32_t length, v8::Isolate* isolate, bool* success = 0)
{
Vector<RefPtr<T> > result;
result.reserveInitialCapacity(length);
v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value);
for (uint32_t i = 0; i < length; ++i) {
v8::Handle<v8::Value> element = object->Get(i);
if (V8T::hasInstance(element, isolate)) {
v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element);
result.uncheckedAppend(V8T::toNative(elementObject));
} else {
if (success)
*success = false;
throwTypeError("Invalid Array element type", isolate);
return Vector<RefPtr<T> >();
}
}
return result;
}
template <class T, class V8T>
Vector<RefPtr<T> > toRefPtrNativeArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, bool* success = 0)
{
if (success)
*success = true;
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value));
uint32_t length = 0;
if (value->IsArray()) {
length = v8::Local<v8::Array>::Cast(v8Value)->Length();
} else if (toV8Sequence(value, length, isolate).IsEmpty()) {
throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex), isolate);
return Vector<RefPtr<T> >();
}
return toRefPtrNativeArrayUnchecked<T, V8T>(v8Value, length, isolate, success);
}
template <class T, class V8T>
Vector<RefPtr<T> > toRefPtrNativeArray(v8::Handle<v8::Value> value, const String& propertyName, v8::Isolate* isolate, bool* success = 0)
{
if (success)
*success = true;
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value));
uint32_t length = 0;
if (value->IsArray()) {
length = v8::Local<v8::Array>::Cast(v8Value)->Length();
} else if (toV8Sequence(value, length, isolate).IsEmpty()) {
throwTypeError(ExceptionMessages::notASequenceTypeProperty(propertyName), isolate);
return Vector<RefPtr<T> >();
}
return toRefPtrNativeArrayUnchecked<T, V8T>(v8Value, length, isolate, success);
}
template <class T, class V8T>
HeapVector<Member<T> > toMemberNativeArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, bool* success = 0)
{
if (success)
*success = true;
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value));
uint32_t length = 0;
if (value->IsArray()) {
length = v8::Local<v8::Array>::Cast(v8Value)->Length();
} else if (toV8Sequence(value, length, isolate).IsEmpty()) {
throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex), isolate);
return HeapVector<Member<T> >();
}
HeapVector<Member<T> > result;
result.reserveInitialCapacity(length);
v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value);
for (uint32_t i = 0; i < length; ++i) {
v8::Handle<v8::Value> element = object->Get(i);
if (V8T::hasInstance(element, isolate)) {
v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element);
result.uncheckedAppend(V8T::toNative(elementObject));
} else {
if (success)
*success = false;
throwTypeError("Invalid Array element type", isolate);
return HeapVector<Member<T> >();
}
}
return result;
}
template <class T>
Vector<T> toNativeArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate)
{
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value));
uint32_t length = 0;
if (value->IsArray()) {
length = v8::Local<v8::Array>::Cast(v8Value)->Length();
} else if (toV8Sequence(value, length, isolate).IsEmpty()) {
throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex), isolate);
return Vector<T>();
}
Vector<T> result;
result.reserveInitialCapacity(length);
typedef NativeValueTraits<T> TraitsType;
v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value);
for (uint32_t i = 0; i < length; ++i)
result.uncheckedAppend(TraitsType::nativeValue(object->Get(i), isolate));
return result;
}
template <class T>
Vector<T> toNativeArguments(const v8::FunctionCallbackInfo<v8::Value>& info, int startIndex)
{
ASSERT(startIndex <= info.Length());
Vector<T> result;
typedef NativeValueTraits<T> TraitsType;
int length = info.Length();
result.reserveInitialCapacity(length);
for (int i = startIndex; i < length; ++i)
result.uncheckedAppend(TraitsType::nativeValue(info[i], info.GetIsolate()));
return result;
}
inline v8::Handle<v8::Value> toV8Sequence(v8::Handle<v8::Value> value, uint32_t& length, v8::Isolate* isolate)
{
ASSERT(!value->IsArray());
if (!value->IsObject() || value->IsDate() || value->IsRegExp()) {
return v8Undefined();
}
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value));
v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value);
v8::Local<v8::String> lengthSymbol = v8AtomicString(isolate, "length");
V8TRYCATCH(v8::Local<v8::Value>, lengthValue, object->Get(lengthSymbol));
if (lengthValue->IsUndefined() || lengthValue->IsNull()) {
return v8Undefined();
}
V8TRYCATCH(uint32_t, sequenceLength, lengthValue->Int32Value());
length = sequenceLength;
return v8Value;
}
v8::Isolate* toIsolate(ExecutionContext*);
v8::Isolate* toIsolate(LocalFrame*);
DOMWindow* toDOMWindow(v8::Handle<v8::Value>, v8::Isolate*);
DOMWindow* toDOMWindow(v8::Handle<v8::Context>);
DOMWindow* enteredDOMWindow(v8::Isolate*);
DOMWindow* currentDOMWindow(v8::Isolate*);
DOMWindow* callingDOMWindow(v8::Isolate*);
ExecutionContext* toExecutionContext(v8::Handle<v8::Context>);
ExecutionContext* currentExecutionContext(v8::Isolate*);
ExecutionContext* callingExecutionContext(v8::Isolate*);
v8::Local<v8::Context> toV8Context(ExecutionContext*, DOMWrapperWorld&);
v8::Local<v8::Context> toV8Context(v8::Isolate*, LocalFrame*, DOMWrapperWorld&);
LocalFrame* toFrameIfNotDetached(v8::Handle<v8::Context>);
bool handleOutOfMemory();
v8::Local<v8::Value> handleMaxRecursionDepthExceeded(v8::Isolate*);
void crashIfV8IsDead();
inline bool isUndefinedOrNull(v8::Handle<v8::Value> value)
{
return value->IsNull() || value->IsUndefined();
}
v8::Handle<v8::Function> getBoundFunction(v8::Handle<v8::Function>);
inline v8::Local<v8::Function> createClosure(v8::FunctionCallback function, v8::Handle<v8::Value> environment, v8::Isolate* isolate)
{
return v8::Function::New(isolate, function, environment);
}
template<class Collection> static void indexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info)
{
Collection* collection = reinterpret_cast<Collection*>(info.Holder()->GetAlignedPointerFromInternalField(v8DOMWrapperObjectIndex));
int length = collection->length();
v8::Handle<v8::Array> properties = v8::Array::New(info.GetIsolate(), length);
for (int i = 0; i < length; ++i) {
v8::Handle<v8::Integer> integer = v8::Integer::New(info.GetIsolate(), i);
properties->Set(integer, integer);
}
v8SetReturnValue(info, properties);
}
void addHiddenValueToArray(v8::Handle<v8::Object>, v8::Local<v8::Value>, int cacheIndex, v8::Isolate*);
void removeHiddenValueFromArray(v8::Handle<v8::Object>, v8::Local<v8::Value>, int cacheIndex, v8::Isolate*);
void moveEventListenerToNewWrapper(v8::Handle<v8::Object>, EventListener* oldValue, v8::Local<v8::Value> newValue, int cacheIndex, v8::Isolate*);
template<typename T>
v8::Handle<v8::Value> toV8NoInline(T* impl, v8::Handle<v8::Object> creationContext, v8::Isolate*);
template<typename T>
v8::Handle<v8::Value> toV8NoInline(T* impl, ExecutionContext* context)
{
v8::Isolate* isolate = toIsolate(context);
v8::Handle<v8::Context> v8Context = toV8Context(context, DOMWrapperWorld::current(isolate));
return toV8NoInline(impl, v8Context->Global(), isolate);
}
enum DeleteResult {
DeleteSuccess,
DeleteReject,
DeleteUnknownProperty
};
class V8IsolateInterruptor : public ThreadState::Interruptor {
public:
explicit V8IsolateInterruptor(v8::Isolate* isolate) : m_isolate(isolate) { }
static void onInterruptCallback(v8::Isolate* isolate, void* data)
{
reinterpret_cast<V8IsolateInterruptor*>(data)->onInterrupted();
}
virtual void requestInterrupt() OVERRIDE
{
m_isolate->RequestInterrupt(&onInterruptCallback, this);
}
virtual void clearInterrupt() OVERRIDE
{
m_isolate->ClearInterrupt();
}
private:
v8::Isolate* m_isolate;
};
class V8ExecutionScope {
public:
static PassOwnPtr<V8ExecutionScope> create(v8::Isolate*);
explicit V8ExecutionScope(v8::Isolate*);
private:
v8::HandleScope m_handleScope;
v8::Context::Scope m_contextScope;
RefPtr<NewScriptState> m_scriptState;
};
}
#endif