1/* 2* Copyright (C) 2009 Google Inc. All rights reserved. 3* Copyright (C) 2012 Ericsson AB. All rights reserved. 4* 5* Redistribution and use in source and binary forms, with or without 6* modification, are permitted provided that the following conditions are 7* met: 8* 9* * Redistributions of source code must retain the above copyright 10* notice, this list of conditions and the following disclaimer. 11* * Redistributions in binary form must reproduce the above 12* copyright notice, this list of conditions and the following disclaimer 13* in the documentation and/or other materials provided with the 14* distribution. 15* * Neither the name of Google Inc. nor the names of its 16* contributors may be used to endorse or promote products derived from 17* this software without specific prior written permission. 18* 19* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30*/ 31 32#ifndef V8Binding_h 33#define V8Binding_h 34 35#include "bindings/core/v8/DOMWrapperWorld.h" 36#include "bindings/core/v8/ExceptionMessages.h" 37#include "bindings/core/v8/ExceptionState.h" 38#include "bindings/core/v8/ScriptValue.h" 39#include "bindings/core/v8/ScriptWrappable.h" 40#include "bindings/core/v8/V8BindingMacros.h" 41#include "bindings/core/v8/V8PerIsolateData.h" 42#include "bindings/core/v8/V8StringResource.h" 43#include "bindings/core/v8/V8ThrowException.h" 44#include "bindings/core/v8/V8ValueCache.h" 45#include "platform/heap/Heap.h" 46#include "wtf/GetPtr.h" 47#include "wtf/MathExtras.h" 48#include "wtf/text/AtomicString.h" 49#include <v8.h> 50 51namespace blink { 52 53class LocalDOMWindow; 54class Document; 55class EventListener; 56class ExecutionContext; 57class ExceptionState; 58class LocalFrame; 59class NodeFilter; 60class XPathNSResolver; 61 62namespace TraceEvent { 63class ConvertableToTraceFormat; 64} 65 66const int kMaxRecursionDepth = 22; 67 68// Helpers for throwing JavaScript TypeErrors for arity mismatches. 69void setArityTypeError(ExceptionState&, const char* valid, unsigned provided); 70v8::Local<v8::Value> createMinimumArityTypeErrorForMethod(const char* method, const char* type, unsigned expected, unsigned provided, v8::Isolate*); 71v8::Local<v8::Value> createMinimumArityTypeErrorForConstructor(const char* type, unsigned expected, unsigned provided, v8::Isolate*); 72void setMinimumArityTypeError(ExceptionState&, unsigned expected, unsigned provided); 73 74v8::ArrayBuffer::Allocator* v8ArrayBufferAllocator(); 75 76template<typename CallbackInfo, typename V> 77inline void v8SetReturnValue(const CallbackInfo& info, V v) 78{ 79 info.GetReturnValue().Set(v); 80} 81 82template<typename CallbackInfo> 83inline void v8SetReturnValueBool(const CallbackInfo& info, bool v) 84{ 85 info.GetReturnValue().Set(v); 86} 87 88template<typename CallbackInfo> 89inline void v8SetReturnValueInt(const CallbackInfo& info, int v) 90{ 91 info.GetReturnValue().Set(v); 92} 93 94template<typename CallbackInfo> 95inline void v8SetReturnValueUnsigned(const CallbackInfo& info, unsigned v) 96{ 97 info.GetReturnValue().Set(v); 98} 99 100template<typename CallbackInfo> 101inline void v8SetReturnValueNull(const CallbackInfo& info) 102{ 103 info.GetReturnValue().SetNull(); 104} 105 106template<typename CallbackInfo> 107inline void v8SetReturnValueUndefined(const CallbackInfo& info) 108{ 109 info.GetReturnValue().SetUndefined(); 110} 111 112template<typename CallbackInfo> 113inline void v8SetReturnValueEmptyString(const CallbackInfo& info) 114{ 115 info.GetReturnValue().SetEmptyString(); 116} 117 118template <class CallbackInfo> 119inline void v8SetReturnValueString(const CallbackInfo& info, const String& string, v8::Isolate* isolate) 120{ 121 if (string.isNull()) { 122 v8SetReturnValueEmptyString(info); 123 return; 124 } 125 V8PerIsolateData::from(isolate)->stringCache()->setReturnValueFromString(info.GetReturnValue(), string.impl()); 126} 127 128template <class CallbackInfo> 129inline void v8SetReturnValueStringOrNull(const CallbackInfo& info, const String& string, v8::Isolate* isolate) 130{ 131 if (string.isNull()) { 132 v8SetReturnValueNull(info); 133 return; 134 } 135 V8PerIsolateData::from(isolate)->stringCache()->setReturnValueFromString(info.GetReturnValue(), string.impl()); 136} 137 138template <class CallbackInfo> 139inline void v8SetReturnValueStringOrUndefined(const CallbackInfo& info, const String& string, v8::Isolate* isolate) 140{ 141 if (string.isNull()) { 142 v8SetReturnValueUndefined(info); 143 return; 144 } 145 V8PerIsolateData::from(isolate)->stringCache()->setReturnValueFromString(info.GetReturnValue(), string.impl()); 146} 147 148// Convert v8::String to a WTF::String. If the V8 string is not already 149// an external string then it is transformed into an external string at this 150// point to avoid repeated conversions. 151inline String toCoreString(v8::Handle<v8::String> value) 152{ 153 return v8StringToWebCoreString<String>(value, Externalize); 154} 155 156inline String toCoreStringWithNullCheck(v8::Handle<v8::String> value) 157{ 158 if (value.IsEmpty() || value->IsNull()) 159 return String(); 160 return toCoreString(value); 161} 162 163inline String toCoreStringWithUndefinedOrNullCheck(v8::Handle<v8::String> value) 164{ 165 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) 166 return String(); 167 return toCoreString(value); 168} 169 170inline AtomicString toCoreAtomicString(v8::Handle<v8::String> value) 171{ 172 return v8StringToWebCoreString<AtomicString>(value, Externalize); 173} 174 175// This method will return a null String if the v8::Value does not contain a v8::String. 176// It will not call ToString() on the v8::Value. If you want ToString() to be called, 177// please use the TONATIVE_FOR_V8STRINGRESOURCE_*() macros instead. 178inline String toCoreStringWithUndefinedOrNullCheck(v8::Handle<v8::Value> value) 179{ 180 if (value.IsEmpty() || !value->IsString()) 181 return String(); 182 return toCoreString(value.As<v8::String>()); 183} 184 185// Convert a string to a V8 string. 186// Return a V8 external string that shares the underlying buffer with the given 187// WebCore string. The reference counting mechanism is used to keep the 188// underlying buffer alive while the string is still live in the V8 engine. 189inline v8::Handle<v8::String> v8String(v8::Isolate* isolate, const String& string) 190{ 191 if (string.isNull()) 192 return v8::String::Empty(isolate); 193 return V8PerIsolateData::from(isolate)->stringCache()->v8ExternalString(string.impl(), isolate); 194} 195 196inline v8::Handle<v8::String> v8AtomicString(v8::Isolate* isolate, const char* str) 197{ 198 ASSERT(isolate); 199 return v8::String::NewFromUtf8(isolate, str, v8::String::kInternalizedString, strlen(str)); 200} 201 202inline v8::Handle<v8::String> v8AtomicString(v8::Isolate* isolate, const char* str, size_t length) 203{ 204 ASSERT(isolate); 205 return v8::String::NewFromUtf8(isolate, str, v8::String::kInternalizedString, length); 206} 207 208inline v8::Handle<v8::Value> v8Undefined() 209{ 210 return v8::Handle<v8::Value>(); 211} 212 213// Converts a DOM object to a v8 value. This function is intended to be used 214// internally. If you want to convert a DOM object to a V8 value, 215// - Use toV8 if you can include V8X.h. 216// - Use V8ValueTraits<T>::toV8Value if you cannot include V8X.h. 217// Note: Including bindings/{core, modules}/v8/V8*.h from core and modules 218// is fine. In such a case, perhaps toV8 is what you want. 219// Note: toV8NoInline is a non-inline toV8 and V8ValueTraits::toV8Value offers 220// more: You can handle value conversion generally with it. 221template<typename T> 222v8::Handle<v8::Value> toV8NoInline(T* impl, v8::Handle<v8::Object> creationContext, v8::Isolate*); 223 224template <typename T> 225struct V8ValueTraits { 226 static v8::Handle<v8::Value> toV8Value(const T& value, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 227 { 228 if (!WTF::getPtr(value)) 229 return v8::Null(isolate); 230 return toV8NoInline(WTF::getPtr(value), creationContext, isolate); 231 } 232}; 233 234template<> 235struct V8ValueTraits<String> { 236 static inline v8::Handle<v8::Value> toV8Value(const String& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 237 { 238 return v8String(isolate, value); 239 } 240}; 241 242template<> 243struct V8ValueTraits<AtomicString> { 244 static inline v8::Handle<v8::Value> toV8Value(const AtomicString& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 245 { 246 return v8String(isolate, value); 247 } 248}; 249 250template<size_t n> 251struct V8ValueTraits<char[n]> { 252 static inline v8::Handle<v8::Value> toV8Value(char const (&value)[n], v8::Handle<v8::Object>, v8::Isolate* isolate) 253 { 254 return v8String(isolate, value); 255 } 256}; 257 258template<size_t n> 259struct V8ValueTraits<char const[n]> { 260 static inline v8::Handle<v8::Value> toV8Value(char const (&value)[n], v8::Handle<v8::Object>, v8::Isolate* isolate) 261 { 262 return v8String(isolate, value); 263 } 264}; 265 266template<> 267struct V8ValueTraits<const char*> { 268 static inline v8::Handle<v8::Value> toV8Value(const char* const& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 269 { 270 if (!value) { 271 // We return an empty string, not null, in order to align 272 // with v8String(isolate, String()). 273 return v8::String::Empty(isolate); 274 } 275 return v8String(isolate, value); 276 } 277}; 278 279template<> 280struct V8ValueTraits<char*> { 281 static inline v8::Handle<v8::Value> toV8Value(char* const& value, v8::Handle<v8::Object> object, v8::Isolate* isolate) 282 { 283 return V8ValueTraits<const char*>::toV8Value(value, object, isolate); 284 } 285}; 286 287template<> 288struct V8ValueTraits<int> { 289 static inline v8::Handle<v8::Value> toV8Value(const int& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 290 { 291 return v8::Integer::New(isolate, value); 292 } 293}; 294 295template<> 296struct V8ValueTraits<long> { 297 static inline v8::Handle<v8::Value> toV8Value(const long& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 298 { 299 return v8::Integer::New(isolate, value); 300 } 301}; 302 303template<> 304struct V8ValueTraits<unsigned> { 305 static inline v8::Handle<v8::Value> toV8Value(const unsigned& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 306 { 307 return v8::Integer::NewFromUnsigned(isolate, value); 308 } 309}; 310 311template<> 312struct V8ValueTraits<unsigned long> { 313 static inline v8::Handle<v8::Value> toV8Value(const unsigned long& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 314 { 315 return v8::Integer::NewFromUnsigned(isolate, value); 316 } 317}; 318 319template<> 320struct V8ValueTraits<float> { 321 static inline v8::Handle<v8::Value> toV8Value(const float& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 322 { 323 return v8::Number::New(isolate, value); 324 } 325}; 326 327template<> 328struct V8ValueTraits<double> { 329 static inline v8::Handle<v8::Value> toV8Value(const double& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 330 { 331 return v8::Number::New(isolate, value); 332 } 333}; 334 335template<> 336struct V8ValueTraits<bool> { 337 static inline v8::Handle<v8::Value> toV8Value(const bool& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 338 { 339 return v8::Boolean::New(isolate, value); 340 } 341}; 342 343// V8NullType and V8UndefinedType are used only for the value conversion. 344class V8NullType { }; 345class V8UndefinedType { }; 346 347template<> 348struct V8ValueTraits<V8NullType> { 349 static inline v8::Handle<v8::Value> toV8Value(const V8NullType&, v8::Handle<v8::Object>, v8::Isolate* isolate) 350 { 351 return v8::Null(isolate); 352 } 353}; 354 355template<> 356struct V8ValueTraits<V8UndefinedType> { 357 static inline v8::Handle<v8::Value> toV8Value(const V8UndefinedType&, v8::Handle<v8::Object>, v8::Isolate* isolate) 358 { 359 return v8::Undefined(isolate); 360 } 361}; 362 363template<> 364struct V8ValueTraits<ScriptValue> { 365 static inline v8::Handle<v8::Value> toV8Value(const ScriptValue& value, v8::Handle<v8::Object>, v8::Isolate*) 366 { 367 return value.v8Value(); 368 } 369}; 370 371template<> 372struct V8ValueTraits<v8::Handle<v8::Value> > { 373 static inline v8::Handle<v8::Value> toV8Value(const v8::Handle<v8::Value>& value, v8::Handle<v8::Object>, v8::Isolate*) 374 { 375 return value; 376 } 377}; 378 379template<> 380struct V8ValueTraits<v8::Local<v8::Value> > { 381 static inline v8::Handle<v8::Value> toV8Value(const v8::Local<v8::Value>& value, v8::Handle<v8::Object>, v8::Isolate*) 382 { 383 return value; 384 } 385}; 386 387template<typename T, size_t inlineCapacity> 388v8::Handle<v8::Value> v8Array(const Vector<T, inlineCapacity>& iterator, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 389{ 390 v8::Local<v8::Array> result = v8::Array::New(isolate, iterator.size()); 391 int index = 0; 392 typename Vector<T, inlineCapacity>::const_iterator end = iterator.end(); 393 typedef V8ValueTraits<T> TraitsType; 394 for (typename Vector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter) 395 result->Set(v8::Integer::New(isolate, index++), TraitsType::toV8Value(*iter, creationContext, isolate)); 396 return result; 397} 398 399template <typename T, size_t inlineCapacity, typename Allocator> 400struct V8ValueTraits<WTF::Vector<T, inlineCapacity, Allocator> > { 401 static v8::Handle<v8::Value> toV8Value(const Vector<T, inlineCapacity, Allocator>& value, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 402 { 403 return v8Array(value, creationContext, isolate); 404 } 405}; 406 407template<typename T, size_t inlineCapacity> 408v8::Handle<v8::Value> v8Array(const HeapVector<T, inlineCapacity>& iterator, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 409{ 410 v8::Local<v8::Array> result = v8::Array::New(isolate, iterator.size()); 411 int index = 0; 412 typename HeapVector<T, inlineCapacity>::const_iterator end = iterator.end(); 413 typedef V8ValueTraits<T> TraitsType; 414 for (typename HeapVector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter) 415 result->Set(v8::Integer::New(isolate, index++), TraitsType::toV8Value(*iter, creationContext, isolate)); 416 return result; 417} 418 419template <typename T, size_t inlineCapacity> 420struct V8ValueTraits<HeapVector<T, inlineCapacity> > { 421 static v8::Handle<v8::Value> toV8Value(const HeapVector<T, inlineCapacity>& value, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 422 { 423 return v8Array(value, creationContext, isolate); 424 } 425}; 426 427// Conversion flags, used in toIntXX/toUIntXX. 428enum IntegerConversionConfiguration { 429 NormalConversion, 430 EnforceRange, 431 Clamp 432}; 433 434// Convert a value to a 8-bit signed integer. The conversion fails if the 435// value cannot be converted to a number or the range violated per WebIDL: 436// http://www.w3.org/TR/WebIDL/#es-byte 437int8_t toInt8(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 438inline int8_t toInt8(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 439{ 440 return toInt8(value, NormalConversion, exceptionState); 441} 442 443// Convert a value to a 8-bit integer assuming the conversion cannot fail. 444int8_t toInt8(v8::Handle<v8::Value>); 445 446// Convert a value to a 8-bit unsigned integer. The conversion fails if the 447// value cannot be converted to a number or the range violated per WebIDL: 448// http://www.w3.org/TR/WebIDL/#es-octet 449uint8_t toUInt8(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 450inline uint8_t toUInt8(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 451{ 452 return toUInt8(value, NormalConversion, exceptionState); 453} 454 455// Convert a value to a 8-bit unsigned integer assuming the conversion cannot fail. 456uint8_t toUInt8(v8::Handle<v8::Value>); 457 458// Convert a value to a 16-bit signed integer. The conversion fails if the 459// value cannot be converted to a number or the range violated per WebIDL: 460// http://www.w3.org/TR/WebIDL/#es-short 461int16_t toInt16(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 462inline int16_t toInt16(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 463{ 464 return toInt16(value, NormalConversion, exceptionState); 465} 466 467// Convert a value to a 16-bit integer assuming the conversion cannot fail. 468int16_t toInt16(v8::Handle<v8::Value>); 469 470// Convert a value to a 16-bit unsigned integer. The conversion fails if the 471// value cannot be converted to a number or the range violated per WebIDL: 472// http://www.w3.org/TR/WebIDL/#es-unsigned-short 473uint16_t toUInt16(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 474inline uint16_t toUInt16(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 475{ 476 return toUInt16(value, NormalConversion, exceptionState); 477} 478 479// Convert a value to a 16-bit unsigned integer assuming the conversion cannot fail. 480uint16_t toUInt16(v8::Handle<v8::Value>); 481 482// Convert a value to a 32-bit signed integer. The conversion fails if the 483// value cannot be converted to a number or the range violated per WebIDL: 484// http://www.w3.org/TR/WebIDL/#es-long 485int32_t toInt32(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 486inline int32_t toInt32(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 487{ 488 return toInt32(value, NormalConversion, exceptionState); 489} 490 491// Convert a value to a 32-bit integer assuming the conversion cannot fail. 492int32_t toInt32(v8::Handle<v8::Value>); 493 494// Convert a value to a 32-bit unsigned integer. The conversion fails if the 495// value cannot be converted to a number or the range violated per WebIDL: 496// http://www.w3.org/TR/WebIDL/#es-unsigned-long 497uint32_t toUInt32(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 498inline uint32_t toUInt32(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 499{ 500 return toUInt32(value, NormalConversion, exceptionState); 501} 502 503// Convert a value to a 32-bit unsigned integer assuming the conversion cannot fail. 504uint32_t toUInt32(v8::Handle<v8::Value>); 505 506// Convert a value to a 64-bit signed integer. The conversion fails if the 507// value cannot be converted to a number or the range violated per WebIDL: 508// http://www.w3.org/TR/WebIDL/#es-long-long 509int64_t toInt64(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 510inline int64_t toInt64(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 511{ 512 return toInt64(value, NormalConversion, exceptionState); 513} 514 515// Convert a value to a 64-bit integer assuming the conversion cannot fail. 516int64_t toInt64(v8::Handle<v8::Value>); 517 518// Convert a value to a 64-bit unsigned integer. The conversion fails if the 519// value cannot be converted to a number or the range violated per WebIDL: 520// http://www.w3.org/TR/WebIDL/#es-unsigned-long-long 521uint64_t toUInt64(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 522inline uint64_t toUInt64(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 523{ 524 return toUInt64(value, NormalConversion, exceptionState); 525} 526 527// Convert a value to a 64-bit unsigned integer assuming the conversion cannot fail. 528uint64_t toUInt64(v8::Handle<v8::Value>); 529 530// Convert a value to a single precision float, which might fail. 531float toFloat(v8::Handle<v8::Value>, ExceptionState&); 532 533// Convert a value to a single precision float assuming the conversion cannot fail. 534inline float toFloat(v8::Local<v8::Value> value) 535{ 536 return static_cast<float>(value->NumberValue()); 537} 538 539// Convert a value to a double precision float, which might fail. 540double toDouble(v8::Handle<v8::Value>, ExceptionState&); 541 542// Converts a value to a String, throwing if any code unit is outside 0-255. 543String toByteString(v8::Handle<v8::Value>, ExceptionState&); 544 545// Converts a value to a String, replacing unmatched UTF-16 surrogates with replacement characters. 546String toScalarValueString(v8::Handle<v8::Value>, ExceptionState&); 547 548inline v8::Handle<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) 549{ 550 return value ? v8::True(isolate) : v8::False(isolate); 551} 552 553inline double toCoreDate(v8::Handle<v8::Value> object) 554{ 555 if (object->IsDate()) 556 return v8::Handle<v8::Date>::Cast(object)->ValueOf(); 557 if (object->IsNumber()) 558 return object->NumberValue(); 559 return std::numeric_limits<double>::quiet_NaN(); 560} 561 562inline v8::Handle<v8::Value> v8DateOrNaN(double value, v8::Isolate* isolate) 563{ 564 ASSERT(isolate); 565 return v8::Date::New(isolate, std::isfinite(value) ? value : std::numeric_limits<double>::quiet_NaN()); 566} 567 568// FIXME: Remove the special casing for NodeFilter and XPathNSResolver. 569PassRefPtrWillBeRawPtr<NodeFilter> toNodeFilter(v8::Handle<v8::Value>, v8::Handle<v8::Object>, ScriptState*); 570PassRefPtrWillBeRawPtr<XPathNSResolver> toXPathNSResolver(v8::Handle<v8::Value>, v8::Isolate*); 571 572template<class T> struct NativeValueTraits; 573 574bool toV8Sequence(v8::Handle<v8::Value>, uint32_t& length, v8::Isolate*, ExceptionState&); 575 576// Converts a JavaScript value to an array as per the Web IDL specification: 577// http://www.w3.org/TR/2012/CR-WebIDL-20120419/#es-array 578template <class T, class V8T> 579Vector<RefPtr<T> > toRefPtrNativeArrayUnchecked(v8::Local<v8::Value> v8Value, uint32_t length, v8::Isolate* isolate, ExceptionState& exceptionState) 580{ 581 Vector<RefPtr<T> > result; 582 result.reserveInitialCapacity(length); 583 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value); 584 v8::TryCatch block; 585 for (uint32_t i = 0; i < length; ++i) { 586 v8::Handle<v8::Value> element = object->Get(i); 587 if (block.HasCaught()) { 588 exceptionState.rethrowV8Exception(block.Exception()); 589 return Vector<RefPtr<T> >(); 590 } 591 if (V8T::hasInstance(element, isolate)) { 592 v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element); 593 result.uncheckedAppend(V8T::toImpl(elementObject)); 594 } else { 595 exceptionState.throwTypeError("Invalid Array element type"); 596 return Vector<RefPtr<T> >(); 597 } 598 } 599 return result; 600} 601 602template <class T, class V8T> 603Vector<RefPtr<T> > toRefPtrNativeArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, ExceptionState& exceptionState) 604{ 605 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 606 uint32_t length = 0; 607 if (value->IsArray()) { 608 length = v8::Local<v8::Array>::Cast(v8Value)->Length(); 609 } else if (!toV8Sequence(value, length, isolate, exceptionState)) { 610 if (!exceptionState.hadException()) 611 exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex)); 612 return Vector<RefPtr<T> >(); 613 } 614 return toRefPtrNativeArrayUnchecked<T, V8T>(v8Value, length, isolate, exceptionState); 615} 616 617template <class T, class V8T> 618Vector<RefPtr<T> > toRefPtrNativeArray(v8::Handle<v8::Value> value, const String& propertyName, v8::Isolate* isolate, ExceptionState& exceptionState) 619{ 620 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 621 uint32_t length = 0; 622 if (value->IsArray()) { 623 length = v8::Local<v8::Array>::Cast(v8Value)->Length(); 624 } else if (!toV8Sequence(value, length, isolate, exceptionState)) { 625 if (!exceptionState.hadException()) 626 exceptionState.throwTypeError(ExceptionMessages::notASequenceTypeProperty(propertyName)); 627 return Vector<RefPtr<T> >(); 628 } 629 return toRefPtrNativeArrayUnchecked<T, V8T>(v8Value, length, isolate, exceptionState); 630} 631 632template <class T, class V8T> 633WillBeHeapVector<RefPtrWillBeMember<T> > toRefPtrWillBeMemberNativeArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, ExceptionState& exceptionState) 634{ 635 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 636 uint32_t length = 0; 637 if (value->IsArray()) { 638 length = v8::Local<v8::Array>::Cast(v8Value)->Length(); 639 } else if (!toV8Sequence(value, length, isolate, exceptionState)) { 640 if (!exceptionState.hadException()) 641 exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex)); 642 return WillBeHeapVector<RefPtrWillBeMember<T> >(); 643 } 644 645 WillBeHeapVector<RefPtrWillBeMember<T> > result; 646 result.reserveInitialCapacity(length); 647 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value); 648 v8::TryCatch block; 649 for (uint32_t i = 0; i < length; ++i) { 650 v8::Handle<v8::Value> element = object->Get(i); 651 if (block.HasCaught()) { 652 exceptionState.rethrowV8Exception(block.Exception()); 653 return WillBeHeapVector<RefPtrWillBeMember<T> >(); 654 } 655 if (V8T::hasInstance(element, isolate)) { 656 v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element); 657 result.uncheckedAppend(V8T::toImpl(elementObject)); 658 } else { 659 exceptionState.throwTypeError("Invalid Array element type"); 660 return WillBeHeapVector<RefPtrWillBeMember<T> >(); 661 } 662 } 663 return result; 664} 665 666template <class T, class V8T> 667WillBeHeapVector<RefPtrWillBeMember<T> > toRefPtrWillBeMemberNativeArray(v8::Handle<v8::Value> value, const String& propertyName, v8::Isolate* isolate, ExceptionState& exceptionState) 668{ 669 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 670 uint32_t length = 0; 671 if (value->IsArray()) { 672 length = v8::Local<v8::Array>::Cast(v8Value)->Length(); 673 } else if (!toV8Sequence(value, length, isolate, exceptionState)) { 674 if (!exceptionState.hadException()) 675 exceptionState.throwTypeError(ExceptionMessages::notASequenceTypeProperty(propertyName)); 676 return WillBeHeapVector<RefPtrWillBeMember<T> >(); 677 } 678 679 WillBeHeapVector<RefPtrWillBeMember<T> > result; 680 result.reserveInitialCapacity(length); 681 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value); 682 v8::TryCatch block; 683 for (uint32_t i = 0; i < length; ++i) { 684 v8::Handle<v8::Value> element = object->Get(i); 685 if (block.HasCaught()) { 686 exceptionState.rethrowV8Exception(block.Exception()); 687 return WillBeHeapVector<RefPtrWillBeMember<T> >(); 688 } 689 if (V8T::hasInstance(element, isolate)) { 690 v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element); 691 result.uncheckedAppend(V8T::toImpl(elementObject)); 692 } else { 693 exceptionState.throwTypeError("Invalid Array element type"); 694 return WillBeHeapVector<RefPtrWillBeMember<T> >(); 695 } 696 } 697 return result; 698} 699 700template <class T, class V8T> 701HeapVector<Member<T> > toMemberNativeArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, ExceptionState& exceptionState) 702{ 703 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 704 uint32_t length = 0; 705 if (value->IsArray()) { 706 length = v8::Local<v8::Array>::Cast(v8Value)->Length(); 707 } else if (!toV8Sequence(value, length, isolate, exceptionState)) { 708 if (!exceptionState.hadException()) 709 exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex)); 710 return HeapVector<Member<T> >(); 711 } 712 713 HeapVector<Member<T> > result; 714 result.reserveInitialCapacity(length); 715 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value); 716 v8::TryCatch block; 717 for (uint32_t i = 0; i < length; ++i) { 718 v8::Handle<v8::Value> element = object->Get(i); 719 if (UNLIKELY(block.HasCaught())) { 720 exceptionState.rethrowV8Exception(block.Exception()); 721 return HeapVector<Member<T> >(); 722 } 723 if (V8T::hasInstance(element, isolate)) { 724 v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element); 725 result.uncheckedAppend(V8T::toImpl(elementObject)); 726 } else { 727 exceptionState.throwTypeError("Invalid Array element type"); 728 return HeapVector<Member<T> >(); 729 } 730 } 731 return result; 732} 733 734// Converts a JavaScript value to an array as per the Web IDL specification: 735// http://www.w3.org/TR/2012/CR-WebIDL-20120419/#es-array 736template <class T> 737Vector<T> toImplArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, ExceptionState& exceptionState) 738{ 739 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 740 uint32_t length = 0; 741 if (value->IsArray()) { 742 length = v8::Local<v8::Array>::Cast(v8Value)->Length(); 743 } else if (!toV8Sequence(value, length, isolate, exceptionState)) { 744 if (!exceptionState.hadException()) 745 exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex)); 746 return Vector<T>(); 747 } 748 749 Vector<T> result; 750 result.reserveInitialCapacity(length); 751 typedef NativeValueTraits<T> TraitsType; 752 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value); 753 v8::TryCatch block; 754 for (uint32_t i = 0; i < length; ++i) { 755 v8::Handle<v8::Value> element = object->Get(i); 756 if (UNLIKELY(block.HasCaught())) { 757 exceptionState.rethrowV8Exception(block.Exception()); 758 return Vector<T>(); 759 } 760 result.uncheckedAppend(TraitsType::nativeValue(element, isolate, exceptionState)); 761 if (exceptionState.hadException()) 762 return Vector<T>(); 763 } 764 return result; 765} 766 767template <class T> 768Vector<T> toImplArguments(const v8::FunctionCallbackInfo<v8::Value>& info, int startIndex, ExceptionState& exceptionState) 769{ 770 ASSERT(startIndex <= info.Length()); 771 Vector<T> result; 772 typedef NativeValueTraits<T> TraitsType; 773 int length = info.Length(); 774 result.reserveInitialCapacity(length); 775 for (int i = startIndex; i < length; ++i) { 776 result.uncheckedAppend(TraitsType::nativeValue(info[i], info.GetIsolate(), exceptionState)); 777 if (exceptionState.hadException()) 778 return Vector<T>(); 779 } 780 return result; 781} 782 783// Validates that the passed object is a sequence type per WebIDL spec 784// http://www.w3.org/TR/2012/CR-WebIDL-20120419/#es-sequence 785inline bool toV8Sequence(v8::Handle<v8::Value> value, uint32_t& length, v8::Isolate* isolate, ExceptionState& exceptionState) 786{ 787 // Attempt converting to a sequence if the value is not already an array but is 788 // any kind of object except for a native Date object or a native RegExp object. 789 ASSERT(!value->IsArray()); 790 // FIXME: Do we really need to special case Date and RegExp object? 791 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=22806 792 if (!value->IsObject() || value->IsDate() || value->IsRegExp()) { 793 // The caller is responsible for reporting a TypeError. 794 return false; 795 } 796 797 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 798 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value); 799 v8::Local<v8::String> lengthSymbol = v8AtomicString(isolate, "length"); 800 801 // FIXME: The specification states that the length property should be used as fallback, if value 802 // is not a platform object that supports indexed properties. If it supports indexed properties, 803 // length should actually be one greater than value’s maximum indexed property index. 804 v8::TryCatch block; 805 v8::Local<v8::Value> lengthValue = object->Get(lengthSymbol); 806 if (block.HasCaught()) { 807 exceptionState.rethrowV8Exception(block.Exception()); 808 return false; 809 } 810 811 if (lengthValue->IsUndefined() || lengthValue->IsNull()) { 812 // The caller is responsible for reporting a TypeError. 813 return false; 814 } 815 816 uint32_t sequenceLength = lengthValue->Int32Value(); 817 if (block.HasCaught()) { 818 exceptionState.rethrowV8Exception(block.Exception()); 819 return false; 820 } 821 822 length = sequenceLength; 823 return true; 824} 825 826template<> 827struct NativeValueTraits<String> { 828 static inline String nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState) 829 { 830 V8StringResource<> stringValue(value); 831 if (!stringValue.prepare(exceptionState)) 832 return String(); 833 return stringValue; 834 } 835}; 836 837template<> 838struct NativeValueTraits<int> { 839 static inline int nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState) 840 { 841 return toInt32(value, exceptionState); 842 } 843}; 844 845template<> 846struct NativeValueTraits<unsigned> { 847 static inline unsigned nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState) 848 { 849 return toUInt32(value, exceptionState); 850 } 851}; 852 853template<> 854struct NativeValueTraits<float> { 855 static inline float nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState) 856 { 857 return toFloat(value, exceptionState); 858 } 859}; 860 861template<> 862struct NativeValueTraits<double> { 863 static inline double nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState) 864 { 865 return toDouble(value, exceptionState); 866 } 867}; 868 869template<> 870struct NativeValueTraits<v8::Handle<v8::Value> > { 871 static inline v8::Handle<v8::Value> nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState&) 872 { 873 return value; 874 } 875}; 876 877template<> 878struct NativeValueTraits<ScriptValue> { 879 static inline ScriptValue nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState&) 880 { 881 return ScriptValue(ScriptState::current(isolate), value); 882 } 883}; 884 885template <typename T> 886struct NativeValueTraits<Vector<T> > { 887 static inline Vector<T> nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState) 888 { 889 return toImplArray<T>(value, 0, isolate, exceptionState); 890 } 891}; 892 893v8::Isolate* toIsolate(ExecutionContext*); 894v8::Isolate* toIsolate(LocalFrame*); 895 896LocalDOMWindow* toDOMWindow(v8::Handle<v8::Value>, v8::Isolate*); 897LocalDOMWindow* toDOMWindow(v8::Handle<v8::Context>); 898LocalDOMWindow* enteredDOMWindow(v8::Isolate*); 899LocalDOMWindow* currentDOMWindow(v8::Isolate*); 900LocalDOMWindow* callingDOMWindow(v8::Isolate*); 901ExecutionContext* toExecutionContext(v8::Handle<v8::Context>); 902ExecutionContext* currentExecutionContext(v8::Isolate*); 903ExecutionContext* callingExecutionContext(v8::Isolate*); 904 905// Returns a V8 context associated with a ExecutionContext and a DOMWrapperWorld. 906// This method returns an empty context if there is no frame or the frame is already detached. 907v8::Local<v8::Context> toV8Context(ExecutionContext*, DOMWrapperWorld&); 908// Returns a V8 context associated with a LocalFrame and a DOMWrapperWorld. 909// This method returns an empty context if the frame is already detached. 910v8::Local<v8::Context> toV8Context(LocalFrame*, DOMWrapperWorld&); 911 912// Returns the frame object of the window object associated with 913// a context, if the window is currently being displayed in the LocalFrame. 914LocalFrame* toFrameIfNotDetached(v8::Handle<v8::Context>); 915 916// If the current context causes out of memory, JavaScript setting 917// is disabled and it returns true. 918bool handleOutOfMemory(); 919void crashIfV8IsDead(); 920 921inline bool isUndefinedOrNull(v8::Handle<v8::Value> value) 922{ 923 return value->IsNull() || value->IsUndefined(); 924} 925v8::Handle<v8::Function> getBoundFunction(v8::Handle<v8::Function>); 926 927// Attaches |environment| to |function| and returns it. 928inline v8::Local<v8::Function> createClosure(v8::FunctionCallback function, v8::Handle<v8::Value> environment, v8::Isolate* isolate) 929{ 930 return v8::Function::New(isolate, function, environment); 931} 932 933// FIXME: This will be soon embedded in the generated code. 934template<class Collection> static void indexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) 935{ 936 Collection* collection = toScriptWrappableBase(info.Holder())->toImpl<Collection>(); 937 int length = collection->length(); 938 v8::Handle<v8::Array> properties = v8::Array::New(info.GetIsolate(), length); 939 for (int i = 0; i < length; ++i) { 940 // FIXME: Do we need to check that the item function returns a non-null value for this index? 941 v8::Handle<v8::Integer> integer = v8::Integer::New(info.GetIsolate(), i); 942 properties->Set(integer, integer); 943 } 944 v8SetReturnValue(info, properties); 945} 946 947// These methods store hidden values into an array that is stored in the internal field of a DOM wrapper. 948void addHiddenValueToArray(v8::Handle<v8::Object>, v8::Local<v8::Value>, int cacheIndex, v8::Isolate*); 949void removeHiddenValueFromArray(v8::Handle<v8::Object>, v8::Local<v8::Value>, int cacheIndex, v8::Isolate*); 950void moveEventListenerToNewWrapper(v8::Handle<v8::Object>, EventListener* oldValue, v8::Local<v8::Value> newValue, int cacheIndex, v8::Isolate*); 951 952PassRefPtr<JSONValue> v8ToJSONValue(v8::Isolate*, v8::Handle<v8::Value>, int); 953 954// Result values for platform object 'deleter' methods, 955// http://www.w3.org/TR/WebIDL/#delete 956enum DeleteResult { 957 DeleteSuccess, 958 DeleteReject, 959 DeleteUnknownProperty 960}; 961 962class V8IsolateInterruptor : public ThreadState::Interruptor { 963public: 964 explicit V8IsolateInterruptor(v8::Isolate* isolate) : m_isolate(isolate) { } 965 966 static void onInterruptCallback(v8::Isolate* isolate, void* data) 967 { 968 reinterpret_cast<V8IsolateInterruptor*>(data)->onInterrupted(); 969 } 970 971 virtual void requestInterrupt() OVERRIDE 972 { 973 m_isolate->RequestInterrupt(&onInterruptCallback, this); 974 } 975 976 virtual void clearInterrupt() OVERRIDE 977 { 978 m_isolate->ClearInterrupt(); 979 } 980 981private: 982 v8::Isolate* m_isolate; 983}; 984 985class V8TestingScope { 986public: 987 explicit V8TestingScope(v8::Isolate*); 988 ScriptState* scriptState() const; 989 v8::Isolate* isolate() const; 990 ~V8TestingScope(); 991 992private: 993 v8::HandleScope m_handleScope; 994 v8::Context::Scope m_contextScope; 995 RefPtr<ScriptState> m_scriptState; 996}; 997 998void GetDevToolsFunctionInfo(v8::Handle<v8::Function>, v8::Isolate*, int& scriptId, String& resourceName, int& lineNumber); 999PassRefPtr<TraceEvent::ConvertableToTraceFormat> devToolsTraceEventData(ExecutionContext*, v8::Handle<v8::Function>, v8::Isolate*); 1000 1001class V8RethrowTryCatchScope FINAL { 1002public: 1003 explicit V8RethrowTryCatchScope(v8::TryCatch& block) : m_block(block) { } 1004 ~V8RethrowTryCatchScope() 1005 { 1006 // ReThrow() is a no-op if no exception has been caught, so always call. 1007 m_block.ReThrow(); 1008 } 1009 1010private: 1011 v8::TryCatch& m_block; 1012}; 1013 1014// Returns an object representing {done: true, value: undefined}. 1015v8::Local<v8::Value> v8DoneIteratorResult(v8::Isolate*); 1016 1017// Returns an object representing {done: false, value: |value|}. 1018v8::Local<v8::Value> v8IteratorResult(v8::Isolate*, v8::Handle<v8::Value>); 1019template <typename T> 1020v8::Local<v8::Value> v8IteratorResult(ScriptState* scriptState, const T& value) 1021{ 1022 return v8IteratorResult(scriptState->isolate(), V8ValueTraits<T>::toV8Value(value, scriptState->context()->Global(), scriptState->isolate())); 1023} 1024 1025} // namespace blink 1026 1027#endif // V8Binding_h 1028