This source file includes following definitions.
- throwError
- throwError
- throwTypeError
- throwArityTypeErrorForMethod
- throwArityTypeErrorForConstructor
- throwArityTypeError
- Allocate
- AllocateUninitialized
- Free
- v8ArrayBufferAllocator
- toNodeFilter
- enforceRange
- toSmallerInt
- toSmallerUInt
- toInt8
- toInt8
- toUInt8
- toUInt8
- toInt16
- toInt16
- toUInt16
- toUInt16
- toInt32
- toInt32
- toUInt32
- toUInt32
- toInt64
- toInt64
- toUInt64
- toUInt64
- toFloat
- toXPathNSResolver
- toDOMWindow
- toDOMWindow
- enteredDOMWindow
- currentDOMWindow
- callingDOMWindow
- toExecutionContext
- currentExecutionContext
- callingExecutionContext
- toFrameIfNotDetached
- toV8Context
- toV8Context
- handleMaxRecursionDepthExceeded
- crashIfV8IsDead
- getBoundFunction
- addHiddenValueToArray
- removeHiddenValueFromArray
- moveEventListenerToNewWrapper
- toIsolate
- toIsolate
- create
- m_scriptState
#include "config.h"
#include "bindings/v8/V8Binding.h"
#include "V8Element.h"
#include "V8NodeFilter.h"
#include "V8Window.h"
#include "V8WorkerGlobalScope.h"
#include "V8XPathNSResolver.h"
#include "bindings/v8/ScriptController.h"
#include "bindings/v8/V8AbstractEventListener.h"
#include "bindings/v8/V8BindingMacros.h"
#include "bindings/v8/V8NodeFilterCondition.h"
#include "bindings/v8/V8ObjectConstructor.h"
#include "bindings/v8/V8WindowShell.h"
#include "bindings/v8/WorkerScriptController.h"
#include "bindings/v8/custom/V8CustomXPathNSResolver.h"
#include "core/dom/Element.h"
#include "core/dom/NodeFilter.h"
#include "core/dom/QualifiedName.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h"
#include "core/inspector/BindingVisitors.h"
#include "core/loader/FrameLoader.h"
#include "core/loader/FrameLoaderClient.h"
#include "core/workers/WorkerGlobalScope.h"
#include "core/xml/XPathNSResolver.h"
#include "wtf/ArrayBufferContents.h"
#include "wtf/MainThread.h"
#include "wtf/MathExtras.h"
#include "wtf/StdLibExtras.h"
#include "wtf/Threading.h"
#include "wtf/text/AtomicString.h"
#include "wtf/text/CString.h"
#include "wtf/text/StringBuffer.h"
#include "wtf/text/StringHash.h"
#include "wtf/text/WTFString.h"
namespace WebCore {
v8::Handle<v8::Value> throwError(V8ErrorType errorType, const String& message, v8::Isolate* isolate)
{
return V8ThrowException::throwError(errorType, message, isolate);
}
v8::Handle<v8::Value> throwError(v8::Handle<v8::Value> exception, v8::Isolate* isolate)
{
return V8ThrowException::throwError(exception, isolate);
}
v8::Handle<v8::Value> throwTypeError(const String& message, v8::Isolate* isolate)
{
return V8ThrowException::throwTypeError(message, isolate);
}
void throwArityTypeErrorForMethod(const char* method, const char* type, unsigned expected, unsigned providedLeastNumMandatoryParams, v8::Isolate* isolate)
{
throwTypeError(ExceptionMessages::failedToExecute(method, type, ExceptionMessages::notEnoughArguments(expected, providedLeastNumMandatoryParams)), isolate);
}
void throwArityTypeErrorForConstructor(const char* type, unsigned expected, unsigned providedLeastNumMandatoryParams, v8::Isolate* isolate)
{
throwTypeError(ExceptionMessages::failedToConstruct(type, ExceptionMessages::notEnoughArguments(expected, providedLeastNumMandatoryParams)), isolate);
}
void throwArityTypeError(ExceptionState& exceptionState, unsigned expected, unsigned providedLeastNumMandatoryParams)
{
exceptionState.throwTypeError(ExceptionMessages::notEnoughArguments(expected, providedLeastNumMandatoryParams));
exceptionState.throwIfNeeded();
}
class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
virtual void* Allocate(size_t size) OVERRIDE
{
void* data;
WTF::ArrayBufferContents::allocateMemory(size, WTF::ArrayBufferContents::ZeroInitialize, data);
return data;
}
virtual void* AllocateUninitialized(size_t size) OVERRIDE
{
void* data;
WTF::ArrayBufferContents::allocateMemory(size, WTF::ArrayBufferContents::DontInitialize, data);
return data;
}
virtual void Free(void* data, size_t size) OVERRIDE
{
WTF::ArrayBufferContents::freeMemory(data, size);
}
};
v8::ArrayBuffer::Allocator* v8ArrayBufferAllocator()
{
DEFINE_STATIC_LOCAL(ArrayBufferAllocator, arrayBufferAllocator, ());
return &arrayBufferAllocator;
}
PassRefPtr<NodeFilter> toNodeFilter(v8::Handle<v8::Value> callback, v8::Isolate* isolate)
{
RefPtr<NodeFilter> filter = NodeFilter::create();
v8::Handle<v8::Object> filterWrapper = toV8(filter, v8::Handle<v8::Object>(), isolate).As<v8::Object>();
RefPtr<NodeFilterCondition> condition = V8NodeFilterCondition::create(callback, filterWrapper, isolate);
filter->setCondition(condition.release());
return filter.release();
}
const int32_t kMaxInt32 = 0x7fffffff;
const int32_t kMinInt32 = -kMaxInt32 - 1;
const uint32_t kMaxUInt32 = 0xffffffff;
const int64_t kJSMaxInteger = 0x20000000000000LL - 1;
static double enforceRange(double x, double minimum, double maximum, const char* typeName, ExceptionState& exceptionState)
{
if (std::isnan(x) || std::isinf(x)) {
exceptionState.throwTypeError("Value is" + String(std::isinf(x) ? " infinite and" : "") + " not of type '" + String(typeName) + "'.");
return 0;
}
x = trunc(x);
if (x < minimum || x > maximum) {
exceptionState.throwTypeError("Value is outside the '" + String(typeName) + "' value range.");
return 0;
}
return x;
}
template <typename T>
struct IntTypeLimits {
};
template <>
struct IntTypeLimits<int8_t> {
static const int8_t minValue = -128;
static const int8_t maxValue = 127;
static const unsigned numberOfValues = 256;
};
template <>
struct IntTypeLimits<uint8_t> {
static const uint8_t maxValue = 255;
static const unsigned numberOfValues = 256;
};
template <>
struct IntTypeLimits<int16_t> {
static const short minValue = -32768;
static const short maxValue = 32767;
static const unsigned numberOfValues = 65536;
};
template <>
struct IntTypeLimits<uint16_t> {
static const unsigned short maxValue = 65535;
static const unsigned numberOfValues = 65536;
};
template <typename T>
static inline T toSmallerInt(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, const char* typeName, ExceptionState& exceptionState)
{
typedef IntTypeLimits<T> LimitsTrait;
if (value->IsInt32()) {
int32_t result = value->Int32Value();
if (result >= LimitsTrait::minValue && result <= LimitsTrait::maxValue)
return static_cast<T>(result);
if (configuration == EnforceRange) {
exceptionState.throwTypeError("Value is outside the '" + String(typeName) + "' value range.");
return 0;
}
result %= LimitsTrait::numberOfValues;
return static_cast<T>(result > LimitsTrait::maxValue ? result - LimitsTrait::numberOfValues : result);
}
V8TRYCATCH_EXCEPTION_RETURN(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
if (numberObject.IsEmpty()) {
exceptionState.throwTypeError("Not convertible to a number value (of type '" + String(typeName) + "'.");
return 0;
}
if (configuration == EnforceRange)
return enforceRange(numberObject->Value(), LimitsTrait::minValue, LimitsTrait::maxValue, typeName, exceptionState);
double numberValue = numberObject->Value();
if (std::isnan(numberValue) || std::isinf(numberValue) || !numberValue)
return 0;
numberValue = numberValue < 0 ? -floor(fabs(numberValue)) : floor(fabs(numberValue));
numberValue = fmod(numberValue, LimitsTrait::numberOfValues);
return static_cast<T>(numberValue > LimitsTrait::maxValue ? numberValue - LimitsTrait::numberOfValues : numberValue);
}
template <typename T>
static inline T toSmallerUInt(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, const char* typeName, ExceptionState& exceptionState)
{
typedef IntTypeLimits<T> LimitsTrait;
if (value->IsInt32()) {
int32_t result = value->Int32Value();
if (result >= 0 && result <= LimitsTrait::maxValue)
return static_cast<T>(result);
if (configuration == EnforceRange) {
exceptionState.throwTypeError("Value is outside the '" + String(typeName) + "' value range.");
return 0;
}
return static_cast<T>(result);
}
V8TRYCATCH_EXCEPTION_RETURN(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
if (numberObject.IsEmpty()) {
exceptionState.throwTypeError("Not convertible to a number value (of type '" + String(typeName) + "'.");
return 0;
}
if (configuration == EnforceRange)
return enforceRange(numberObject->Value(), 0, LimitsTrait::maxValue, typeName, exceptionState);
double numberValue = numberObject->Value();
if (std::isnan(numberValue) || std::isinf(numberValue) || !numberValue)
return 0;
if (configuration == Clamp)
return clampTo<T>(numberObject->Value());
numberValue = numberValue < 0 ? -floor(fabs(numberValue)) : floor(fabs(numberValue));
return static_cast<T>(fmod(numberValue, LimitsTrait::numberOfValues));
}
int8_t toInt8(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
{
return toSmallerInt<int8_t>(value, configuration, "byte", exceptionState);
}
int8_t toInt8(v8::Handle<v8::Value> value)
{
NonThrowableExceptionState exceptionState;
return toInt8(value, NormalConversion, exceptionState);
}
uint8_t toUInt8(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
{
return toSmallerUInt<uint8_t>(value, configuration, "octet", exceptionState);
}
uint8_t toUInt8(v8::Handle<v8::Value> value)
{
NonThrowableExceptionState exceptionState;
return toUInt8(value, NormalConversion, exceptionState);
}
int16_t toInt16(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
{
return toSmallerInt<int16_t>(value, configuration, "short", exceptionState);
}
int16_t toInt16(v8::Handle<v8::Value> value)
{
NonThrowableExceptionState exceptionState;
return toInt16(value, NormalConversion, exceptionState);
}
uint16_t toUInt16(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
{
return toSmallerUInt<uint16_t>(value, configuration, "unsigned short", exceptionState);
}
uint16_t toUInt16(v8::Handle<v8::Value> value)
{
NonThrowableExceptionState exceptionState;
return toUInt16(value, NormalConversion, exceptionState);
}
int32_t toInt32(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
{
if (value->IsInt32())
return value->Int32Value();
V8TRYCATCH_EXCEPTION_RETURN(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
if (numberObject.IsEmpty()) {
exceptionState.throwTypeError("Not convertible to a number value (of type 'long'.)");
return 0;
}
if (configuration == EnforceRange)
return enforceRange(numberObject->Value(), kMinInt32, kMaxInt32, "long", exceptionState);
double numberValue = numberObject->Value();
if (std::isnan(numberValue) || std::isinf(numberValue))
return 0;
if (configuration == Clamp)
return clampTo<int32_t>(numberObject->Value());
V8TRYCATCH_EXCEPTION_RETURN(int32_t, result, numberObject->Int32Value(), exceptionState, 0);
return result;
}
int32_t toInt32(v8::Handle<v8::Value> value)
{
NonThrowableExceptionState exceptionState;
return toInt32(value, NormalConversion, exceptionState);
}
uint32_t toUInt32(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
{
if (value->IsUint32())
return value->Uint32Value();
if (value->IsInt32()) {
int32_t result = value->Int32Value();
if (result >= 0)
return result;
if (configuration == EnforceRange) {
exceptionState.throwTypeError("Value is outside the 'unsigned long' value range.");
return 0;
}
return result;
}
V8TRYCATCH_EXCEPTION_RETURN(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
if (numberObject.IsEmpty()) {
exceptionState.throwTypeError("Not convertible to a number value (of type 'unsigned long'.)");
return 0;
}
if (configuration == EnforceRange)
return enforceRange(numberObject->Value(), 0, kMaxUInt32, "unsigned long", exceptionState);
double numberValue = numberObject->Value();
if (std::isnan(numberValue) || std::isinf(numberValue))
return 0;
if (configuration == Clamp)
return clampTo<uint32_t>(numberObject->Value());
V8TRYCATCH_RETURN(uint32_t, result, numberObject->Uint32Value(), 0);
return result;
}
uint32_t toUInt32(v8::Handle<v8::Value> value)
{
NonThrowableExceptionState exceptionState;
return toUInt32(value, NormalConversion, exceptionState);
}
int64_t toInt64(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
{
if (value->IsInt32())
return value->Int32Value();
V8TRYCATCH_EXCEPTION_RETURN(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
if (numberObject.IsEmpty()) {
exceptionState.throwTypeError("Not convertible to a number value (of type 'long long'.)");
return 0;
}
double x = numberObject->Value();
if (configuration == EnforceRange)
return enforceRange(x, -kJSMaxInteger, kJSMaxInteger, "long long", exceptionState);
if (std::isnan(x) || std::isinf(x))
return 0;
unsigned long long integer;
doubleToInteger(x, integer);
return integer;
}
int64_t toInt64(v8::Handle<v8::Value> value)
{
NonThrowableExceptionState exceptionState;
return toInt64(value, NormalConversion, exceptionState);
}
uint64_t toUInt64(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
{
if (value->IsUint32())
return value->Uint32Value();
if (value->IsInt32()) {
int32_t result = value->Int32Value();
if (result >= 0)
return result;
if (configuration == EnforceRange) {
exceptionState.throwTypeError("Value is outside the 'unsigned long long' value range.");
return 0;
}
return result;
}
V8TRYCATCH_EXCEPTION_RETURN(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
if (numberObject.IsEmpty()) {
exceptionState.throwTypeError("Not convertible to a number value (of type 'unsigned long long'.)");
return 0;
}
double x = numberObject->Value();
if (configuration == EnforceRange)
return enforceRange(x, 0, kJSMaxInteger, "unsigned long long", exceptionState);
if (std::isnan(x) || std::isinf(x))
return 0;
unsigned long long integer;
doubleToInteger(x, integer);
return integer;
}
uint64_t toUInt64(v8::Handle<v8::Value> value)
{
NonThrowableExceptionState exceptionState;
return toUInt64(value, NormalConversion, exceptionState);
}
float toFloat(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
{
V8TRYCATCH_EXCEPTION_RETURN(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
return numberObject->NumberValue();
}
PassRefPtrWillBeRawPtr<XPathNSResolver> toXPathNSResolver(v8::Handle<v8::Value> value, v8::Isolate* isolate)
{
RefPtrWillBeRawPtr<XPathNSResolver> resolver = nullptr;
if (V8XPathNSResolver::hasInstance(value, isolate))
resolver = V8XPathNSResolver::toNative(v8::Handle<v8::Object>::Cast(value));
else if (value->IsObject())
resolver = V8CustomXPathNSResolver::create(value->ToObject(), isolate);
return resolver;
}
DOMWindow* toDOMWindow(v8::Handle<v8::Value> value, v8::Isolate* isolate)
{
if (value.IsEmpty() || !value->IsObject())
return 0;
v8::Handle<v8::Object> windowWrapper = V8Window::findInstanceInPrototypeChain(v8::Handle<v8::Object>::Cast(value), isolate);
if (!windowWrapper.IsEmpty())
return V8Window::toNative(windowWrapper);
return 0;
}
DOMWindow* toDOMWindow(v8::Handle<v8::Context> context)
{
if (context.IsEmpty())
return 0;
return toDOMWindow(context->Global(), context->GetIsolate());
}
DOMWindow* enteredDOMWindow(v8::Isolate* isolate)
{
return toDOMWindow(isolate->GetEnteredContext());
}
DOMWindow* currentDOMWindow(v8::Isolate* isolate)
{
return toDOMWindow(isolate->GetCurrentContext());
}
DOMWindow* callingDOMWindow(v8::Isolate* isolate)
{
v8::Handle<v8::Context> context = isolate->GetCallingContext();
if (context.IsEmpty()) {
context = isolate->GetEnteredContext();
}
return toDOMWindow(context);
}
ExecutionContext* toExecutionContext(v8::Handle<v8::Context> context)
{
v8::Handle<v8::Object> global = context->Global();
v8::Handle<v8::Object> windowWrapper = V8Window::findInstanceInPrototypeChain(global, context->GetIsolate());
if (!windowWrapper.IsEmpty())
return V8Window::toNative(windowWrapper)->executionContext();
v8::Handle<v8::Object> workerWrapper = V8WorkerGlobalScope::findInstanceInPrototypeChain(global, context->GetIsolate());
if (!workerWrapper.IsEmpty())
return V8WorkerGlobalScope::toNative(workerWrapper)->executionContext();
return 0;
}
ExecutionContext* currentExecutionContext(v8::Isolate* isolate)
{
return toExecutionContext(isolate->GetCurrentContext());
}
ExecutionContext* callingExecutionContext(v8::Isolate* isolate)
{
v8::Handle<v8::Context> context = isolate->GetCallingContext();
if (context.IsEmpty()) {
context = isolate->GetEnteredContext();
}
return toExecutionContext(context);
}
LocalFrame* toFrameIfNotDetached(v8::Handle<v8::Context> context)
{
DOMWindow* window = toDOMWindow(context);
if (window && window->isCurrentlyDisplayedInFrame())
return window->frame();
return 0;
}
v8::Local<v8::Context> toV8Context(ExecutionContext* context, DOMWrapperWorld& world)
{
ASSERT(context);
if (context->isDocument()) {
if (LocalFrame* frame = toDocument(context)->frame())
return frame->script().windowShell(world)->context();
} else if (context->isWorkerGlobalScope()) {
if (WorkerScriptController* script = toWorkerGlobalScope(context)->script())
return script->context();
}
return v8::Local<v8::Context>();
}
v8::Local<v8::Context> toV8Context(v8::Isolate* isolate, LocalFrame* frame, DOMWrapperWorld& world)
{
if (!frame)
return v8::Local<v8::Context>();
v8::Local<v8::Context> context = frame->script().windowShell(world)->context();
if (context.IsEmpty())
return v8::Local<v8::Context>();
LocalFrame* attachedFrame= toFrameIfNotDetached(context);
return frame == attachedFrame ? context : v8::Local<v8::Context>();
}
v8::Local<v8::Value> handleMaxRecursionDepthExceeded(v8::Isolate* isolate)
{
throwError(v8RangeError, "Maximum call stack size exceeded.", isolate);
return v8::Local<v8::Value>();
}
void crashIfV8IsDead()
{
if (v8::V8::IsDead()) {
CRASH();
}
}
v8::Handle<v8::Function> getBoundFunction(v8::Handle<v8::Function> function)
{
v8::Handle<v8::Value> boundFunction = function->GetBoundFunction();
return boundFunction->IsFunction() ? v8::Handle<v8::Function>::Cast(boundFunction) : function;
}
void addHiddenValueToArray(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int arrayIndex, v8::Isolate* isolate)
{
v8::Local<v8::Value> arrayValue = object->GetInternalField(arrayIndex);
if (arrayValue->IsNull() || arrayValue->IsUndefined()) {
arrayValue = v8::Array::New(isolate);
object->SetInternalField(arrayIndex, arrayValue);
}
v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(arrayValue);
array->Set(v8::Integer::New(isolate, array->Length()), value);
}
void removeHiddenValueFromArray(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int arrayIndex, v8::Isolate* isolate)
{
v8::Local<v8::Value> arrayValue = object->GetInternalField(arrayIndex);
if (!arrayValue->IsArray())
return;
v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(arrayValue);
for (int i = array->Length() - 1; i >= 0; --i) {
v8::Local<v8::Value> item = array->Get(v8::Integer::New(isolate, i));
if (item->StrictEquals(value)) {
array->Delete(i);
return;
}
}
}
void moveEventListenerToNewWrapper(v8::Handle<v8::Object> object, EventListener* oldValue, v8::Local<v8::Value> newValue, int arrayIndex, v8::Isolate* isolate)
{
if (oldValue) {
V8AbstractEventListener* oldListener = V8AbstractEventListener::cast(oldValue);
if (oldListener) {
v8::Local<v8::Object> oldListenerObject = oldListener->getExistingListenerObject();
if (!oldListenerObject.IsEmpty())
removeHiddenValueFromArray(object, oldListenerObject, arrayIndex, isolate);
}
}
if (newValue->IsFunction())
addHiddenValueToArray(object, newValue, arrayIndex, isolate);
}
v8::Isolate* toIsolate(ExecutionContext* context)
{
if (context && context->isDocument())
return V8PerIsolateData::mainThreadIsolate();
return v8::Isolate::GetCurrent();
}
v8::Isolate* toIsolate(LocalFrame* frame)
{
ASSERT(frame);
return frame->script().isolate();
}
PassOwnPtr<V8ExecutionScope> V8ExecutionScope::create(v8::Isolate* isolate)
{
return adoptPtr(new V8ExecutionScope(isolate));
}
V8ExecutionScope::V8ExecutionScope(v8::Isolate* isolate)
: m_handleScope(isolate)
, m_contextScope(v8::Context::New(isolate))
, m_scriptState(NewScriptState::create(isolate->GetCurrentContext(), DOMWrapperWorld::create()))
{
}
}