#ifndef V8Binding_h
#define V8Binding_h
#include "BindingSecurity.h"
#include "DOMDataStore.h"
#include "PlatformString.h"
#include "V8DOMWrapper.h"
#include "V8GCController.h"
#include "V8HiddenPropertyName.h"
#include <wtf/MathExtras.h>
#include <wtf/Noncopyable.h>
#include <wtf/text/AtomicString.h>
#include <v8.h>
namespace WebCore {
class DOMStringList;
class DOMWrapperVisitor;
class EventListener;
class EventTarget;
class V8Binding {
};
typedef BindingSecurity<V8Binding> V8BindingSecurity;
class StringCache {
public:
StringCache() { }
v8::Local<v8::String> v8ExternalString(StringImpl* stringImpl)
{
if (m_lastStringImpl.get() == stringImpl) {
ASSERT(!m_lastV8String.IsNearDeath());
ASSERT(!m_lastV8String.IsEmpty());
return v8::Local<v8::String>::New(m_lastV8String);
}
return v8ExternalStringSlow(stringImpl);
}
void clearOnGC()
{
m_lastStringImpl = 0;
m_lastV8String.Clear();
}
void remove(StringImpl*);
private:
v8::Local<v8::String> v8ExternalStringSlow(StringImpl*);
HashMap<StringImpl*, v8::String*> m_stringCache;
v8::Persistent<v8::String> m_lastV8String;
RefPtr<StringImpl> m_lastStringImpl;
};
class ScriptGCEventListener;
class GCEventData {
public:
typedef Vector<ScriptGCEventListener*> GCEventListeners;
GCEventData() : startTime(0.0), usedHeapSize(0) { }
void clear()
{
startTime = 0.0;
usedHeapSize = 0;
}
GCEventListeners& listeners() { return m_listeners; }
double startTime;
size_t usedHeapSize;
private:
GCEventListeners m_listeners;
};
class ConstructorMode;
#ifndef NDEBUG
typedef HashMap<v8::Value*, GlobalHandleInfo*> GlobalHandleMap;
#endif
class V8BindingPerIsolateData {
public:
static V8BindingPerIsolateData* create(v8::Isolate*);
static void ensureInitialized(v8::Isolate*);
static V8BindingPerIsolateData* get(v8::Isolate* isolate)
{
ASSERT(isolate->GetData());
return static_cast<V8BindingPerIsolateData*>(isolate->GetData());
}
static V8BindingPerIsolateData* current(v8::Isolate* isolate = 0)
{
return isolate ? static_cast<V8BindingPerIsolateData*>(isolate->GetData()) : get(v8::Isolate::GetCurrent());
}
static void dispose(v8::Isolate*);
typedef HashMap<WrapperTypeInfo*, v8::Persistent<v8::FunctionTemplate> > TemplateMap;
TemplateMap& rawTemplateMap() { return m_rawTemplates; }
TemplateMap& templateMap() { return m_templates; }
v8::Persistent<v8::String>& toStringName() { return m_toStringName; }
v8::Persistent<v8::FunctionTemplate>& toStringTemplate() { return m_toStringTemplate; }
v8::Persistent<v8::FunctionTemplate>& lazyEventListenerToStringTemplate()
{
return m_lazyEventListenerToStringTemplate;
}
StringCache* stringCache() { return &m_stringCache; }
#if ENABLE(INSPECTOR)
void visitJSExternalStrings(DOMWrapperVisitor*);
#endif
DOMDataList& allStores() { return m_domDataList; }
V8HiddenPropertyName* hiddenPropertyName() { return &m_hiddenPropertyName; }
v8::Persistent<v8::Context>& auxiliaryContext() { return m_auxiliaryContext; }
void registerDOMDataStore(DOMDataStore* domDataStore)
{
m_domDataList.append(domDataStore);
}
void unregisterDOMDataStore(DOMDataStore* domDataStore)
{
ASSERT(m_domDataList.find(domDataStore));
m_domDataList.remove(m_domDataList.find(domDataStore));
}
DOMDataStore* domDataStore() { return m_domDataStore; }
void setDOMDataStore(DOMDataStore* store) { m_domDataStore = store; }
int recursionLevel() const { return m_recursionLevel; }
int incrementRecursionLevel() { return ++m_recursionLevel; }
int decrementRecursionLevel() { return --m_recursionLevel; }
#ifndef NDEBUG
GlobalHandleMap& globalHandleMap() { return m_globalHandleMap; }
int internalScriptRecursionLevel() const { return m_internalScriptRecursionLevel; }
int incrementInternalScriptRecursionLevel() { return ++m_internalScriptRecursionLevel; }
int decrementInternalScriptRecursionLevel() { return --m_internalScriptRecursionLevel; }
#endif
GCEventData& gcEventData() { return m_gcEventData; }
private:
explicit V8BindingPerIsolateData(v8::Isolate*);
~V8BindingPerIsolateData();
TemplateMap m_rawTemplates;
TemplateMap m_templates;
v8::Persistent<v8::String> m_toStringName;
v8::Persistent<v8::FunctionTemplate> m_toStringTemplate;
v8::Persistent<v8::FunctionTemplate> m_lazyEventListenerToStringTemplate;
StringCache m_stringCache;
DOMDataList m_domDataList;
DOMDataStore* m_domDataStore;
V8HiddenPropertyName m_hiddenPropertyName;
v8::Persistent<v8::Context> m_auxiliaryContext;
bool m_constructorMode;
friend class ConstructorMode;
int m_recursionLevel;
#ifndef NDEBUG
GlobalHandleMap m_globalHandleMap;
int m_internalScriptRecursionLevel;
#endif
GCEventData m_gcEventData;
};
class ConstructorMode {
public:
enum Mode {
WrapExistingObject,
CreateNewObject
};
ConstructorMode()
{
V8BindingPerIsolateData* data = V8BindingPerIsolateData::current();
m_previous = data->m_constructorMode;
data->m_constructorMode = WrapExistingObject;
}
~ConstructorMode()
{
V8BindingPerIsolateData* data = V8BindingPerIsolateData::current();
data->m_constructorMode = m_previous;
}
static bool current() { return V8BindingPerIsolateData::current()->m_constructorMode; }
private:
bool m_previous;
};
enum ExternalMode {
Externalize,
DoNotExternalize
};
template <typename StringType>
StringType v8StringToWebCoreString(v8::Handle<v8::String> v8String, ExternalMode external);
inline String v8StringToWebCoreString(v8::Handle<v8::String> v8String)
{
return v8StringToWebCoreString<String>(v8String, Externalize);
}
String v8NonStringValueToWebCoreString(v8::Handle<v8::Value>);
String v8ValueToWebCoreString(v8::Handle<v8::Value> value);
inline AtomicString v8StringToAtomicWebCoreString(v8::Handle<v8::String> v8String)
{
return v8StringToWebCoreString<AtomicString>(v8String, Externalize);
}
AtomicString v8NonStringValueToAtomicWebCoreString(v8::Handle<v8::Value>);
AtomicString v8ValueToAtomicWebCoreString(v8::Handle<v8::Value> value);
inline v8::Local<v8::String> v8ExternalString(const String& string, v8::Isolate* isolate = 0)
{
StringImpl* stringImpl = string.impl();
if (!stringImpl)
return v8::String::Empty();
V8BindingPerIsolateData* data = V8BindingPerIsolateData::current(isolate);
return data->stringCache()->v8ExternalString(stringImpl);
}
inline v8::Handle<v8::String> v8String(const String& string, v8::Isolate* isolate = 0)
{
return v8ExternalString(string, isolate);
}
template<typename T>
v8::Handle<v8::Value> v8Array(const Vector<T>& iterator, v8::Isolate* isolate)
{
v8::Local<v8::Array> result = v8::Array::New(iterator.size());
int index = 0;
typename Vector<T>::const_iterator end = iterator.end();
for (typename Vector<T>::const_iterator iter = iterator.begin(); iter != end; ++iter)
result->Set(v8::Integer::New(index++), toV8(WTF::getPtr(*iter), isolate));
return result;
}
template<>
inline v8::Handle<v8::Value> v8Array(const Vector<String>& iterator, v8::Isolate* isolate)
{
v8::Local<v8::Array> array = v8::Array::New(iterator.size());
Vector<String>::const_iterator end = iterator.end();
int index = 0;
for (Vector<String>::const_iterator iter = iterator.begin(); iter != end; ++iter)
array->Set(v8::Integer::New(index++), v8String(*iter, isolate));
return array;
}
template <class T>
Vector<T> toNativeArray(v8::Handle<v8::Value> value)
{
if (!value->IsArray())
return Vector<T>();
Vector<T> result;
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(value));
v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(v8Value);
size_t length = array->Length();
for (size_t i = 0; i < length; ++i) {
result.append(v8ValueToWebCoreString(array->Get(i)));
}
return result;
}
void enableStringImplCache();
int toInt32(v8::Handle<v8::Value> value, bool& ok);
inline int toInt32(v8::Handle<v8::Value> value)
{
bool ok;
return toInt32(value, ok);
}
uint32_t toUInt32(v8::Handle<v8::Value> value, bool& ok);
inline uint32_t toUInt32(v8::Handle<v8::Value> value)
{
bool ok;
return toUInt32(value, ok);
}
inline float toFloat(v8::Local<v8::Value> value)
{
return static_cast<float>(value->NumberValue());
}
inline long long toInt64(v8::Local<v8::Value> value)
{
return static_cast<long long>(value->IntegerValue());
}
inline String toWebCoreString(v8::Handle<v8::Value> object)
{
return v8ValueToWebCoreString(object);
}
inline String toWebCoreString(const v8::Arguments& args, int index)
{
return v8ValueToWebCoreString(args[index]);
}
inline const uint16_t* fromWebCoreString(const String& str)
{
return reinterpret_cast<const uint16_t*>(str.characters());
}
inline bool isUndefinedOrNull(v8::Handle<v8::Value> value)
{
return value->IsNull() || value->IsUndefined();
}
inline bool isHostObject(v8::Handle<v8::Object> object)
{
return object->InternalFieldCount() || object->HasIndexedPropertiesInExternalArrayData();
}
inline v8::Handle<v8::Boolean> v8Boolean(bool value)
{
return value ? v8::True() : v8::False();
}
inline String toWebCoreStringWithNullCheck(v8::Handle<v8::Value> value)
{
return value->IsNull() ? String() : v8ValueToWebCoreString(value);
}
inline AtomicString toAtomicWebCoreStringWithNullCheck(v8::Handle<v8::Value> value)
{
return value->IsNull() ? AtomicString() : v8ValueToAtomicWebCoreString(value);
}
inline String toWebCoreStringWithNullOrUndefinedCheck(v8::Handle<v8::Value> value)
{
return (value->IsNull() || value->IsUndefined()) ? String() : toWebCoreString(value);
}
inline v8::Handle<v8::String> v8UndetectableString(const String& str)
{
return v8::String::NewUndetectable(fromWebCoreString(str), str.length());
}
inline v8::Handle<v8::Value> v8StringOrNull(const String& str, v8::Isolate* isolate = 0)
{
return str.isNull() ? v8::Handle<v8::Value>(v8::Null()) : v8::Handle<v8::Value>(v8String(str, isolate));
}
inline v8::Handle<v8::Value> v8StringOrUndefined(const String& str, v8::Isolate* isolate = 0)
{
return str.isNull() ? v8::Handle<v8::Value>(v8::Undefined()) : v8::Handle<v8::Value>(v8String(str, isolate));
}
inline v8::Handle<v8::Value> v8StringOrFalse(const String& str, v8::Isolate* isolate = 0)
{
return str.isNull() ? v8::Handle<v8::Value>(v8::False()) : v8::Handle<v8::Value>(v8String(str, isolate));
}
template <class T> v8::Handle<v8::Value> v8NumberArray(const Vector<T>& values)
{
size_t size = values.size();
v8::Local<v8::Array> result = v8::Array::New(size);
for (size_t i = 0; i < size; ++i)
result->Set(i, v8::Number::New(values[i]));
return result;
}
inline double toWebCoreDate(v8::Handle<v8::Value> object)
{
return (object->IsDate() || object->IsNumber()) ? object->NumberValue() : std::numeric_limits<double>::quiet_NaN();
}
inline v8::Handle<v8::Value> v8DateOrNull(double value)
{
return isfinite(value) ? v8::Date::New(value) : v8::Handle<v8::Value>(v8::Null());
}
v8::Persistent<v8::FunctionTemplate> createRawTemplate();
struct BatchedAttribute;
struct BatchedCallback;
v8::Local<v8::Signature> configureTemplate(v8::Persistent<v8::FunctionTemplate>,
const char* interfaceName,
v8::Persistent<v8::FunctionTemplate> parentClass,
int fieldCount,
const BatchedAttribute*,
size_t attributeCount,
const BatchedCallback*,
size_t callbackCount);
v8::Handle<v8::Value> getElementStringAttr(const v8::AccessorInfo&,
const QualifiedName&);
void setElementStringAttr(const v8::AccessorInfo&,
const QualifiedName&,
v8::Local<v8::Value>);
v8::Persistent<v8::String> getToStringName();
v8::Persistent<v8::FunctionTemplate> getToStringTemplate();
String int32ToWebCoreString(int value);
template <class T> Vector<T> v8NumberArrayToVector(v8::Handle<v8::Value> value)
{
v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(value));
if (!v8Value->IsArray())
return Vector<T>();
Vector<T> result;
v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
size_t length = v8Array->Length();
for (size_t i = 0; i < length; ++i) {
v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Integer::New(i));
result.append(static_cast<T>(indexedValue->NumberValue()));
}
return result;
}
PassRefPtr<DOMStringList> v8ValueToWebCoreDOMStringList(v8::Handle<v8::Value>);
class V8ParameterBase {
public:
operator String() { return toString<String>(); }
operator AtomicString() { return toString<AtomicString>(); }
protected:
V8ParameterBase(v8::Local<v8::Value> object) : m_v8Object(object), m_mode(Externalize), m_string() { }
bool prepareBase()
{
if (m_v8Object.IsEmpty())
return true;
if (LIKELY(m_v8Object->IsString()))
return true;
if (LIKELY(m_v8Object->IsInt32())) {
setString(int32ToWebCoreString(m_v8Object->Int32Value()));
return true;
}
m_mode = DoNotExternalize;
v8::TryCatch block;
m_v8Object = m_v8Object->ToString();
if (block.HasCaught()) {
block.ReThrow();
return false;
}
return true;
}
v8::Local<v8::Value> object() { return m_v8Object; }
void setString(const String& string)
{
m_string = string;
m_v8Object.Clear(); }
private:
v8::Local<v8::Value> m_v8Object;
ExternalMode m_mode;
String m_string;
template <class StringType>
StringType toString()
{
if (LIKELY(!m_v8Object.IsEmpty()))
return v8StringToWebCoreString<StringType>(m_v8Object.As<v8::String>(), m_mode);
return StringType(m_string);
}
};
enum V8ParameterMode {
DefaultMode,
WithNullCheck,
WithUndefinedOrNullCheck
};
template <V8ParameterMode MODE = DefaultMode>
class V8Parameter: public V8ParameterBase {
public:
V8Parameter(v8::Local<v8::Value> object) : V8ParameterBase(object) { }
V8Parameter(v8::Local<v8::Value> object, bool) : V8ParameterBase(object) { prepare(); }
bool prepare();
};
template<> inline bool V8Parameter<DefaultMode>::prepare()
{
return V8ParameterBase::prepareBase();
}
template<> inline bool V8Parameter<WithNullCheck>::prepare()
{
if (object().IsEmpty() || object()->IsNull()) {
setString(String());
return true;
}
return V8ParameterBase::prepareBase();
}
template<> inline bool V8Parameter<WithUndefinedOrNullCheck>::prepare()
{
if (object().IsEmpty() || object()->IsNull() || object()->IsUndefined()) {
setString(String());
return true;
}
return V8ParameterBase::prepareBase();
}
enum ParameterDefaultPolicy {
DefaultIsUndefined,
DefaultIsNullString
};
}
#endif // V8Binding_h