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 "V8DOMStringList.h" 35 #include "V8Element.h" 36 #include "V8NodeFilter.h" 37 #include "V8Window.h" 38 #include "V8WorkerGlobalScope.h" 39 #include "V8XPathNSResolver.h" 40 #include "bindings/v8/ScriptController.h" 41 #include "bindings/v8/V8NodeFilterCondition.h" 42 #include "bindings/v8/V8ObjectConstructor.h" 43 #include "bindings/v8/V8WindowShell.h" 44 #include "bindings/v8/WorkerScriptController.h" 45 #include "bindings/v8/custom/V8CustomXPathNSResolver.h" 46 #include "core/dom/DOMStringList.h" 47 #include "core/dom/Element.h" 48 #include "core/dom/NodeFilter.h" 49 #include "core/dom/QualifiedName.h" 50 #include "core/inspector/BindingVisitors.h" 51 #include "core/loader/FrameLoader.h" 52 #include "core/loader/FrameLoaderClient.h" 53 #include "core/page/Frame.h" 54 #include "core/page/Settings.h" 55 #include "core/workers/WorkerGlobalScope.h" 56 #include "core/xml/XPathNSResolver.h" 57 #include "wtf/ArrayBufferContents.h" 58 #include "wtf/MainThread.h" 59 #include "wtf/MathExtras.h" 60 #include "wtf/StdLibExtras.h" 61 #include "wtf/Threading.h" 62 #include "wtf/text/AtomicString.h" 63 #include "wtf/text/CString.h" 64 #include "wtf/text/StringBuffer.h" 65 #include "wtf/text/StringHash.h" 66 #include "wtf/text/WTFString.h" 67 68 namespace WebCore { 69 70 v8::Handle<v8::Value> setDOMException(int exceptionCode, v8::Isolate* isolate) 71 { 72 return V8ThrowException::throwDOMException(exceptionCode, isolate); 73 } 74 75 v8::Handle<v8::Value> setDOMException(int exceptionCode, const String& message, v8::Isolate* isolate) 76 { 77 return V8ThrowException::throwDOMException(exceptionCode, message, isolate); 78 } 79 80 v8::Handle<v8::Value> throwError(V8ErrorType errorType, const String& message, v8::Isolate* isolate) 81 { 82 return V8ThrowException::throwError(errorType, message, isolate); 83 } 84 85 v8::Handle<v8::Value> throwError(v8::Handle<v8::Value> exception) 86 { 87 return V8ThrowException::throwError(exception); 88 } 89 90 v8::Handle<v8::Value> throwTypeError(v8::Isolate* isolate) 91 { 92 return V8ThrowException::throwTypeError(String(), isolate); 93 } 94 95 v8::Handle<v8::Value> throwTypeError(const String& message, v8::Isolate* isolate) 96 { 97 return V8ThrowException::throwTypeError(message, isolate); 98 } 99 100 v8::Handle<v8::Value> throwNotEnoughArgumentsError(v8::Isolate* isolate) 101 { 102 return V8ThrowException::throwNotEnoughArgumentsError(isolate); 103 } 104 105 class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { 106 virtual void* Allocate(size_t size) OVERRIDE 107 { 108 void* data; 109 WTF::ArrayBufferContents::allocateMemory(size, WTF::ArrayBufferContents::ZeroInitialize, data); 110 return data; 111 } 112 113 virtual void* AllocateUninitialized(size_t size) OVERRIDE 114 { 115 void* data; 116 WTF::ArrayBufferContents::allocateMemory(size, WTF::ArrayBufferContents::DontInitialize, data); 117 return data; 118 } 119 120 virtual void Free(void*) 121 { 122 IMMEDIATE_CRASH(); 123 } 124 125 virtual void Free(void* data, size_t size) OVERRIDE 126 { 127 WTF::ArrayBufferContents::freeMemory(data, size); 128 } 129 }; 130 131 v8::ArrayBuffer::Allocator* v8ArrayBufferAllocator() 132 { 133 DEFINE_STATIC_LOCAL(ArrayBufferAllocator, arrayBufferAllocator, ()); 134 return &arrayBufferAllocator; 135 } 136 137 138 v8::Handle<v8::Value> v8Array(PassRefPtr<DOMStringList> stringList, v8::Isolate* isolate) 139 { 140 if (!stringList) 141 return v8::Array::New(); 142 v8::Local<v8::Array> result = v8::Array::New(stringList->length()); 143 for (unsigned i = 0; i < stringList->length(); ++i) 144 result->Set(v8::Integer::New(i, isolate), v8String(stringList->item(i), isolate)); 145 return result; 146 } 147 148 Vector<v8::Handle<v8::Value> > toVectorOfArguments(const v8::FunctionCallbackInfo<v8::Value>& args) 149 { 150 Vector<v8::Handle<v8::Value> > result; 151 size_t length = args.Length(); 152 for (size_t i = 0; i < length; ++i) 153 result.append(args[i]); 154 return result; 155 } 156 157 PassRefPtr<NodeFilter> toNodeFilter(v8::Handle<v8::Value> callback, v8::Isolate* isolate) 158 { 159 RefPtr<NodeFilter> filter = NodeFilter::create(); 160 161 // FIXME: Should pass in appropriate creationContext 162 v8::Handle<v8::Object> filterWrapper = toV8(filter, v8::Handle<v8::Object>(), isolate).As<v8::Object>(); 163 164 RefPtr<NodeFilterCondition> condition = V8NodeFilterCondition::create(callback, filterWrapper); 165 filter->setCondition(condition.release()); 166 167 return filter.release(); 168 } 169 170 static const int8_t kMaxInt8 = 127; 171 static const int8_t kMinInt8 = -128; 172 static const uint8_t kMaxUInt8 = 255; 173 const int32_t kMaxInt32 = 0x7fffffff; 174 const int32_t kMinInt32 = -kMaxInt32 - 1; 175 const uint32_t kMaxUInt32 = 0xffffffff; 176 const int64_t kJSMaxInteger = 0x20000000000000LL - 1; // 2^53 - 1, maximum integer exactly representable in ECMAScript. 177 178 static double enforceRange(double x, double minimum, double maximum, bool& ok) 179 { 180 if (std::isnan(x) || std::isinf(x)) { 181 ok = false; 182 return 0; 183 } 184 x = trunc(x); 185 if (x < minimum || x > maximum) { 186 ok = false; 187 return 0; 188 } 189 return x; 190 } 191 192 int8_t toInt8(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok) 193 { 194 ok = true; 195 196 // Fast case. The value is already a 32-bit integer in the right range. 197 if (value->IsInt32()) { 198 int32_t result = value->Int32Value(); 199 if (result >= kMinInt8 && result <= kMaxInt8) 200 return static_cast<int8_t>(result); 201 if (configuration == EnforceRange) { 202 ok = false; 203 return 0; 204 } 205 result %= 256; // 2^8. 206 return static_cast<int8_t>(result > kMaxInt8 ? result - 256 : result); 207 } 208 209 // Can the value be converted to a number? 210 v8::Local<v8::Number> numberObject = value->ToNumber(); 211 if (numberObject.IsEmpty()) { 212 ok = false; 213 return 0; 214 } 215 216 if (configuration == EnforceRange) 217 return enforceRange(numberObject->Value(), kMinInt8, kMaxInt8, ok); 218 219 double numberValue = numberObject->Value(); 220 if (std::isnan(numberValue) || std::isinf(numberValue) || !numberValue) 221 return 0; 222 223 numberValue = numberValue < 0 ? -floor(abs(numberValue)) : floor(abs(numberValue)); 224 numberValue = fmod(numberValue, 256); // 2^8. 225 226 return static_cast<int8_t>(numberValue > kMaxInt8 ? numberValue - 256 : numberValue); 227 } 228 229 uint8_t toUInt8(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok) 230 { 231 ok = true; 232 233 // Fast case. The value is a 32-bit signed integer - possibly positive? 234 if (value->IsInt32()) { 235 int32_t result = value->Int32Value(); 236 if (result >= 0 && result <= kMaxUInt8) 237 return static_cast<uint8_t>(result); 238 if (configuration == EnforceRange) { 239 ok = false; 240 return 0; 241 } 242 // Converting to uint8_t will cause the resulting value to be the value modulo 2^8. 243 return static_cast<uint8_t>(result); 244 } 245 246 // Can the value be converted to a number? 247 v8::Local<v8::Number> numberObject = value->ToNumber(); 248 if (numberObject.IsEmpty()) { 249 ok = false; 250 return 0; 251 } 252 253 if (configuration == EnforceRange) 254 return enforceRange(numberObject->Value(), 0, kMaxUInt8, ok); 255 256 // Does the value convert to nan or to an infinity? 257 double numberValue = numberObject->Value(); 258 if (std::isnan(numberValue) || std::isinf(numberValue) || !numberValue) 259 return 0; 260 261 numberValue = numberValue < 0 ? -floor(abs(numberValue)) : floor(abs(numberValue)); 262 return static_cast<uint8_t>(fmod(numberValue, 256)); // 2^8. 263 } 264 265 int32_t toInt32(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok) 266 { 267 ok = true; 268 269 // Fast case. The value is already a 32-bit integer. 270 if (value->IsInt32()) 271 return value->Int32Value(); 272 273 // Can the value be converted to a number? 274 v8::Local<v8::Number> numberObject = value->ToNumber(); 275 if (numberObject.IsEmpty()) { 276 ok = false; 277 return 0; 278 } 279 280 if (configuration == EnforceRange) 281 return enforceRange(numberObject->Value(), kMinInt32, kMaxInt32, ok); 282 283 // Does the value convert to nan or to an infinity? 284 double numberValue = numberObject->Value(); 285 if (std::isnan(numberValue) || std::isinf(numberValue)) 286 return 0; 287 return numberObject->Int32Value(); 288 } 289 290 uint32_t toUInt32(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok) 291 { 292 ok = true; 293 294 // Fast case. The value is already a 32-bit unsigned integer. 295 if (value->IsUint32()) 296 return value->Uint32Value(); 297 298 // Fast case. The value is a 32-bit signed integer - possibly positive? 299 if (value->IsInt32()) { 300 int32_t result = value->Int32Value(); 301 if (result >= 0) 302 return result; 303 if (configuration == EnforceRange) { 304 ok = false; 305 return 0; 306 } 307 return result; 308 } 309 310 // Can the value be converted to a number? 311 v8::Local<v8::Number> numberObject = value->ToNumber(); 312 if (numberObject.IsEmpty()) { 313 ok = false; 314 return 0; 315 } 316 317 if (configuration == EnforceRange) 318 return enforceRange(numberObject->Value(), 0, kMaxUInt32, ok); 319 320 // Does the value convert to nan or to an infinity? 321 double numberValue = numberObject->Value(); 322 if (std::isnan(numberValue) || std::isinf(numberValue)) 323 return 0; 324 return numberObject->Uint32Value(); 325 } 326 327 int64_t toInt64(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok) 328 { 329 ok = true; 330 331 // Fast case. The value is a 32-bit integer. 332 if (value->IsInt32()) 333 return value->Int32Value(); 334 335 // Can the value be converted to a number? 336 v8::Local<v8::Number> numberObject = value->ToNumber(); 337 if (numberObject.IsEmpty()) { 338 ok = false; 339 return 0; 340 } 341 342 double x = numberObject->Value(); 343 344 if (configuration == EnforceRange) 345 return enforceRange(x, -kJSMaxInteger, kJSMaxInteger, ok); 346 347 // NaNs and +/-Infinity should be 0, otherwise modulo 2^64. 348 unsigned long long integer; 349 doubleToInteger(x, integer); 350 return integer; 351 } 352 353 uint64_t toUInt64(v8::Handle<v8::Value> value, IntegerConversionConfiguration configuration, bool& ok) 354 { 355 ok = true; 356 357 // Fast case. The value is a 32-bit unsigned integer. 358 if (value->IsUint32()) 359 return value->Uint32Value(); 360 361 // Fast case. The value is a 32-bit integer. 362 if (value->IsInt32()) { 363 int32_t result = value->Int32Value(); 364 if (result >= 0) 365 return result; 366 if (configuration == EnforceRange) { 367 ok = false; 368 return 0; 369 } 370 return result; 371 } 372 373 // Can the value be converted to a number? 374 v8::Local<v8::Number> numberObject = value->ToNumber(); 375 if (numberObject.IsEmpty()) { 376 ok = false; 377 return 0; 378 } 379 380 double x = numberObject->Value(); 381 382 if (configuration == EnforceRange) 383 return enforceRange(x, 0, kJSMaxInteger, ok); 384 385 // NaNs and +/-Infinity should be 0, otherwise modulo 2^64. 386 unsigned long long integer; 387 doubleToInteger(x, integer); 388 return integer; 389 } 390 391 v8::Handle<v8::FunctionTemplate> createRawTemplate(v8::Isolate* isolate) 392 { 393 v8::HandleScope scope(isolate); 394 v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(V8ObjectConstructor::isValidConstructorMode); 395 return scope.Close(result); 396 } 397 398 PassRefPtr<DOMStringList> toDOMStringList(v8::Handle<v8::Value> value, v8::Isolate* isolate) 399 { 400 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(value)); 401 402 if (V8DOMStringList::HasInstance(v8Value, isolate, worldType(isolate))) { 403 RefPtr<DOMStringList> ret = V8DOMStringList::toNative(v8::Handle<v8::Object>::Cast(v8Value)); 404 return ret.release(); 405 } 406 407 if (!v8Value->IsArray()) 408 return 0; 409 410 RefPtr<DOMStringList> ret = DOMStringList::create(); 411 v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value); 412 for (size_t i = 0; i < v8Array->Length(); ++i) { 413 v8::Local<v8::Value> indexedValue = v8Array->Get(v8::Integer::New(i, isolate)); 414 ret->append(toWebCoreString(indexedValue)); 415 } 416 return ret.release(); 417 } 418 419 PassRefPtr<XPathNSResolver> toXPathNSResolver(v8::Handle<v8::Value> value, v8::Isolate* isolate) 420 { 421 RefPtr<XPathNSResolver> resolver; 422 if (V8XPathNSResolver::HasInstance(value, isolate, worldType(isolate))) 423 resolver = V8XPathNSResolver::toNative(v8::Handle<v8::Object>::Cast(value)); 424 else if (value->IsObject()) 425 resolver = V8CustomXPathNSResolver::create(value->ToObject(), isolate); 426 return resolver; 427 } 428 429 v8::Handle<v8::Object> toInnerGlobalObject(v8::Handle<v8::Context> context) 430 { 431 return v8::Handle<v8::Object>::Cast(context->Global()->GetPrototype()); 432 } 433 434 DOMWindow* toDOMWindow(v8::Handle<v8::Context> context) 435 { 436 v8::Handle<v8::Object> global = context->Global(); 437 ASSERT(!global.IsEmpty()); 438 v8::Handle<v8::Object> window = global->FindInstanceInPrototypeChain(V8Window::GetTemplate(context->GetIsolate(), MainWorld)); 439 if (!window.IsEmpty()) 440 return V8Window::toNative(window); 441 window = global->FindInstanceInPrototypeChain(V8Window::GetTemplate(context->GetIsolate(), IsolatedWorld)); 442 ASSERT(!window.IsEmpty()); 443 return V8Window::toNative(window); 444 } 445 446 ScriptExecutionContext* toScriptExecutionContext(v8::Handle<v8::Context> context) 447 { 448 v8::Handle<v8::Object> global = context->Global(); 449 v8::Handle<v8::Object> windowWrapper = global->FindInstanceInPrototypeChain(V8Window::GetTemplate(context->GetIsolate(), MainWorld)); 450 if (!windowWrapper.IsEmpty()) 451 return V8Window::toNative(windowWrapper)->scriptExecutionContext(); 452 windowWrapper = global->FindInstanceInPrototypeChain(V8Window::GetTemplate(context->GetIsolate(), IsolatedWorld)); 453 if (!windowWrapper.IsEmpty()) 454 return V8Window::toNative(windowWrapper)->scriptExecutionContext(); 455 v8::Handle<v8::Object> workerWrapper = global->FindInstanceInPrototypeChain(V8WorkerGlobalScope::GetTemplate(context->GetIsolate(), WorkerWorld)); 456 if (!workerWrapper.IsEmpty()) 457 return V8WorkerGlobalScope::toNative(workerWrapper)->scriptExecutionContext(); 458 // FIXME: Is this line of code reachable? 459 return 0; 460 } 461 462 DOMWindow* activeDOMWindow() 463 { 464 v8::Handle<v8::Context> context = v8::Context::GetCalling(); 465 if (context.IsEmpty()) { 466 // Unfortunately, when processing script from a plug-in, we might not 467 // have a calling context. In those cases, we fall back to the 468 // entered context. 469 context = v8::Context::GetEntered(); 470 } 471 return toDOMWindow(context); 472 } 473 474 DOMWindow* firstDOMWindow() 475 { 476 return toDOMWindow(v8::Context::GetEntered()); 477 } 478 479 Document* currentDocument() 480 { 481 return toDOMWindow(v8::Context::GetCurrent())->document(); 482 } 483 484 Frame* toFrameIfNotDetached(v8::Handle<v8::Context> context) 485 { 486 DOMWindow* window = toDOMWindow(context); 487 if (window->isCurrentlyDisplayedInFrame()) 488 return window->frame(); 489 // We return 0 here because |context| is detached from the Frame. If we 490 // did return |frame| we could get in trouble because the frame could be 491 // navigated to another security origin. 492 return 0; 493 } 494 495 v8::Local<v8::Context> toV8Context(ScriptExecutionContext* context, DOMWrapperWorld* world) 496 { 497 if (context->isDocument()) { 498 ASSERT(world); 499 if (Frame* frame = toDocument(context)->frame()) 500 return frame->script()->windowShell(world)->context(); 501 } else if (context->isWorkerGlobalScope()) { 502 ASSERT(!world); 503 if (WorkerScriptController* script = toWorkerGlobalScope(context)->script()) 504 return script->context(); 505 } 506 return v8::Local<v8::Context>(); 507 } 508 509 bool handleOutOfMemory() 510 { 511 v8::Local<v8::Context> context = v8::Context::GetCurrent(); 512 513 if (!context->HasOutOfMemoryException()) 514 return false; 515 516 // Warning, error, disable JS for this frame? 517 Frame* frame = toFrameIfNotDetached(context); 518 if (!frame) 519 return true; 520 521 frame->script()->clearForOutOfMemory(); 522 frame->loader()->client()->didExhaustMemoryAvailableForScript(); 523 524 if (Settings* settings = frame->settings()) 525 settings->setScriptEnabled(false); 526 527 return true; 528 } 529 530 v8::Local<v8::Value> handleMaxRecursionDepthExceeded() 531 { 532 throwError(v8RangeError, "Maximum call stack size exceeded.", v8::Isolate::GetCurrent()); 533 return v8::Local<v8::Value>(); 534 } 535 536 void crashIfV8IsDead() 537 { 538 if (v8::V8::IsDead()) { 539 // FIXME: We temporarily deal with V8 internal error situations 540 // such as out-of-memory by crashing the renderer. 541 CRASH(); 542 } 543 } 544 545 WrapperWorldType worldType(v8::Isolate* isolate) 546 { 547 V8PerIsolateData* data = V8PerIsolateData::from(isolate); 548 if (!data->workerDOMDataStore()) 549 return worldTypeInMainThread(isolate); 550 return WorkerWorld; 551 } 552 553 WrapperWorldType worldTypeInMainThread(v8::Isolate* isolate) 554 { 555 if (!DOMWrapperWorld::isolatedWorldsExist()) 556 return MainWorld; 557 ASSERT(!v8::Context::GetEntered().IsEmpty()); 558 DOMWrapperWorld* isolatedWorld = DOMWrapperWorld::isolatedWorld(v8::Context::GetEntered()); 559 if (isolatedWorld) 560 return IsolatedWorld; 561 return MainWorld; 562 } 563 564 DOMWrapperWorld* isolatedWorldForIsolate(v8::Isolate* isolate) 565 { 566 V8PerIsolateData* data = V8PerIsolateData::from(isolate); 567 if (data->workerDOMDataStore()) 568 return 0; 569 if (!DOMWrapperWorld::isolatedWorldsExist()) 570 return 0; 571 ASSERT(v8::Context::InContext()); 572 return DOMWrapperWorld::isolatedWorld(v8::Context::GetCurrent()); 573 } 574 575 v8::Local<v8::Value> getHiddenValueFromMainWorldWrapper(v8::Isolate* isolate, ScriptWrappable* wrappable, v8::Handle<v8::String> key) 576 { 577 v8::Local<v8::Object> wrapper = wrappable->newLocalWrapper(isolate); 578 return wrapper.IsEmpty() ? v8::Local<v8::Value>() : wrapper->GetHiddenValue(key); 579 } 580 581 } // namespace WebCore 582