• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
throwError(V8ErrorType errorType,const String & message,v8::Isolate * isolate)75 v8::Handle<v8::Value> throwError(V8ErrorType errorType, const String& message, v8::Isolate* isolate)
76 {
77     return V8ThrowException::throwError(errorType, message, isolate);
78 }
79 
throwError(v8::Handle<v8::Value> exception,v8::Isolate * isolate)80 v8::Handle<v8::Value> throwError(v8::Handle<v8::Value> exception, v8::Isolate* isolate)
81 {
82     return V8ThrowException::throwError(exception, isolate);
83 }
84 
throwTypeError(const String & message,v8::Isolate * isolate)85 v8::Handle<v8::Value> throwTypeError(const String& message, v8::Isolate* isolate)
86 {
87     return V8ThrowException::throwTypeError(message, isolate);
88 }
89 
throwArityTypeErrorForMethod(const char * method,const char * type,const char * valid,unsigned provided,v8::Isolate * isolate)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 
throwArityTypeErrorForConstructor(const char * type,const char * valid,unsigned provided,v8::Isolate * isolate)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 
throwArityTypeError(ExceptionState & exceptionState,const char * valid,unsigned provided)100 void throwArityTypeError(ExceptionState& exceptionState, const char* valid, unsigned provided)
101 {
102     exceptionState.throwTypeError(ExceptionMessages::invalidArity(valid, provided));
103     exceptionState.throwIfNeeded();
104 }
105 
throwMinimumArityTypeErrorForMethod(const char * method,const char * type,unsigned expected,unsigned providedLeastNumMandatoryParams,v8::Isolate * isolate)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 
throwMinimumArityTypeErrorForConstructor(const char * type,unsigned expected,unsigned providedLeastNumMandatoryParams,v8::Isolate * isolate)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 
throwMinimumArityTypeError(ExceptionState & exceptionState,unsigned expected,unsigned providedLeastNumMandatoryParams)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 {
Allocate(size_t size)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 
AllocateUninitialized(size_t size)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 
Free(void * data,size_t size)137     virtual void Free(void* data, size_t size) OVERRIDE
138     {
139         WTF::ArrayBufferContents::freeMemory(data, size);
140     }
141 };
142 
v8ArrayBufferAllocator()143 v8::ArrayBuffer::Allocator* v8ArrayBufferAllocator()
144 {
145     DEFINE_STATIC_LOCAL(ArrayBufferAllocator, arrayBufferAllocator, ());
146     return &arrayBufferAllocator;
147 }
148 
toNodeFilter(v8::Handle<v8::Value> callback,v8::Handle<v8::Object> creationContext,ScriptState * scriptState)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 
enforceRange(double x,double minimum,double maximum,const char * typeName,ExceptionState & exceptionState)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>
toSmallerInt(v8::Handle<v8::Value> value,IntegerConversionConfiguration configuration,const char * typeName,ExceptionState & exceptionState)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>
toSmallerUInt(v8::Handle<v8::Value> value,IntegerConversionConfiguration configuration,const char * typeName,ExceptionState & exceptionState)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 
toInt8(v8::Handle<v8::Value> value,IntegerConversionConfiguration configuration,ExceptionState & exceptionState)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 
toInt8(v8::Handle<v8::Value> value)292 int8_t toInt8(v8::Handle<v8::Value> value)
293 {
294     NonThrowableExceptionState exceptionState;
295     return toInt8(value, NormalConversion, exceptionState);
296 }
297 
toUInt8(v8::Handle<v8::Value> value,IntegerConversionConfiguration configuration,ExceptionState & exceptionState)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 
toUInt8(v8::Handle<v8::Value> value)303 uint8_t toUInt8(v8::Handle<v8::Value> value)
304 {
305     NonThrowableExceptionState exceptionState;
306     return toUInt8(value, NormalConversion, exceptionState);
307 }
308 
toInt16(v8::Handle<v8::Value> value,IntegerConversionConfiguration configuration,ExceptionState & exceptionState)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 
toInt16(v8::Handle<v8::Value> value)314 int16_t toInt16(v8::Handle<v8::Value> value)
315 {
316     NonThrowableExceptionState exceptionState;
317     return toInt16(value, NormalConversion, exceptionState);
318 }
319 
toUInt16(v8::Handle<v8::Value> value,IntegerConversionConfiguration configuration,ExceptionState & exceptionState)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 
toUInt16(v8::Handle<v8::Value> value)325 uint16_t toUInt16(v8::Handle<v8::Value> value)
326 {
327     NonThrowableExceptionState exceptionState;
328     return toUInt16(value, NormalConversion, exceptionState);
329 }
330 
toInt32(v8::Handle<v8::Value> value,IntegerConversionConfiguration configuration,ExceptionState & exceptionState)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 
toInt32(v8::Handle<v8::Value> value)359 int32_t toInt32(v8::Handle<v8::Value> value)
360 {
361     NonThrowableExceptionState exceptionState;
362     return toInt32(value, NormalConversion, exceptionState);
363 }
364 
toUInt32(v8::Handle<v8::Value> value,IntegerConversionConfiguration configuration,ExceptionState & exceptionState)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 
toUInt32(v8::Handle<v8::Value> value)405 uint32_t toUInt32(v8::Handle<v8::Value> value)
406 {
407     NonThrowableExceptionState exceptionState;
408     return toUInt32(value, NormalConversion, exceptionState);
409 }
410 
toInt64(v8::Handle<v8::Value> value,IntegerConversionConfiguration configuration,ExceptionState & exceptionState)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 
toInt64(v8::Handle<v8::Value> value)439 int64_t toInt64(v8::Handle<v8::Value> value)
440 {
441     NonThrowableExceptionState exceptionState;
442     return toInt64(value, NormalConversion, exceptionState);
443 }
444 
toUInt64(v8::Handle<v8::Value> value,IntegerConversionConfiguration configuration,ExceptionState & exceptionState)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 
toUInt64(v8::Handle<v8::Value> value)485 uint64_t toUInt64(v8::Handle<v8::Value> value)
486 {
487     NonThrowableExceptionState exceptionState;
488     return toUInt64(value, NormalConversion, exceptionState);
489 }
490 
toFloat(v8::Handle<v8::Value> value,ExceptionState & exceptionState)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 
toByteString(v8::Handle<v8::Value> value,ExceptionState & exceptionState)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 
hasUnmatchedSurrogates(const String & string)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.
replaceUnmatchedSurrogates(const String & string)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 = n−1, then append to U a U+FFFD REPLACEMENT CHARACTER.
597                 u.append(WTF::Unicode::replacementCharacter);
598             } else {
599                 // 2. Otherwise, i < n−1:
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 
toScalarValueString(v8::Handle<v8::Value> value,ExceptionState & exceptionState)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 
toXPathNSResolver(v8::Handle<v8::Value> value,v8::Isolate * isolate)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 
toDOMWindow(v8::Handle<v8::Value> value,v8::Isolate * isolate)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 
toDOMWindow(v8::Handle<v8::Context> context)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 
enteredDOMWindow(v8::Isolate * isolate)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 
currentDOMWindow(v8::Isolate * isolate)682 LocalDOMWindow* currentDOMWindow(v8::Isolate* isolate)
683 {
684     return toDOMWindow(isolate->GetCurrentContext());
685 }
686 
callingDOMWindow(v8::Isolate * isolate)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 
toExecutionContext(v8::Handle<v8::Context> context)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 
currentExecutionContext(v8::Isolate * isolate)712 ExecutionContext* currentExecutionContext(v8::Isolate* isolate)
713 {
714     return toExecutionContext(isolate->GetCurrentContext());
715 }
716 
callingExecutionContext(v8::Isolate * isolate)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 
toFrameIfNotDetached(v8::Handle<v8::Context> context)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 
toV8Context(ExecutionContext * context,DOMWrapperWorld & world)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 
toV8Context(LocalFrame * frame,DOMWrapperWorld & world)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 
handleMaxRecursionDepthExceeded(v8::Isolate * isolate)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 
crashIfV8IsDead()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 
getBoundFunction(v8::Handle<v8::Function> function)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 
addHiddenValueToArray(v8::Handle<v8::Object> object,v8::Local<v8::Value> value,int arrayIndex,v8::Isolate * isolate)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 
removeHiddenValueFromArray(v8::Handle<v8::Object> object,v8::Local<v8::Value> value,int arrayIndex,v8::Isolate * isolate)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 
moveEventListenerToNewWrapper(v8::Handle<v8::Object> object,EventListener * oldValue,v8::Local<v8::Value> newValue,int arrayIndex,v8::Isolate * isolate)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 
toIsolate(ExecutionContext * context)827 v8::Isolate* toIsolate(ExecutionContext* context)
828 {
829     if (context && context->isDocument())
830         return V8PerIsolateData::mainThreadIsolate();
831     return v8::Isolate::GetCurrent();
832 }
833 
toIsolate(LocalFrame * frame)834 v8::Isolate* toIsolate(LocalFrame* frame)
835 {
836     ASSERT(frame);
837     return frame->script().isolate();
838 }
839 
v8ToJSONValue(v8::Isolate * isolate,v8::Handle<v8::Value> value,int maxDepth)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 
V8TestingScope(v8::Isolate * isolate)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 
~V8TestingScope()901 V8TestingScope::~V8TestingScope()
902 {
903     m_scriptState->disposePerContextData();
904 }
905 
scriptState() const906 ScriptState* V8TestingScope::scriptState() const
907 {
908     return m_scriptState.get();
909 }
910 
isolate() const911 v8::Isolate* V8TestingScope::isolate() const
912 {
913     return m_scriptState->isolate();
914 }
915 
GetDevToolsFunctionInfo(v8::Handle<v8::Function> function,v8::Isolate * isolate,int & scriptId,String & resourceName,int & lineNumber)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 
devToolsTraceEventData(ExecutionContext * context,v8::Handle<v8::Function> function,v8::Isolate * isolate)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