• 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 "V8Binding.h"
33 
34 #include "DOMStringList.h"
35 #include "Element.h"
36 #include "MathExtras.h"
37 #include "PlatformString.h"
38 #include "QualifiedName.h"
39 #include "StdLibExtras.h"
40 #include "Threading.h"
41 #include "V8Element.h"
42 #include "V8Proxy.h"
43 #include <wtf/text/AtomicString.h>
44 #include <wtf/text/CString.h>
45 #include <wtf/text/StringBuffer.h>
46 #include <wtf/text/StringHash.h>
47 
48 namespace WebCore {
49 
50 // WebCoreStringResource is a helper class for v8ExternalString. It is used
51 // to manage the life-cycle of the underlying buffer of the external string.
52 class WebCoreStringResource : public v8::String::ExternalStringResource {
53 public:
WebCoreStringResource(const String & string)54     explicit WebCoreStringResource(const String& string)
55         : m_plainString(string)
56     {
57 #ifndef NDEBUG
58         m_threadId = WTF::currentThread();
59 #endif
60         ASSERT(!string.isNull());
61         v8::V8::AdjustAmountOfExternalAllocatedMemory(2 * string.length());
62     }
63 
WebCoreStringResource(const AtomicString & string)64     explicit WebCoreStringResource(const AtomicString& string)
65         : m_plainString(string.string())
66         , m_atomicString(string)
67     {
68 #ifndef NDEBUG
69         m_threadId = WTF::currentThread();
70 #endif
71         ASSERT(!string.isNull());
72         v8::V8::AdjustAmountOfExternalAllocatedMemory(2 * string.length());
73     }
74 
~WebCoreStringResource()75     virtual ~WebCoreStringResource()
76     {
77 #ifndef NDEBUG
78         ASSERT(m_threadId == WTF::currentThread());
79 #endif
80         int reducedExternalMemory = -2 * m_plainString.length();
81         if (m_plainString.impl() != m_atomicString.impl() && !m_atomicString.isNull())
82             reducedExternalMemory *= 2;
83         v8::V8::AdjustAmountOfExternalAllocatedMemory(reducedExternalMemory);
84     }
85 
data() const86     virtual const uint16_t* data() const
87     {
88         return reinterpret_cast<const uint16_t*>(m_plainString.impl()->characters());
89     }
90 
length() const91     virtual size_t length() const { return m_plainString.impl()->length(); }
92 
webcoreString()93     String webcoreString() { return m_plainString; }
94 
atomicString()95     AtomicString atomicString()
96     {
97 #ifndef NDEBUG
98         ASSERT(m_threadId == WTF::currentThread());
99 #endif
100         if (m_atomicString.isNull()) {
101             m_atomicString = AtomicString(m_plainString);
102             ASSERT(!m_atomicString.isNull());
103             if (m_plainString.impl() != m_atomicString.impl())
104                 v8::V8::AdjustAmountOfExternalAllocatedMemory(2 * m_atomicString.length());
105         }
106         return m_atomicString;
107     }
108 
toStringResource(v8::Handle<v8::String> v8String)109     static WebCoreStringResource* toStringResource(v8::Handle<v8::String> v8String)
110     {
111         return static_cast<WebCoreStringResource*>(v8String->GetExternalStringResource());
112     }
113 
114 private:
115     // A shallow copy of the string. Keeps the string buffer alive until the V8 engine garbage collects it.
116     String m_plainString;
117     // If this string is atomic or has been made atomic earlier the
118     // atomic string is held here. In the case where the string starts
119     // off non-atomic and becomes atomic later it is necessary to keep
120     // the original string alive because v8 may keep derived pointers
121     // into that string.
122     AtomicString m_atomicString;
123 
124 #ifndef NDEBUG
125     WTF::ThreadIdentifier m_threadId;
126 #endif
127 };
128 
v8ValueToWebCoreString(v8::Handle<v8::Value> value)129 String v8ValueToWebCoreString(v8::Handle<v8::Value> value)
130 {
131     if (value->IsString())
132         return v8StringToWebCoreString(v8::Handle<v8::String>::Cast(value));
133     return v8NonStringValueToWebCoreString(value);
134 }
135 
v8ValueToAtomicWebCoreString(v8::Handle<v8::Value> value)136 AtomicString v8ValueToAtomicWebCoreString(v8::Handle<v8::Value> value)
137 {
138     if (value->IsString())
139         return v8StringToAtomicWebCoreString(v8::Handle<v8::String>::Cast(value));
140     return v8NonStringValueToAtomicWebCoreString(value);
141 }
142 
toInt32(v8::Handle<v8::Value> value,bool & ok)143 int toInt32(v8::Handle<v8::Value> value, bool& ok)
144 {
145     ok = true;
146 
147     // Fast case.  The value is already a 32-bit integer.
148     if (value->IsInt32())
149         return value->Int32Value();
150 
151     // Can the value be converted to a number?
152     v8::Local<v8::Number> numberObject = value->ToNumber();
153     if (numberObject.IsEmpty()) {
154         ok = false;
155         return 0;
156     }
157 
158     // Does the value convert to nan or to an infinity?
159     double numberValue = numberObject->Value();
160     if (isnan(numberValue) || isinf(numberValue)) {
161         ok = false;
162         return 0;
163     }
164 
165     // Can the value be converted to a 32-bit integer?
166     v8::Local<v8::Int32> intValue = value->ToInt32();
167     if (intValue.IsEmpty()) {
168         ok = false;
169         return 0;
170     }
171 
172     // Return the result of the int32 conversion.
173     return intValue->Value();
174 }
175 
toUInt32(v8::Handle<v8::Value> value,bool & ok)176 uint32_t toUInt32(v8::Handle<v8::Value> value, bool& ok)
177 {
178     ok = true;
179 
180     // FIXME: there is currently no Value::IsUint32(). This code does
181     // some contortions to avoid silently converting out-of-range
182     // values to uint32_t.
183 
184     // Fast case.  The value is already a 32-bit positive integer.
185     if (value->IsInt32()) {
186         int32_t result = value->Int32Value();
187         if (result >= 0)
188             return result;
189     }
190 
191     // Can the value be converted to a number?
192     v8::Local<v8::Number> numberObject = value->ToNumber();
193     if (numberObject.IsEmpty()) {
194         ok = false;
195         return 0;
196     }
197 
198     // Does the value convert to nan or to an infinity?
199     double numberValue = numberObject->Value();
200     if (isnan(numberValue) || isinf(numberValue)) {
201         ok = false;
202         return 0;
203     }
204 
205     // Can the value be converted to a 32-bit unsigned integer?
206     v8::Local<v8::Uint32> uintValue = value->ToUint32();
207     if (uintValue.IsEmpty()) {
208         ok = false;
209         return 0;
210     }
211 
212     // FIXME: v8::Uint32::Value is not defined!
213     // http://code.google.com/p/v8/issues/detail?id=624
214     v8::Local<v8::Int32> intValue = value->ToInt32();
215     if (intValue.IsEmpty()) {
216         ok = false;
217         return 0;
218     }
219 
220     return static_cast<uint32_t>(intValue->Value());
221 }
222 
toWebCoreString(const v8::Arguments & args,int index)223 String toWebCoreString(const v8::Arguments& args, int index) {
224     return v8ValueToWebCoreString(args[index]);
225 }
226 
227 
toWebCoreStringWithNullCheck(v8::Handle<v8::Value> value)228 String toWebCoreStringWithNullCheck(v8::Handle<v8::Value> value)
229 {
230     if (value->IsNull())
231         return String();
232     return v8ValueToWebCoreString(value);
233 }
234 
toAtomicWebCoreStringWithNullCheck(v8::Handle<v8::Value> value)235 AtomicString toAtomicWebCoreStringWithNullCheck(v8::Handle<v8::Value> value)
236 {
237     if (value->IsNull())
238         return AtomicString();
239     return v8ValueToAtomicWebCoreString(value);
240 }
241 
toWebCoreStringWithNullOrUndefinedCheck(v8::Handle<v8::Value> value)242 String toWebCoreStringWithNullOrUndefinedCheck(v8::Handle<v8::Value> value)
243 {
244     if (value->IsNull() || value->IsUndefined())
245         return String();
246     return toWebCoreString(value);
247 }
248 
isUndefinedOrNull(v8::Handle<v8::Value> value)249 bool isUndefinedOrNull(v8::Handle<v8::Value> value)
250 {
251     return value->IsNull() || value->IsUndefined();
252 }
253 
v8Boolean(bool value)254 v8::Handle<v8::Boolean> v8Boolean(bool value)
255 {
256     return value ? v8::True() : v8::False();
257 }
258 
v8UndetectableString(const String & str)259 v8::Handle<v8::String> v8UndetectableString(const String& str)
260 {
261     return v8::String::NewUndetectable(fromWebCoreString(str), str.length());
262 }
263 
v8StringOrNull(const String & str)264 v8::Handle<v8::Value> v8StringOrNull(const String& str)
265 {
266     return str.isNull() ? v8::Handle<v8::Value>(v8::Null()) : v8::Handle<v8::Value>(v8String(str));
267 }
268 
v8StringOrUndefined(const String & str)269 v8::Handle<v8::Value> v8StringOrUndefined(const String& str)
270 {
271     return str.isNull() ? v8::Handle<v8::Value>(v8::Undefined()) : v8::Handle<v8::Value>(v8String(str));
272 }
273 
v8StringOrFalse(const String & str)274 v8::Handle<v8::Value> v8StringOrFalse(const String& str)
275 {
276     return str.isNull() ? v8::Handle<v8::Value>(v8::False()) : v8::Handle<v8::Value>(v8String(str));
277 }
278 
toWebCoreDate(v8::Handle<v8::Value> object)279 double toWebCoreDate(v8::Handle<v8::Value> object)
280 {
281     return (object->IsDate() || object->IsNumber()) ? object->NumberValue() : std::numeric_limits<double>::quiet_NaN();
282 }
283 
v8DateOrNull(double value)284 v8::Handle<v8::Value> v8DateOrNull(double value)
285 {
286     if (isfinite(value))
287         return v8::Date::New(value);
288     return v8::Null();
289 }
290 
291 template <class S> struct StringTraits
292 {
293     static S fromStringResource(WebCoreStringResource* resource);
294 
295     static S fromV8String(v8::Handle<v8::String> v8String, int length);
296 };
297 
298 template<>
299 struct StringTraits<String>
300 {
fromStringResourceWebCore::StringTraits301     static String fromStringResource(WebCoreStringResource* resource)
302     {
303         return resource->webcoreString();
304     }
305 
fromV8StringWebCore::StringTraits306     static String fromV8String(v8::Handle<v8::String> v8String, int length)
307     {
308         ASSERT(v8String->Length() == length);
309         // NOTE: as of now, String(const UChar*, int) performs String::createUninitialized
310         // anyway, so no need to optimize like we do for AtomicString below.
311         UChar* buffer;
312         String result = String::createUninitialized(length, buffer);
313         v8String->Write(reinterpret_cast<uint16_t*>(buffer), 0, length);
314         return result;
315     }
316 };
317 
318 template<>
319 struct StringTraits<AtomicString>
320 {
fromStringResourceWebCore::StringTraits321     static AtomicString fromStringResource(WebCoreStringResource* resource)
322     {
323         return resource->atomicString();
324     }
325 
fromV8StringWebCore::StringTraits326     static AtomicString fromV8String(v8::Handle<v8::String> v8String, int length)
327     {
328         ASSERT(v8String->Length() == length);
329         static const int inlineBufferSize = 16;
330         if (length <= inlineBufferSize) {
331             UChar inlineBuffer[inlineBufferSize];
332             v8String->Write(reinterpret_cast<uint16_t*>(inlineBuffer), 0, length);
333             return AtomicString(inlineBuffer, length);
334         }
335         UChar* buffer;
336         String tmp = String::createUninitialized(length, buffer);
337         v8String->Write(reinterpret_cast<uint16_t*>(buffer), 0, length);
338         return AtomicString(tmp);
339     }
340 };
341 
342 template <typename StringType>
v8StringToWebCoreString(v8::Handle<v8::String> v8String,ExternalMode external)343 StringType v8StringToWebCoreString(v8::Handle<v8::String> v8String, ExternalMode external)
344 {
345     WebCoreStringResource* stringResource = WebCoreStringResource::toStringResource(v8String);
346     if (stringResource)
347         return StringTraits<StringType>::fromStringResource(stringResource);
348 
349     int length = v8String->Length();
350     if (!length) {
351         // Avoid trying to morph empty strings, as they do not have enough room to contain the external reference.
352         return StringImpl::empty();
353     }
354 
355     StringType result(StringTraits<StringType>::fromV8String(v8String, length));
356 
357     if (external == Externalize && v8String->CanMakeExternal()) {
358         stringResource = new WebCoreStringResource(result);
359         if (!v8String->MakeExternal(stringResource)) {
360             // In case of a failure delete the external resource as it was not used.
361             delete stringResource;
362         }
363     }
364     return result;
365 }
366 
367 // Explicitly instantiate the above template with the expected parameterizations,
368 // to ensure the compiler generates the code; otherwise link errors can result in GCC 4.4.
369 template String v8StringToWebCoreString<String>(v8::Handle<v8::String>, ExternalMode);
370 template AtomicString v8StringToWebCoreString<AtomicString>(v8::Handle<v8::String>, ExternalMode);
371 
372 // Fast but non thread-safe version.
int32ToWebCoreStringFast(int value)373 String int32ToWebCoreStringFast(int value)
374 {
375     // Caching of small strings below is not thread safe: newly constructed AtomicString
376     // are not safely published.
377     ASSERT(WTF::isMainThread());
378 
379     // Most numbers used are <= 100. Even if they aren't used there's very little cost in using the space.
380     const int kLowNumbers = 100;
381     DEFINE_STATIC_LOCAL(Vector<AtomicString>, lowNumbers, (kLowNumbers + 1));
382     String webCoreString;
383     if (0 <= value && value <= kLowNumbers) {
384         webCoreString = lowNumbers[value];
385         if (!webCoreString) {
386             AtomicString valueString = AtomicString(String::number(value));
387             lowNumbers[value] = valueString;
388             webCoreString = valueString;
389         }
390     } else
391         webCoreString = String::number(value);
392     return webCoreString;
393 }
394 
int32ToWebCoreString(int value)395 String int32ToWebCoreString(int value)
396 {
397     // If we are on the main thread (this should always true for non-workers), call the faster one.
398     if (WTF::isMainThread())
399         return int32ToWebCoreStringFast(value);
400     return String::number(value);
401 }
402 
v8NonStringValueToWebCoreString(v8::Handle<v8::Value> object)403 String v8NonStringValueToWebCoreString(v8::Handle<v8::Value> object)
404 {
405     ASSERT(!object->IsString());
406     if (object->IsInt32())
407         return int32ToWebCoreString(object->Int32Value());
408 
409     v8::TryCatch block;
410     v8::Handle<v8::String> v8String = object->ToString();
411     // Handle the case where an exception is thrown as part of invoking toString on the object.
412     if (block.HasCaught()) {
413         throwError(block.Exception());
414         return StringImpl::empty();
415     }
416     // This path is unexpected.  However there is hypothesis that it
417     // might be combination of v8 and v8 bindings bugs.  For now
418     // just bailout as we'll crash if attempt to convert empty handle into a string.
419     if (v8String.IsEmpty()) {
420         ASSERT_NOT_REACHED();
421         return StringImpl::empty();
422     }
423     return v8StringToWebCoreString<String>(v8String, DoNotExternalize);
424 }
425 
v8NonStringValueToAtomicWebCoreString(v8::Handle<v8::Value> object)426 AtomicString v8NonStringValueToAtomicWebCoreString(v8::Handle<v8::Value> object)
427 {
428     ASSERT(!object->IsString());
429     return AtomicString(v8NonStringValueToWebCoreString(object));
430 }
431 
432 static bool stringImplCacheEnabled = false;
433 
enableStringImplCache()434 void enableStringImplCache()
435 {
436     stringImplCacheEnabled = true;
437 }
438 
makeExternalString(const String & string)439 static v8::Local<v8::String> makeExternalString(const String& string)
440 {
441     WebCoreStringResource* stringResource = new WebCoreStringResource(string);
442     v8::Local<v8::String> newString = v8::String::NewExternal(stringResource);
443     if (newString.IsEmpty())
444         delete stringResource;
445 
446     return newString;
447 }
448 
449 typedef HashMap<StringImpl*, v8::String*> StringCache;
450 
getStringCache()451 static StringCache& getStringCache()
452 {
453     ASSERT(WTF::isMainThread());
454     DEFINE_STATIC_LOCAL(StringCache, mainThreadStringCache, ());
455     return mainThreadStringCache;
456 }
457 
cachedStringCallback(v8::Persistent<v8::Value> wrapper,void * parameter)458 static void cachedStringCallback(v8::Persistent<v8::Value> wrapper, void* parameter)
459 {
460     ASSERT(WTF::isMainThread());
461     StringImpl* stringImpl = static_cast<StringImpl*>(parameter);
462     ASSERT(getStringCache().contains(stringImpl));
463     getStringCache().remove(stringImpl);
464     wrapper.Dispose();
465     stringImpl->deref();
466 }
467 
468 RefPtr<StringImpl> lastStringImpl = 0;
469 v8::Persistent<v8::String> lastV8String;
470 
v8ExternalStringSlow(StringImpl * stringImpl)471 v8::Local<v8::String> v8ExternalStringSlow(StringImpl* stringImpl)
472 {
473     if (!stringImpl->length())
474         return v8::String::Empty();
475 
476     if (!stringImplCacheEnabled)
477         return makeExternalString(String(stringImpl));
478 
479     StringCache& stringCache = getStringCache();
480     v8::String* cachedV8String = stringCache.get(stringImpl);
481     if (cachedV8String) {
482         v8::Persistent<v8::String> handle(cachedV8String);
483         if (!handle.IsNearDeath() && !handle.IsEmpty()) {
484             lastStringImpl = stringImpl;
485             lastV8String = handle;
486             return v8::Local<v8::String>::New(handle);
487         }
488     }
489 
490     v8::Local<v8::String> newString = makeExternalString(String(stringImpl));
491     if (newString.IsEmpty())
492         return newString;
493 
494     v8::Persistent<v8::String> wrapper = v8::Persistent<v8::String>::New(newString);
495     if (wrapper.IsEmpty())
496         return newString;
497 
498     stringImpl->ref();
499     wrapper.MakeWeak(stringImpl, cachedStringCallback);
500     stringCache.set(stringImpl, *wrapper);
501 
502     lastStringImpl = stringImpl;
503     lastV8String = wrapper;
504 
505     return newString;
506 }
507 
createRawTemplate()508 v8::Persistent<v8::FunctionTemplate> createRawTemplate()
509 {
510     v8::HandleScope scope;
511     v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(V8Proxy::checkNewLegal);
512     return v8::Persistent<v8::FunctionTemplate>::New(result);
513 }
514 
configureTemplate(v8::Persistent<v8::FunctionTemplate> desc,const char * interfaceName,v8::Persistent<v8::FunctionTemplate> parentClass,int fieldCount,const BatchedAttribute * attributes,size_t attributeCount,const BatchedCallback * callbacks,size_t callbackCount)515 v8::Local<v8::Signature> configureTemplate(v8::Persistent<v8::FunctionTemplate> desc,
516                                            const char *interfaceName,
517                                            v8::Persistent<v8::FunctionTemplate> parentClass,
518                                            int fieldCount,
519                                            const BatchedAttribute* attributes,
520                                            size_t attributeCount,
521                                            const BatchedCallback* callbacks,
522                                            size_t callbackCount)
523 {
524     desc->SetClassName(v8::String::New(interfaceName));
525     v8::Local<v8::ObjectTemplate> instance = desc->InstanceTemplate();
526     instance->SetInternalFieldCount(fieldCount);
527     if (!parentClass.IsEmpty())
528         desc->Inherit(parentClass);
529     if (attributeCount)
530         batchConfigureAttributes(instance, desc->PrototypeTemplate(),
531                                  attributes, attributeCount);
532     v8::Local<v8::Signature> defaultSignature = v8::Signature::New(desc);
533     if (callbackCount)
534         batchConfigureCallbacks(desc->PrototypeTemplate(),
535                                 defaultSignature,
536                                 static_cast<v8::PropertyAttribute>(v8::DontDelete),
537                                 callbacks, callbackCount);
538     return defaultSignature;
539 }
540 
getToStringName()541 v8::Persistent<v8::String> getToStringName()
542 {
543     DEFINE_STATIC_LOCAL(v8::Persistent<v8::String>, value, ());
544     if (value.IsEmpty())
545         value = v8::Persistent<v8::String>::New(v8::String::New("toString"));
546     return value;
547 }
548 
constructorToString(const v8::Arguments & args)549 static v8::Handle<v8::Value> constructorToString(const v8::Arguments& args)
550 {
551     // The DOM constructors' toString functions grab the current toString
552     // for Functions by taking the toString function of itself and then
553     // calling it with the constructor as its receiver. This means that
554     // changes to the Function prototype chain or toString function are
555     // reflected when printing DOM constructors. The only wart is that
556     // changes to a DOM constructor's toString's toString will cause the
557     // toString of the DOM constructor itself to change. This is extremely
558     // obscure and unlikely to be a problem.
559     v8::Handle<v8::Value> value = args.Callee()->Get(getToStringName());
560     if (!value->IsFunction())
561         return v8::String::New("");
562     return v8::Handle<v8::Function>::Cast(value)->Call(args.This(), 0, 0);
563 }
564 
getToStringTemplate()565 v8::Persistent<v8::FunctionTemplate> getToStringTemplate()
566 {
567     DEFINE_STATIC_LOCAL(v8::Persistent<v8::FunctionTemplate>, toStringTemplate, ());
568     if (toStringTemplate.IsEmpty())
569         toStringTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(constructorToString));
570     return toStringTemplate;
571 }
572 
getElementStringAttr(const v8::AccessorInfo & info,const QualifiedName & name)573 v8::Handle<v8::Value> getElementStringAttr(const v8::AccessorInfo& info,
574                                            const QualifiedName& name)
575 {
576     Element* imp = V8Element::toNative(info.Holder());
577     return v8ExternalString(imp->getAttribute(name));
578 }
579 
setElementStringAttr(const v8::AccessorInfo & info,const QualifiedName & name,v8::Local<v8::Value> value)580 void setElementStringAttr(const v8::AccessorInfo& info,
581                           const QualifiedName& name,
582                           v8::Local<v8::Value> value)
583 {
584     Element* imp = V8Element::toNative(info.Holder());
585     AtomicString v = toAtomicWebCoreStringWithNullCheck(value);
586     imp->setAttribute(name, v);
587 }
588 
v8ValueToWebCoreDOMStringList(v8::Handle<v8::Value> value)589 PassRefPtr<DOMStringList> v8ValueToWebCoreDOMStringList(v8::Handle<v8::Value> value)
590 {
591     v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(value));
592     if (!v8Value->IsArray())
593         return 0;
594 
595     RefPtr<DOMStringList> ret = DOMStringList::create();
596     v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
597     for (size_t i = 0; i < v8Array->Length(); ++i) {
598         v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Integer::New(i));
599         ret->append(v8ValueToWebCoreString(indexedValue));
600     }
601     return ret.release();
602 }
603 
604 } // namespace WebCore
605