Home | History | Annotate | Download | only in v8
      1 /*
      2  * Copyright (C) 2006, 2007, 2008, 2009 Google Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions are
      6  * met:
      7  *
      8  *     * Redistributions of source code must retain the above copyright
      9  * notice, this list of conditions and the following disclaimer.
     10  *     * Redistributions in binary form must reproduce the above
     11  * copyright notice, this list of conditions and the following disclaimer
     12  * in the documentation and/or other materials provided with the
     13  * distribution.
     14  *     * Neither the name of Google Inc. nor the names of its
     15  * contributors may be used to endorse or promote products derived from
     16  * this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "config.h"
     32 #include "bindings/v8/V8Binding.h"
     33 
     34 #include "bindings/core/v8/V8Element.h"
     35 #include "bindings/core/v8/V8NodeFilter.h"
     36 #include "bindings/core/v8/V8Window.h"
     37 #include "bindings/core/v8/V8WorkerGlobalScope.h"
     38 #include "bindings/core/v8/V8XPathNSResolver.h"
     39 #include "bindings/v8/ScriptController.h"
     40 #include "bindings/v8/V8AbstractEventListener.h"
     41 #include "bindings/v8/V8BindingMacros.h"
     42 #include "bindings/v8/V8NodeFilterCondition.h"
     43 #include "bindings/v8/V8ObjectConstructor.h"
     44 #include "bindings/v8/V8WindowShell.h"
     45 #include "bindings/v8/WorkerScriptController.h"
     46 #include "bindings/v8/custom/V8CustomXPathNSResolver.h"
     47 #include "core/dom/Element.h"
     48 #include "core/dom/NodeFilter.h"
     49 #include "core/dom/QualifiedName.h"
     50 #include "core/frame/LocalFrame.h"
     51 #include "core/frame/Settings.h"
     52 #include "core/inspector/BindingVisitors.h"
     53 #include "core/inspector/InspectorTraceEvents.h"
     54 #include "core/loader/FrameLoader.h"
     55 #include "core/loader/FrameLoaderClient.h"
     56 #include "core/workers/WorkerGlobalScope.h"
     57 #include "core/xml/XPathNSResolver.h"
     58 #include "platform/EventTracer.h"
     59 #include "platform/JSONValues.h"
     60 #include "wtf/ArrayBufferContents.h"
     61 #include "wtf/MainThread.h"
     62 #include "wtf/MathExtras.h"
     63 #include "wtf/StdLibExtras.h"
     64 #include "wtf/Threading.h"
     65 #include "wtf/text/AtomicString.h"
     66 #include "wtf/text/CString.h"
     67 #include "wtf/text/StringBuffer.h"
     68 #include "wtf/text/StringHash.h"
     69 #include "wtf/text/WTFString.h"
     70 #include "wtf/unicode/CharacterNames.h"
     71 #include "wtf/unicode/Unicode.h"
     72 
     73 namespace WebCore {
     74 
     75 v8::Handle<v8::Value> throwError(V8ErrorType errorType, const String& message, v8::Isolate* isolate)
     76 {
     77     return V8ThrowException::throwError(errorType, message, isolate);
     78 }
     79 
     80 v8::Handle<v8::Value> throwError(v8::Handle<v8::Value> exception, v8::Isolate* isolate)
     81 {
     82     return V8ThrowException::throwError(exception, isolate);
     83 }
     84 
     85 v8::Handle<v8::Value> throwTypeError(const String& message, v8::Isolate* isolate)
     86 {
     87     return V8ThrowException::throwTypeError(message, isolate);
     88 }
     89 
     90 void throwArityTypeErrorForMethod(const char* method, const char* type, const char* valid, unsigned provided, v8::Isolate* isolate)
     91 {
     92     throwTypeError(ExceptionMessages::failedToExecute(method, type, ExceptionMessages::invalidArity(valid, provided)), isolate);
     93 }
     94 
     95 void throwArityTypeErrorForConstructor(const char* type, const char* valid, unsigned provided, v8::Isolate* isolate)
     96 {
     97     throwTypeError(ExceptionMessages::failedToConstruct(type, ExceptionMessages::invalidArity(valid, provided)), isolate);
     98 }
     99 
    100 void throwArityTypeError(ExceptionState& exceptionState, const char* valid, unsigned provided)
    101 {
    102     exceptionState.throwTypeError(ExceptionMessages::invalidArity(valid, provided));
    103     exceptionState.throwIfNeeded();
    104 }
    105 
    106 void throwMinimumArityTypeErrorForMethod(const char* method, const char* type, unsigned expected, unsigned providedLeastNumMandatoryParams, v8::Isolate* isolate)
    107 {
    108     throwTypeError(ExceptionMessages::failedToExecute(method, type, ExceptionMessages::notEnoughArguments(expected, providedLeastNumMandatoryParams)), isolate);
    109 }
    110 
    111 void throwMinimumArityTypeErrorForConstructor(const char* type, unsigned expected, unsigned providedLeastNumMandatoryParams, v8::Isolate* isolate)
    112 {
    113     throwTypeError(ExceptionMessages::failedToConstruct(type, ExceptionMessages::notEnoughArguments(expected, providedLeastNumMandatoryParams)), isolate);
    114 }
    115 
    116 void throwMinimumArityTypeError(ExceptionState& exceptionState, unsigned expected, unsigned providedLeastNumMandatoryParams)
    117 {
    118     exceptionState.throwTypeError(ExceptionMessages::notEnoughArguments(expected, providedLeastNumMandatoryParams));
    119     exceptionState.throwIfNeeded();
    120 }
    121 
    122 class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator {
    123     virtual void* Allocate(size_t size) OVERRIDE
    124     {
    125         void* data;
    126         WTF::ArrayBufferContents::allocateMemory(size, WTF::ArrayBufferContents::ZeroInitialize, data);
    127         return data;
    128     }
    129 
    130     virtual void* AllocateUninitialized(size_t size) OVERRIDE
    131     {
    132         void* data;
    133         WTF::ArrayBufferContents::allocateMemory(size, WTF::ArrayBufferContents::DontInitialize, data);
    134         return data;
    135     }
    136 
    137     virtual void Free(void* data, size_t size) OVERRIDE
    138     {
    139         WTF::ArrayBufferContents::freeMemory(data, size);
    140     }
    141 };
    142 
    143 v8::ArrayBuffer::Allocator* v8ArrayBufferAllocator()
    144 {
    145     DEFINE_STATIC_LOCAL(ArrayBufferAllocator, arrayBufferAllocator, ());
    146     return &arrayBufferAllocator;
    147 }
    148 
    149 PassRefPtrWillBeRawPtr<NodeFilter> toNodeFilter(v8::Handle<v8::Value> callback, v8::Handle<v8::Object> creationContext, ScriptState* scriptState)
    150 {
    151     RefPtrWillBeRawPtr<NodeFilter> filter = NodeFilter::create();
    152 
    153     v8::Handle<v8::Object> filterWrapper = toV8(filter, creationContext, scriptState->isolate()).As<v8::Object>();
    154 
    155     RefPtrWillBeRawPtr<NodeFilterCondition> condition = V8NodeFilterCondition::create(callback, filterWrapper, scriptState);
    156     filter->setCondition(condition.release());
    157 
    158     return filter.release();
    159 }
    160 
    161 const int32_t kMaxInt32 = 0x7fffffff;
    162 const int32_t kMinInt32 = -kMaxInt32 - 1;
    163 const uint32_t kMaxUInt32 = 0xffffffff;
    164 const int64_t kJSMaxInteger = 0x20000000000000LL - 1; // 2^53 - 1, maximum uniquely representable integer in ECMAScript.
    165 
    166 static double enforceRange(double x, double minimum, double maximum, const char* typeName, ExceptionState& exceptionState)
    167 {
    168     if (std::isnan(x) || std::isinf(x)) {
    169         exceptionState.throwTypeError("Value is" + String(std::isinf(x) ? " infinite and" : "") + " not of type '" + String(typeName) + "'.");
    170         return 0;
    171     }
    172     x = trunc(x);
    173     if (x < minimum || x > maximum) {
    174         exceptionState.throwTypeError("Value is outside the '" + String(typeName) + "' value range.");
    175         return 0;
    176     }
    177     return x;
    178 }
    179 
    180 template <typename T>
    181 struct IntTypeLimits {
    182 };
    183 
    184 template <>
    185 struct IntTypeLimits<int8_t> {
    186     static const int8_t minValue = -128;
    187     static const int8_t maxValue = 127;
    188     static const unsigned numberOfValues = 256; // 2^8
    189 };
    190 
    191 template <>
    192 struct IntTypeLimits<uint8_t> {
    193     static const uint8_t maxValue = 255;
    194     static const unsigned numberOfValues = 256; // 2^8
    195 };
    196 
    197 template <>
    198 struct IntTypeLimits<int16_t> {
    199     static const short minValue = -32768;
    200     static const short maxValue = 32767;
    201     static const unsigned numberOfValues = 65536; // 2^16
    202 };
    203 
    204 template <>
    205 struct IntTypeLimits<uint16_t> {
    206     static const unsigned short maxValue = 65535;
    207     static const unsigned numberOfValues = 65536; // 2^16
    208 };
    209 
    210 template <typename T>
    211 static inline T toSmallerInt(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, const char* typeName, ExceptionState& exceptionState)
    212 {
    213     typedef IntTypeLimits<T> LimitsTrait;
    214 
    215     // Fast case. The value is already a 32-bit integer in the right range.
    216     if (value->IsInt32()) {
    217         int32_t result = value->Int32Value();
    218         if (result >= LimitsTrait::minValue && result <= LimitsTrait::maxValue)
    219             return static_cast<T>(result);
    220         if (configuration == EnforceRange) {
    221             exceptionState.throwTypeError("Value is outside the '" + String(typeName) + "' value range.");
    222             return 0;
    223         }
    224         result %= LimitsTrait::numberOfValues;
    225         return static_cast<T>(result > LimitsTrait::maxValue ? result - LimitsTrait::numberOfValues : result);
    226     }
    227 
    228     // Can the value be converted to a number?
    229     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
    230     if (numberObject.IsEmpty()) {
    231         exceptionState.throwTypeError("Not convertible to a number value (of type '" + String(typeName) + "'.");
    232         return 0;
    233     }
    234 
    235     if (configuration == EnforceRange)
    236         return enforceRange(numberObject->Value(), LimitsTrait::minValue, LimitsTrait::maxValue, typeName, exceptionState);
    237 
    238     double numberValue = numberObject->Value();
    239     if (std::isnan(numberValue) || std::isinf(numberValue) || !numberValue)
    240         return 0;
    241 
    242     numberValue = numberValue < 0 ? -floor(fabs(numberValue)) : floor(fabs(numberValue));
    243     numberValue = fmod(numberValue, LimitsTrait::numberOfValues);
    244 
    245     return static_cast<T>(numberValue > LimitsTrait::maxValue ? numberValue - LimitsTrait::numberOfValues : numberValue);
    246 }
    247 
    248 template <typename T>
    249 static inline T toSmallerUInt(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, const char* typeName, ExceptionState& exceptionState)
    250 {
    251     typedef IntTypeLimits<T> LimitsTrait;
    252 
    253     // Fast case. The value is a 32-bit signed integer - possibly positive?
    254     if (value->IsInt32()) {
    255         int32_t result = value->Int32Value();
    256         if (result >= 0 && result <= LimitsTrait::maxValue)
    257             return static_cast<T>(result);
    258         if (configuration == EnforceRange) {
    259             exceptionState.throwTypeError("Value is outside the '" + String(typeName) + "' value range.");
    260             return 0;
    261         }
    262         return static_cast<T>(result);
    263     }
    264 
    265     // Can the value be converted to a number?
    266     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
    267     if (numberObject.IsEmpty()) {
    268         exceptionState.throwTypeError("Not convertible to a number value (of type '" + String(typeName) + "'.");
    269         return 0;
    270     }
    271 
    272     if (configuration == EnforceRange)
    273         return enforceRange(numberObject->Value(), 0, LimitsTrait::maxValue, typeName, exceptionState);
    274 
    275     // Does the value convert to nan or to an infinity?
    276     double numberValue = numberObject->Value();
    277     if (std::isnan(numberValue) || std::isinf(numberValue) || !numberValue)
    278         return 0;
    279 
    280     if (configuration == Clamp)
    281         return clampTo<T>(numberObject->Value());
    282 
    283     numberValue = numberValue < 0 ? -floor(fabs(numberValue)) : floor(fabs(numberValue));
    284     return static_cast<T>(fmod(numberValue, LimitsTrait::numberOfValues));
    285 }
    286 
    287 int8_t toInt8(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
    288 {
    289     return toSmallerInt<int8_t>(value, configuration, "byte", exceptionState);
    290 }
    291 
    292 int8_t toInt8(v8::Handle<v8::Value> value)
    293 {
    294     NonThrowableExceptionState exceptionState;
    295     return toInt8(value, NormalConversion, exceptionState);
    296 }
    297 
    298 uint8_t toUInt8(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
    299 {
    300     return toSmallerUInt<uint8_t>(value, configuration, "octet", exceptionState);
    301 }
    302 
    303 uint8_t toUInt8(v8::Handle<v8::Value> value)
    304 {
    305     NonThrowableExceptionState exceptionState;
    306     return toUInt8(value, NormalConversion, exceptionState);
    307 }
    308 
    309 int16_t toInt16(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
    310 {
    311     return toSmallerInt<int16_t>(value, configuration, "short", exceptionState);
    312 }
    313 
    314 int16_t toInt16(v8::Handle<v8::Value> value)
    315 {
    316     NonThrowableExceptionState exceptionState;
    317     return toInt16(value, NormalConversion, exceptionState);
    318 }
    319 
    320 uint16_t toUInt16(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
    321 {
    322     return toSmallerUInt<uint16_t>(value, configuration, "unsigned short", exceptionState);
    323 }
    324 
    325 uint16_t toUInt16(v8::Handle<v8::Value> value)
    326 {
    327     NonThrowableExceptionState exceptionState;
    328     return toUInt16(value, NormalConversion, exceptionState);
    329 }
    330 
    331 int32_t toInt32(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
    332 {
    333     // Fast case. The value is already a 32-bit integer.
    334     if (value->IsInt32())
    335         return value->Int32Value();
    336 
    337     // Can the value be converted to a number?
    338     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
    339     if (numberObject.IsEmpty()) {
    340         exceptionState.throwTypeError("Not convertible to a number value (of type 'long'.)");
    341         return 0;
    342     }
    343 
    344     if (configuration == EnforceRange)
    345         return enforceRange(numberObject->Value(), kMinInt32, kMaxInt32, "long", exceptionState);
    346 
    347     // Does the value convert to nan or to an infinity?
    348     double numberValue = numberObject->Value();
    349     if (std::isnan(numberValue) || std::isinf(numberValue))
    350         return 0;
    351 
    352     if (configuration == Clamp)
    353         return clampTo<int32_t>(numberObject->Value());
    354 
    355     TONATIVE_DEFAULT_EXCEPTIONSTATE(int32_t, result, numberObject->Int32Value(), exceptionState, 0);
    356     return result;
    357 }
    358 
    359 int32_t toInt32(v8::Handle<v8::Value> value)
    360 {
    361     NonThrowableExceptionState exceptionState;
    362     return toInt32(value, NormalConversion, exceptionState);
    363 }
    364 
    365 uint32_t toUInt32(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
    366 {
    367     // Fast case. The value is already a 32-bit unsigned integer.
    368     if (value->IsUint32())
    369         return value->Uint32Value();
    370 
    371     // Fast case. The value is a 32-bit signed integer - possibly positive?
    372     if (value->IsInt32()) {
    373         int32_t result = value->Int32Value();
    374         if (result >= 0)
    375             return result;
    376         if (configuration == EnforceRange) {
    377             exceptionState.throwTypeError("Value is outside the 'unsigned long' value range.");
    378             return 0;
    379         }
    380         return result;
    381     }
    382 
    383     // Can the value be converted to a number?
    384     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
    385     if (numberObject.IsEmpty()) {
    386         exceptionState.throwTypeError("Not convertible to a number value (of type 'unsigned long'.)");
    387         return 0;
    388     }
    389 
    390     if (configuration == EnforceRange)
    391         return enforceRange(numberObject->Value(), 0, kMaxUInt32, "unsigned long", exceptionState);
    392 
    393     // Does the value convert to nan or to an infinity?
    394     double numberValue = numberObject->Value();
    395     if (std::isnan(numberValue) || std::isinf(numberValue))
    396         return 0;
    397 
    398     if (configuration == Clamp)
    399         return clampTo<uint32_t>(numberObject->Value());
    400 
    401     TONATIVE_DEFAULT(uint32_t, result, numberObject->Uint32Value(), 0);
    402     return result;
    403 }
    404 
    405 uint32_t toUInt32(v8::Handle<v8::Value> value)
    406 {
    407     NonThrowableExceptionState exceptionState;
    408     return toUInt32(value, NormalConversion, exceptionState);
    409 }
    410 
    411 int64_t toInt64(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
    412 {
    413     // Fast case. The value is a 32-bit integer.
    414     if (value->IsInt32())
    415         return value->Int32Value();
    416 
    417     // Can the value be converted to a number?
    418     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
    419     if (numberObject.IsEmpty()) {
    420         exceptionState.throwTypeError("Not convertible to a number value (of type 'long long'.)");
    421         return 0;
    422     }
    423 
    424     double x = numberObject->Value();
    425 
    426     if (configuration == EnforceRange)
    427         return enforceRange(x, -kJSMaxInteger, kJSMaxInteger, "long long", exceptionState);
    428 
    429     // Does the value convert to nan or to an infinity?
    430     if (std::isnan(x) || std::isinf(x))
    431         return 0;
    432 
    433     // NaNs and +/-Infinity should be 0, otherwise modulo 2^64.
    434     unsigned long long integer;
    435     doubleToInteger(x, integer);
    436     return integer;
    437 }
    438 
    439 int64_t toInt64(v8::Handle<v8::Value> value)
    440 {
    441     NonThrowableExceptionState exceptionState;
    442     return toInt64(value, NormalConversion, exceptionState);
    443 }
    444 
    445 uint64_t toUInt64(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, ExceptionState& exceptionState)
    446 {
    447     // Fast case. The value is a 32-bit unsigned integer.
    448     if (value->IsUint32())
    449         return value->Uint32Value();
    450 
    451     // Fast case. The value is a 32-bit integer.
    452     if (value->IsInt32()) {
    453         int32_t result = value->Int32Value();
    454         if (result >= 0)
    455             return result;
    456         if (configuration == EnforceRange) {
    457             exceptionState.throwTypeError("Value is outside the 'unsigned long long' value range.");
    458             return 0;
    459         }
    460         return result;
    461     }
    462 
    463     // Can the value be converted to a number?
    464     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
    465     if (numberObject.IsEmpty()) {
    466         exceptionState.throwTypeError("Not convertible to a number value (of type 'unsigned long long'.)");
    467         return 0;
    468     }
    469 
    470     double x = numberObject->Value();
    471 
    472     if (configuration == EnforceRange)
    473         return enforceRange(x, 0, kJSMaxInteger, "unsigned long long", exceptionState);
    474 
    475     // Does the value convert to nan or to an infinity?
    476     if (std::isnan(x) || std::isinf(x))
    477         return 0;
    478 
    479     // NaNs and +/-Infinity should be 0, otherwise modulo 2^64.
    480     unsigned long long integer;
    481     doubleToInteger(x, integer);
    482     return integer;
    483 }
    484 
    485 uint64_t toUInt64(v8::Handle<v8::Value> value)
    486 {
    487     NonThrowableExceptionState exceptionState;
    488     return toUInt64(value, NormalConversion, exceptionState);
    489 }
    490 
    491 float toFloat(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
    492 {
    493     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::Number>, numberObject, value->ToNumber(), exceptionState, 0);
    494     return numberObject->NumberValue();
    495 }
    496 
    497 String toByteString(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
    498 {
    499     // Handle null default value.
    500     if (value.IsEmpty())
    501         return String();
    502 
    503     // From the Web IDL spec: http://heycam.github.io/webidl/#es-ByteString
    504     if (value.IsEmpty())
    505         return String();
    506 
    507     // 1. Let x be ToString(v)
    508     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::String>, stringObject, value->ToString(), exceptionState, String());
    509     String x = toCoreString(stringObject);
    510 
    511     // 2. If the value of any element of x is greater than 255, then throw a TypeError.
    512     if (!x.containsOnlyLatin1()) {
    513         exceptionState.throwTypeError("Value is not a valid ByteString.");
    514         return String();
    515     }
    516 
    517     // 3. Return an IDL ByteString value whose length is the length of x, and where the
    518     // value of each element is the value of the corresponding element of x.
    519     // Blink: A ByteString is simply a String with a range constrained per the above, so
    520     // this is the identity operation.
    521     return x;
    522 }
    523 
    524 static bool hasUnmatchedSurrogates(const String& string)
    525 {
    526     // By definition, 8-bit strings are confined to the Latin-1 code page and
    527     // have no surrogates, matched or otherwise.
    528     if (string.is8Bit())
    529         return false;
    530 
    531     const UChar* characters = string.characters16();
    532     const unsigned length = string.length();
    533 
    534     for (unsigned i = 0; i < length; ++i) {
    535         UChar c = characters[i];
    536         if (U16_IS_SINGLE(c))
    537             continue;
    538         if (U16_IS_TRAIL(c))
    539             return true;
    540         ASSERT(U16_IS_LEAD(c));
    541         if (i == length - 1)
    542             return true;
    543         UChar d = characters[i + 1];
    544         if (!U16_IS_TRAIL(d))
    545             return true;
    546         ++i;
    547     }
    548     return false;
    549 }
    550 
    551 // Replace unmatched surrogates with REPLACEMENT CHARACTER U+FFFD.
    552 static String replaceUnmatchedSurrogates(const String& string)
    553 {
    554     // This roughly implements http://heycam.github.io/webidl/#dfn-obtain-unicode
    555     // but since Blink strings are 16-bits internally, the output is simply
    556     // re-encoded to UTF-16.
    557 
    558     // The concept of surrogate pairs is explained at:
    559     // http://www.unicode.org/versions/Unicode6.2.0/ch03.pdf#G2630
    560 
    561     // Blink-specific optimization to avoid making an unnecessary copy.
    562     if (!hasUnmatchedSurrogates(string))
    563         return string;
    564     ASSERT(!string.is8Bit());
    565 
    566     // 1. Let S be the DOMString value.
    567     const UChar* s = string.characters16();
    568 
    569     // 2. Let n be the length of S.
    570     const unsigned n = string.length();
    571 
    572     // 3. Initialize i to 0.
    573     unsigned i = 0;
    574 
    575     // 4. Initialize U to be an empty sequence of Unicode characters.
    576     StringBuilder u;
    577     u.reserveCapacity(n);
    578 
    579     // 5. While i < n:
    580     while (i < n) {
    581         // 1. Let c be the code unit in S at index i.
    582         UChar c = s[i];
    583         // 2. Depending on the value of c:
    584         if (U16_IS_SINGLE(c)) {
    585             // c < 0xD800 or c > 0xDFFF
    586             // Append to U the Unicode character with code point c.
    587             u.append(c);
    588         } else if (U16_IS_TRAIL(c)) {
    589             // 0xDC00 <= c <= 0xDFFF
    590             // Append to U a U+FFFD REPLACEMENT CHARACTER.
    591             u.append(WTF::Unicode::replacementCharacter);
    592         } else {
    593             // 0xD800 <= c <= 0xDBFF
    594             ASSERT(U16_IS_LEAD(c));
    595             if (i == n - 1) {
    596                 // 1. If i = n1, then append to U a U+FFFD REPLACEMENT CHARACTER.
    597                 u.append(WTF::Unicode::replacementCharacter);
    598             } else {
    599                 // 2. Otherwise, i < n1:
    600                 ASSERT(i < n - 1);
    601                 // ....1. Let d be the code unit in S at index i+1.
    602                 UChar d = s[i + 1];
    603                 if (U16_IS_TRAIL(d)) {
    604                     // 2. If 0xDC00 <= d <= 0xDFFF, then:
    605                     // ..1. Let a be c & 0x3FF.
    606                     // ..2. Let b be d & 0x3FF.
    607                     // ..3. Append to U the Unicode character with code point 2^16+2^10*a+b.
    608                     u.append(U16_GET_SUPPLEMENTARY(c, d));
    609                     // Blink: This is equivalent to u.append(c); u.append(d);
    610                     ++i;
    611                 } else {
    612                     // 3. Otherwise, d < 0xDC00 or d > 0xDFFF. Append to U a U+FFFD REPLACEMENT CHARACTER.
    613                     u.append(WTF::Unicode::replacementCharacter);
    614                 }
    615             }
    616         }
    617         // 3. Set i to i+1.
    618         ++i;
    619     }
    620 
    621     // 6. Return U.
    622     ASSERT(u.length() == string.length());
    623     return u.toString();
    624 }
    625 
    626 String toScalarValueString(v8::Handle<v8::Value> value, ExceptionState& exceptionState)
    627 {
    628     // From the Encoding standard (with a TODO to move to Web IDL):
    629     // http://encoding.spec.whatwg.org/#type-scalarvaluestring
    630     if (value.IsEmpty())
    631         return String();
    632     TONATIVE_DEFAULT_EXCEPTIONSTATE(v8::Local<v8::String>, stringObject, value->ToString(), exceptionState, String());
    633 
    634     // ScalarValueString is identical to DOMString except that "convert a
    635     // DOMString to a sequence of Unicode characters" is used subsequently
    636     // when converting to an IDL value
    637     String x = toCoreString(stringObject);
    638     return replaceUnmatchedSurrogates(x);
    639 }
    640 
    641 PassRefPtrWillBeRawPtr<XPathNSResolver> toXPathNSResolver(v8::Handle<v8::Value> value, v8::Isolate* isolate)
    642 {
    643     RefPtrWillBeRawPtr<XPathNSResolver> resolver = nullptr;
    644     if (V8XPathNSResolver::hasInstance(value, isolate))
    645         resolver = V8XPathNSResolver::toNative(v8::Handle<v8::Object>::Cast(value));
    646     else if (value->IsObject())
    647         resolver = V8CustomXPathNSResolver::create(value->ToObject(), isolate);
    648     return resolver;
    649 }
    650 
    651 LocalDOMWindow* toDOMWindow(v8::Handle<v8::Value> value, v8::Isolate* isolate)
    652 {
    653     if (value.IsEmpty() || !value->IsObject())
    654         return 0;
    655 
    656     v8::Handle<v8::Object> windowWrapper = V8Window::findInstanceInPrototypeChain(v8::Handle<v8::Object>::Cast(value), isolate);
    657     if (!windowWrapper.IsEmpty())
    658         return V8Window::toNative(windowWrapper);
    659     return 0;
    660 }
    661 
    662 LocalDOMWindow* toDOMWindow(v8::Handle<v8::Context> context)
    663 {
    664     if (context.IsEmpty())
    665         return 0;
    666     return toDOMWindow(context->Global(), context->GetIsolate());
    667 }
    668 
    669 LocalDOMWindow* enteredDOMWindow(v8::Isolate* isolate)
    670 {
    671     LocalDOMWindow* window = toDOMWindow(isolate->GetEnteredContext());
    672     if (!window) {
    673         // We don't always have an entered DOM window, for example during microtask callbacks from V8
    674         // (where the entered context may be the DOM-in-JS context). In that case, we fall back
    675         // to the current context.
    676         window = currentDOMWindow(isolate);
    677         ASSERT(window);
    678     }
    679     return window;
    680 }
    681 
    682 LocalDOMWindow* currentDOMWindow(v8::Isolate* isolate)
    683 {
    684     return toDOMWindow(isolate->GetCurrentContext());
    685 }
    686 
    687 LocalDOMWindow* callingDOMWindow(v8::Isolate* isolate)
    688 {
    689     v8::Handle<v8::Context> context = isolate->GetCallingContext();
    690     if (context.IsEmpty()) {
    691         // Unfortunately, when processing script from a plug-in, we might not
    692         // have a calling context. In those cases, we fall back to the
    693         // entered context.
    694         context = isolate->GetEnteredContext();
    695     }
    696     return toDOMWindow(context);
    697 }
    698 
    699 ExecutionContext* toExecutionContext(v8::Handle<v8::Context> context)
    700 {
    701     v8::Handle<v8::Object> global = context->Global();
    702     v8::Handle<v8::Object> windowWrapper = V8Window::findInstanceInPrototypeChain(global, context->GetIsolate());
    703     if (!windowWrapper.IsEmpty())
    704         return V8Window::toNative(windowWrapper)->executionContext();
    705     v8::Handle<v8::Object> workerWrapper = V8WorkerGlobalScope::findInstanceInPrototypeChain(global, context->GetIsolate());
    706     if (!workerWrapper.IsEmpty())
    707         return V8WorkerGlobalScope::toNative(workerWrapper)->executionContext();
    708     // FIXME: Is this line of code reachable?
    709     return 0;
    710 }
    711 
    712 ExecutionContext* currentExecutionContext(v8::Isolate* isolate)
    713 {
    714     return toExecutionContext(isolate->GetCurrentContext());
    715 }
    716 
    717 ExecutionContext* callingExecutionContext(v8::Isolate* isolate)
    718 {
    719     v8::Handle<v8::Context> context = isolate->GetCallingContext();
    720     if (context.IsEmpty()) {
    721         // Unfortunately, when processing script from a plug-in, we might not
    722         // have a calling context. In those cases, we fall back to the
    723         // entered context.
    724         context = isolate->GetEnteredContext();
    725     }
    726     return toExecutionContext(context);
    727 }
    728 
    729 LocalFrame* toFrameIfNotDetached(v8::Handle<v8::Context> context)
    730 {
    731     LocalDOMWindow* window = toDOMWindow(context);
    732     if (window && window->isCurrentlyDisplayedInFrame())
    733         return window->frame();
    734     // We return 0 here because |context| is detached from the LocalFrame. If we
    735     // did return |frame| we could get in trouble because the frame could be
    736     // navigated to another security origin.
    737     return 0;
    738 }
    739 
    740 v8::Local<v8::Context> toV8Context(ExecutionContext* context, DOMWrapperWorld& world)
    741 {
    742     ASSERT(context);
    743     if (context->isDocument()) {
    744         if (LocalFrame* frame = toDocument(context)->frame())
    745             return frame->script().windowShell(world)->context();
    746     } else if (context->isWorkerGlobalScope()) {
    747         if (WorkerScriptController* script = toWorkerGlobalScope(context)->script())
    748             return script->context();
    749     }
    750     return v8::Local<v8::Context>();
    751 }
    752 
    753 v8::Local<v8::Context> toV8Context(LocalFrame* frame, DOMWrapperWorld& world)
    754 {
    755     if (!frame)
    756         return v8::Local<v8::Context>();
    757     v8::Local<v8::Context> context = frame->script().windowShell(world)->context();
    758     if (context.IsEmpty())
    759         return v8::Local<v8::Context>();
    760     LocalFrame* attachedFrame= toFrameIfNotDetached(context);
    761     return frame == attachedFrame ? context : v8::Local<v8::Context>();
    762 }
    763 
    764 v8::Local<v8::Value> handleMaxRecursionDepthExceeded(v8::Isolate* isolate)
    765 {
    766     throwError(v8RangeError, "Maximum call stack size exceeded.", isolate);
    767     return v8::Local<v8::Value>();
    768 }
    769 
    770 void crashIfV8IsDead()
    771 {
    772     if (v8::V8::IsDead()) {
    773         // FIXME: We temporarily deal with V8 internal error situations
    774         // such as out-of-memory by crashing the renderer.
    775         CRASH();
    776     }
    777 }
    778 
    779 v8::Handle<v8::Function> getBoundFunction(v8::Handle<v8::Function> function)
    780 {
    781     v8::Handle<v8::Value> boundFunction = function->GetBoundFunction();
    782     return boundFunction->IsFunction() ? v8::Handle<v8::Function>::Cast(boundFunction) : function;
    783 }
    784 
    785 void addHiddenValueToArray(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int arrayIndex, v8::Isolate* isolate)
    786 {
    787     v8::Local<v8::Value> arrayValue = object->GetInternalField(arrayIndex);
    788     if (arrayValue->IsNull() || arrayValue->IsUndefined()) {
    789         arrayValue = v8::Array::New(isolate);
    790         object->SetInternalField(arrayIndex, arrayValue);
    791     }
    792 
    793     v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(arrayValue);
    794     array->Set(v8::Integer::New(isolate, array->Length()), value);
    795 }
    796 
    797 void removeHiddenValueFromArray(v8::Handle<v8::Object> object, v8::Local<v8::Value> value, int arrayIndex, v8::Isolate* isolate)
    798 {
    799     v8::Local<v8::Value> arrayValue = object->GetInternalField(arrayIndex);
    800     if (!arrayValue->IsArray())
    801         return;
    802     v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(arrayValue);
    803     for (int i = array->Length() - 1; i >= 0; --i) {
    804         v8::Local<v8::Value> item = array->Get(v8::Integer::New(isolate, i));
    805         if (item->StrictEquals(value)) {
    806             array->Delete(i);
    807             return;
    808         }
    809     }
    810 }
    811 
    812 void moveEventListenerToNewWrapper(v8::Handle<v8::Object> object, EventListener* oldValue, v8::Local<v8::Value> newValue, int arrayIndex, v8::Isolate* isolate)
    813 {
    814     if (oldValue) {
    815         V8AbstractEventListener* oldListener = V8AbstractEventListener::cast(oldValue);
    816         if (oldListener) {
    817             v8::Local<v8::Object> oldListenerObject = oldListener->getExistingListenerObject();
    818             if (!oldListenerObject.IsEmpty())
    819                 removeHiddenValueFromArray(object, oldListenerObject, arrayIndex, isolate);
    820         }
    821     }
    822     // Non-callable input is treated as null and ignored
    823     if (newValue->IsFunction())
    824         addHiddenValueToArray(object, newValue, arrayIndex, isolate);
    825 }
    826 
    827 v8::Isolate* toIsolate(ExecutionContext* context)
    828 {
    829     if (context && context->isDocument())
    830         return V8PerIsolateData::mainThreadIsolate();
    831     return v8::Isolate::GetCurrent();
    832 }
    833 
    834 v8::Isolate* toIsolate(LocalFrame* frame)
    835 {
    836     ASSERT(frame);
    837     return frame->script().isolate();
    838 }
    839 
    840 PassRefPtr<JSONValue> v8ToJSONValue(v8::Isolate* isolate, v8::Handle<v8::Value> value, int maxDepth)
    841 {
    842     if (value.IsEmpty()) {
    843         ASSERT_NOT_REACHED();
    844         return nullptr;
    845     }
    846 
    847     if (!maxDepth)
    848         return nullptr;
    849     maxDepth--;
    850 
    851     if (value->IsNull() || value->IsUndefined())
    852         return JSONValue::null();
    853     if (value->IsBoolean())
    854         return JSONBasicValue::create(value->BooleanValue());
    855     if (value->IsNumber())
    856         return JSONBasicValue::create(value->NumberValue());
    857     if (value->IsString())
    858         return JSONString::create(toCoreString(value.As<v8::String>()));
    859     if (value->IsArray()) {
    860         v8::Handle<v8::Array> array = v8::Handle<v8::Array>::Cast(value);
    861         RefPtr<JSONArray> inspectorArray = JSONArray::create();
    862         uint32_t length = array->Length();
    863         for (uint32_t i = 0; i < length; i++) {
    864             v8::Local<v8::Value> value = array->Get(v8::Int32::New(isolate, i));
    865             RefPtr<JSONValue> element = v8ToJSONValue(isolate, value, maxDepth);
    866             if (!element)
    867                 return nullptr;
    868             inspectorArray->pushValue(element);
    869         }
    870         return inspectorArray;
    871     }
    872     if (value->IsObject()) {
    873         RefPtr<JSONObject> jsonObject = JSONObject::create();
    874         v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(value);
    875         v8::Local<v8::Array> propertyNames = object->GetPropertyNames();
    876         uint32_t length = propertyNames->Length();
    877         for (uint32_t i = 0; i < length; i++) {
    878             v8::Local<v8::Value> name = propertyNames->Get(v8::Int32::New(isolate, i));
    879             // FIXME(yurys): v8::Object should support GetOwnPropertyNames
    880             if (name->IsString() && !object->HasRealNamedProperty(v8::Handle<v8::String>::Cast(name)))
    881                 continue;
    882             RefPtr<JSONValue> propertyValue = v8ToJSONValue(isolate, object->Get(name), maxDepth);
    883             if (!propertyValue)
    884                 return nullptr;
    885             TOSTRING_DEFAULT(V8StringResource<WithNullCheck>, nameString, name, nullptr);
    886             jsonObject->setValue(nameString, propertyValue);
    887         }
    888         return jsonObject;
    889     }
    890     ASSERT_NOT_REACHED();
    891     return nullptr;
    892 }
    893 
    894 V8TestingScope::V8TestingScope(v8::Isolate* isolate)
    895     : m_handleScope(isolate)
    896     , m_contextScope(v8::Context::New(isolate))
    897     , m_scriptState(ScriptStateForTesting::create(isolate->GetCurrentContext(), DOMWrapperWorld::create()))
    898 {
    899 }
    900 
    901 V8TestingScope::~V8TestingScope()
    902 {
    903     m_scriptState->disposePerContextData();
    904 }
    905 
    906 ScriptState* V8TestingScope::scriptState() const
    907 {
    908     return m_scriptState.get();
    909 }
    910 
    911 v8::Isolate* V8TestingScope::isolate() const
    912 {
    913     return m_scriptState->isolate();
    914 }
    915 
    916 void GetDevToolsFunctionInfo(v8::Handle<v8::Function> function, v8::Isolate* isolate, int& scriptId, String& resourceName, int& lineNumber)
    917 {
    918     v8::Handle<v8::Function> originalFunction = getBoundFunction(function);
    919     scriptId = originalFunction->ScriptId();
    920     v8::ScriptOrigin origin = originalFunction->GetScriptOrigin();
    921     if (!origin.ResourceName().IsEmpty()) {
    922         resourceName = NativeValueTraits<String>::nativeValue(origin.ResourceName(), isolate);
    923         lineNumber = originalFunction->GetScriptLineNumber() + 1;
    924     }
    925     if (resourceName.isEmpty()) {
    926         resourceName = "undefined";
    927         lineNumber = 1;
    928     }
    929 }
    930 
    931 PassRefPtr<TraceEvent::ConvertableToTraceFormat> devToolsTraceEventData(ExecutionContext* context, v8::Handle<v8::Function> function, v8::Isolate* isolate)
    932 {
    933     int scriptId = 0;
    934     String resourceName;
    935     int lineNumber = 1;
    936     GetDevToolsFunctionInfo(function, isolate, scriptId, resourceName, lineNumber);
    937     return InspectorFunctionCallEvent::data(context, scriptId, resourceName, lineNumber);
    938 }
    939 
    940 } // namespace WebCore
    941