test-api.cc revision 3fb3ca8c7ca439d408449a395897395c0faae8d1
1// Copyright 2011 the V8 project authors. All rights reserved. 2// Redistribution and use in source and binary forms, with or without 3// modification, are permitted provided that the following conditions are 4// met: 5// 6// * Redistributions of source code must retain the above copyright 7// notice, this list of conditions and the following disclaimer. 8// * Redistributions in binary form must reproduce the above 9// copyright notice, this list of conditions and the following 10// disclaimer in the documentation and/or other materials provided 11// with the distribution. 12// * Neither the name of Google Inc. nor the names of its 13// contributors may be used to endorse or promote products derived 14// from this software without specific prior written permission. 15// 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28#include <limits.h> 29 30#include "v8.h" 31 32#include "api.h" 33#include "isolate.h" 34#include "compilation-cache.h" 35#include "execution.h" 36#include "snapshot.h" 37#include "platform.h" 38#include "utils.h" 39#include "cctest.h" 40#include "parser.h" 41#include "unicode-inl.h" 42 43static const bool kLogThreading = false; 44 45static bool IsNaN(double x) { 46#ifdef WIN32 47 return _isnan(x); 48#else 49 return isnan(x); 50#endif 51} 52 53using ::v8::AccessorInfo; 54using ::v8::Arguments; 55using ::v8::Context; 56using ::v8::Extension; 57using ::v8::Function; 58using ::v8::FunctionTemplate; 59using ::v8::Handle; 60using ::v8::HandleScope; 61using ::v8::Local; 62using ::v8::Message; 63using ::v8::MessageCallback; 64using ::v8::Object; 65using ::v8::ObjectTemplate; 66using ::v8::Persistent; 67using ::v8::Script; 68using ::v8::StackTrace; 69using ::v8::String; 70using ::v8::TryCatch; 71using ::v8::Undefined; 72using ::v8::V8; 73using ::v8::Value; 74 75namespace i = ::i; 76 77 78static void ExpectString(const char* code, const char* expected) { 79 Local<Value> result = CompileRun(code); 80 CHECK(result->IsString()); 81 String::AsciiValue ascii(result); 82 CHECK_EQ(expected, *ascii); 83} 84 85 86static void ExpectBoolean(const char* code, bool expected) { 87 Local<Value> result = CompileRun(code); 88 CHECK(result->IsBoolean()); 89 CHECK_EQ(expected, result->BooleanValue()); 90} 91 92 93static void ExpectTrue(const char* code) { 94 ExpectBoolean(code, true); 95} 96 97 98static void ExpectFalse(const char* code) { 99 ExpectBoolean(code, false); 100} 101 102 103static void ExpectObject(const char* code, Local<Value> expected) { 104 Local<Value> result = CompileRun(code); 105 CHECK(result->Equals(expected)); 106} 107 108 109static void ExpectUndefined(const char* code) { 110 Local<Value> result = CompileRun(code); 111 CHECK(result->IsUndefined()); 112} 113 114 115static int signature_callback_count; 116static v8::Handle<Value> IncrementingSignatureCallback( 117 const v8::Arguments& args) { 118 ApiTestFuzzer::Fuzz(); 119 signature_callback_count++; 120 v8::Handle<v8::Array> result = v8::Array::New(args.Length()); 121 for (int i = 0; i < args.Length(); i++) 122 result->Set(v8::Integer::New(i), args[i]); 123 return result; 124} 125 126 127static v8::Handle<Value> SignatureCallback(const v8::Arguments& args) { 128 ApiTestFuzzer::Fuzz(); 129 v8::Handle<v8::Array> result = v8::Array::New(args.Length()); 130 for (int i = 0; i < args.Length(); i++) { 131 result->Set(v8::Integer::New(i), args[i]); 132 } 133 return result; 134} 135 136 137THREADED_TEST(Handles) { 138 v8::HandleScope scope; 139 Local<Context> local_env; 140 { 141 LocalContext env; 142 local_env = env.local(); 143 } 144 145 // Local context should still be live. 146 CHECK(!local_env.IsEmpty()); 147 local_env->Enter(); 148 149 v8::Handle<v8::Primitive> undef = v8::Undefined(); 150 CHECK(!undef.IsEmpty()); 151 CHECK(undef->IsUndefined()); 152 153 const char* c_source = "1 + 2 + 3"; 154 Local<String> source = String::New(c_source); 155 Local<Script> script = Script::Compile(source); 156 CHECK_EQ(6, script->Run()->Int32Value()); 157 158 local_env->Exit(); 159} 160 161 162THREADED_TEST(ReceiverSignature) { 163 v8::HandleScope scope; 164 LocalContext env; 165 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(); 166 v8::Handle<v8::Signature> sig = v8::Signature::New(fun); 167 fun->PrototypeTemplate()->Set( 168 v8_str("m"), 169 v8::FunctionTemplate::New(IncrementingSignatureCallback, 170 v8::Handle<Value>(), 171 sig)); 172 env->Global()->Set(v8_str("Fun"), fun->GetFunction()); 173 signature_callback_count = 0; 174 CompileRun( 175 "var o = new Fun();" 176 "o.m();"); 177 CHECK_EQ(1, signature_callback_count); 178 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(); 179 sub_fun->Inherit(fun); 180 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction()); 181 CompileRun( 182 "var o = new SubFun();" 183 "o.m();"); 184 CHECK_EQ(2, signature_callback_count); 185 186 v8::TryCatch try_catch; 187 CompileRun( 188 "var o = { };" 189 "o.m = Fun.prototype.m;" 190 "o.m();"); 191 CHECK_EQ(2, signature_callback_count); 192 CHECK(try_catch.HasCaught()); 193 try_catch.Reset(); 194 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New(); 195 sub_fun->Inherit(fun); 196 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction()); 197 CompileRun( 198 "var o = new UnrelFun();" 199 "o.m = Fun.prototype.m;" 200 "o.m();"); 201 CHECK_EQ(2, signature_callback_count); 202 CHECK(try_catch.HasCaught()); 203} 204 205 206THREADED_TEST(ArgumentSignature) { 207 v8::HandleScope scope; 208 LocalContext env; 209 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(); 210 cons->SetClassName(v8_str("Cons")); 211 v8::Handle<v8::Signature> sig = 212 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons); 213 v8::Handle<v8::FunctionTemplate> fun = 214 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig); 215 env->Global()->Set(v8_str("Cons"), cons->GetFunction()); 216 env->Global()->Set(v8_str("Fun1"), fun->GetFunction()); 217 218 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';"); 219 CHECK(value1->IsTrue()); 220 221 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';"); 222 CHECK(value2->IsTrue()); 223 224 v8::Handle<Value> value3 = CompileRun("Fun1() == '';"); 225 CHECK(value3->IsTrue()); 226 227 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(); 228 cons1->SetClassName(v8_str("Cons1")); 229 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(); 230 cons2->SetClassName(v8_str("Cons2")); 231 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(); 232 cons3->SetClassName(v8_str("Cons3")); 233 234 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 }; 235 v8::Handle<v8::Signature> wsig = 236 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args); 237 v8::Handle<v8::FunctionTemplate> fun2 = 238 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig); 239 240 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction()); 241 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction()); 242 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction()); 243 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction()); 244 v8::Handle<Value> value4 = CompileRun( 245 "Fun2(new Cons1(), new Cons2(), new Cons3()) ==" 246 "'[object Cons1],[object Cons2],[object Cons3]'"); 247 CHECK(value4->IsTrue()); 248 249 v8::Handle<Value> value5 = CompileRun( 250 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'"); 251 CHECK(value5->IsTrue()); 252 253 v8::Handle<Value> value6 = CompileRun( 254 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'"); 255 CHECK(value6->IsTrue()); 256 257 v8::Handle<Value> value7 = CompileRun( 258 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == " 259 "'[object Cons1],[object Cons2],[object Cons3],d';"); 260 CHECK(value7->IsTrue()); 261 262 v8::Handle<Value> value8 = CompileRun( 263 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'"); 264 CHECK(value8->IsTrue()); 265} 266 267 268THREADED_TEST(HulIgennem) { 269 v8::HandleScope scope; 270 LocalContext env; 271 v8::Handle<v8::Primitive> undef = v8::Undefined(); 272 Local<String> undef_str = undef->ToString(); 273 char* value = i::NewArray<char>(undef_str->Length() + 1); 274 undef_str->WriteAscii(value); 275 CHECK_EQ(0, strcmp(value, "undefined")); 276 i::DeleteArray(value); 277} 278 279 280THREADED_TEST(Access) { 281 v8::HandleScope scope; 282 LocalContext env; 283 Local<v8::Object> obj = v8::Object::New(); 284 Local<Value> foo_before = obj->Get(v8_str("foo")); 285 CHECK(foo_before->IsUndefined()); 286 Local<String> bar_str = v8_str("bar"); 287 obj->Set(v8_str("foo"), bar_str); 288 Local<Value> foo_after = obj->Get(v8_str("foo")); 289 CHECK(!foo_after->IsUndefined()); 290 CHECK(foo_after->IsString()); 291 CHECK_EQ(bar_str, foo_after); 292} 293 294 295THREADED_TEST(AccessElement) { 296 v8::HandleScope scope; 297 LocalContext env; 298 Local<v8::Object> obj = v8::Object::New(); 299 Local<Value> before = obj->Get(1); 300 CHECK(before->IsUndefined()); 301 Local<String> bar_str = v8_str("bar"); 302 obj->Set(1, bar_str); 303 Local<Value> after = obj->Get(1); 304 CHECK(!after->IsUndefined()); 305 CHECK(after->IsString()); 306 CHECK_EQ(bar_str, after); 307 308 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>(); 309 CHECK_EQ(v8_str("a"), value->Get(0)); 310 CHECK_EQ(v8_str("b"), value->Get(1)); 311} 312 313 314THREADED_TEST(Script) { 315 v8::HandleScope scope; 316 LocalContext env; 317 const char* c_source = "1 + 2 + 3"; 318 Local<String> source = String::New(c_source); 319 Local<Script> script = Script::Compile(source); 320 CHECK_EQ(6, script->Run()->Int32Value()); 321} 322 323 324static uint16_t* AsciiToTwoByteString(const char* source) { 325 int array_length = i::StrLength(source) + 1; 326 uint16_t* converted = i::NewArray<uint16_t>(array_length); 327 for (int i = 0; i < array_length; i++) converted[i] = source[i]; 328 return converted; 329} 330 331 332class TestResource: public String::ExternalStringResource { 333 public: 334 static int dispose_count; 335 336 explicit TestResource(uint16_t* data) 337 : data_(data), length_(0) { 338 while (data[length_]) ++length_; 339 } 340 341 ~TestResource() { 342 i::DeleteArray(data_); 343 ++dispose_count; 344 } 345 346 const uint16_t* data() const { 347 return data_; 348 } 349 350 size_t length() const { 351 return length_; 352 } 353 private: 354 uint16_t* data_; 355 size_t length_; 356}; 357 358 359int TestResource::dispose_count = 0; 360 361 362class TestAsciiResource: public String::ExternalAsciiStringResource { 363 public: 364 static int dispose_count; 365 366 explicit TestAsciiResource(const char* data) 367 : data_(data), 368 length_(strlen(data)) { } 369 370 ~TestAsciiResource() { 371 i::DeleteArray(data_); 372 ++dispose_count; 373 } 374 375 const char* data() const { 376 return data_; 377 } 378 379 size_t length() const { 380 return length_; 381 } 382 private: 383 const char* data_; 384 size_t length_; 385}; 386 387 388int TestAsciiResource::dispose_count = 0; 389 390 391THREADED_TEST(ScriptUsingStringResource) { 392 TestResource::dispose_count = 0; 393 const char* c_source = "1 + 2 * 3"; 394 uint16_t* two_byte_source = AsciiToTwoByteString(c_source); 395 { 396 v8::HandleScope scope; 397 LocalContext env; 398 TestResource* resource = new TestResource(two_byte_source); 399 Local<String> source = String::NewExternal(resource); 400 Local<Script> script = Script::Compile(source); 401 Local<Value> value = script->Run(); 402 CHECK(value->IsNumber()); 403 CHECK_EQ(7, value->Int32Value()); 404 CHECK(source->IsExternal()); 405 CHECK_EQ(resource, 406 static_cast<TestResource*>(source->GetExternalStringResource())); 407 HEAP->CollectAllGarbage(false); 408 CHECK_EQ(0, TestResource::dispose_count); 409 } 410 v8::internal::Isolate::Current()->compilation_cache()->Clear(); 411 HEAP->CollectAllGarbage(false); 412 CHECK_EQ(1, TestResource::dispose_count); 413} 414 415 416THREADED_TEST(ScriptUsingAsciiStringResource) { 417 TestAsciiResource::dispose_count = 0; 418 const char* c_source = "1 + 2 * 3"; 419 { 420 v8::HandleScope scope; 421 LocalContext env; 422 Local<String> source = 423 String::NewExternal(new TestAsciiResource(i::StrDup(c_source))); 424 Local<Script> script = Script::Compile(source); 425 Local<Value> value = script->Run(); 426 CHECK(value->IsNumber()); 427 CHECK_EQ(7, value->Int32Value()); 428 HEAP->CollectAllGarbage(false); 429 CHECK_EQ(0, TestAsciiResource::dispose_count); 430 } 431 i::Isolate::Current()->compilation_cache()->Clear(); 432 HEAP->CollectAllGarbage(false); 433 CHECK_EQ(1, TestAsciiResource::dispose_count); 434} 435 436 437THREADED_TEST(ScriptMakingExternalString) { 438 TestResource::dispose_count = 0; 439 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3"); 440 { 441 v8::HandleScope scope; 442 LocalContext env; 443 Local<String> source = String::New(two_byte_source); 444 // Trigger GCs so that the newly allocated string moves to old gen. 445 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now 446 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now 447 bool success = source->MakeExternal(new TestResource(two_byte_source)); 448 CHECK(success); 449 Local<Script> script = Script::Compile(source); 450 Local<Value> value = script->Run(); 451 CHECK(value->IsNumber()); 452 CHECK_EQ(7, value->Int32Value()); 453 HEAP->CollectAllGarbage(false); 454 CHECK_EQ(0, TestResource::dispose_count); 455 } 456 i::Isolate::Current()->compilation_cache()->Clear(); 457 HEAP->CollectAllGarbage(false); 458 CHECK_EQ(1, TestResource::dispose_count); 459} 460 461 462THREADED_TEST(ScriptMakingExternalAsciiString) { 463 TestAsciiResource::dispose_count = 0; 464 const char* c_source = "1 + 2 * 3"; 465 { 466 v8::HandleScope scope; 467 LocalContext env; 468 Local<String> source = v8_str(c_source); 469 // Trigger GCs so that the newly allocated string moves to old gen. 470 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now 471 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now 472 bool success = source->MakeExternal( 473 new TestAsciiResource(i::StrDup(c_source))); 474 CHECK(success); 475 Local<Script> script = Script::Compile(source); 476 Local<Value> value = script->Run(); 477 CHECK(value->IsNumber()); 478 CHECK_EQ(7, value->Int32Value()); 479 HEAP->CollectAllGarbage(false); 480 CHECK_EQ(0, TestAsciiResource::dispose_count); 481 } 482 i::Isolate::Current()->compilation_cache()->Clear(); 483 HEAP->CollectAllGarbage(false); 484 CHECK_EQ(1, TestAsciiResource::dispose_count); 485} 486 487 488TEST(MakingExternalStringConditions) { 489 v8::HandleScope scope; 490 LocalContext env; 491 492 // Free some space in the new space so that we can check freshness. 493 HEAP->CollectGarbage(i::NEW_SPACE); 494 HEAP->CollectGarbage(i::NEW_SPACE); 495 496 uint16_t* two_byte_string = AsciiToTwoByteString("small"); 497 Local<String> small_string = String::New(two_byte_string); 498 i::DeleteArray(two_byte_string); 499 500 // We should refuse to externalize newly created small string. 501 CHECK(!small_string->CanMakeExternal()); 502 // Trigger GCs so that the newly allocated string moves to old gen. 503 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now 504 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now 505 // Old space strings should be accepted. 506 CHECK(small_string->CanMakeExternal()); 507 508 two_byte_string = AsciiToTwoByteString("small 2"); 509 small_string = String::New(two_byte_string); 510 i::DeleteArray(two_byte_string); 511 512 // We should refuse externalizing newly created small string. 513 CHECK(!small_string->CanMakeExternal()); 514 for (int i = 0; i < 100; i++) { 515 String::Value value(small_string); 516 } 517 // Frequently used strings should be accepted. 518 CHECK(small_string->CanMakeExternal()); 519 520 const int buf_size = 10 * 1024; 521 char* buf = i::NewArray<char>(buf_size); 522 memset(buf, 'a', buf_size); 523 buf[buf_size - 1] = '\0'; 524 525 two_byte_string = AsciiToTwoByteString(buf); 526 Local<String> large_string = String::New(two_byte_string); 527 i::DeleteArray(buf); 528 i::DeleteArray(two_byte_string); 529 // Large strings should be immediately accepted. 530 CHECK(large_string->CanMakeExternal()); 531} 532 533 534TEST(MakingExternalAsciiStringConditions) { 535 v8::HandleScope scope; 536 LocalContext env; 537 538 // Free some space in the new space so that we can check freshness. 539 HEAP->CollectGarbage(i::NEW_SPACE); 540 HEAP->CollectGarbage(i::NEW_SPACE); 541 542 Local<String> small_string = String::New("small"); 543 // We should refuse to externalize newly created small string. 544 CHECK(!small_string->CanMakeExternal()); 545 // Trigger GCs so that the newly allocated string moves to old gen. 546 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now 547 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now 548 // Old space strings should be accepted. 549 CHECK(small_string->CanMakeExternal()); 550 551 small_string = String::New("small 2"); 552 // We should refuse externalizing newly created small string. 553 CHECK(!small_string->CanMakeExternal()); 554 for (int i = 0; i < 100; i++) { 555 String::Value value(small_string); 556 } 557 // Frequently used strings should be accepted. 558 CHECK(small_string->CanMakeExternal()); 559 560 const int buf_size = 10 * 1024; 561 char* buf = i::NewArray<char>(buf_size); 562 memset(buf, 'a', buf_size); 563 buf[buf_size - 1] = '\0'; 564 Local<String> large_string = String::New(buf); 565 i::DeleteArray(buf); 566 // Large strings should be immediately accepted. 567 CHECK(large_string->CanMakeExternal()); 568} 569 570 571THREADED_TEST(UsingExternalString) { 572 { 573 v8::HandleScope scope; 574 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 575 Local<String> string = 576 String::NewExternal(new TestResource(two_byte_string)); 577 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 578 // Trigger GCs so that the newly allocated string moves to old gen. 579 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now 580 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now 581 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring); 582 CHECK(isymbol->IsSymbol()); 583 } 584 HEAP->CollectAllGarbage(false); 585 HEAP->CollectAllGarbage(false); 586} 587 588 589THREADED_TEST(UsingExternalAsciiString) { 590 { 591 v8::HandleScope scope; 592 const char* one_byte_string = "test string"; 593 Local<String> string = String::NewExternal( 594 new TestAsciiResource(i::StrDup(one_byte_string))); 595 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 596 // Trigger GCs so that the newly allocated string moves to old gen. 597 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now 598 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now 599 i::Handle<i::String> isymbol = FACTORY->SymbolFromString(istring); 600 CHECK(isymbol->IsSymbol()); 601 } 602 HEAP->CollectAllGarbage(false); 603 HEAP->CollectAllGarbage(false); 604} 605 606 607THREADED_TEST(ScavengeExternalString) { 608 TestResource::dispose_count = 0; 609 bool in_new_space = false; 610 { 611 v8::HandleScope scope; 612 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 613 Local<String> string = 614 String::NewExternal(new TestResource(two_byte_string)); 615 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 616 HEAP->CollectGarbage(i::NEW_SPACE); 617 in_new_space = HEAP->InNewSpace(*istring); 618 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring)); 619 CHECK_EQ(0, TestResource::dispose_count); 620 } 621 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE); 622 CHECK_EQ(1, TestResource::dispose_count); 623} 624 625 626THREADED_TEST(ScavengeExternalAsciiString) { 627 TestAsciiResource::dispose_count = 0; 628 bool in_new_space = false; 629 { 630 v8::HandleScope scope; 631 const char* one_byte_string = "test string"; 632 Local<String> string = String::NewExternal( 633 new TestAsciiResource(i::StrDup(one_byte_string))); 634 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 635 HEAP->CollectGarbage(i::NEW_SPACE); 636 in_new_space = HEAP->InNewSpace(*istring); 637 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring)); 638 CHECK_EQ(0, TestAsciiResource::dispose_count); 639 } 640 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE); 641 CHECK_EQ(1, TestAsciiResource::dispose_count); 642} 643 644 645class TestAsciiResourceWithDisposeControl: public TestAsciiResource { 646 public: 647 static int dispose_calls; 648 649 TestAsciiResourceWithDisposeControl(const char* data, bool dispose) 650 : TestAsciiResource(data), 651 dispose_(dispose) { } 652 653 void Dispose() { 654 ++dispose_calls; 655 if (dispose_) delete this; 656 } 657 private: 658 bool dispose_; 659}; 660 661 662int TestAsciiResourceWithDisposeControl::dispose_calls = 0; 663 664 665TEST(ExternalStringWithDisposeHandling) { 666 const char* c_source = "1 + 2 * 3"; 667 668 // Use a stack allocated external string resource allocated object. 669 TestAsciiResource::dispose_count = 0; 670 TestAsciiResourceWithDisposeControl::dispose_calls = 0; 671 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false); 672 { 673 v8::HandleScope scope; 674 LocalContext env; 675 Local<String> source = String::NewExternal(&res_stack); 676 Local<Script> script = Script::Compile(source); 677 Local<Value> value = script->Run(); 678 CHECK(value->IsNumber()); 679 CHECK_EQ(7, value->Int32Value()); 680 HEAP->CollectAllGarbage(false); 681 CHECK_EQ(0, TestAsciiResource::dispose_count); 682 } 683 i::Isolate::Current()->compilation_cache()->Clear(); 684 HEAP->CollectAllGarbage(false); 685 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls); 686 CHECK_EQ(0, TestAsciiResource::dispose_count); 687 688 // Use a heap allocated external string resource allocated object. 689 TestAsciiResource::dispose_count = 0; 690 TestAsciiResourceWithDisposeControl::dispose_calls = 0; 691 TestAsciiResource* res_heap = 692 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true); 693 { 694 v8::HandleScope scope; 695 LocalContext env; 696 Local<String> source = String::NewExternal(res_heap); 697 Local<Script> script = Script::Compile(source); 698 Local<Value> value = script->Run(); 699 CHECK(value->IsNumber()); 700 CHECK_EQ(7, value->Int32Value()); 701 HEAP->CollectAllGarbage(false); 702 CHECK_EQ(0, TestAsciiResource::dispose_count); 703 } 704 i::Isolate::Current()->compilation_cache()->Clear(); 705 HEAP->CollectAllGarbage(false); 706 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls); 707 CHECK_EQ(1, TestAsciiResource::dispose_count); 708} 709 710 711THREADED_TEST(StringConcat) { 712 { 713 v8::HandleScope scope; 714 LocalContext env; 715 const char* one_byte_string_1 = "function a_times_t"; 716 const char* two_byte_string_1 = "wo_plus_b(a, b) {return "; 717 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + "; 718 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + "; 719 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 720 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 721 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);"; 722 Local<String> left = v8_str(one_byte_string_1); 723 724 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1); 725 Local<String> right = String::New(two_byte_source); 726 i::DeleteArray(two_byte_source); 727 728 Local<String> source = String::Concat(left, right); 729 right = String::NewExternal( 730 new TestAsciiResource(i::StrDup(one_byte_extern_1))); 731 source = String::Concat(source, right); 732 right = String::NewExternal( 733 new TestResource(AsciiToTwoByteString(two_byte_extern_1))); 734 source = String::Concat(source, right); 735 right = v8_str(one_byte_string_2); 736 source = String::Concat(source, right); 737 738 two_byte_source = AsciiToTwoByteString(two_byte_string_2); 739 right = String::New(two_byte_source); 740 i::DeleteArray(two_byte_source); 741 742 source = String::Concat(source, right); 743 right = String::NewExternal( 744 new TestResource(AsciiToTwoByteString(two_byte_extern_2))); 745 source = String::Concat(source, right); 746 Local<Script> script = Script::Compile(source); 747 Local<Value> value = script->Run(); 748 CHECK(value->IsNumber()); 749 CHECK_EQ(68, value->Int32Value()); 750 } 751 i::Isolate::Current()->compilation_cache()->Clear(); 752 HEAP->CollectAllGarbage(false); 753 HEAP->CollectAllGarbage(false); 754} 755 756 757THREADED_TEST(GlobalProperties) { 758 v8::HandleScope scope; 759 LocalContext env; 760 v8::Handle<v8::Object> global = env->Global(); 761 global->Set(v8_str("pi"), v8_num(3.1415926)); 762 Local<Value> pi = global->Get(v8_str("pi")); 763 CHECK_EQ(3.1415926, pi->NumberValue()); 764} 765 766 767static v8::Handle<Value> handle_call(const v8::Arguments& args) { 768 ApiTestFuzzer::Fuzz(); 769 return v8_num(102); 770} 771 772 773static v8::Handle<Value> construct_call(const v8::Arguments& args) { 774 ApiTestFuzzer::Fuzz(); 775 args.This()->Set(v8_str("x"), v8_num(1)); 776 args.This()->Set(v8_str("y"), v8_num(2)); 777 return args.This(); 778} 779 780static v8::Handle<Value> Return239(Local<String> name, const AccessorInfo&) { 781 ApiTestFuzzer::Fuzz(); 782 return v8_num(239); 783} 784 785 786THREADED_TEST(FunctionTemplate) { 787 v8::HandleScope scope; 788 LocalContext env; 789 { 790 Local<v8::FunctionTemplate> fun_templ = 791 v8::FunctionTemplate::New(handle_call); 792 Local<Function> fun = fun_templ->GetFunction(); 793 env->Global()->Set(v8_str("obj"), fun); 794 Local<Script> script = v8_compile("obj()"); 795 CHECK_EQ(102, script->Run()->Int32Value()); 796 } 797 // Use SetCallHandler to initialize a function template, should work like the 798 // previous one. 799 { 800 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 801 fun_templ->SetCallHandler(handle_call); 802 Local<Function> fun = fun_templ->GetFunction(); 803 env->Global()->Set(v8_str("obj"), fun); 804 Local<Script> script = v8_compile("obj()"); 805 CHECK_EQ(102, script->Run()->Int32Value()); 806 } 807 // Test constructor calls. 808 { 809 Local<v8::FunctionTemplate> fun_templ = 810 v8::FunctionTemplate::New(construct_call); 811 fun_templ->SetClassName(v8_str("funky")); 812 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), Return239); 813 Local<Function> fun = fun_templ->GetFunction(); 814 env->Global()->Set(v8_str("obj"), fun); 815 Local<Script> script = v8_compile("var s = new obj(); s.x"); 816 CHECK_EQ(1, script->Run()->Int32Value()); 817 818 Local<Value> result = v8_compile("(new obj()).toString()")->Run(); 819 CHECK_EQ(v8_str("[object funky]"), result); 820 821 result = v8_compile("(new obj()).m")->Run(); 822 CHECK_EQ(239, result->Int32Value()); 823 } 824} 825 826 827static void* expected_ptr; 828static v8::Handle<v8::Value> callback(const v8::Arguments& args) { 829 void* ptr = v8::External::Unwrap(args.Data()); 830 CHECK_EQ(expected_ptr, ptr); 831 return v8::Boolean::New(true); 832} 833 834 835static void TestExternalPointerWrapping() { 836 v8::HandleScope scope; 837 LocalContext env; 838 839 v8::Handle<v8::Value> data = v8::External::Wrap(expected_ptr); 840 841 v8::Handle<v8::Object> obj = v8::Object::New(); 842 obj->Set(v8_str("func"), 843 v8::FunctionTemplate::New(callback, data)->GetFunction()); 844 env->Global()->Set(v8_str("obj"), obj); 845 846 CHECK(CompileRun( 847 "function foo() {\n" 848 " for (var i = 0; i < 13; i++) obj.func();\n" 849 "}\n" 850 "foo(), true")->BooleanValue()); 851} 852 853 854THREADED_TEST(ExternalWrap) { 855 // Check heap allocated object. 856 int* ptr = new int; 857 expected_ptr = ptr; 858 TestExternalPointerWrapping(); 859 delete ptr; 860 861 // Check stack allocated object. 862 int foo; 863 expected_ptr = &foo; 864 TestExternalPointerWrapping(); 865 866 // Check not aligned addresses. 867 const int n = 100; 868 char* s = new char[n]; 869 for (int i = 0; i < n; i++) { 870 expected_ptr = s + i; 871 TestExternalPointerWrapping(); 872 } 873 874 delete[] s; 875 876 // Check several invalid addresses. 877 expected_ptr = reinterpret_cast<void*>(1); 878 TestExternalPointerWrapping(); 879 880 expected_ptr = reinterpret_cast<void*>(0xdeadbeef); 881 TestExternalPointerWrapping(); 882 883 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1); 884 TestExternalPointerWrapping(); 885 886#if defined(V8_HOST_ARCH_X64) 887 // Check a value with a leading 1 bit in x64 Smi encoding. 888 expected_ptr = reinterpret_cast<void*>(0x400000000); 889 TestExternalPointerWrapping(); 890 891 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef); 892 TestExternalPointerWrapping(); 893 894 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1); 895 TestExternalPointerWrapping(); 896#endif 897} 898 899 900THREADED_TEST(FindInstanceInPrototypeChain) { 901 v8::HandleScope scope; 902 LocalContext env; 903 904 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(); 905 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(); 906 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(); 907 derived->Inherit(base); 908 909 Local<v8::Function> base_function = base->GetFunction(); 910 Local<v8::Function> derived_function = derived->GetFunction(); 911 Local<v8::Function> other_function = other->GetFunction(); 912 913 Local<v8::Object> base_instance = base_function->NewInstance(); 914 Local<v8::Object> derived_instance = derived_function->NewInstance(); 915 Local<v8::Object> derived_instance2 = derived_function->NewInstance(); 916 Local<v8::Object> other_instance = other_function->NewInstance(); 917 derived_instance2->Set(v8_str("__proto__"), derived_instance); 918 other_instance->Set(v8_str("__proto__"), derived_instance2); 919 920 // base_instance is only an instance of base. 921 CHECK_EQ(base_instance, 922 base_instance->FindInstanceInPrototypeChain(base)); 923 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty()); 924 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty()); 925 926 // derived_instance is an instance of base and derived. 927 CHECK_EQ(derived_instance, 928 derived_instance->FindInstanceInPrototypeChain(base)); 929 CHECK_EQ(derived_instance, 930 derived_instance->FindInstanceInPrototypeChain(derived)); 931 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty()); 932 933 // other_instance is an instance of other and its immediate 934 // prototype derived_instance2 is an instance of base and derived. 935 // Note, derived_instance is an instance of base and derived too, 936 // but it comes after derived_instance2 in the prototype chain of 937 // other_instance. 938 CHECK_EQ(derived_instance2, 939 other_instance->FindInstanceInPrototypeChain(base)); 940 CHECK_EQ(derived_instance2, 941 other_instance->FindInstanceInPrototypeChain(derived)); 942 CHECK_EQ(other_instance, 943 other_instance->FindInstanceInPrototypeChain(other)); 944} 945 946 947THREADED_TEST(TinyInteger) { 948 v8::HandleScope scope; 949 LocalContext env; 950 int32_t value = 239; 951 Local<v8::Integer> value_obj = v8::Integer::New(value); 952 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 953} 954 955 956THREADED_TEST(BigSmiInteger) { 957 v8::HandleScope scope; 958 LocalContext env; 959 int32_t value = i::Smi::kMaxValue; 960 // We cannot add one to a Smi::kMaxValue without wrapping. 961 if (i::kSmiValueSize < 32) { 962 CHECK(i::Smi::IsValid(value)); 963 CHECK(!i::Smi::IsValid(value + 1)); 964 Local<v8::Integer> value_obj = v8::Integer::New(value); 965 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 966 } 967} 968 969 970THREADED_TEST(BigInteger) { 971 v8::HandleScope scope; 972 LocalContext env; 973 // We cannot add one to a Smi::kMaxValue without wrapping. 974 if (i::kSmiValueSize < 32) { 975 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1. 976 // The code will not be run in that case, due to the "if" guard. 977 int32_t value = 978 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1); 979 CHECK(value > i::Smi::kMaxValue); 980 CHECK(!i::Smi::IsValid(value)); 981 Local<v8::Integer> value_obj = v8::Integer::New(value); 982 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 983 } 984} 985 986 987THREADED_TEST(TinyUnsignedInteger) { 988 v8::HandleScope scope; 989 LocalContext env; 990 uint32_t value = 239; 991 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); 992 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 993} 994 995 996THREADED_TEST(BigUnsignedSmiInteger) { 997 v8::HandleScope scope; 998 LocalContext env; 999 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue); 1000 CHECK(i::Smi::IsValid(value)); 1001 CHECK(!i::Smi::IsValid(value + 1)); 1002 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); 1003 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1004} 1005 1006 1007THREADED_TEST(BigUnsignedInteger) { 1008 v8::HandleScope scope; 1009 LocalContext env; 1010 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1; 1011 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue)); 1012 CHECK(!i::Smi::IsValid(value)); 1013 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); 1014 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1015} 1016 1017 1018THREADED_TEST(OutOfSignedRangeUnsignedInteger) { 1019 v8::HandleScope scope; 1020 LocalContext env; 1021 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1; 1022 uint32_t value = INT32_MAX_AS_UINT + 1; 1023 CHECK(value > INT32_MAX_AS_UINT); // No overflow. 1024 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); 1025 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1026} 1027 1028 1029THREADED_TEST(IsNativeError) { 1030 v8::HandleScope scope; 1031 LocalContext env; 1032 v8::Handle<Value> syntax_error = CompileRun( 1033 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; "); 1034 CHECK(syntax_error->IsNativeError()); 1035 v8::Handle<Value> not_error = CompileRun("{a:42}"); 1036 CHECK(!not_error->IsNativeError()); 1037 v8::Handle<Value> not_object = CompileRun("42"); 1038 CHECK(!not_object->IsNativeError()); 1039} 1040 1041 1042THREADED_TEST(StringObject) { 1043 v8::HandleScope scope; 1044 LocalContext env; 1045 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")"); 1046 CHECK(boxed_string->IsStringObject()); 1047 v8::Handle<Value> unboxed_string = CompileRun("\"test\""); 1048 CHECK(!unboxed_string->IsStringObject()); 1049 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)"); 1050 CHECK(!boxed_not_string->IsStringObject()); 1051 v8::Handle<Value> not_object = CompileRun("0"); 1052 CHECK(!not_object->IsStringObject()); 1053 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>(); 1054 CHECK(!as_boxed.IsEmpty()); 1055 Local<v8::String> the_string = as_boxed->StringValue(); 1056 CHECK(!the_string.IsEmpty()); 1057 ExpectObject("\"test\"", the_string); 1058 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string); 1059 CHECK(new_boxed_string->IsStringObject()); 1060 as_boxed = new_boxed_string.As<v8::StringObject>(); 1061 the_string = as_boxed->StringValue(); 1062 CHECK(!the_string.IsEmpty()); 1063 ExpectObject("\"test\"", the_string); 1064} 1065 1066 1067THREADED_TEST(NumberObject) { 1068 v8::HandleScope scope; 1069 LocalContext env; 1070 v8::Handle<Value> boxed_number = CompileRun("new Number(42)"); 1071 CHECK(boxed_number->IsNumberObject()); 1072 v8::Handle<Value> unboxed_number = CompileRun("42"); 1073 CHECK(!unboxed_number->IsNumberObject()); 1074 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)"); 1075 CHECK(!boxed_not_number->IsNumberObject()); 1076 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>(); 1077 CHECK(!as_boxed.IsEmpty()); 1078 double the_number = as_boxed->NumberValue(); 1079 CHECK_EQ(42.0, the_number); 1080 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43); 1081 CHECK(new_boxed_number->IsNumberObject()); 1082 as_boxed = new_boxed_number.As<v8::NumberObject>(); 1083 the_number = as_boxed->NumberValue(); 1084 CHECK_EQ(43.0, the_number); 1085} 1086 1087 1088THREADED_TEST(BooleanObject) { 1089 v8::HandleScope scope; 1090 LocalContext env; 1091 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)"); 1092 CHECK(boxed_boolean->IsBooleanObject()); 1093 v8::Handle<Value> unboxed_boolean = CompileRun("true"); 1094 CHECK(!unboxed_boolean->IsBooleanObject()); 1095 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)"); 1096 CHECK(!boxed_not_boolean->IsBooleanObject()); 1097 v8::Handle<v8::BooleanObject> as_boxed = 1098 boxed_boolean.As<v8::BooleanObject>(); 1099 CHECK(!as_boxed.IsEmpty()); 1100 bool the_boolean = as_boxed->BooleanValue(); 1101 CHECK_EQ(true, the_boolean); 1102 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true); 1103 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false); 1104 CHECK(boxed_true->IsBooleanObject()); 1105 CHECK(boxed_false->IsBooleanObject()); 1106 as_boxed = boxed_true.As<v8::BooleanObject>(); 1107 CHECK_EQ(true, as_boxed->BooleanValue()); 1108 as_boxed = boxed_false.As<v8::BooleanObject>(); 1109 CHECK_EQ(false, as_boxed->BooleanValue()); 1110} 1111 1112 1113THREADED_TEST(Number) { 1114 v8::HandleScope scope; 1115 LocalContext env; 1116 double PI = 3.1415926; 1117 Local<v8::Number> pi_obj = v8::Number::New(PI); 1118 CHECK_EQ(PI, pi_obj->NumberValue()); 1119} 1120 1121 1122THREADED_TEST(ToNumber) { 1123 v8::HandleScope scope; 1124 LocalContext env; 1125 Local<String> str = v8_str("3.1415926"); 1126 CHECK_EQ(3.1415926, str->NumberValue()); 1127 v8::Handle<v8::Boolean> t = v8::True(); 1128 CHECK_EQ(1.0, t->NumberValue()); 1129 v8::Handle<v8::Boolean> f = v8::False(); 1130 CHECK_EQ(0.0, f->NumberValue()); 1131} 1132 1133 1134THREADED_TEST(Date) { 1135 v8::HandleScope scope; 1136 LocalContext env; 1137 double PI = 3.1415926; 1138 Local<Value> date = v8::Date::New(PI); 1139 CHECK_EQ(3.0, date->NumberValue()); 1140 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42)); 1141 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value()); 1142} 1143 1144 1145THREADED_TEST(Boolean) { 1146 v8::HandleScope scope; 1147 LocalContext env; 1148 v8::Handle<v8::Boolean> t = v8::True(); 1149 CHECK(t->Value()); 1150 v8::Handle<v8::Boolean> f = v8::False(); 1151 CHECK(!f->Value()); 1152 v8::Handle<v8::Primitive> u = v8::Undefined(); 1153 CHECK(!u->BooleanValue()); 1154 v8::Handle<v8::Primitive> n = v8::Null(); 1155 CHECK(!n->BooleanValue()); 1156 v8::Handle<String> str1 = v8_str(""); 1157 CHECK(!str1->BooleanValue()); 1158 v8::Handle<String> str2 = v8_str("x"); 1159 CHECK(str2->BooleanValue()); 1160 CHECK(!v8::Number::New(0)->BooleanValue()); 1161 CHECK(v8::Number::New(-1)->BooleanValue()); 1162 CHECK(v8::Number::New(1)->BooleanValue()); 1163 CHECK(v8::Number::New(42)->BooleanValue()); 1164 CHECK(!v8_compile("NaN")->Run()->BooleanValue()); 1165} 1166 1167 1168static v8::Handle<Value> DummyCallHandler(const v8::Arguments& args) { 1169 ApiTestFuzzer::Fuzz(); 1170 return v8_num(13.4); 1171} 1172 1173 1174static v8::Handle<Value> GetM(Local<String> name, const AccessorInfo&) { 1175 ApiTestFuzzer::Fuzz(); 1176 return v8_num(876); 1177} 1178 1179 1180THREADED_TEST(GlobalPrototype) { 1181 v8::HandleScope scope; 1182 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New(); 1183 func_templ->PrototypeTemplate()->Set( 1184 "dummy", 1185 v8::FunctionTemplate::New(DummyCallHandler)); 1186 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate(); 1187 templ->Set("x", v8_num(200)); 1188 templ->SetAccessor(v8_str("m"), GetM); 1189 LocalContext env(0, templ); 1190 v8::Handle<v8::Object> obj = env->Global(); 1191 v8::Handle<Script> script = v8_compile("dummy()"); 1192 v8::Handle<Value> result = script->Run(); 1193 CHECK_EQ(13.4, result->NumberValue()); 1194 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value()); 1195 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value()); 1196} 1197 1198 1199THREADED_TEST(ObjectTemplate) { 1200 v8::HandleScope scope; 1201 Local<ObjectTemplate> templ1 = ObjectTemplate::New(); 1202 templ1->Set("x", v8_num(10)); 1203 templ1->Set("y", v8_num(13)); 1204 LocalContext env; 1205 Local<v8::Object> instance1 = templ1->NewInstance(); 1206 env->Global()->Set(v8_str("p"), instance1); 1207 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue()); 1208 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue()); 1209 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(); 1210 fun->PrototypeTemplate()->Set("nirk", v8_num(123)); 1211 Local<ObjectTemplate> templ2 = fun->InstanceTemplate(); 1212 templ2->Set("a", v8_num(12)); 1213 templ2->Set("b", templ1); 1214 Local<v8::Object> instance2 = templ2->NewInstance(); 1215 env->Global()->Set(v8_str("q"), instance2); 1216 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue()); 1217 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue()); 1218 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue()); 1219 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue()); 1220} 1221 1222 1223static v8::Handle<Value> GetFlabby(const v8::Arguments& args) { 1224 ApiTestFuzzer::Fuzz(); 1225 return v8_num(17.2); 1226} 1227 1228 1229static v8::Handle<Value> GetKnurd(Local<String> property, const AccessorInfo&) { 1230 ApiTestFuzzer::Fuzz(); 1231 return v8_num(15.2); 1232} 1233 1234 1235THREADED_TEST(DescriptorInheritance) { 1236 v8::HandleScope scope; 1237 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(); 1238 super->PrototypeTemplate()->Set("flabby", 1239 v8::FunctionTemplate::New(GetFlabby)); 1240 super->PrototypeTemplate()->Set("PI", v8_num(3.14)); 1241 1242 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd); 1243 1244 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(); 1245 base1->Inherit(super); 1246 base1->PrototypeTemplate()->Set("v1", v8_num(20.1)); 1247 1248 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(); 1249 base2->Inherit(super); 1250 base2->PrototypeTemplate()->Set("v2", v8_num(10.1)); 1251 1252 LocalContext env; 1253 1254 env->Global()->Set(v8_str("s"), super->GetFunction()); 1255 env->Global()->Set(v8_str("base1"), base1->GetFunction()); 1256 env->Global()->Set(v8_str("base2"), base2->GetFunction()); 1257 1258 // Checks right __proto__ chain. 1259 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue()); 1260 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue()); 1261 1262 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue()); 1263 1264 // Instance accessor should not be visible on function object or its prototype 1265 CHECK(CompileRun("s.knurd == undefined")->BooleanValue()); 1266 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue()); 1267 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue()); 1268 1269 env->Global()->Set(v8_str("obj"), 1270 base1->GetFunction()->NewInstance()); 1271 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue()); 1272 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue()); 1273 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue()); 1274 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue()); 1275 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue()); 1276 1277 env->Global()->Set(v8_str("obj2"), 1278 base2->GetFunction()->NewInstance()); 1279 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue()); 1280 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue()); 1281 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue()); 1282 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue()); 1283 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue()); 1284 1285 // base1 and base2 cannot cross reference to each's prototype 1286 CHECK(v8_compile("obj.v2")->Run()->IsUndefined()); 1287 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined()); 1288} 1289 1290 1291int echo_named_call_count; 1292 1293 1294static v8::Handle<Value> EchoNamedProperty(Local<String> name, 1295 const AccessorInfo& info) { 1296 ApiTestFuzzer::Fuzz(); 1297 CHECK_EQ(v8_str("data"), info.Data()); 1298 echo_named_call_count++; 1299 return name; 1300} 1301 1302 1303THREADED_TEST(NamedPropertyHandlerGetter) { 1304 echo_named_call_count = 0; 1305 v8::HandleScope scope; 1306 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 1307 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty, 1308 0, 0, 0, 0, 1309 v8_str("data")); 1310 LocalContext env; 1311 env->Global()->Set(v8_str("obj"), 1312 templ->GetFunction()->NewInstance()); 1313 CHECK_EQ(echo_named_call_count, 0); 1314 v8_compile("obj.x")->Run(); 1315 CHECK_EQ(echo_named_call_count, 1); 1316 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;"; 1317 v8::Handle<Value> str = CompileRun(code); 1318 String::AsciiValue value(str); 1319 CHECK_EQ(*value, "oddlepoddle"); 1320 // Check default behavior 1321 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10); 1322 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue()); 1323 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue()); 1324} 1325 1326 1327int echo_indexed_call_count = 0; 1328 1329 1330static v8::Handle<Value> EchoIndexedProperty(uint32_t index, 1331 const AccessorInfo& info) { 1332 ApiTestFuzzer::Fuzz(); 1333 CHECK_EQ(v8_num(637), info.Data()); 1334 echo_indexed_call_count++; 1335 return v8_num(index); 1336} 1337 1338 1339THREADED_TEST(IndexedPropertyHandlerGetter) { 1340 v8::HandleScope scope; 1341 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 1342 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty, 1343 0, 0, 0, 0, 1344 v8_num(637)); 1345 LocalContext env; 1346 env->Global()->Set(v8_str("obj"), 1347 templ->GetFunction()->NewInstance()); 1348 Local<Script> script = v8_compile("obj[900]"); 1349 CHECK_EQ(script->Run()->Int32Value(), 900); 1350} 1351 1352 1353v8::Handle<v8::Object> bottom; 1354 1355static v8::Handle<Value> CheckThisIndexedPropertyHandler( 1356 uint32_t index, 1357 const AccessorInfo& info) { 1358 ApiTestFuzzer::Fuzz(); 1359 CHECK(info.This()->Equals(bottom)); 1360 return v8::Handle<Value>(); 1361} 1362 1363static v8::Handle<Value> CheckThisNamedPropertyHandler( 1364 Local<String> name, 1365 const AccessorInfo& info) { 1366 ApiTestFuzzer::Fuzz(); 1367 CHECK(info.This()->Equals(bottom)); 1368 return v8::Handle<Value>(); 1369} 1370 1371 1372v8::Handle<Value> CheckThisIndexedPropertySetter(uint32_t index, 1373 Local<Value> value, 1374 const AccessorInfo& info) { 1375 ApiTestFuzzer::Fuzz(); 1376 CHECK(info.This()->Equals(bottom)); 1377 return v8::Handle<Value>(); 1378} 1379 1380 1381v8::Handle<Value> CheckThisNamedPropertySetter(Local<String> property, 1382 Local<Value> value, 1383 const AccessorInfo& info) { 1384 ApiTestFuzzer::Fuzz(); 1385 CHECK(info.This()->Equals(bottom)); 1386 return v8::Handle<Value>(); 1387} 1388 1389v8::Handle<v8::Integer> CheckThisIndexedPropertyQuery( 1390 uint32_t index, 1391 const AccessorInfo& info) { 1392 ApiTestFuzzer::Fuzz(); 1393 CHECK(info.This()->Equals(bottom)); 1394 return v8::Handle<v8::Integer>(); 1395} 1396 1397 1398v8::Handle<v8::Integer> CheckThisNamedPropertyQuery(Local<String> property, 1399 const AccessorInfo& info) { 1400 ApiTestFuzzer::Fuzz(); 1401 CHECK(info.This()->Equals(bottom)); 1402 return v8::Handle<v8::Integer>(); 1403} 1404 1405 1406v8::Handle<v8::Boolean> CheckThisIndexedPropertyDeleter( 1407 uint32_t index, 1408 const AccessorInfo& info) { 1409 ApiTestFuzzer::Fuzz(); 1410 CHECK(info.This()->Equals(bottom)); 1411 return v8::Handle<v8::Boolean>(); 1412} 1413 1414 1415v8::Handle<v8::Boolean> CheckThisNamedPropertyDeleter( 1416 Local<String> property, 1417 const AccessorInfo& info) { 1418 ApiTestFuzzer::Fuzz(); 1419 CHECK(info.This()->Equals(bottom)); 1420 return v8::Handle<v8::Boolean>(); 1421} 1422 1423 1424v8::Handle<v8::Array> CheckThisIndexedPropertyEnumerator( 1425 const AccessorInfo& info) { 1426 ApiTestFuzzer::Fuzz(); 1427 CHECK(info.This()->Equals(bottom)); 1428 return v8::Handle<v8::Array>(); 1429} 1430 1431 1432v8::Handle<v8::Array> CheckThisNamedPropertyEnumerator( 1433 const AccessorInfo& info) { 1434 ApiTestFuzzer::Fuzz(); 1435 CHECK(info.This()->Equals(bottom)); 1436 return v8::Handle<v8::Array>(); 1437} 1438 1439 1440THREADED_TEST(PropertyHandlerInPrototype) { 1441 v8::HandleScope scope; 1442 LocalContext env; 1443 1444 // Set up a prototype chain with three interceptors. 1445 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 1446 templ->InstanceTemplate()->SetIndexedPropertyHandler( 1447 CheckThisIndexedPropertyHandler, 1448 CheckThisIndexedPropertySetter, 1449 CheckThisIndexedPropertyQuery, 1450 CheckThisIndexedPropertyDeleter, 1451 CheckThisIndexedPropertyEnumerator); 1452 1453 templ->InstanceTemplate()->SetNamedPropertyHandler( 1454 CheckThisNamedPropertyHandler, 1455 CheckThisNamedPropertySetter, 1456 CheckThisNamedPropertyQuery, 1457 CheckThisNamedPropertyDeleter, 1458 CheckThisNamedPropertyEnumerator); 1459 1460 bottom = templ->GetFunction()->NewInstance(); 1461 Local<v8::Object> top = templ->GetFunction()->NewInstance(); 1462 Local<v8::Object> middle = templ->GetFunction()->NewInstance(); 1463 1464 bottom->Set(v8_str("__proto__"), middle); 1465 middle->Set(v8_str("__proto__"), top); 1466 env->Global()->Set(v8_str("obj"), bottom); 1467 1468 // Indexed and named get. 1469 Script::Compile(v8_str("obj[0]"))->Run(); 1470 Script::Compile(v8_str("obj.x"))->Run(); 1471 1472 // Indexed and named set. 1473 Script::Compile(v8_str("obj[1] = 42"))->Run(); 1474 Script::Compile(v8_str("obj.y = 42"))->Run(); 1475 1476 // Indexed and named query. 1477 Script::Compile(v8_str("0 in obj"))->Run(); 1478 Script::Compile(v8_str("'x' in obj"))->Run(); 1479 1480 // Indexed and named deleter. 1481 Script::Compile(v8_str("delete obj[0]"))->Run(); 1482 Script::Compile(v8_str("delete obj.x"))->Run(); 1483 1484 // Enumerators. 1485 Script::Compile(v8_str("for (var p in obj) ;"))->Run(); 1486} 1487 1488 1489static v8::Handle<Value> PrePropertyHandlerGet(Local<String> key, 1490 const AccessorInfo& info) { 1491 ApiTestFuzzer::Fuzz(); 1492 if (v8_str("pre")->Equals(key)) { 1493 return v8_str("PrePropertyHandler: pre"); 1494 } 1495 return v8::Handle<String>(); 1496} 1497 1498 1499static v8::Handle<v8::Integer> PrePropertyHandlerQuery(Local<String> key, 1500 const AccessorInfo&) { 1501 if (v8_str("pre")->Equals(key)) { 1502 return v8::Integer::New(v8::None); 1503 } 1504 1505 return v8::Handle<v8::Integer>(); // do not intercept the call 1506} 1507 1508 1509THREADED_TEST(PrePropertyHandler) { 1510 v8::HandleScope scope; 1511 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(); 1512 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet, 1513 0, 1514 PrePropertyHandlerQuery); 1515 LocalContext env(NULL, desc->InstanceTemplate()); 1516 Script::Compile(v8_str( 1517 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run(); 1518 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run(); 1519 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre); 1520 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run(); 1521 CHECK_EQ(v8_str("Object: on"), result_on); 1522 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run(); 1523 CHECK(result_post.IsEmpty()); 1524} 1525 1526 1527THREADED_TEST(UndefinedIsNotEnumerable) { 1528 v8::HandleScope scope; 1529 LocalContext env; 1530 v8::Handle<Value> result = Script::Compile(v8_str( 1531 "this.propertyIsEnumerable(undefined)"))->Run(); 1532 CHECK(result->IsFalse()); 1533} 1534 1535 1536v8::Handle<Script> call_recursively_script; 1537static const int kTargetRecursionDepth = 200; // near maximum 1538 1539 1540static v8::Handle<Value> CallScriptRecursivelyCall(const v8::Arguments& args) { 1541 ApiTestFuzzer::Fuzz(); 1542 int depth = args.This()->Get(v8_str("depth"))->Int32Value(); 1543 if (depth == kTargetRecursionDepth) return v8::Undefined(); 1544 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1)); 1545 return call_recursively_script->Run(); 1546} 1547 1548 1549static v8::Handle<Value> CallFunctionRecursivelyCall( 1550 const v8::Arguments& args) { 1551 ApiTestFuzzer::Fuzz(); 1552 int depth = args.This()->Get(v8_str("depth"))->Int32Value(); 1553 if (depth == kTargetRecursionDepth) { 1554 printf("[depth = %d]\n", depth); 1555 return v8::Undefined(); 1556 } 1557 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1)); 1558 v8::Handle<Value> function = 1559 args.This()->Get(v8_str("callFunctionRecursively")); 1560 return function.As<Function>()->Call(args.This(), 0, NULL); 1561} 1562 1563 1564THREADED_TEST(DeepCrossLanguageRecursion) { 1565 v8::HandleScope scope; 1566 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(); 1567 global->Set(v8_str("callScriptRecursively"), 1568 v8::FunctionTemplate::New(CallScriptRecursivelyCall)); 1569 global->Set(v8_str("callFunctionRecursively"), 1570 v8::FunctionTemplate::New(CallFunctionRecursivelyCall)); 1571 LocalContext env(NULL, global); 1572 1573 env->Global()->Set(v8_str("depth"), v8::Integer::New(0)); 1574 call_recursively_script = v8_compile("callScriptRecursively()"); 1575 v8::Handle<Value> result = call_recursively_script->Run(); 1576 call_recursively_script = v8::Handle<Script>(); 1577 1578 env->Global()->Set(v8_str("depth"), v8::Integer::New(0)); 1579 Script::Compile(v8_str("callFunctionRecursively()"))->Run(); 1580} 1581 1582 1583static v8::Handle<Value> 1584 ThrowingPropertyHandlerGet(Local<String> key, const AccessorInfo&) { 1585 ApiTestFuzzer::Fuzz(); 1586 return v8::ThrowException(key); 1587} 1588 1589 1590static v8::Handle<Value> ThrowingPropertyHandlerSet(Local<String> key, 1591 Local<Value>, 1592 const AccessorInfo&) { 1593 v8::ThrowException(key); 1594 return v8::Undefined(); // not the same as v8::Handle<v8::Value>() 1595} 1596 1597 1598THREADED_TEST(CallbackExceptionRegression) { 1599 v8::HandleScope scope; 1600 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 1601 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet, 1602 ThrowingPropertyHandlerSet); 1603 LocalContext env; 1604 env->Global()->Set(v8_str("obj"), obj->NewInstance()); 1605 v8::Handle<Value> otto = Script::Compile(v8_str( 1606 "try { with (obj) { otto; } } catch (e) { e; }"))->Run(); 1607 CHECK_EQ(v8_str("otto"), otto); 1608 v8::Handle<Value> netto = Script::Compile(v8_str( 1609 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run(); 1610 CHECK_EQ(v8_str("netto"), netto); 1611} 1612 1613 1614THREADED_TEST(FunctionPrototype) { 1615 v8::HandleScope scope; 1616 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(); 1617 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321)); 1618 LocalContext env; 1619 env->Global()->Set(v8_str("Foo"), Foo->GetFunction()); 1620 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak")); 1621 CHECK_EQ(script->Run()->Int32Value(), 321); 1622} 1623 1624 1625THREADED_TEST(InternalFields) { 1626 v8::HandleScope scope; 1627 LocalContext env; 1628 1629 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 1630 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 1631 instance_templ->SetInternalFieldCount(1); 1632 Local<v8::Object> obj = templ->GetFunction()->NewInstance(); 1633 CHECK_EQ(1, obj->InternalFieldCount()); 1634 CHECK(obj->GetInternalField(0)->IsUndefined()); 1635 obj->SetInternalField(0, v8_num(17)); 1636 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value()); 1637} 1638 1639 1640THREADED_TEST(GlobalObjectInternalFields) { 1641 v8::HandleScope scope; 1642 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 1643 global_template->SetInternalFieldCount(1); 1644 LocalContext env(NULL, global_template); 1645 v8::Handle<v8::Object> global_proxy = env->Global(); 1646 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>(); 1647 CHECK_EQ(1, global->InternalFieldCount()); 1648 CHECK(global->GetInternalField(0)->IsUndefined()); 1649 global->SetInternalField(0, v8_num(17)); 1650 CHECK_EQ(17, global->GetInternalField(0)->Int32Value()); 1651} 1652 1653 1654THREADED_TEST(InternalFieldsNativePointers) { 1655 v8::HandleScope scope; 1656 LocalContext env; 1657 1658 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 1659 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 1660 instance_templ->SetInternalFieldCount(1); 1661 Local<v8::Object> obj = templ->GetFunction()->NewInstance(); 1662 CHECK_EQ(1, obj->InternalFieldCount()); 1663 CHECK(obj->GetPointerFromInternalField(0) == NULL); 1664 1665 char* data = new char[100]; 1666 1667 void* aligned = data; 1668 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1)); 1669 void* unaligned = data + 1; 1670 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1)); 1671 1672 // Check reading and writing aligned pointers. 1673 obj->SetPointerInInternalField(0, aligned); 1674 HEAP->CollectAllGarbage(false); 1675 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0)); 1676 1677 // Check reading and writing unaligned pointers. 1678 obj->SetPointerInInternalField(0, unaligned); 1679 HEAP->CollectAllGarbage(false); 1680 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0)); 1681 1682 delete[] data; 1683} 1684 1685 1686THREADED_TEST(InternalFieldsNativePointersAndExternal) { 1687 v8::HandleScope scope; 1688 LocalContext env; 1689 1690 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 1691 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 1692 instance_templ->SetInternalFieldCount(1); 1693 Local<v8::Object> obj = templ->GetFunction()->NewInstance(); 1694 CHECK_EQ(1, obj->InternalFieldCount()); 1695 CHECK(obj->GetPointerFromInternalField(0) == NULL); 1696 1697 char* data = new char[100]; 1698 1699 void* aligned = data; 1700 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(aligned) & 0x1)); 1701 void* unaligned = data + 1; 1702 CHECK_EQ(1, static_cast<int>(reinterpret_cast<uintptr_t>(unaligned) & 0x1)); 1703 1704 obj->SetPointerInInternalField(0, aligned); 1705 HEAP->CollectAllGarbage(false); 1706 CHECK_EQ(aligned, v8::External::Unwrap(obj->GetInternalField(0))); 1707 1708 obj->SetPointerInInternalField(0, unaligned); 1709 HEAP->CollectAllGarbage(false); 1710 CHECK_EQ(unaligned, v8::External::Unwrap(obj->GetInternalField(0))); 1711 1712 obj->SetInternalField(0, v8::External::Wrap(aligned)); 1713 HEAP->CollectAllGarbage(false); 1714 CHECK_EQ(aligned, obj->GetPointerFromInternalField(0)); 1715 1716 obj->SetInternalField(0, v8::External::Wrap(unaligned)); 1717 HEAP->CollectAllGarbage(false); 1718 CHECK_EQ(unaligned, obj->GetPointerFromInternalField(0)); 1719 1720 delete[] data; 1721} 1722 1723 1724THREADED_TEST(IdentityHash) { 1725 v8::HandleScope scope; 1726 LocalContext env; 1727 1728 // Ensure that the test starts with an fresh heap to test whether the hash 1729 // code is based on the address. 1730 HEAP->CollectAllGarbage(false); 1731 Local<v8::Object> obj = v8::Object::New(); 1732 int hash = obj->GetIdentityHash(); 1733 int hash1 = obj->GetIdentityHash(); 1734 CHECK_EQ(hash, hash1); 1735 int hash2 = v8::Object::New()->GetIdentityHash(); 1736 // Since the identity hash is essentially a random number two consecutive 1737 // objects should not be assigned the same hash code. If the test below fails 1738 // the random number generator should be evaluated. 1739 CHECK_NE(hash, hash2); 1740 HEAP->CollectAllGarbage(false); 1741 int hash3 = v8::Object::New()->GetIdentityHash(); 1742 // Make sure that the identity hash is not based on the initial address of 1743 // the object alone. If the test below fails the random number generator 1744 // should be evaluated. 1745 CHECK_NE(hash, hash3); 1746 int hash4 = obj->GetIdentityHash(); 1747 CHECK_EQ(hash, hash4); 1748 1749 // Check identity hashes behaviour in the presence of JS accessors. 1750 // Put a getter for 'v8::IdentityHash' on the Object's prototype: 1751 { 1752 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n"); 1753 Local<v8::Object> o1 = v8::Object::New(); 1754 Local<v8::Object> o2 = v8::Object::New(); 1755 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 1756 } 1757 { 1758 CompileRun( 1759 "function cnst() { return 42; };\n" 1760 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n"); 1761 Local<v8::Object> o1 = v8::Object::New(); 1762 Local<v8::Object> o2 = v8::Object::New(); 1763 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 1764 } 1765} 1766 1767 1768THREADED_TEST(HiddenProperties) { 1769 v8::HandleScope scope; 1770 LocalContext env; 1771 1772 v8::Local<v8::Object> obj = v8::Object::New(); 1773 v8::Local<v8::String> key = v8_str("api-test::hidden-key"); 1774 v8::Local<v8::String> empty = v8_str(""); 1775 v8::Local<v8::String> prop_name = v8_str("prop_name"); 1776 1777 HEAP->CollectAllGarbage(false); 1778 1779 // Make sure delete of a non-existent hidden value works 1780 CHECK(obj->DeleteHiddenValue(key)); 1781 1782 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503))); 1783 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value()); 1784 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002))); 1785 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 1786 1787 HEAP->CollectAllGarbage(false); 1788 1789 // Make sure we do not find the hidden property. 1790 CHECK(!obj->Has(empty)); 1791 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 1792 CHECK(obj->Get(empty)->IsUndefined()); 1793 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 1794 CHECK(obj->Set(empty, v8::Integer::New(2003))); 1795 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 1796 CHECK_EQ(2003, obj->Get(empty)->Int32Value()); 1797 1798 HEAP->CollectAllGarbage(false); 1799 1800 // Add another property and delete it afterwards to force the object in 1801 // slow case. 1802 CHECK(obj->Set(prop_name, v8::Integer::New(2008))); 1803 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 1804 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value()); 1805 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 1806 CHECK(obj->Delete(prop_name)); 1807 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 1808 1809 HEAP->CollectAllGarbage(false); 1810 1811 CHECK(obj->DeleteHiddenValue(key)); 1812 CHECK(obj->GetHiddenValue(key).IsEmpty()); 1813} 1814 1815 1816THREADED_TEST(Regress97784) { 1817 // Regression test for crbug.com/97784 1818 // Messing with the Object.prototype should not have effect on 1819 // hidden properties. 1820 v8::HandleScope scope; 1821 LocalContext env; 1822 1823 v8::Local<v8::Object> obj = v8::Object::New(); 1824 v8::Local<v8::String> key = v8_str("hidden"); 1825 1826 CompileRun( 1827 "set_called = false;" 1828 "Object.defineProperty(" 1829 " Object.prototype," 1830 " 'hidden'," 1831 " {get: function() { return 45; }," 1832 " set: function() { set_called = true; }})"); 1833 1834 CHECK(obj->GetHiddenValue(key).IsEmpty()); 1835 // Make sure that the getter and setter from Object.prototype is not invoked. 1836 // If it did we would have full access to the hidden properties in 1837 // the accessor. 1838 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42))); 1839 ExpectFalse("set_called"); 1840 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value()); 1841} 1842 1843 1844static bool interceptor_for_hidden_properties_called; 1845static v8::Handle<Value> InterceptorForHiddenProperties( 1846 Local<String> name, const AccessorInfo& info) { 1847 interceptor_for_hidden_properties_called = true; 1848 return v8::Handle<Value>(); 1849} 1850 1851 1852THREADED_TEST(HiddenPropertiesWithInterceptors) { 1853 v8::HandleScope scope; 1854 LocalContext context; 1855 1856 interceptor_for_hidden_properties_called = false; 1857 1858 v8::Local<v8::String> key = v8_str("api-test::hidden-key"); 1859 1860 // Associate an interceptor with an object and start setting hidden values. 1861 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 1862 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 1863 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties); 1864 Local<v8::Function> function = fun_templ->GetFunction(); 1865 Local<v8::Object> obj = function->NewInstance(); 1866 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302))); 1867 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value()); 1868 CHECK(!interceptor_for_hidden_properties_called); 1869} 1870 1871 1872THREADED_TEST(External) { 1873 v8::HandleScope scope; 1874 int x = 3; 1875 Local<v8::External> ext = v8::External::New(&x); 1876 LocalContext env; 1877 env->Global()->Set(v8_str("ext"), ext); 1878 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run(); 1879 v8::Handle<v8::External> reext = reext_obj.As<v8::External>(); 1880 int* ptr = static_cast<int*>(reext->Value()); 1881 CHECK_EQ(x, 3); 1882 *ptr = 10; 1883 CHECK_EQ(x, 10); 1884 1885 // Make sure unaligned pointers are wrapped properly. 1886 char* data = i::StrDup("0123456789"); 1887 Local<v8::Value> zero = v8::External::Wrap(&data[0]); 1888 Local<v8::Value> one = v8::External::Wrap(&data[1]); 1889 Local<v8::Value> two = v8::External::Wrap(&data[2]); 1890 Local<v8::Value> three = v8::External::Wrap(&data[3]); 1891 1892 char* char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(zero)); 1893 CHECK_EQ('0', *char_ptr); 1894 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(one)); 1895 CHECK_EQ('1', *char_ptr); 1896 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(two)); 1897 CHECK_EQ('2', *char_ptr); 1898 char_ptr = reinterpret_cast<char*>(v8::External::Unwrap(three)); 1899 CHECK_EQ('3', *char_ptr); 1900 i::DeleteArray(data); 1901} 1902 1903 1904THREADED_TEST(GlobalHandle) { 1905 v8::Persistent<String> global; 1906 { 1907 v8::HandleScope scope; 1908 Local<String> str = v8_str("str"); 1909 global = v8::Persistent<String>::New(str); 1910 } 1911 CHECK_EQ(global->Length(), 3); 1912 global.Dispose(); 1913} 1914 1915 1916static int NumberOfWeakCalls = 0; 1917static void WeakPointerCallback(Persistent<Value> handle, void* id) { 1918 CHECK_EQ(reinterpret_cast<void*>(1234), id); 1919 NumberOfWeakCalls++; 1920 handle.Dispose(); 1921} 1922 1923THREADED_TEST(ApiObjectGroups) { 1924 HandleScope scope; 1925 LocalContext env; 1926 1927 NumberOfWeakCalls = 0; 1928 1929 Persistent<Object> g1s1; 1930 Persistent<Object> g1s2; 1931 Persistent<Object> g1c1; 1932 Persistent<Object> g2s1; 1933 Persistent<Object> g2s2; 1934 Persistent<Object> g2c1; 1935 1936 { 1937 HandleScope scope; 1938 g1s1 = Persistent<Object>::New(Object::New()); 1939 g1s2 = Persistent<Object>::New(Object::New()); 1940 g1c1 = Persistent<Object>::New(Object::New()); 1941 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 1942 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 1943 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 1944 1945 g2s1 = Persistent<Object>::New(Object::New()); 1946 g2s2 = Persistent<Object>::New(Object::New()); 1947 g2c1 = Persistent<Object>::New(Object::New()); 1948 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 1949 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 1950 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 1951 } 1952 1953 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root. 1954 1955 // Connect group 1 and 2, make a cycle. 1956 CHECK(g1s2->Set(0, g2s2)); 1957 CHECK(g2s1->Set(0, g1s1)); 1958 1959 { 1960 Persistent<Value> g1_objects[] = { g1s1, g1s2 }; 1961 Persistent<Value> g1_children[] = { g1c1 }; 1962 Persistent<Value> g2_objects[] = { g2s1, g2s2 }; 1963 Persistent<Value> g2_children[] = { g2c1 }; 1964 V8::AddObjectGroup(g1_objects, 2); 1965 V8::AddImplicitReferences(g1s1, g1_children, 1); 1966 V8::AddObjectGroup(g2_objects, 2); 1967 V8::AddImplicitReferences(g2s2, g2_children, 1); 1968 } 1969 // Do a full GC 1970 HEAP->CollectGarbage(i::OLD_POINTER_SPACE); 1971 1972 // All object should be alive. 1973 CHECK_EQ(0, NumberOfWeakCalls); 1974 1975 // Weaken the root. 1976 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 1977 // But make children strong roots---all the objects (except for children) 1978 // should be collectable now. 1979 g1c1.ClearWeak(); 1980 g2c1.ClearWeak(); 1981 1982 // Groups are deleted, rebuild groups. 1983 { 1984 Persistent<Value> g1_objects[] = { g1s1, g1s2 }; 1985 Persistent<Value> g1_children[] = { g1c1 }; 1986 Persistent<Value> g2_objects[] = { g2s1, g2s2 }; 1987 Persistent<Value> g2_children[] = { g2c1 }; 1988 V8::AddObjectGroup(g1_objects, 2); 1989 V8::AddImplicitReferences(g1s1, g1_children, 1); 1990 V8::AddObjectGroup(g2_objects, 2); 1991 V8::AddImplicitReferences(g2s2, g2_children, 1); 1992 } 1993 1994 HEAP->CollectGarbage(i::OLD_POINTER_SPACE); 1995 1996 // All objects should be gone. 5 global handles in total. 1997 CHECK_EQ(5, NumberOfWeakCalls); 1998 1999 // And now make children weak again and collect them. 2000 g1c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 2001 g2c1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 2002 2003 HEAP->CollectGarbage(i::OLD_POINTER_SPACE); 2004 CHECK_EQ(7, NumberOfWeakCalls); 2005} 2006 2007 2008THREADED_TEST(ApiObjectGroupsCycle) { 2009 HandleScope scope; 2010 LocalContext env; 2011 2012 NumberOfWeakCalls = 0; 2013 2014 Persistent<Object> g1s1; 2015 Persistent<Object> g1s2; 2016 Persistent<Object> g2s1; 2017 Persistent<Object> g2s2; 2018 Persistent<Object> g3s1; 2019 Persistent<Object> g3s2; 2020 2021 { 2022 HandleScope scope; 2023 g1s1 = Persistent<Object>::New(Object::New()); 2024 g1s2 = Persistent<Object>::New(Object::New()); 2025 g1s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 2026 g1s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 2027 2028 g2s1 = Persistent<Object>::New(Object::New()); 2029 g2s2 = Persistent<Object>::New(Object::New()); 2030 g2s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 2031 g2s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 2032 2033 g3s1 = Persistent<Object>::New(Object::New()); 2034 g3s2 = Persistent<Object>::New(Object::New()); 2035 g3s1.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 2036 g3s2.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 2037 } 2038 2039 Persistent<Object> root = Persistent<Object>::New(g1s1); // make a root. 2040 2041 // Connect groups. We're building the following cycle: 2042 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other 2043 // groups. 2044 { 2045 Persistent<Value> g1_objects[] = { g1s1, g1s2 }; 2046 Persistent<Value> g1_children[] = { g2s1 }; 2047 Persistent<Value> g2_objects[] = { g2s1, g2s2 }; 2048 Persistent<Value> g2_children[] = { g3s1 }; 2049 Persistent<Value> g3_objects[] = { g3s1, g3s2 }; 2050 Persistent<Value> g3_children[] = { g1s1 }; 2051 V8::AddObjectGroup(g1_objects, 2); 2052 V8::AddImplicitReferences(g1s1, g1_children, 1); 2053 V8::AddObjectGroup(g2_objects, 2); 2054 V8::AddImplicitReferences(g2s1, g2_children, 1); 2055 V8::AddObjectGroup(g3_objects, 2); 2056 V8::AddImplicitReferences(g3s1, g3_children, 1); 2057 } 2058 // Do a full GC 2059 HEAP->CollectGarbage(i::OLD_POINTER_SPACE); 2060 2061 // All object should be alive. 2062 CHECK_EQ(0, NumberOfWeakCalls); 2063 2064 // Weaken the root. 2065 root.MakeWeak(reinterpret_cast<void*>(1234), &WeakPointerCallback); 2066 2067 // Groups are deleted, rebuild groups. 2068 { 2069 Persistent<Value> g1_objects[] = { g1s1, g1s2 }; 2070 Persistent<Value> g1_children[] = { g2s1 }; 2071 Persistent<Value> g2_objects[] = { g2s1, g2s2 }; 2072 Persistent<Value> g2_children[] = { g3s1 }; 2073 Persistent<Value> g3_objects[] = { g3s1, g3s2 }; 2074 Persistent<Value> g3_children[] = { g1s1 }; 2075 V8::AddObjectGroup(g1_objects, 2); 2076 V8::AddImplicitReferences(g1s1, g1_children, 1); 2077 V8::AddObjectGroup(g2_objects, 2); 2078 V8::AddImplicitReferences(g2s1, g2_children, 1); 2079 V8::AddObjectGroup(g3_objects, 2); 2080 V8::AddImplicitReferences(g3s1, g3_children, 1); 2081 } 2082 2083 HEAP->CollectGarbage(i::OLD_POINTER_SPACE); 2084 2085 // All objects should be gone. 7 global handles in total. 2086 CHECK_EQ(7, NumberOfWeakCalls); 2087} 2088 2089 2090THREADED_TEST(ScriptException) { 2091 v8::HandleScope scope; 2092 LocalContext env; 2093 Local<Script> script = Script::Compile(v8_str("throw 'panama!';")); 2094 v8::TryCatch try_catch; 2095 Local<Value> result = script->Run(); 2096 CHECK(result.IsEmpty()); 2097 CHECK(try_catch.HasCaught()); 2098 String::AsciiValue exception_value(try_catch.Exception()); 2099 CHECK_EQ(*exception_value, "panama!"); 2100} 2101 2102 2103bool message_received; 2104 2105 2106static void check_message(v8::Handle<v8::Message> message, 2107 v8::Handle<Value> data) { 2108 CHECK_EQ(5.76, data->NumberValue()); 2109 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 2110 CHECK_EQ(7.56, message->GetScriptData()->NumberValue()); 2111 message_received = true; 2112} 2113 2114 2115THREADED_TEST(MessageHandlerData) { 2116 message_received = false; 2117 v8::HandleScope scope; 2118 CHECK(!message_received); 2119 v8::V8::AddMessageListener(check_message, v8_num(5.76)); 2120 LocalContext context; 2121 v8::ScriptOrigin origin = 2122 v8::ScriptOrigin(v8_str("6.75")); 2123 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 2124 &origin); 2125 script->SetData(v8_str("7.56")); 2126 script->Run(); 2127 CHECK(message_received); 2128 // clear out the message listener 2129 v8::V8::RemoveMessageListeners(check_message); 2130} 2131 2132 2133THREADED_TEST(GetSetProperty) { 2134 v8::HandleScope scope; 2135 LocalContext context; 2136 context->Global()->Set(v8_str("foo"), v8_num(14)); 2137 context->Global()->Set(v8_str("12"), v8_num(92)); 2138 context->Global()->Set(v8::Integer::New(16), v8_num(32)); 2139 context->Global()->Set(v8_num(13), v8_num(56)); 2140 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run(); 2141 CHECK_EQ(14, foo->Int32Value()); 2142 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run(); 2143 CHECK_EQ(92, twelve->Int32Value()); 2144 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run(); 2145 CHECK_EQ(32, sixteen->Int32Value()); 2146 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run(); 2147 CHECK_EQ(56, thirteen->Int32Value()); 2148 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value()); 2149 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value()); 2150 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value()); 2151 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value()); 2152 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value()); 2153 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value()); 2154 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value()); 2155 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value()); 2156 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value()); 2157} 2158 2159 2160THREADED_TEST(PropertyAttributes) { 2161 v8::HandleScope scope; 2162 LocalContext context; 2163 // none 2164 Local<String> prop = v8_str("none"); 2165 context->Global()->Set(prop, v8_num(7)); 2166 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop)); 2167 // read-only 2168 prop = v8_str("read_only"); 2169 context->Global()->Set(prop, v8_num(7), v8::ReadOnly); 2170 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 2171 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop)); 2172 Script::Compile(v8_str("read_only = 9"))->Run(); 2173 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 2174 context->Global()->Set(prop, v8_num(10)); 2175 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 2176 // dont-delete 2177 prop = v8_str("dont_delete"); 2178 context->Global()->Set(prop, v8_num(13), v8::DontDelete); 2179 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); 2180 Script::Compile(v8_str("delete dont_delete"))->Run(); 2181 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); 2182 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop)); 2183 // dont-enum 2184 prop = v8_str("dont_enum"); 2185 context->Global()->Set(prop, v8_num(28), v8::DontEnum); 2186 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop)); 2187 // absent 2188 prop = v8_str("absent"); 2189 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop)); 2190 Local<Value> fake_prop = v8_num(1); 2191 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop)); 2192 // exception 2193 TryCatch try_catch; 2194 Local<Value> exception = 2195 CompileRun("({ toString: function() { throw 'exception';} })"); 2196 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception)); 2197 CHECK(try_catch.HasCaught()); 2198 String::AsciiValue exception_value(try_catch.Exception()); 2199 CHECK_EQ("exception", *exception_value); 2200 try_catch.Reset(); 2201} 2202 2203 2204THREADED_TEST(Array) { 2205 v8::HandleScope scope; 2206 LocalContext context; 2207 Local<v8::Array> array = v8::Array::New(); 2208 CHECK_EQ(0, array->Length()); 2209 CHECK(array->Get(0)->IsUndefined()); 2210 CHECK(!array->Has(0)); 2211 CHECK(array->Get(100)->IsUndefined()); 2212 CHECK(!array->Has(100)); 2213 array->Set(2, v8_num(7)); 2214 CHECK_EQ(3, array->Length()); 2215 CHECK(!array->Has(0)); 2216 CHECK(!array->Has(1)); 2217 CHECK(array->Has(2)); 2218 CHECK_EQ(7, array->Get(2)->Int32Value()); 2219 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run(); 2220 Local<v8::Array> arr = obj.As<v8::Array>(); 2221 CHECK_EQ(3, arr->Length()); 2222 CHECK_EQ(1, arr->Get(0)->Int32Value()); 2223 CHECK_EQ(2, arr->Get(1)->Int32Value()); 2224 CHECK_EQ(3, arr->Get(2)->Int32Value()); 2225 array = v8::Array::New(27); 2226 CHECK_EQ(27, array->Length()); 2227 array = v8::Array::New(-27); 2228 CHECK_EQ(0, array->Length()); 2229} 2230 2231 2232v8::Handle<Value> HandleF(const v8::Arguments& args) { 2233 v8::HandleScope scope; 2234 ApiTestFuzzer::Fuzz(); 2235 Local<v8::Array> result = v8::Array::New(args.Length()); 2236 for (int i = 0; i < args.Length(); i++) 2237 result->Set(i, args[i]); 2238 return scope.Close(result); 2239} 2240 2241 2242THREADED_TEST(Vector) { 2243 v8::HandleScope scope; 2244 Local<ObjectTemplate> global = ObjectTemplate::New(); 2245 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF)); 2246 LocalContext context(0, global); 2247 2248 const char* fun = "f()"; 2249 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>(); 2250 CHECK_EQ(0, a0->Length()); 2251 2252 const char* fun2 = "f(11)"; 2253 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>(); 2254 CHECK_EQ(1, a1->Length()); 2255 CHECK_EQ(11, a1->Get(0)->Int32Value()); 2256 2257 const char* fun3 = "f(12, 13)"; 2258 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>(); 2259 CHECK_EQ(2, a2->Length()); 2260 CHECK_EQ(12, a2->Get(0)->Int32Value()); 2261 CHECK_EQ(13, a2->Get(1)->Int32Value()); 2262 2263 const char* fun4 = "f(14, 15, 16)"; 2264 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>(); 2265 CHECK_EQ(3, a3->Length()); 2266 CHECK_EQ(14, a3->Get(0)->Int32Value()); 2267 CHECK_EQ(15, a3->Get(1)->Int32Value()); 2268 CHECK_EQ(16, a3->Get(2)->Int32Value()); 2269 2270 const char* fun5 = "f(17, 18, 19, 20)"; 2271 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>(); 2272 CHECK_EQ(4, a4->Length()); 2273 CHECK_EQ(17, a4->Get(0)->Int32Value()); 2274 CHECK_EQ(18, a4->Get(1)->Int32Value()); 2275 CHECK_EQ(19, a4->Get(2)->Int32Value()); 2276 CHECK_EQ(20, a4->Get(3)->Int32Value()); 2277} 2278 2279 2280THREADED_TEST(FunctionCall) { 2281 v8::HandleScope scope; 2282 LocalContext context; 2283 CompileRun( 2284 "function Foo() {" 2285 " var result = [];" 2286 " for (var i = 0; i < arguments.length; i++) {" 2287 " result.push(arguments[i]);" 2288 " }" 2289 " return result;" 2290 "}"); 2291 Local<Function> Foo = 2292 Local<Function>::Cast(context->Global()->Get(v8_str("Foo"))); 2293 2294 v8::Handle<Value>* args0 = NULL; 2295 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0)); 2296 CHECK_EQ(0, a0->Length()); 2297 2298 v8::Handle<Value> args1[] = { v8_num(1.1) }; 2299 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1)); 2300 CHECK_EQ(1, a1->Length()); 2301 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue()); 2302 2303 v8::Handle<Value> args2[] = { v8_num(2.2), 2304 v8_num(3.3) }; 2305 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2)); 2306 CHECK_EQ(2, a2->Length()); 2307 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue()); 2308 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue()); 2309 2310 v8::Handle<Value> args3[] = { v8_num(4.4), 2311 v8_num(5.5), 2312 v8_num(6.6) }; 2313 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3)); 2314 CHECK_EQ(3, a3->Length()); 2315 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue()); 2316 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue()); 2317 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue()); 2318 2319 v8::Handle<Value> args4[] = { v8_num(7.7), 2320 v8_num(8.8), 2321 v8_num(9.9), 2322 v8_num(10.11) }; 2323 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4)); 2324 CHECK_EQ(4, a4->Length()); 2325 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue()); 2326 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue()); 2327 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue()); 2328 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue()); 2329} 2330 2331 2332static const char* js_code_causing_out_of_memory = 2333 "var a = new Array(); while(true) a.push(a);"; 2334 2335 2336// These tests run for a long time and prevent us from running tests 2337// that come after them so they cannot run in parallel. 2338TEST(OutOfMemory) { 2339 // It's not possible to read a snapshot into a heap with different dimensions. 2340 if (i::Snapshot::IsEnabled()) return; 2341 // Set heap limits. 2342 static const int K = 1024; 2343 v8::ResourceConstraints constraints; 2344 constraints.set_max_young_space_size(256 * K); 2345 constraints.set_max_old_space_size(4 * K * K); 2346 v8::SetResourceConstraints(&constraints); 2347 2348 // Execute a script that causes out of memory. 2349 v8::HandleScope scope; 2350 LocalContext context; 2351 v8::V8::IgnoreOutOfMemoryException(); 2352 Local<Script> script = 2353 Script::Compile(String::New(js_code_causing_out_of_memory)); 2354 Local<Value> result = script->Run(); 2355 2356 // Check for out of memory state. 2357 CHECK(result.IsEmpty()); 2358 CHECK(context->HasOutOfMemoryException()); 2359} 2360 2361 2362v8::Handle<Value> ProvokeOutOfMemory(const v8::Arguments& args) { 2363 ApiTestFuzzer::Fuzz(); 2364 2365 v8::HandleScope scope; 2366 LocalContext context; 2367 Local<Script> script = 2368 Script::Compile(String::New(js_code_causing_out_of_memory)); 2369 Local<Value> result = script->Run(); 2370 2371 // Check for out of memory state. 2372 CHECK(result.IsEmpty()); 2373 CHECK(context->HasOutOfMemoryException()); 2374 2375 return result; 2376} 2377 2378 2379TEST(OutOfMemoryNested) { 2380 // It's not possible to read a snapshot into a heap with different dimensions. 2381 if (i::Snapshot::IsEnabled()) return; 2382 // Set heap limits. 2383 static const int K = 1024; 2384 v8::ResourceConstraints constraints; 2385 constraints.set_max_young_space_size(256 * K); 2386 constraints.set_max_old_space_size(4 * K * K); 2387 v8::SetResourceConstraints(&constraints); 2388 2389 v8::HandleScope scope; 2390 Local<ObjectTemplate> templ = ObjectTemplate::New(); 2391 templ->Set(v8_str("ProvokeOutOfMemory"), 2392 v8::FunctionTemplate::New(ProvokeOutOfMemory)); 2393 LocalContext context(0, templ); 2394 v8::V8::IgnoreOutOfMemoryException(); 2395 Local<Value> result = CompileRun( 2396 "var thrown = false;" 2397 "try {" 2398 " ProvokeOutOfMemory();" 2399 "} catch (e) {" 2400 " thrown = true;" 2401 "}"); 2402 // Check for out of memory state. 2403 CHECK(result.IsEmpty()); 2404 CHECK(context->HasOutOfMemoryException()); 2405} 2406 2407 2408TEST(HugeConsStringOutOfMemory) { 2409 // It's not possible to read a snapshot into a heap with different dimensions. 2410 if (i::Snapshot::IsEnabled()) return; 2411 // Set heap limits. 2412 static const int K = 1024; 2413 v8::ResourceConstraints constraints; 2414 constraints.set_max_young_space_size(256 * K); 2415 constraints.set_max_old_space_size(2 * K * K); 2416 v8::SetResourceConstraints(&constraints); 2417 2418 // Execute a script that causes out of memory. 2419 v8::V8::IgnoreOutOfMemoryException(); 2420 2421 v8::HandleScope scope; 2422 LocalContext context; 2423 2424 // Build huge string. This should fail with out of memory exception. 2425 Local<Value> result = CompileRun( 2426 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();" 2427 "for (var i = 0; i < 22; i++) { str = str + str; }"); 2428 2429 // Check for out of memory state. 2430 CHECK(result.IsEmpty()); 2431 CHECK(context->HasOutOfMemoryException()); 2432} 2433 2434 2435THREADED_TEST(ConstructCall) { 2436 v8::HandleScope scope; 2437 LocalContext context; 2438 CompileRun( 2439 "function Foo() {" 2440 " var result = [];" 2441 " for (var i = 0; i < arguments.length; i++) {" 2442 " result.push(arguments[i]);" 2443 " }" 2444 " return result;" 2445 "}"); 2446 Local<Function> Foo = 2447 Local<Function>::Cast(context->Global()->Get(v8_str("Foo"))); 2448 2449 v8::Handle<Value>* args0 = NULL; 2450 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0)); 2451 CHECK_EQ(0, a0->Length()); 2452 2453 v8::Handle<Value> args1[] = { v8_num(1.1) }; 2454 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1)); 2455 CHECK_EQ(1, a1->Length()); 2456 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue()); 2457 2458 v8::Handle<Value> args2[] = { v8_num(2.2), 2459 v8_num(3.3) }; 2460 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2)); 2461 CHECK_EQ(2, a2->Length()); 2462 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue()); 2463 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue()); 2464 2465 v8::Handle<Value> args3[] = { v8_num(4.4), 2466 v8_num(5.5), 2467 v8_num(6.6) }; 2468 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3)); 2469 CHECK_EQ(3, a3->Length()); 2470 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue()); 2471 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue()); 2472 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue()); 2473 2474 v8::Handle<Value> args4[] = { v8_num(7.7), 2475 v8_num(8.8), 2476 v8_num(9.9), 2477 v8_num(10.11) }; 2478 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4)); 2479 CHECK_EQ(4, a4->Length()); 2480 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue()); 2481 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue()); 2482 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue()); 2483 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue()); 2484} 2485 2486 2487static void CheckUncle(v8::TryCatch* try_catch) { 2488 CHECK(try_catch->HasCaught()); 2489 String::AsciiValue str_value(try_catch->Exception()); 2490 CHECK_EQ(*str_value, "uncle?"); 2491 try_catch->Reset(); 2492} 2493 2494 2495THREADED_TEST(ConversionNumber) { 2496 v8::HandleScope scope; 2497 LocalContext env; 2498 // Very large number. 2499 CompileRun("var obj = Math.pow(2,32) * 1237;"); 2500 Local<Value> obj = env->Global()->Get(v8_str("obj")); 2501 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value()); 2502 CHECK_EQ(0, obj->ToInt32()->Value()); 2503 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned. 2504 // Large number. 2505 CompileRun("var obj = -1234567890123;"); 2506 obj = env->Global()->Get(v8_str("obj")); 2507 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value()); 2508 CHECK_EQ(-1912276171, obj->ToInt32()->Value()); 2509 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT 2510 // Small positive integer. 2511 CompileRun("var obj = 42;"); 2512 obj = env->Global()->Get(v8_str("obj")); 2513 CHECK_EQ(42.0, obj->ToNumber()->Value()); 2514 CHECK_EQ(42, obj->ToInt32()->Value()); 2515 CHECK(42u == obj->ToUint32()->Value()); // NOLINT 2516 // Negative integer. 2517 CompileRun("var obj = -37;"); 2518 obj = env->Global()->Get(v8_str("obj")); 2519 CHECK_EQ(-37.0, obj->ToNumber()->Value()); 2520 CHECK_EQ(-37, obj->ToInt32()->Value()); 2521 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT 2522 // Positive non-int32 integer. 2523 CompileRun("var obj = 0x81234567;"); 2524 obj = env->Global()->Get(v8_str("obj")); 2525 CHECK_EQ(2166572391.0, obj->ToNumber()->Value()); 2526 CHECK_EQ(-2128394905, obj->ToInt32()->Value()); 2527 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT 2528 // Fraction. 2529 CompileRun("var obj = 42.3;"); 2530 obj = env->Global()->Get(v8_str("obj")); 2531 CHECK_EQ(42.3, obj->ToNumber()->Value()); 2532 CHECK_EQ(42, obj->ToInt32()->Value()); 2533 CHECK(42u == obj->ToUint32()->Value()); // NOLINT 2534 // Large negative fraction. 2535 CompileRun("var obj = -5726623061.75;"); 2536 obj = env->Global()->Get(v8_str("obj")); 2537 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value()); 2538 CHECK_EQ(-1431655765, obj->ToInt32()->Value()); 2539 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT 2540} 2541 2542 2543THREADED_TEST(isNumberType) { 2544 v8::HandleScope scope; 2545 LocalContext env; 2546 // Very large number. 2547 CompileRun("var obj = Math.pow(2,32) * 1237;"); 2548 Local<Value> obj = env->Global()->Get(v8_str("obj")); 2549 CHECK(!obj->IsInt32()); 2550 CHECK(!obj->IsUint32()); 2551 // Large negative number. 2552 CompileRun("var obj = -1234567890123;"); 2553 obj = env->Global()->Get(v8_str("obj")); 2554 CHECK(!obj->IsInt32()); 2555 CHECK(!obj->IsUint32()); 2556 // Small positive integer. 2557 CompileRun("var obj = 42;"); 2558 obj = env->Global()->Get(v8_str("obj")); 2559 CHECK(obj->IsInt32()); 2560 CHECK(obj->IsUint32()); 2561 // Negative integer. 2562 CompileRun("var obj = -37;"); 2563 obj = env->Global()->Get(v8_str("obj")); 2564 CHECK(obj->IsInt32()); 2565 CHECK(!obj->IsUint32()); 2566 // Positive non-int32 integer. 2567 CompileRun("var obj = 0x81234567;"); 2568 obj = env->Global()->Get(v8_str("obj")); 2569 CHECK(!obj->IsInt32()); 2570 CHECK(obj->IsUint32()); 2571 // Fraction. 2572 CompileRun("var obj = 42.3;"); 2573 obj = env->Global()->Get(v8_str("obj")); 2574 CHECK(!obj->IsInt32()); 2575 CHECK(!obj->IsUint32()); 2576 // Large negative fraction. 2577 CompileRun("var obj = -5726623061.75;"); 2578 obj = env->Global()->Get(v8_str("obj")); 2579 CHECK(!obj->IsInt32()); 2580 CHECK(!obj->IsUint32()); 2581} 2582 2583 2584THREADED_TEST(ConversionException) { 2585 v8::HandleScope scope; 2586 LocalContext env; 2587 CompileRun( 2588 "function TestClass() { };" 2589 "TestClass.prototype.toString = function () { throw 'uncle?'; };" 2590 "var obj = new TestClass();"); 2591 Local<Value> obj = env->Global()->Get(v8_str("obj")); 2592 2593 v8::TryCatch try_catch; 2594 2595 Local<Value> to_string_result = obj->ToString(); 2596 CHECK(to_string_result.IsEmpty()); 2597 CheckUncle(&try_catch); 2598 2599 Local<Value> to_number_result = obj->ToNumber(); 2600 CHECK(to_number_result.IsEmpty()); 2601 CheckUncle(&try_catch); 2602 2603 Local<Value> to_integer_result = obj->ToInteger(); 2604 CHECK(to_integer_result.IsEmpty()); 2605 CheckUncle(&try_catch); 2606 2607 Local<Value> to_uint32_result = obj->ToUint32(); 2608 CHECK(to_uint32_result.IsEmpty()); 2609 CheckUncle(&try_catch); 2610 2611 Local<Value> to_int32_result = obj->ToInt32(); 2612 CHECK(to_int32_result.IsEmpty()); 2613 CheckUncle(&try_catch); 2614 2615 Local<Value> to_object_result = v8::Undefined()->ToObject(); 2616 CHECK(to_object_result.IsEmpty()); 2617 CHECK(try_catch.HasCaught()); 2618 try_catch.Reset(); 2619 2620 int32_t int32_value = obj->Int32Value(); 2621 CHECK_EQ(0, int32_value); 2622 CheckUncle(&try_catch); 2623 2624 uint32_t uint32_value = obj->Uint32Value(); 2625 CHECK_EQ(0, uint32_value); 2626 CheckUncle(&try_catch); 2627 2628 double number_value = obj->NumberValue(); 2629 CHECK_NE(0, IsNaN(number_value)); 2630 CheckUncle(&try_catch); 2631 2632 int64_t integer_value = obj->IntegerValue(); 2633 CHECK_EQ(0.0, static_cast<double>(integer_value)); 2634 CheckUncle(&try_catch); 2635} 2636 2637 2638v8::Handle<Value> ThrowFromC(const v8::Arguments& args) { 2639 ApiTestFuzzer::Fuzz(); 2640 return v8::ThrowException(v8_str("konto")); 2641} 2642 2643 2644v8::Handle<Value> CCatcher(const v8::Arguments& args) { 2645 if (args.Length() < 1) return v8::Boolean::New(false); 2646 v8::HandleScope scope; 2647 v8::TryCatch try_catch; 2648 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run(); 2649 CHECK(!try_catch.HasCaught() || result.IsEmpty()); 2650 return v8::Boolean::New(try_catch.HasCaught()); 2651} 2652 2653 2654THREADED_TEST(APICatch) { 2655 v8::HandleScope scope; 2656 Local<ObjectTemplate> templ = ObjectTemplate::New(); 2657 templ->Set(v8_str("ThrowFromC"), 2658 v8::FunctionTemplate::New(ThrowFromC)); 2659 LocalContext context(0, templ); 2660 CompileRun( 2661 "var thrown = false;" 2662 "try {" 2663 " ThrowFromC();" 2664 "} catch (e) {" 2665 " thrown = true;" 2666 "}"); 2667 Local<Value> thrown = context->Global()->Get(v8_str("thrown")); 2668 CHECK(thrown->BooleanValue()); 2669} 2670 2671 2672THREADED_TEST(APIThrowTryCatch) { 2673 v8::HandleScope scope; 2674 Local<ObjectTemplate> templ = ObjectTemplate::New(); 2675 templ->Set(v8_str("ThrowFromC"), 2676 v8::FunctionTemplate::New(ThrowFromC)); 2677 LocalContext context(0, templ); 2678 v8::TryCatch try_catch; 2679 CompileRun("ThrowFromC();"); 2680 CHECK(try_catch.HasCaught()); 2681} 2682 2683 2684// Test that a try-finally block doesn't shadow a try-catch block 2685// when setting up an external handler. 2686// 2687// BUG(271): Some of the exception propagation does not work on the 2688// ARM simulator because the simulator separates the C++ stack and the 2689// JS stack. This test therefore fails on the simulator. The test is 2690// not threaded to allow the threading tests to run on the simulator. 2691TEST(TryCatchInTryFinally) { 2692 v8::HandleScope scope; 2693 Local<ObjectTemplate> templ = ObjectTemplate::New(); 2694 templ->Set(v8_str("CCatcher"), 2695 v8::FunctionTemplate::New(CCatcher)); 2696 LocalContext context(0, templ); 2697 Local<Value> result = CompileRun("try {" 2698 " try {" 2699 " CCatcher('throw 7;');" 2700 " } finally {" 2701 " }" 2702 "} catch (e) {" 2703 "}"); 2704 CHECK(result->IsTrue()); 2705} 2706 2707 2708static void check_reference_error_message( 2709 v8::Handle<v8::Message> message, 2710 v8::Handle<v8::Value> data) { 2711 const char* reference_error = "Uncaught ReferenceError: asdf is not defined"; 2712 CHECK(message->Get()->Equals(v8_str(reference_error))); 2713} 2714 2715 2716static v8::Handle<Value> Fail(const v8::Arguments& args) { 2717 ApiTestFuzzer::Fuzz(); 2718 CHECK(false); 2719 return v8::Undefined(); 2720} 2721 2722 2723// Test that overwritten methods are not invoked on uncaught exception 2724// formatting. However, they are invoked when performing normal error 2725// string conversions. 2726TEST(APIThrowMessageOverwrittenToString) { 2727 v8::HandleScope scope; 2728 v8::V8::AddMessageListener(check_reference_error_message); 2729 Local<ObjectTemplate> templ = ObjectTemplate::New(); 2730 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail)); 2731 LocalContext context(NULL, templ); 2732 CompileRun("asdf;"); 2733 CompileRun("var limit = {};" 2734 "limit.valueOf = fail;" 2735 "Error.stackTraceLimit = limit;"); 2736 CompileRun("asdf"); 2737 CompileRun("Array.prototype.pop = fail;"); 2738 CompileRun("Object.prototype.hasOwnProperty = fail;"); 2739 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }"); 2740 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }"); 2741 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }"); 2742 CompileRun("ReferenceError.prototype.toString =" 2743 " function() { return 'Whoops' }"); 2744 CompileRun("asdf;"); 2745 CompileRun("ReferenceError.prototype.constructor.name = void 0;"); 2746 CompileRun("asdf;"); 2747 CompileRun("ReferenceError.prototype.constructor = void 0;"); 2748 CompileRun("asdf;"); 2749 CompileRun("ReferenceError.prototype.__proto__ = new Object();"); 2750 CompileRun("asdf;"); 2751 CompileRun("ReferenceError.prototype = new Object();"); 2752 CompileRun("asdf;"); 2753 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }"); 2754 CHECK(string->Equals(v8_str("Whoops"))); 2755 CompileRun("ReferenceError.prototype.constructor = new Object();" 2756 "ReferenceError.prototype.constructor.name = 1;" 2757 "Number.prototype.toString = function() { return 'Whoops'; };" 2758 "ReferenceError.prototype.toString = Object.prototype.toString;"); 2759 CompileRun("asdf;"); 2760 v8::V8::RemoveMessageListeners(check_message); 2761} 2762 2763 2764static void receive_message(v8::Handle<v8::Message> message, 2765 v8::Handle<v8::Value> data) { 2766 message->Get(); 2767 message_received = true; 2768} 2769 2770 2771TEST(APIThrowMessage) { 2772 message_received = false; 2773 v8::HandleScope scope; 2774 v8::V8::AddMessageListener(receive_message); 2775 Local<ObjectTemplate> templ = ObjectTemplate::New(); 2776 templ->Set(v8_str("ThrowFromC"), 2777 v8::FunctionTemplate::New(ThrowFromC)); 2778 LocalContext context(0, templ); 2779 CompileRun("ThrowFromC();"); 2780 CHECK(message_received); 2781 v8::V8::RemoveMessageListeners(check_message); 2782} 2783 2784 2785TEST(APIThrowMessageAndVerboseTryCatch) { 2786 message_received = false; 2787 v8::HandleScope scope; 2788 v8::V8::AddMessageListener(receive_message); 2789 Local<ObjectTemplate> templ = ObjectTemplate::New(); 2790 templ->Set(v8_str("ThrowFromC"), 2791 v8::FunctionTemplate::New(ThrowFromC)); 2792 LocalContext context(0, templ); 2793 v8::TryCatch try_catch; 2794 try_catch.SetVerbose(true); 2795 Local<Value> result = CompileRun("ThrowFromC();"); 2796 CHECK(try_catch.HasCaught()); 2797 CHECK(result.IsEmpty()); 2798 CHECK(message_received); 2799 v8::V8::RemoveMessageListeners(check_message); 2800} 2801 2802 2803TEST(APIStackOverflowAndVerboseTryCatch) { 2804 message_received = false; 2805 v8::HandleScope scope; 2806 v8::V8::AddMessageListener(receive_message); 2807 LocalContext context; 2808 v8::TryCatch try_catch; 2809 try_catch.SetVerbose(true); 2810 Local<Value> result = CompileRun("function foo() { foo(); } foo();"); 2811 CHECK(try_catch.HasCaught()); 2812 CHECK(result.IsEmpty()); 2813 CHECK(message_received); 2814 v8::V8::RemoveMessageListeners(receive_message); 2815} 2816 2817 2818THREADED_TEST(ExternalScriptException) { 2819 v8::HandleScope scope; 2820 Local<ObjectTemplate> templ = ObjectTemplate::New(); 2821 templ->Set(v8_str("ThrowFromC"), 2822 v8::FunctionTemplate::New(ThrowFromC)); 2823 LocalContext context(0, templ); 2824 2825 v8::TryCatch try_catch; 2826 Local<Script> script 2827 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';")); 2828 Local<Value> result = script->Run(); 2829 CHECK(result.IsEmpty()); 2830 CHECK(try_catch.HasCaught()); 2831 String::AsciiValue exception_value(try_catch.Exception()); 2832 CHECK_EQ("konto", *exception_value); 2833} 2834 2835 2836 2837v8::Handle<Value> CThrowCountDown(const v8::Arguments& args) { 2838 ApiTestFuzzer::Fuzz(); 2839 CHECK_EQ(4, args.Length()); 2840 int count = args[0]->Int32Value(); 2841 int cInterval = args[2]->Int32Value(); 2842 if (count == 0) { 2843 return v8::ThrowException(v8_str("FromC")); 2844 } else { 2845 Local<v8::Object> global = Context::GetCurrent()->Global(); 2846 Local<Value> fun = global->Get(v8_str("JSThrowCountDown")); 2847 v8::Handle<Value> argv[] = { v8_num(count - 1), 2848 args[1], 2849 args[2], 2850 args[3] }; 2851 if (count % cInterval == 0) { 2852 v8::TryCatch try_catch; 2853 Local<Value> result = fun.As<Function>()->Call(global, 4, argv); 2854 int expected = args[3]->Int32Value(); 2855 if (try_catch.HasCaught()) { 2856 CHECK_EQ(expected, count); 2857 CHECK(result.IsEmpty()); 2858 CHECK(!i::Isolate::Current()->has_scheduled_exception()); 2859 } else { 2860 CHECK_NE(expected, count); 2861 } 2862 return result; 2863 } else { 2864 return fun.As<Function>()->Call(global, 4, argv); 2865 } 2866 } 2867} 2868 2869 2870v8::Handle<Value> JSCheck(const v8::Arguments& args) { 2871 ApiTestFuzzer::Fuzz(); 2872 CHECK_EQ(3, args.Length()); 2873 bool equality = args[0]->BooleanValue(); 2874 int count = args[1]->Int32Value(); 2875 int expected = args[2]->Int32Value(); 2876 if (equality) { 2877 CHECK_EQ(count, expected); 2878 } else { 2879 CHECK_NE(count, expected); 2880 } 2881 return v8::Undefined(); 2882} 2883 2884 2885THREADED_TEST(EvalInTryFinally) { 2886 v8::HandleScope scope; 2887 LocalContext context; 2888 v8::TryCatch try_catch; 2889 CompileRun("(function() {" 2890 " try {" 2891 " eval('asldkf (*&^&*^');" 2892 " } finally {" 2893 " return;" 2894 " }" 2895 "})()"); 2896 CHECK(!try_catch.HasCaught()); 2897} 2898 2899 2900// This test works by making a stack of alternating JavaScript and C 2901// activations. These activations set up exception handlers with regular 2902// intervals, one interval for C activations and another for JavaScript 2903// activations. When enough activations have been created an exception is 2904// thrown and we check that the right activation catches the exception and that 2905// no other activations do. The right activation is always the topmost one with 2906// a handler, regardless of whether it is in JavaScript or C. 2907// 2908// The notation used to describe a test case looks like this: 2909// 2910// *JS[4] *C[3] @JS[2] C[1] JS[0] 2911// 2912// Each entry is an activation, either JS or C. The index is the count at that 2913// level. Stars identify activations with exception handlers, the @ identifies 2914// the exception handler that should catch the exception. 2915// 2916// BUG(271): Some of the exception propagation does not work on the 2917// ARM simulator because the simulator separates the C++ stack and the 2918// JS stack. This test therefore fails on the simulator. The test is 2919// not threaded to allow the threading tests to run on the simulator. 2920TEST(ExceptionOrder) { 2921 v8::HandleScope scope; 2922 Local<ObjectTemplate> templ = ObjectTemplate::New(); 2923 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck)); 2924 templ->Set(v8_str("CThrowCountDown"), 2925 v8::FunctionTemplate::New(CThrowCountDown)); 2926 LocalContext context(0, templ); 2927 CompileRun( 2928 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {" 2929 " if (count == 0) throw 'FromJS';" 2930 " if (count % jsInterval == 0) {" 2931 " try {" 2932 " var value = CThrowCountDown(count - 1," 2933 " jsInterval," 2934 " cInterval," 2935 " expected);" 2936 " check(false, count, expected);" 2937 " return value;" 2938 " } catch (e) {" 2939 " check(true, count, expected);" 2940 " }" 2941 " } else {" 2942 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);" 2943 " }" 2944 "}"); 2945 Local<Function> fun = 2946 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown"))); 2947 2948 const int argc = 4; 2949 // count jsInterval cInterval expected 2950 2951 // *JS[4] *C[3] @JS[2] C[1] JS[0] 2952 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) }; 2953 fun->Call(fun, argc, a0); 2954 2955 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0] 2956 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) }; 2957 fun->Call(fun, argc, a1); 2958 2959 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0] 2960 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) }; 2961 fun->Call(fun, argc, a2); 2962 2963 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0] 2964 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) }; 2965 fun->Call(fun, argc, a3); 2966 2967 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0] 2968 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) }; 2969 fun->Call(fun, argc, a4); 2970 2971 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0] 2972 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) }; 2973 fun->Call(fun, argc, a5); 2974} 2975 2976 2977v8::Handle<Value> ThrowValue(const v8::Arguments& args) { 2978 ApiTestFuzzer::Fuzz(); 2979 CHECK_EQ(1, args.Length()); 2980 return v8::ThrowException(args[0]); 2981} 2982 2983 2984THREADED_TEST(ThrowValues) { 2985 v8::HandleScope scope; 2986 Local<ObjectTemplate> templ = ObjectTemplate::New(); 2987 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue)); 2988 LocalContext context(0, templ); 2989 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 2990 "function Run(obj) {" 2991 " try {" 2992 " Throw(obj);" 2993 " } catch (e) {" 2994 " return e;" 2995 " }" 2996 " return 'no exception';" 2997 "}" 2998 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];")); 2999 CHECK_EQ(5, result->Length()); 3000 CHECK(result->Get(v8::Integer::New(0))->IsString()); 3001 CHECK(result->Get(v8::Integer::New(1))->IsNumber()); 3002 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value()); 3003 CHECK(result->Get(v8::Integer::New(2))->IsNumber()); 3004 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value()); 3005 CHECK(result->Get(v8::Integer::New(3))->IsNull()); 3006 CHECK(result->Get(v8::Integer::New(4))->IsUndefined()); 3007} 3008 3009 3010THREADED_TEST(CatchZero) { 3011 v8::HandleScope scope; 3012 LocalContext context; 3013 v8::TryCatch try_catch; 3014 CHECK(!try_catch.HasCaught()); 3015 Script::Compile(v8_str("throw 10"))->Run(); 3016 CHECK(try_catch.HasCaught()); 3017 CHECK_EQ(10, try_catch.Exception()->Int32Value()); 3018 try_catch.Reset(); 3019 CHECK(!try_catch.HasCaught()); 3020 Script::Compile(v8_str("throw 0"))->Run(); 3021 CHECK(try_catch.HasCaught()); 3022 CHECK_EQ(0, try_catch.Exception()->Int32Value()); 3023} 3024 3025 3026THREADED_TEST(CatchExceptionFromWith) { 3027 v8::HandleScope scope; 3028 LocalContext context; 3029 v8::TryCatch try_catch; 3030 CHECK(!try_catch.HasCaught()); 3031 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run(); 3032 CHECK(try_catch.HasCaught()); 3033} 3034 3035 3036THREADED_TEST(TryCatchAndFinallyHidingException) { 3037 v8::HandleScope scope; 3038 LocalContext context; 3039 v8::TryCatch try_catch; 3040 CHECK(!try_catch.HasCaught()); 3041 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };"); 3042 CompileRun("f({toString: function() { throw 42; }});"); 3043 CHECK(!try_catch.HasCaught()); 3044} 3045 3046 3047v8::Handle<v8::Value> WithTryCatch(const v8::Arguments& args) { 3048 v8::TryCatch try_catch; 3049 return v8::Undefined(); 3050} 3051 3052 3053THREADED_TEST(TryCatchAndFinally) { 3054 v8::HandleScope scope; 3055 LocalContext context; 3056 context->Global()->Set( 3057 v8_str("native_with_try_catch"), 3058 v8::FunctionTemplate::New(WithTryCatch)->GetFunction()); 3059 v8::TryCatch try_catch; 3060 CHECK(!try_catch.HasCaught()); 3061 CompileRun( 3062 "try {\n" 3063 " throw new Error('a');\n" 3064 "} finally {\n" 3065 " native_with_try_catch();\n" 3066 "}\n"); 3067 CHECK(try_catch.HasCaught()); 3068} 3069 3070 3071THREADED_TEST(Equality) { 3072 v8::HandleScope scope; 3073 LocalContext context; 3074 // Check that equality works at all before relying on CHECK_EQ 3075 CHECK(v8_str("a")->Equals(v8_str("a"))); 3076 CHECK(!v8_str("a")->Equals(v8_str("b"))); 3077 3078 CHECK_EQ(v8_str("a"), v8_str("a")); 3079 CHECK_NE(v8_str("a"), v8_str("b")); 3080 CHECK_EQ(v8_num(1), v8_num(1)); 3081 CHECK_EQ(v8_num(1.00), v8_num(1)); 3082 CHECK_NE(v8_num(1), v8_num(2)); 3083 3084 // Assume String is not symbol. 3085 CHECK(v8_str("a")->StrictEquals(v8_str("a"))); 3086 CHECK(!v8_str("a")->StrictEquals(v8_str("b"))); 3087 CHECK(!v8_str("5")->StrictEquals(v8_num(5))); 3088 CHECK(v8_num(1)->StrictEquals(v8_num(1))); 3089 CHECK(!v8_num(1)->StrictEquals(v8_num(2))); 3090 CHECK(v8_num(0)->StrictEquals(v8_num(-0))); 3091 Local<Value> not_a_number = v8_num(i::OS::nan_value()); 3092 CHECK(!not_a_number->StrictEquals(not_a_number)); 3093 CHECK(v8::False()->StrictEquals(v8::False())); 3094 CHECK(!v8::False()->StrictEquals(v8::Undefined())); 3095 3096 v8::Handle<v8::Object> obj = v8::Object::New(); 3097 v8::Persistent<v8::Object> alias = v8::Persistent<v8::Object>::New(obj); 3098 CHECK(alias->StrictEquals(obj)); 3099 alias.Dispose(); 3100} 3101 3102 3103THREADED_TEST(MultiRun) { 3104 v8::HandleScope scope; 3105 LocalContext context; 3106 Local<Script> script = Script::Compile(v8_str("x")); 3107 for (int i = 0; i < 10; i++) 3108 script->Run(); 3109} 3110 3111 3112static v8::Handle<Value> GetXValue(Local<String> name, 3113 const AccessorInfo& info) { 3114 ApiTestFuzzer::Fuzz(); 3115 CHECK_EQ(info.Data(), v8_str("donut")); 3116 CHECK_EQ(name, v8_str("x")); 3117 return name; 3118} 3119 3120 3121THREADED_TEST(SimplePropertyRead) { 3122 v8::HandleScope scope; 3123 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3124 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 3125 LocalContext context; 3126 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 3127 Local<Script> script = Script::Compile(v8_str("obj.x")); 3128 for (int i = 0; i < 10; i++) { 3129 Local<Value> result = script->Run(); 3130 CHECK_EQ(result, v8_str("x")); 3131 } 3132} 3133 3134THREADED_TEST(DefinePropertyOnAPIAccessor) { 3135 v8::HandleScope scope; 3136 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3137 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 3138 LocalContext context; 3139 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 3140 3141 // Uses getOwnPropertyDescriptor to check the configurable status 3142 Local<Script> script_desc 3143 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( " 3144 "obj, 'x');" 3145 "prop.configurable;")); 3146 Local<Value> result = script_desc->Run(); 3147 CHECK_EQ(result->BooleanValue(), true); 3148 3149 // Redefine get - but still configurable 3150 Local<Script> script_define 3151 = Script::Compile(v8_str("var desc = { get: function(){return 42; }," 3152 " configurable: true };" 3153 "Object.defineProperty(obj, 'x', desc);" 3154 "obj.x")); 3155 result = script_define->Run(); 3156 CHECK_EQ(result, v8_num(42)); 3157 3158 // Check that the accessor is still configurable 3159 result = script_desc->Run(); 3160 CHECK_EQ(result->BooleanValue(), true); 3161 3162 // Redefine to a non-configurable 3163 script_define 3164 = Script::Compile(v8_str("var desc = { get: function(){return 43; }," 3165 " configurable: false };" 3166 "Object.defineProperty(obj, 'x', desc);" 3167 "obj.x")); 3168 result = script_define->Run(); 3169 CHECK_EQ(result, v8_num(43)); 3170 result = script_desc->Run(); 3171 CHECK_EQ(result->BooleanValue(), false); 3172 3173 // Make sure that it is not possible to redefine again 3174 v8::TryCatch try_catch; 3175 result = script_define->Run(); 3176 CHECK(try_catch.HasCaught()); 3177 String::AsciiValue exception_value(try_catch.Exception()); 3178 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 3179} 3180 3181THREADED_TEST(DefinePropertyOnDefineGetterSetter) { 3182 v8::HandleScope scope; 3183 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3184 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 3185 LocalContext context; 3186 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 3187 3188 Local<Script> script_desc = Script::Compile(v8_str("var prop =" 3189 "Object.getOwnPropertyDescriptor( " 3190 "obj, 'x');" 3191 "prop.configurable;")); 3192 Local<Value> result = script_desc->Run(); 3193 CHECK_EQ(result->BooleanValue(), true); 3194 3195 Local<Script> script_define = 3196 Script::Compile(v8_str("var desc = {get: function(){return 42; }," 3197 " configurable: true };" 3198 "Object.defineProperty(obj, 'x', desc);" 3199 "obj.x")); 3200 result = script_define->Run(); 3201 CHECK_EQ(result, v8_num(42)); 3202 3203 3204 result = script_desc->Run(); 3205 CHECK_EQ(result->BooleanValue(), true); 3206 3207 3208 script_define = 3209 Script::Compile(v8_str("var desc = {get: function(){return 43; }," 3210 " configurable: false };" 3211 "Object.defineProperty(obj, 'x', desc);" 3212 "obj.x")); 3213 result = script_define->Run(); 3214 CHECK_EQ(result, v8_num(43)); 3215 result = script_desc->Run(); 3216 3217 CHECK_EQ(result->BooleanValue(), false); 3218 3219 v8::TryCatch try_catch; 3220 result = script_define->Run(); 3221 CHECK(try_catch.HasCaught()); 3222 String::AsciiValue exception_value(try_catch.Exception()); 3223 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 3224} 3225 3226 3227static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context, 3228 char const* name) { 3229 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name))); 3230} 3231 3232 3233THREADED_TEST(DefineAPIAccessorOnObject) { 3234 v8::HandleScope scope; 3235 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3236 LocalContext context; 3237 3238 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 3239 CompileRun("var obj2 = {};"); 3240 3241 CHECK(CompileRun("obj1.x")->IsUndefined()); 3242 CHECK(CompileRun("obj2.x")->IsUndefined()); 3243 3244 CHECK(GetGlobalProperty(&context, "obj1")-> 3245 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 3246 3247 ExpectString("obj1.x", "x"); 3248 CHECK(CompileRun("obj2.x")->IsUndefined()); 3249 3250 CHECK(GetGlobalProperty(&context, "obj2")-> 3251 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 3252 3253 ExpectString("obj1.x", "x"); 3254 ExpectString("obj2.x", "x"); 3255 3256 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 3257 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 3258 3259 CompileRun("Object.defineProperty(obj1, 'x'," 3260 "{ get: function() { return 'y'; }, configurable: true })"); 3261 3262 ExpectString("obj1.x", "y"); 3263 ExpectString("obj2.x", "x"); 3264 3265 CompileRun("Object.defineProperty(obj2, 'x'," 3266 "{ get: function() { return 'y'; }, configurable: true })"); 3267 3268 ExpectString("obj1.x", "y"); 3269 ExpectString("obj2.x", "y"); 3270 3271 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 3272 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 3273 3274 CHECK(GetGlobalProperty(&context, "obj1")-> 3275 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 3276 CHECK(GetGlobalProperty(&context, "obj2")-> 3277 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 3278 3279 ExpectString("obj1.x", "x"); 3280 ExpectString("obj2.x", "x"); 3281 3282 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 3283 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 3284 3285 // Define getters/setters, but now make them not configurable. 3286 CompileRun("Object.defineProperty(obj1, 'x'," 3287 "{ get: function() { return 'z'; }, configurable: false })"); 3288 CompileRun("Object.defineProperty(obj2, 'x'," 3289 "{ get: function() { return 'z'; }, configurable: false })"); 3290 3291 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 3292 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 3293 3294 ExpectString("obj1.x", "z"); 3295 ExpectString("obj2.x", "z"); 3296 3297 CHECK(!GetGlobalProperty(&context, "obj1")-> 3298 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 3299 CHECK(!GetGlobalProperty(&context, "obj2")-> 3300 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 3301 3302 ExpectString("obj1.x", "z"); 3303 ExpectString("obj2.x", "z"); 3304} 3305 3306 3307THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) { 3308 v8::HandleScope scope; 3309 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3310 LocalContext context; 3311 3312 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 3313 CompileRun("var obj2 = {};"); 3314 3315 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor( 3316 v8_str("x"), 3317 GetXValue, NULL, 3318 v8_str("donut"), v8::DEFAULT, v8::DontDelete)); 3319 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor( 3320 v8_str("x"), 3321 GetXValue, NULL, 3322 v8_str("donut"), v8::DEFAULT, v8::DontDelete)); 3323 3324 ExpectString("obj1.x", "x"); 3325 ExpectString("obj2.x", "x"); 3326 3327 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 3328 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 3329 3330 CHECK(!GetGlobalProperty(&context, "obj1")-> 3331 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 3332 CHECK(!GetGlobalProperty(&context, "obj2")-> 3333 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 3334 3335 { 3336 v8::TryCatch try_catch; 3337 CompileRun("Object.defineProperty(obj1, 'x'," 3338 "{get: function() { return 'func'; }})"); 3339 CHECK(try_catch.HasCaught()); 3340 String::AsciiValue exception_value(try_catch.Exception()); 3341 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 3342 } 3343 { 3344 v8::TryCatch try_catch; 3345 CompileRun("Object.defineProperty(obj2, 'x'," 3346 "{get: function() { return 'func'; }})"); 3347 CHECK(try_catch.HasCaught()); 3348 String::AsciiValue exception_value(try_catch.Exception()); 3349 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 3350 } 3351} 3352 3353 3354static v8::Handle<Value> Get239Value(Local<String> name, 3355 const AccessorInfo& info) { 3356 ApiTestFuzzer::Fuzz(); 3357 CHECK_EQ(info.Data(), v8_str("donut")); 3358 CHECK_EQ(name, v8_str("239")); 3359 return name; 3360} 3361 3362 3363THREADED_TEST(ElementAPIAccessor) { 3364 v8::HandleScope scope; 3365 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3366 LocalContext context; 3367 3368 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 3369 CompileRun("var obj2 = {};"); 3370 3371 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor( 3372 v8_str("239"), 3373 Get239Value, NULL, 3374 v8_str("donut"))); 3375 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor( 3376 v8_str("239"), 3377 Get239Value, NULL, 3378 v8_str("donut"))); 3379 3380 ExpectString("obj1[239]", "239"); 3381 ExpectString("obj2[239]", "239"); 3382 ExpectString("obj1['239']", "239"); 3383 ExpectString("obj2['239']", "239"); 3384} 3385 3386 3387v8::Persistent<Value> xValue; 3388 3389 3390static void SetXValue(Local<String> name, 3391 Local<Value> value, 3392 const AccessorInfo& info) { 3393 CHECK_EQ(value, v8_num(4)); 3394 CHECK_EQ(info.Data(), v8_str("donut")); 3395 CHECK_EQ(name, v8_str("x")); 3396 CHECK(xValue.IsEmpty()); 3397 xValue = v8::Persistent<Value>::New(value); 3398} 3399 3400 3401THREADED_TEST(SimplePropertyWrite) { 3402 v8::HandleScope scope; 3403 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3404 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut")); 3405 LocalContext context; 3406 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 3407 Local<Script> script = Script::Compile(v8_str("obj.x = 4")); 3408 for (int i = 0; i < 10; i++) { 3409 CHECK(xValue.IsEmpty()); 3410 script->Run(); 3411 CHECK_EQ(v8_num(4), xValue); 3412 xValue.Dispose(); 3413 xValue = v8::Persistent<Value>(); 3414 } 3415} 3416 3417 3418static v8::Handle<Value> XPropertyGetter(Local<String> property, 3419 const AccessorInfo& info) { 3420 ApiTestFuzzer::Fuzz(); 3421 CHECK(info.Data()->IsUndefined()); 3422 return property; 3423} 3424 3425 3426THREADED_TEST(NamedInterceptorPropertyRead) { 3427 v8::HandleScope scope; 3428 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3429 templ->SetNamedPropertyHandler(XPropertyGetter); 3430 LocalContext context; 3431 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 3432 Local<Script> script = Script::Compile(v8_str("obj.x")); 3433 for (int i = 0; i < 10; i++) { 3434 Local<Value> result = script->Run(); 3435 CHECK_EQ(result, v8_str("x")); 3436 } 3437} 3438 3439 3440THREADED_TEST(NamedInterceptorDictionaryIC) { 3441 v8::HandleScope scope; 3442 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3443 templ->SetNamedPropertyHandler(XPropertyGetter); 3444 LocalContext context; 3445 // Create an object with a named interceptor. 3446 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance()); 3447 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x")); 3448 for (int i = 0; i < 10; i++) { 3449 Local<Value> result = script->Run(); 3450 CHECK_EQ(result, v8_str("x")); 3451 } 3452 // Create a slow case object and a function accessing a property in 3453 // that slow case object (with dictionary probing in generated 3454 // code). Then force object with a named interceptor into slow-case, 3455 // pass it to the function, and check that the interceptor is called 3456 // instead of accessing the local property. 3457 Local<Value> result = 3458 CompileRun("function get_x(o) { return o.x; };" 3459 "var obj = { x : 42, y : 0 };" 3460 "delete obj.y;" 3461 "for (var i = 0; i < 10; i++) get_x(obj);" 3462 "interceptor_obj.x = 42;" 3463 "interceptor_obj.y = 10;" 3464 "delete interceptor_obj.y;" 3465 "get_x(interceptor_obj)"); 3466 CHECK_EQ(result, v8_str("x")); 3467} 3468 3469 3470THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) { 3471 v8::HandleScope scope; 3472 3473 v8::Persistent<Context> context1 = Context::New(); 3474 3475 context1->Enter(); 3476 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3477 templ->SetNamedPropertyHandler(XPropertyGetter); 3478 // Create an object with a named interceptor. 3479 v8::Local<v8::Object> object = templ->NewInstance(); 3480 context1->Global()->Set(v8_str("interceptor_obj"), object); 3481 3482 // Force the object into the slow case. 3483 CompileRun("interceptor_obj.y = 0;" 3484 "delete interceptor_obj.y;"); 3485 context1->Exit(); 3486 3487 { 3488 // Introduce the object into a different context. 3489 // Repeat named loads to exercise ICs. 3490 LocalContext context2; 3491 context2->Global()->Set(v8_str("interceptor_obj"), object); 3492 Local<Value> result = 3493 CompileRun("function get_x(o) { return o.x; }" 3494 "interceptor_obj.x = 42;" 3495 "for (var i=0; i != 10; i++) {" 3496 " get_x(interceptor_obj);" 3497 "}" 3498 "get_x(interceptor_obj)"); 3499 // Check that the interceptor was actually invoked. 3500 CHECK_EQ(result, v8_str("x")); 3501 } 3502 3503 // Return to the original context and force some object to the slow case 3504 // to cause the NormalizedMapCache to verify. 3505 context1->Enter(); 3506 CompileRun("var obj = { x : 0 }; delete obj.x;"); 3507 context1->Exit(); 3508 3509 context1.Dispose(); 3510} 3511 3512 3513static v8::Handle<Value> SetXOnPrototypeGetter(Local<String> property, 3514 const AccessorInfo& info) { 3515 // Set x on the prototype object and do not handle the get request. 3516 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype(); 3517 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23)); 3518 return v8::Handle<Value>(); 3519} 3520 3521 3522// This is a regression test for http://crbug.com/20104. Map 3523// transitions should not interfere with post interceptor lookup. 3524THREADED_TEST(NamedInterceptorMapTransitionRead) { 3525 v8::HandleScope scope; 3526 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New(); 3527 Local<v8::ObjectTemplate> instance_template 3528 = function_template->InstanceTemplate(); 3529 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter); 3530 LocalContext context; 3531 context->Global()->Set(v8_str("F"), function_template->GetFunction()); 3532 // Create an instance of F and introduce a map transition for x. 3533 CompileRun("var o = new F(); o.x = 23;"); 3534 // Create an instance of F and invoke the getter. The result should be 23. 3535 Local<Value> result = CompileRun("o = new F(); o.x"); 3536 CHECK_EQ(result->Int32Value(), 23); 3537} 3538 3539 3540static v8::Handle<Value> IndexedPropertyGetter(uint32_t index, 3541 const AccessorInfo& info) { 3542 ApiTestFuzzer::Fuzz(); 3543 if (index == 37) { 3544 return v8::Handle<Value>(v8_num(625)); 3545 } 3546 return v8::Handle<Value>(); 3547} 3548 3549 3550static v8::Handle<Value> IndexedPropertySetter(uint32_t index, 3551 Local<Value> value, 3552 const AccessorInfo& info) { 3553 ApiTestFuzzer::Fuzz(); 3554 if (index == 39) { 3555 return value; 3556 } 3557 return v8::Handle<Value>(); 3558} 3559 3560 3561THREADED_TEST(IndexedInterceptorWithIndexedAccessor) { 3562 v8::HandleScope scope; 3563 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3564 templ->SetIndexedPropertyHandler(IndexedPropertyGetter, 3565 IndexedPropertySetter); 3566 LocalContext context; 3567 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 3568 Local<Script> getter_script = Script::Compile(v8_str( 3569 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];")); 3570 Local<Script> setter_script = Script::Compile(v8_str( 3571 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});" 3572 "obj[17] = 23;" 3573 "obj.foo;")); 3574 Local<Script> interceptor_setter_script = Script::Compile(v8_str( 3575 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});" 3576 "obj[39] = 47;" 3577 "obj.foo;")); // This setter should not run, due to the interceptor. 3578 Local<Script> interceptor_getter_script = Script::Compile(v8_str( 3579 "obj[37];")); 3580 Local<Value> result = getter_script->Run(); 3581 CHECK_EQ(v8_num(5), result); 3582 result = setter_script->Run(); 3583 CHECK_EQ(v8_num(23), result); 3584 result = interceptor_setter_script->Run(); 3585 CHECK_EQ(v8_num(23), result); 3586 result = interceptor_getter_script->Run(); 3587 CHECK_EQ(v8_num(625), result); 3588} 3589 3590 3591static v8::Handle<Value> IdentityIndexedPropertyGetter( 3592 uint32_t index, 3593 const AccessorInfo& info) { 3594 return v8::Integer::NewFromUnsigned(index); 3595} 3596 3597 3598THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) { 3599 v8::HandleScope scope; 3600 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3601 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 3602 3603 LocalContext context; 3604 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 3605 3606 // Check fast object case. 3607 const char* fast_case_code = 3608 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()"; 3609 ExpectString(fast_case_code, "0"); 3610 3611 // Check slow case. 3612 const char* slow_case_code = 3613 "obj.x = 1; delete obj.x;" 3614 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()"; 3615 ExpectString(slow_case_code, "1"); 3616} 3617 3618 3619THREADED_TEST(IndexedInterceptorWithNoSetter) { 3620 v8::HandleScope scope; 3621 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3622 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 3623 3624 LocalContext context; 3625 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 3626 3627 const char* code = 3628 "try {" 3629 " obj[0] = 239;" 3630 " for (var i = 0; i < 100; i++) {" 3631 " var v = obj[0];" 3632 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;" 3633 " }" 3634 " 'PASSED'" 3635 "} catch(e) {" 3636 " e" 3637 "}"; 3638 ExpectString(code, "PASSED"); 3639} 3640 3641 3642THREADED_TEST(IndexedInterceptorWithAccessorCheck) { 3643 v8::HandleScope scope; 3644 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3645 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 3646 3647 LocalContext context; 3648 Local<v8::Object> obj = templ->NewInstance(); 3649 obj->TurnOnAccessCheck(); 3650 context->Global()->Set(v8_str("obj"), obj); 3651 3652 const char* code = 3653 "try {" 3654 " for (var i = 0; i < 100; i++) {" 3655 " var v = obj[0];" 3656 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;" 3657 " }" 3658 " 'PASSED'" 3659 "} catch(e) {" 3660 " e" 3661 "}"; 3662 ExpectString(code, "PASSED"); 3663} 3664 3665 3666THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) { 3667 i::FLAG_allow_natives_syntax = true; 3668 v8::HandleScope scope; 3669 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3670 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 3671 3672 LocalContext context; 3673 Local<v8::Object> obj = templ->NewInstance(); 3674 context->Global()->Set(v8_str("obj"), obj); 3675 3676 const char* code = 3677 "try {" 3678 " for (var i = 0; i < 100; i++) {" 3679 " var expected = i;" 3680 " if (i == 5) {" 3681 " %EnableAccessChecks(obj);" 3682 " expected = undefined;" 3683 " }" 3684 " var v = obj[i];" 3685 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 3686 " if (i == 5) %DisableAccessChecks(obj);" 3687 " }" 3688 " 'PASSED'" 3689 "} catch(e) {" 3690 " e" 3691 "}"; 3692 ExpectString(code, "PASSED"); 3693} 3694 3695 3696THREADED_TEST(IndexedInterceptorWithDifferentIndices) { 3697 v8::HandleScope scope; 3698 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3699 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 3700 3701 LocalContext context; 3702 Local<v8::Object> obj = templ->NewInstance(); 3703 context->Global()->Set(v8_str("obj"), obj); 3704 3705 const char* code = 3706 "try {" 3707 " for (var i = 0; i < 100; i++) {" 3708 " var v = obj[i];" 3709 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;" 3710 " }" 3711 " 'PASSED'" 3712 "} catch(e) {" 3713 " e" 3714 "}"; 3715 ExpectString(code, "PASSED"); 3716} 3717 3718 3719THREADED_TEST(IndexedInterceptorWithNegativeIndices) { 3720 v8::HandleScope scope; 3721 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3722 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 3723 3724 LocalContext context; 3725 Local<v8::Object> obj = templ->NewInstance(); 3726 context->Global()->Set(v8_str("obj"), obj); 3727 3728 const char* code = 3729 "try {" 3730 " for (var i = 0; i < 100; i++) {" 3731 " var expected = i;" 3732 " var key = i;" 3733 " if (i == 25) {" 3734 " key = -1;" 3735 " expected = undefined;" 3736 " }" 3737 " if (i == 50) {" 3738 " /* probe minimal Smi number on 32-bit platforms */" 3739 " key = -(1 << 30);" 3740 " expected = undefined;" 3741 " }" 3742 " if (i == 75) {" 3743 " /* probe minimal Smi number on 64-bit platforms */" 3744 " key = 1 << 31;" 3745 " expected = undefined;" 3746 " }" 3747 " var v = obj[key];" 3748 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 3749 " }" 3750 " 'PASSED'" 3751 "} catch(e) {" 3752 " e" 3753 "}"; 3754 ExpectString(code, "PASSED"); 3755} 3756 3757 3758THREADED_TEST(IndexedInterceptorWithNotSmiLookup) { 3759 v8::HandleScope scope; 3760 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3761 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 3762 3763 LocalContext context; 3764 Local<v8::Object> obj = templ->NewInstance(); 3765 context->Global()->Set(v8_str("obj"), obj); 3766 3767 const char* code = 3768 "try {" 3769 " for (var i = 0; i < 100; i++) {" 3770 " var expected = i;" 3771 " var key = i;" 3772 " if (i == 50) {" 3773 " key = 'foobar';" 3774 " expected = undefined;" 3775 " }" 3776 " var v = obj[key];" 3777 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 3778 " }" 3779 " 'PASSED'" 3780 "} catch(e) {" 3781 " e" 3782 "}"; 3783 ExpectString(code, "PASSED"); 3784} 3785 3786 3787THREADED_TEST(IndexedInterceptorGoingMegamorphic) { 3788 v8::HandleScope scope; 3789 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3790 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 3791 3792 LocalContext context; 3793 Local<v8::Object> obj = templ->NewInstance(); 3794 context->Global()->Set(v8_str("obj"), obj); 3795 3796 const char* code = 3797 "var original = obj;" 3798 "try {" 3799 " for (var i = 0; i < 100; i++) {" 3800 " var expected = i;" 3801 " if (i == 50) {" 3802 " obj = {50: 'foobar'};" 3803 " expected = 'foobar';" 3804 " }" 3805 " var v = obj[i];" 3806 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 3807 " if (i == 50) obj = original;" 3808 " }" 3809 " 'PASSED'" 3810 "} catch(e) {" 3811 " e" 3812 "}"; 3813 ExpectString(code, "PASSED"); 3814} 3815 3816 3817THREADED_TEST(IndexedInterceptorReceiverTurningSmi) { 3818 v8::HandleScope scope; 3819 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3820 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 3821 3822 LocalContext context; 3823 Local<v8::Object> obj = templ->NewInstance(); 3824 context->Global()->Set(v8_str("obj"), obj); 3825 3826 const char* code = 3827 "var original = obj;" 3828 "try {" 3829 " for (var i = 0; i < 100; i++) {" 3830 " var expected = i;" 3831 " if (i == 5) {" 3832 " obj = 239;" 3833 " expected = undefined;" 3834 " }" 3835 " var v = obj[i];" 3836 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 3837 " if (i == 5) obj = original;" 3838 " }" 3839 " 'PASSED'" 3840 "} catch(e) {" 3841 " e" 3842 "}"; 3843 ExpectString(code, "PASSED"); 3844} 3845 3846 3847THREADED_TEST(IndexedInterceptorOnProto) { 3848 v8::HandleScope scope; 3849 Local<ObjectTemplate> templ = ObjectTemplate::New(); 3850 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 3851 3852 LocalContext context; 3853 Local<v8::Object> obj = templ->NewInstance(); 3854 context->Global()->Set(v8_str("obj"), obj); 3855 3856 const char* code = 3857 "var o = {__proto__: obj};" 3858 "try {" 3859 " for (var i = 0; i < 100; i++) {" 3860 " var v = o[i];" 3861 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;" 3862 " }" 3863 " 'PASSED'" 3864 "} catch(e) {" 3865 " e" 3866 "}"; 3867 ExpectString(code, "PASSED"); 3868} 3869 3870 3871THREADED_TEST(MultiContexts) { 3872 v8::HandleScope scope; 3873 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(); 3874 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler)); 3875 3876 Local<String> password = v8_str("Password"); 3877 3878 // Create an environment 3879 LocalContext context0(0, templ); 3880 context0->SetSecurityToken(password); 3881 v8::Handle<v8::Object> global0 = context0->Global(); 3882 global0->Set(v8_str("custom"), v8_num(1234)); 3883 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value()); 3884 3885 // Create an independent environment 3886 LocalContext context1(0, templ); 3887 context1->SetSecurityToken(password); 3888 v8::Handle<v8::Object> global1 = context1->Global(); 3889 global1->Set(v8_str("custom"), v8_num(1234)); 3890 CHECK_NE(global0, global1); 3891 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value()); 3892 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value()); 3893 3894 // Now create a new context with the old global 3895 LocalContext context2(0, templ, global1); 3896 context2->SetSecurityToken(password); 3897 v8::Handle<v8::Object> global2 = context2->Global(); 3898 CHECK_EQ(global1, global2); 3899 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value()); 3900 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value()); 3901} 3902 3903 3904THREADED_TEST(FunctionPrototypeAcrossContexts) { 3905 // Make sure that functions created by cloning boilerplates cannot 3906 // communicate through their __proto__ field. 3907 3908 v8::HandleScope scope; 3909 3910 LocalContext env0; 3911 v8::Handle<v8::Object> global0 = 3912 env0->Global(); 3913 v8::Handle<v8::Object> object0 = 3914 global0->Get(v8_str("Object")).As<v8::Object>(); 3915 v8::Handle<v8::Object> tostring0 = 3916 object0->Get(v8_str("toString")).As<v8::Object>(); 3917 v8::Handle<v8::Object> proto0 = 3918 tostring0->Get(v8_str("__proto__")).As<v8::Object>(); 3919 proto0->Set(v8_str("custom"), v8_num(1234)); 3920 3921 LocalContext env1; 3922 v8::Handle<v8::Object> global1 = 3923 env1->Global(); 3924 v8::Handle<v8::Object> object1 = 3925 global1->Get(v8_str("Object")).As<v8::Object>(); 3926 v8::Handle<v8::Object> tostring1 = 3927 object1->Get(v8_str("toString")).As<v8::Object>(); 3928 v8::Handle<v8::Object> proto1 = 3929 tostring1->Get(v8_str("__proto__")).As<v8::Object>(); 3930 CHECK(!proto1->Has(v8_str("custom"))); 3931} 3932 3933 3934THREADED_TEST(Regress892105) { 3935 // Make sure that object and array literals created by cloning 3936 // boilerplates cannot communicate through their __proto__ 3937 // field. This is rather difficult to check, but we try to add stuff 3938 // to Object.prototype and Array.prototype and create a new 3939 // environment. This should succeed. 3940 3941 v8::HandleScope scope; 3942 3943 Local<String> source = v8_str("Object.prototype.obj = 1234;" 3944 "Array.prototype.arr = 4567;" 3945 "8901"); 3946 3947 LocalContext env0; 3948 Local<Script> script0 = Script::Compile(source); 3949 CHECK_EQ(8901.0, script0->Run()->NumberValue()); 3950 3951 LocalContext env1; 3952 Local<Script> script1 = Script::Compile(source); 3953 CHECK_EQ(8901.0, script1->Run()->NumberValue()); 3954} 3955 3956 3957THREADED_TEST(UndetectableObject) { 3958 v8::HandleScope scope; 3959 LocalContext env; 3960 3961 Local<v8::FunctionTemplate> desc = 3962 v8::FunctionTemplate::New(0, v8::Handle<Value>()); 3963 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 3964 3965 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 3966 env->Global()->Set(v8_str("undetectable"), obj); 3967 3968 ExpectString("undetectable.toString()", "[object Object]"); 3969 ExpectString("typeof undetectable", "undefined"); 3970 ExpectString("typeof(undetectable)", "undefined"); 3971 ExpectBoolean("typeof undetectable == 'undefined'", true); 3972 ExpectBoolean("typeof undetectable == 'object'", false); 3973 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 3974 ExpectBoolean("!undetectable", true); 3975 3976 ExpectObject("true&&undetectable", obj); 3977 ExpectBoolean("false&&undetectable", false); 3978 ExpectBoolean("true||undetectable", true); 3979 ExpectObject("false||undetectable", obj); 3980 3981 ExpectObject("undetectable&&true", obj); 3982 ExpectObject("undetectable&&false", obj); 3983 ExpectBoolean("undetectable||true", true); 3984 ExpectBoolean("undetectable||false", false); 3985 3986 ExpectBoolean("undetectable==null", true); 3987 ExpectBoolean("null==undetectable", true); 3988 ExpectBoolean("undetectable==undefined", true); 3989 ExpectBoolean("undefined==undetectable", true); 3990 ExpectBoolean("undetectable==undetectable", true); 3991 3992 3993 ExpectBoolean("undetectable===null", false); 3994 ExpectBoolean("null===undetectable", false); 3995 ExpectBoolean("undetectable===undefined", false); 3996 ExpectBoolean("undefined===undetectable", false); 3997 ExpectBoolean("undetectable===undetectable", true); 3998} 3999 4000 4001THREADED_TEST(VoidLiteral) { 4002 v8::HandleScope scope; 4003 LocalContext env; 4004 4005 Local<v8::FunctionTemplate> desc = 4006 v8::FunctionTemplate::New(0, v8::Handle<Value>()); 4007 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 4008 4009 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 4010 env->Global()->Set(v8_str("undetectable"), obj); 4011 4012 ExpectBoolean("undefined == void 0", true); 4013 ExpectBoolean("undetectable == void 0", true); 4014 ExpectBoolean("null == void 0", true); 4015 ExpectBoolean("undefined === void 0", true); 4016 ExpectBoolean("undetectable === void 0", false); 4017 ExpectBoolean("null === void 0", false); 4018 4019 ExpectBoolean("void 0 == undefined", true); 4020 ExpectBoolean("void 0 == undetectable", true); 4021 ExpectBoolean("void 0 == null", true); 4022 ExpectBoolean("void 0 === undefined", true); 4023 ExpectBoolean("void 0 === undetectable", false); 4024 ExpectBoolean("void 0 === null", false); 4025 4026 ExpectString("(function() {" 4027 " try {" 4028 " return x === void 0;" 4029 " } catch(e) {" 4030 " return e.toString();" 4031 " }" 4032 "})()", 4033 "ReferenceError: x is not defined"); 4034 ExpectString("(function() {" 4035 " try {" 4036 " return void 0 === x;" 4037 " } catch(e) {" 4038 " return e.toString();" 4039 " }" 4040 "})()", 4041 "ReferenceError: x is not defined"); 4042} 4043 4044 4045THREADED_TEST(ExtensibleOnUndetectable) { 4046 v8::HandleScope scope; 4047 LocalContext env; 4048 4049 Local<v8::FunctionTemplate> desc = 4050 v8::FunctionTemplate::New(0, v8::Handle<Value>()); 4051 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 4052 4053 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 4054 env->Global()->Set(v8_str("undetectable"), obj); 4055 4056 Local<String> source = v8_str("undetectable.x = 42;" 4057 "undetectable.x"); 4058 4059 Local<Script> script = Script::Compile(source); 4060 4061 CHECK_EQ(v8::Integer::New(42), script->Run()); 4062 4063 ExpectBoolean("Object.isExtensible(undetectable)", true); 4064 4065 source = v8_str("Object.preventExtensions(undetectable);"); 4066 script = Script::Compile(source); 4067 script->Run(); 4068 ExpectBoolean("Object.isExtensible(undetectable)", false); 4069 4070 source = v8_str("undetectable.y = 2000;"); 4071 script = Script::Compile(source); 4072 Local<Value> result = script->Run(); 4073 ExpectBoolean("undetectable.y == undefined", true); 4074} 4075 4076 4077 4078THREADED_TEST(UndetectableString) { 4079 v8::HandleScope scope; 4080 LocalContext env; 4081 4082 Local<String> obj = String::NewUndetectable("foo"); 4083 env->Global()->Set(v8_str("undetectable"), obj); 4084 4085 ExpectString("undetectable", "foo"); 4086 ExpectString("typeof undetectable", "undefined"); 4087 ExpectString("typeof(undetectable)", "undefined"); 4088 ExpectBoolean("typeof undetectable == 'undefined'", true); 4089 ExpectBoolean("typeof undetectable == 'string'", false); 4090 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 4091 ExpectBoolean("!undetectable", true); 4092 4093 ExpectObject("true&&undetectable", obj); 4094 ExpectBoolean("false&&undetectable", false); 4095 ExpectBoolean("true||undetectable", true); 4096 ExpectObject("false||undetectable", obj); 4097 4098 ExpectObject("undetectable&&true", obj); 4099 ExpectObject("undetectable&&false", obj); 4100 ExpectBoolean("undetectable||true", true); 4101 ExpectBoolean("undetectable||false", false); 4102 4103 ExpectBoolean("undetectable==null", true); 4104 ExpectBoolean("null==undetectable", true); 4105 ExpectBoolean("undetectable==undefined", true); 4106 ExpectBoolean("undefined==undetectable", true); 4107 ExpectBoolean("undetectable==undetectable", true); 4108 4109 4110 ExpectBoolean("undetectable===null", false); 4111 ExpectBoolean("null===undetectable", false); 4112 ExpectBoolean("undetectable===undefined", false); 4113 ExpectBoolean("undefined===undetectable", false); 4114 ExpectBoolean("undetectable===undetectable", true); 4115} 4116 4117 4118TEST(UndetectableOptimized) { 4119 i::FLAG_allow_natives_syntax = true; 4120 v8::HandleScope scope; 4121 LocalContext env; 4122 4123 Local<String> obj = String::NewUndetectable("foo"); 4124 env->Global()->Set(v8_str("undetectable"), obj); 4125 env->Global()->Set(v8_str("detectable"), v8_str("bar")); 4126 4127 ExpectString( 4128 "function testBranch() {" 4129 " if (!%_IsUndetectableObject(undetectable)) throw 1;" 4130 " if (%_IsUndetectableObject(detectable)) throw 2;" 4131 "}\n" 4132 "function testBool() {" 4133 " var b1 = !%_IsUndetectableObject(undetectable);" 4134 " var b2 = %_IsUndetectableObject(detectable);" 4135 " if (b1) throw 3;" 4136 " if (b2) throw 4;" 4137 " return b1 == b2;" 4138 "}\n" 4139 "%OptimizeFunctionOnNextCall(testBranch);" 4140 "%OptimizeFunctionOnNextCall(testBool);" 4141 "for (var i = 0; i < 10; i++) {" 4142 " testBranch();" 4143 " testBool();" 4144 "}\n" 4145 "\"PASS\"", 4146 "PASS"); 4147} 4148 4149 4150template <typename T> static void USE(T) { } 4151 4152 4153// This test is not intended to be run, just type checked. 4154static void PersistentHandles() { 4155 USE(PersistentHandles); 4156 Local<String> str = v8_str("foo"); 4157 v8::Persistent<String> p_str = v8::Persistent<String>::New(str); 4158 USE(p_str); 4159 Local<Script> scr = Script::Compile(v8_str("")); 4160 v8::Persistent<Script> p_scr = v8::Persistent<Script>::New(scr); 4161 USE(p_scr); 4162 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4163 v8::Persistent<ObjectTemplate> p_templ = 4164 v8::Persistent<ObjectTemplate>::New(templ); 4165 USE(p_templ); 4166} 4167 4168 4169static v8::Handle<Value> HandleLogDelegator(const v8::Arguments& args) { 4170 ApiTestFuzzer::Fuzz(); 4171 return v8::Undefined(); 4172} 4173 4174 4175THREADED_TEST(GlobalObjectTemplate) { 4176 v8::HandleScope handle_scope; 4177 Local<ObjectTemplate> global_template = ObjectTemplate::New(); 4178 global_template->Set(v8_str("JSNI_Log"), 4179 v8::FunctionTemplate::New(HandleLogDelegator)); 4180 v8::Persistent<Context> context = Context::New(0, global_template); 4181 Context::Scope context_scope(context); 4182 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run(); 4183 context.Dispose(); 4184} 4185 4186 4187static const char* kSimpleExtensionSource = 4188 "function Foo() {" 4189 " return 4;" 4190 "}"; 4191 4192 4193THREADED_TEST(SimpleExtensions) { 4194 v8::HandleScope handle_scope; 4195 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource)); 4196 const char* extension_names[] = { "simpletest" }; 4197 v8::ExtensionConfiguration extensions(1, extension_names); 4198 v8::Handle<Context> context = Context::New(&extensions); 4199 Context::Scope lock(context); 4200 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run(); 4201 CHECK_EQ(result, v8::Integer::New(4)); 4202} 4203 4204 4205static const char* kEvalExtensionSource1 = 4206 "function UseEval1() {" 4207 " var x = 42;" 4208 " return eval('x');" 4209 "}"; 4210 4211 4212static const char* kEvalExtensionSource2 = 4213 "(function() {" 4214 " var x = 42;" 4215 " function e() {" 4216 " return eval('x');" 4217 " }" 4218 " this.UseEval2 = e;" 4219 "})()"; 4220 4221 4222THREADED_TEST(UseEvalFromExtension) { 4223 v8::HandleScope handle_scope; 4224 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1)); 4225 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2)); 4226 const char* extension_names[] = { "evaltest1", "evaltest2" }; 4227 v8::ExtensionConfiguration extensions(2, extension_names); 4228 v8::Handle<Context> context = Context::New(&extensions); 4229 Context::Scope lock(context); 4230 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run(); 4231 CHECK_EQ(result, v8::Integer::New(42)); 4232 result = Script::Compile(v8_str("UseEval2()"))->Run(); 4233 CHECK_EQ(result, v8::Integer::New(42)); 4234} 4235 4236 4237static const char* kWithExtensionSource1 = 4238 "function UseWith1() {" 4239 " var x = 42;" 4240 " with({x:87}) { return x; }" 4241 "}"; 4242 4243 4244 4245static const char* kWithExtensionSource2 = 4246 "(function() {" 4247 " var x = 42;" 4248 " function e() {" 4249 " with ({x:87}) { return x; }" 4250 " }" 4251 " this.UseWith2 = e;" 4252 "})()"; 4253 4254 4255THREADED_TEST(UseWithFromExtension) { 4256 v8::HandleScope handle_scope; 4257 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1)); 4258 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2)); 4259 const char* extension_names[] = { "withtest1", "withtest2" }; 4260 v8::ExtensionConfiguration extensions(2, extension_names); 4261 v8::Handle<Context> context = Context::New(&extensions); 4262 Context::Scope lock(context); 4263 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run(); 4264 CHECK_EQ(result, v8::Integer::New(87)); 4265 result = Script::Compile(v8_str("UseWith2()"))->Run(); 4266 CHECK_EQ(result, v8::Integer::New(87)); 4267} 4268 4269 4270THREADED_TEST(AutoExtensions) { 4271 v8::HandleScope handle_scope; 4272 Extension* extension = new Extension("autotest", kSimpleExtensionSource); 4273 extension->set_auto_enable(true); 4274 v8::RegisterExtension(extension); 4275 v8::Handle<Context> context = Context::New(); 4276 Context::Scope lock(context); 4277 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run(); 4278 CHECK_EQ(result, v8::Integer::New(4)); 4279} 4280 4281 4282static const char* kSyntaxErrorInExtensionSource = 4283 "["; 4284 4285 4286// Test that a syntax error in an extension does not cause a fatal 4287// error but results in an empty context. 4288THREADED_TEST(SyntaxErrorExtensions) { 4289 v8::HandleScope handle_scope; 4290 v8::RegisterExtension(new Extension("syntaxerror", 4291 kSyntaxErrorInExtensionSource)); 4292 const char* extension_names[] = { "syntaxerror" }; 4293 v8::ExtensionConfiguration extensions(1, extension_names); 4294 v8::Handle<Context> context = Context::New(&extensions); 4295 CHECK(context.IsEmpty()); 4296} 4297 4298 4299static const char* kExceptionInExtensionSource = 4300 "throw 42"; 4301 4302 4303// Test that an exception when installing an extension does not cause 4304// a fatal error but results in an empty context. 4305THREADED_TEST(ExceptionExtensions) { 4306 v8::HandleScope handle_scope; 4307 v8::RegisterExtension(new Extension("exception", 4308 kExceptionInExtensionSource)); 4309 const char* extension_names[] = { "exception" }; 4310 v8::ExtensionConfiguration extensions(1, extension_names); 4311 v8::Handle<Context> context = Context::New(&extensions); 4312 CHECK(context.IsEmpty()); 4313} 4314 4315 4316static const char* kNativeCallInExtensionSource = 4317 "function call_runtime_last_index_of(x) {" 4318 " return %StringLastIndexOf(x, 'bob', 10);" 4319 "}"; 4320 4321 4322static const char* kNativeCallTest = 4323 "call_runtime_last_index_of('bobbobboellebobboellebobbob');"; 4324 4325// Test that a native runtime calls are supported in extensions. 4326THREADED_TEST(NativeCallInExtensions) { 4327 v8::HandleScope handle_scope; 4328 v8::RegisterExtension(new Extension("nativecall", 4329 kNativeCallInExtensionSource)); 4330 const char* extension_names[] = { "nativecall" }; 4331 v8::ExtensionConfiguration extensions(1, extension_names); 4332 v8::Handle<Context> context = Context::New(&extensions); 4333 Context::Scope lock(context); 4334 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run(); 4335 CHECK_EQ(result, v8::Integer::New(3)); 4336} 4337 4338 4339class NativeFunctionExtension : public Extension { 4340 public: 4341 NativeFunctionExtension(const char* name, 4342 const char* source, 4343 v8::InvocationCallback fun = &Echo) 4344 : Extension(name, source), 4345 function_(fun) { } 4346 4347 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( 4348 v8::Handle<v8::String> name) { 4349 return v8::FunctionTemplate::New(function_); 4350 } 4351 4352 static v8::Handle<v8::Value> Echo(const v8::Arguments& args) { 4353 if (args.Length() >= 1) return (args[0]); 4354 return v8::Undefined(); 4355 } 4356 private: 4357 v8::InvocationCallback function_; 4358}; 4359 4360 4361THREADED_TEST(NativeFunctionDeclaration) { 4362 v8::HandleScope handle_scope; 4363 const char* name = "nativedecl"; 4364 v8::RegisterExtension(new NativeFunctionExtension(name, 4365 "native function foo();")); 4366 const char* extension_names[] = { name }; 4367 v8::ExtensionConfiguration extensions(1, extension_names); 4368 v8::Handle<Context> context = Context::New(&extensions); 4369 Context::Scope lock(context); 4370 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run(); 4371 CHECK_EQ(result, v8::Integer::New(42)); 4372} 4373 4374 4375THREADED_TEST(NativeFunctionDeclarationError) { 4376 v8::HandleScope handle_scope; 4377 const char* name = "nativedeclerr"; 4378 // Syntax error in extension code. 4379 v8::RegisterExtension(new NativeFunctionExtension(name, 4380 "native\nfunction foo();")); 4381 const char* extension_names[] = { name }; 4382 v8::ExtensionConfiguration extensions(1, extension_names); 4383 v8::Handle<Context> context = Context::New(&extensions); 4384 ASSERT(context.IsEmpty()); 4385} 4386 4387THREADED_TEST(NativeFunctionDeclarationErrorEscape) { 4388 v8::HandleScope handle_scope; 4389 const char* name = "nativedeclerresc"; 4390 // Syntax error in extension code - escape code in "native" means that 4391 // it's not treated as a keyword. 4392 v8::RegisterExtension(new NativeFunctionExtension( 4393 name, 4394 "nativ\\u0065 function foo();")); 4395 const char* extension_names[] = { name }; 4396 v8::ExtensionConfiguration extensions(1, extension_names); 4397 v8::Handle<Context> context = Context::New(&extensions); 4398 ASSERT(context.IsEmpty()); 4399} 4400 4401 4402static void CheckDependencies(const char* name, const char* expected) { 4403 v8::HandleScope handle_scope; 4404 v8::ExtensionConfiguration config(1, &name); 4405 LocalContext context(&config); 4406 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded"))); 4407} 4408 4409 4410/* 4411 * Configuration: 4412 * 4413 * /-- B <--\ 4414 * A <- -- D <-- E 4415 * \-- C <--/ 4416 */ 4417THREADED_TEST(ExtensionDependency) { 4418 static const char* kEDeps[] = { "D" }; 4419 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps)); 4420 static const char* kDDeps[] = { "B", "C" }; 4421 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps)); 4422 static const char* kBCDeps[] = { "A" }; 4423 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps)); 4424 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps)); 4425 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';")); 4426 CheckDependencies("A", "undefinedA"); 4427 CheckDependencies("B", "undefinedAB"); 4428 CheckDependencies("C", "undefinedAC"); 4429 CheckDependencies("D", "undefinedABCD"); 4430 CheckDependencies("E", "undefinedABCDE"); 4431 v8::HandleScope handle_scope; 4432 static const char* exts[2] = { "C", "E" }; 4433 v8::ExtensionConfiguration config(2, exts); 4434 LocalContext context(&config); 4435 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded"))); 4436} 4437 4438 4439static const char* kExtensionTestScript = 4440 "native function A();" 4441 "native function B();" 4442 "native function C();" 4443 "function Foo(i) {" 4444 " if (i == 0) return A();" 4445 " if (i == 1) return B();" 4446 " if (i == 2) return C();" 4447 "}"; 4448 4449 4450static v8::Handle<Value> CallFun(const v8::Arguments& args) { 4451 ApiTestFuzzer::Fuzz(); 4452 if (args.IsConstructCall()) { 4453 args.This()->Set(v8_str("data"), args.Data()); 4454 return v8::Null(); 4455 } 4456 return args.Data(); 4457} 4458 4459 4460class FunctionExtension : public Extension { 4461 public: 4462 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { } 4463 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( 4464 v8::Handle<String> name); 4465}; 4466 4467 4468static int lookup_count = 0; 4469v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction( 4470 v8::Handle<String> name) { 4471 lookup_count++; 4472 if (name->Equals(v8_str("A"))) { 4473 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8)); 4474 } else if (name->Equals(v8_str("B"))) { 4475 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7)); 4476 } else if (name->Equals(v8_str("C"))) { 4477 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6)); 4478 } else { 4479 return v8::Handle<v8::FunctionTemplate>(); 4480 } 4481} 4482 4483 4484THREADED_TEST(FunctionLookup) { 4485 v8::RegisterExtension(new FunctionExtension()); 4486 v8::HandleScope handle_scope; 4487 static const char* exts[1] = { "functiontest" }; 4488 v8::ExtensionConfiguration config(1, exts); 4489 LocalContext context(&config); 4490 CHECK_EQ(3, lookup_count); 4491 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run()); 4492 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run()); 4493 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run()); 4494} 4495 4496 4497THREADED_TEST(NativeFunctionConstructCall) { 4498 v8::RegisterExtension(new FunctionExtension()); 4499 v8::HandleScope handle_scope; 4500 static const char* exts[1] = { "functiontest" }; 4501 v8::ExtensionConfiguration config(1, exts); 4502 LocalContext context(&config); 4503 for (int i = 0; i < 10; i++) { 4504 // Run a few times to ensure that allocation of objects doesn't 4505 // change behavior of a constructor function. 4506 CHECK_EQ(v8::Integer::New(8), 4507 Script::Compile(v8_str("(new A()).data"))->Run()); 4508 CHECK_EQ(v8::Integer::New(7), 4509 Script::Compile(v8_str("(new B()).data"))->Run()); 4510 CHECK_EQ(v8::Integer::New(6), 4511 Script::Compile(v8_str("(new C()).data"))->Run()); 4512 } 4513} 4514 4515 4516static const char* last_location; 4517static const char* last_message; 4518void StoringErrorCallback(const char* location, const char* message) { 4519 if (last_location == NULL) { 4520 last_location = location; 4521 last_message = message; 4522 } 4523} 4524 4525 4526// ErrorReporting creates a circular extensions configuration and 4527// tests that the fatal error handler gets called. This renders V8 4528// unusable and therefore this test cannot be run in parallel. 4529TEST(ErrorReporting) { 4530 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 4531 static const char* aDeps[] = { "B" }; 4532 v8::RegisterExtension(new Extension("A", "", 1, aDeps)); 4533 static const char* bDeps[] = { "A" }; 4534 v8::RegisterExtension(new Extension("B", "", 1, bDeps)); 4535 last_location = NULL; 4536 v8::ExtensionConfiguration config(1, bDeps); 4537 v8::Handle<Context> context = Context::New(&config); 4538 CHECK(context.IsEmpty()); 4539 CHECK_NE(last_location, NULL); 4540} 4541 4542 4543static const char* js_code_causing_huge_string_flattening = 4544 "var str = 'X';" 4545 "for (var i = 0; i < 30; i++) {" 4546 " str = str + str;" 4547 "}" 4548 "str.match(/X/);"; 4549 4550 4551void OOMCallback(const char* location, const char* message) { 4552 exit(0); 4553} 4554 4555 4556TEST(RegexpOutOfMemory) { 4557 // Execute a script that causes out of memory when flattening a string. 4558 v8::HandleScope scope; 4559 v8::V8::SetFatalErrorHandler(OOMCallback); 4560 LocalContext context; 4561 Local<Script> script = 4562 Script::Compile(String::New(js_code_causing_huge_string_flattening)); 4563 last_location = NULL; 4564 Local<Value> result = script->Run(); 4565 4566 CHECK(false); // Should not return. 4567} 4568 4569 4570static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message, 4571 v8::Handle<Value> data) { 4572 CHECK_EQ(v8::Undefined(), data); 4573 CHECK(message->GetScriptResourceName()->IsUndefined()); 4574 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName()); 4575 message->GetLineNumber(); 4576 message->GetSourceLine(); 4577} 4578 4579 4580THREADED_TEST(ErrorWithMissingScriptInfo) { 4581 v8::HandleScope scope; 4582 LocalContext context; 4583 v8::V8::AddMessageListener(MissingScriptInfoMessageListener); 4584 Script::Compile(v8_str("throw Error()"))->Run(); 4585 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener); 4586} 4587 4588 4589int global_index = 0; 4590 4591class Snorkel { 4592 public: 4593 Snorkel() { index_ = global_index++; } 4594 int index_; 4595}; 4596 4597class Whammy { 4598 public: 4599 Whammy() { 4600 cursor_ = 0; 4601 } 4602 ~Whammy() { 4603 script_.Dispose(); 4604 } 4605 v8::Handle<Script> getScript() { 4606 if (script_.IsEmpty()) 4607 script_ = v8::Persistent<Script>::New(v8_compile("({}).blammo")); 4608 return Local<Script>(*script_); 4609 } 4610 4611 public: 4612 static const int kObjectCount = 256; 4613 int cursor_; 4614 v8::Persistent<v8::Object> objects_[kObjectCount]; 4615 v8::Persistent<Script> script_; 4616}; 4617 4618static void HandleWeakReference(v8::Persistent<v8::Value> obj, void* data) { 4619 Snorkel* snorkel = reinterpret_cast<Snorkel*>(data); 4620 delete snorkel; 4621 obj.ClearWeak(); 4622} 4623 4624v8::Handle<Value> WhammyPropertyGetter(Local<String> name, 4625 const AccessorInfo& info) { 4626 Whammy* whammy = 4627 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value()); 4628 4629 v8::Persistent<v8::Object> prev = whammy->objects_[whammy->cursor_]; 4630 4631 v8::Handle<v8::Object> obj = v8::Object::New(); 4632 v8::Persistent<v8::Object> global = v8::Persistent<v8::Object>::New(obj); 4633 if (!prev.IsEmpty()) { 4634 prev->Set(v8_str("next"), obj); 4635 prev.MakeWeak(new Snorkel(), &HandleWeakReference); 4636 whammy->objects_[whammy->cursor_].Clear(); 4637 } 4638 whammy->objects_[whammy->cursor_] = global; 4639 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount; 4640 return whammy->getScript()->Run(); 4641} 4642 4643THREADED_TEST(WeakReference) { 4644 v8::HandleScope handle_scope; 4645 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New(); 4646 Whammy* whammy = new Whammy(); 4647 templ->SetNamedPropertyHandler(WhammyPropertyGetter, 4648 0, 0, 0, 0, 4649 v8::External::New(whammy)); 4650 const char* extension_list[] = { "v8/gc" }; 4651 v8::ExtensionConfiguration extensions(1, extension_list); 4652 v8::Persistent<Context> context = Context::New(&extensions); 4653 Context::Scope context_scope(context); 4654 4655 v8::Handle<v8::Object> interceptor = templ->NewInstance(); 4656 context->Global()->Set(v8_str("whammy"), interceptor); 4657 const char* code = 4658 "var last;" 4659 "for (var i = 0; i < 10000; i++) {" 4660 " var obj = whammy.length;" 4661 " if (last) last.next = obj;" 4662 " last = obj;" 4663 "}" 4664 "gc();" 4665 "4"; 4666 v8::Handle<Value> result = CompileRun(code); 4667 CHECK_EQ(4.0, result->NumberValue()); 4668 delete whammy; 4669 context.Dispose(); 4670} 4671 4672 4673static void DisposeAndSetFlag(v8::Persistent<v8::Value> obj, void* data) { 4674 obj.Dispose(); 4675 obj.Clear(); 4676 *(reinterpret_cast<bool*>(data)) = true; 4677} 4678 4679 4680THREADED_TEST(IndependentWeakHandle) { 4681 v8::Persistent<Context> context = Context::New(); 4682 Context::Scope context_scope(context); 4683 4684 v8::Persistent<v8::Object> object_a; 4685 4686 { 4687 v8::HandleScope handle_scope; 4688 object_a = v8::Persistent<v8::Object>::New(v8::Object::New()); 4689 } 4690 4691 bool object_a_disposed = false; 4692 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag); 4693 object_a.MarkIndependent(); 4694 HEAP->PerformScavenge(); 4695 CHECK(object_a_disposed); 4696} 4697 4698 4699static void InvokeScavenge() { 4700 HEAP->PerformScavenge(); 4701} 4702 4703 4704static void InvokeMarkSweep() { 4705 HEAP->CollectAllGarbage(false); 4706} 4707 4708 4709static void ForceScavenge(v8::Persistent<v8::Value> obj, void* data) { 4710 obj.Dispose(); 4711 obj.Clear(); 4712 *(reinterpret_cast<bool*>(data)) = true; 4713 InvokeScavenge(); 4714} 4715 4716 4717static void ForceMarkSweep(v8::Persistent<v8::Value> obj, void* data) { 4718 obj.Dispose(); 4719 obj.Clear(); 4720 *(reinterpret_cast<bool*>(data)) = true; 4721 InvokeMarkSweep(); 4722} 4723 4724 4725THREADED_TEST(GCFromWeakCallbacks) { 4726 v8::Persistent<Context> context = Context::New(); 4727 Context::Scope context_scope(context); 4728 4729 static const int kNumberOfGCTypes = 2; 4730 v8::WeakReferenceCallback gc_forcing_callback[kNumberOfGCTypes] = 4731 {&ForceScavenge, &ForceMarkSweep}; 4732 4733 typedef void (*GCInvoker)(); 4734 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep}; 4735 4736 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) { 4737 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) { 4738 v8::Persistent<v8::Object> object; 4739 { 4740 v8::HandleScope handle_scope; 4741 object = v8::Persistent<v8::Object>::New(v8::Object::New()); 4742 } 4743 bool disposed = false; 4744 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]); 4745 object.MarkIndependent(); 4746 invoke_gc[outer_gc](); 4747 CHECK(disposed); 4748 } 4749 } 4750} 4751 4752 4753static void RevivingCallback(v8::Persistent<v8::Value> obj, void* data) { 4754 obj.ClearWeak(); 4755 *(reinterpret_cast<bool*>(data)) = true; 4756} 4757 4758 4759THREADED_TEST(IndependentHandleRevival) { 4760 v8::Persistent<Context> context = Context::New(); 4761 Context::Scope context_scope(context); 4762 4763 v8::Persistent<v8::Object> object; 4764 { 4765 v8::HandleScope handle_scope; 4766 object = v8::Persistent<v8::Object>::New(v8::Object::New()); 4767 object->Set(v8_str("x"), v8::Integer::New(1)); 4768 v8::Local<String> y_str = v8_str("y"); 4769 object->Set(y_str, y_str); 4770 } 4771 bool revived = false; 4772 object.MakeWeak(&revived, &RevivingCallback); 4773 object.MarkIndependent(); 4774 HEAP->PerformScavenge(); 4775 CHECK(revived); 4776 HEAP->CollectAllGarbage(true); 4777 { 4778 v8::HandleScope handle_scope; 4779 v8::Local<String> y_str = v8_str("y"); 4780 CHECK_EQ(v8::Integer::New(1), object->Get(v8_str("x"))); 4781 CHECK(object->Get(y_str)->Equals(y_str)); 4782 } 4783} 4784 4785 4786v8::Handle<Function> args_fun; 4787 4788 4789static v8::Handle<Value> ArgumentsTestCallback(const v8::Arguments& args) { 4790 ApiTestFuzzer::Fuzz(); 4791 CHECK_EQ(args_fun, args.Callee()); 4792 CHECK_EQ(3, args.Length()); 4793 CHECK_EQ(v8::Integer::New(1), args[0]); 4794 CHECK_EQ(v8::Integer::New(2), args[1]); 4795 CHECK_EQ(v8::Integer::New(3), args[2]); 4796 CHECK_EQ(v8::Undefined(), args[3]); 4797 v8::HandleScope scope; 4798 HEAP->CollectAllGarbage(false); 4799 return v8::Undefined(); 4800} 4801 4802 4803THREADED_TEST(Arguments) { 4804 v8::HandleScope scope; 4805 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(); 4806 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback)); 4807 LocalContext context(NULL, global); 4808 args_fun = context->Global()->Get(v8_str("f")).As<Function>(); 4809 v8_compile("f(1, 2, 3)")->Run(); 4810} 4811 4812 4813static v8::Handle<Value> NoBlockGetterX(Local<String> name, 4814 const AccessorInfo&) { 4815 return v8::Handle<Value>(); 4816} 4817 4818 4819static v8::Handle<Value> NoBlockGetterI(uint32_t index, 4820 const AccessorInfo&) { 4821 return v8::Handle<Value>(); 4822} 4823 4824 4825static v8::Handle<v8::Boolean> PDeleter(Local<String> name, 4826 const AccessorInfo&) { 4827 if (!name->Equals(v8_str("foo"))) { 4828 return v8::Handle<v8::Boolean>(); // not intercepted 4829 } 4830 4831 return v8::False(); // intercepted, and don't delete the property 4832} 4833 4834 4835static v8::Handle<v8::Boolean> IDeleter(uint32_t index, const AccessorInfo&) { 4836 if (index != 2) { 4837 return v8::Handle<v8::Boolean>(); // not intercepted 4838 } 4839 4840 return v8::False(); // intercepted, and don't delete the property 4841} 4842 4843 4844THREADED_TEST(Deleter) { 4845 v8::HandleScope scope; 4846 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 4847 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL); 4848 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL); 4849 LocalContext context; 4850 context->Global()->Set(v8_str("k"), obj->NewInstance()); 4851 CompileRun( 4852 "k.foo = 'foo';" 4853 "k.bar = 'bar';" 4854 "k[2] = 2;" 4855 "k[4] = 4;"); 4856 CHECK(v8_compile("delete k.foo")->Run()->IsFalse()); 4857 CHECK(v8_compile("delete k.bar")->Run()->IsTrue()); 4858 4859 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo")); 4860 CHECK(v8_compile("k.bar")->Run()->IsUndefined()); 4861 4862 CHECK(v8_compile("delete k[2]")->Run()->IsFalse()); 4863 CHECK(v8_compile("delete k[4]")->Run()->IsTrue()); 4864 4865 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2)); 4866 CHECK(v8_compile("k[4]")->Run()->IsUndefined()); 4867} 4868 4869 4870static v8::Handle<Value> GetK(Local<String> name, const AccessorInfo&) { 4871 ApiTestFuzzer::Fuzz(); 4872 if (name->Equals(v8_str("foo")) || 4873 name->Equals(v8_str("bar")) || 4874 name->Equals(v8_str("baz"))) { 4875 return v8::Undefined(); 4876 } 4877 return v8::Handle<Value>(); 4878} 4879 4880 4881static v8::Handle<Value> IndexedGetK(uint32_t index, const AccessorInfo&) { 4882 ApiTestFuzzer::Fuzz(); 4883 if (index == 0 || index == 1) return v8::Undefined(); 4884 return v8::Handle<Value>(); 4885} 4886 4887 4888static v8::Handle<v8::Array> NamedEnum(const AccessorInfo&) { 4889 ApiTestFuzzer::Fuzz(); 4890 v8::Handle<v8::Array> result = v8::Array::New(3); 4891 result->Set(v8::Integer::New(0), v8_str("foo")); 4892 result->Set(v8::Integer::New(1), v8_str("bar")); 4893 result->Set(v8::Integer::New(2), v8_str("baz")); 4894 return result; 4895} 4896 4897 4898static v8::Handle<v8::Array> IndexedEnum(const AccessorInfo&) { 4899 ApiTestFuzzer::Fuzz(); 4900 v8::Handle<v8::Array> result = v8::Array::New(2); 4901 result->Set(v8::Integer::New(0), v8_str("0")); 4902 result->Set(v8::Integer::New(1), v8_str("1")); 4903 return result; 4904} 4905 4906 4907THREADED_TEST(Enumerators) { 4908 v8::HandleScope scope; 4909 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 4910 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum); 4911 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum); 4912 LocalContext context; 4913 context->Global()->Set(v8_str("k"), obj->NewInstance()); 4914 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 4915 "k[10] = 0;" 4916 "k.a = 0;" 4917 "k[5] = 0;" 4918 "k.b = 0;" 4919 "k[4294967295] = 0;" 4920 "k.c = 0;" 4921 "k[4294967296] = 0;" 4922 "k.d = 0;" 4923 "k[140000] = 0;" 4924 "k.e = 0;" 4925 "k[30000000000] = 0;" 4926 "k.f = 0;" 4927 "var result = [];" 4928 "for (var prop in k) {" 4929 " result.push(prop);" 4930 "}" 4931 "result")); 4932 // Check that we get all the property names returned including the 4933 // ones from the enumerators in the right order: indexed properties 4934 // in numerical order, indexed interceptor properties, named 4935 // properties in insertion order, named interceptor properties. 4936 // This order is not mandated by the spec, so this test is just 4937 // documenting our behavior. 4938 CHECK_EQ(17, result->Length()); 4939 // Indexed properties in numerical order. 4940 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0))); 4941 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1))); 4942 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2))); 4943 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3))); 4944 // Indexed interceptor properties in the order they are returned 4945 // from the enumerator interceptor. 4946 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4))); 4947 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5))); 4948 // Named properties in insertion order. 4949 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6))); 4950 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7))); 4951 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8))); 4952 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9))); 4953 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10))); 4954 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11))); 4955 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12))); 4956 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13))); 4957 // Named interceptor properties. 4958 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14))); 4959 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15))); 4960 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16))); 4961} 4962 4963 4964int p_getter_count; 4965int p_getter_count2; 4966 4967 4968static v8::Handle<Value> PGetter(Local<String> name, const AccessorInfo& info) { 4969 ApiTestFuzzer::Fuzz(); 4970 p_getter_count++; 4971 v8::Handle<v8::Object> global = Context::GetCurrent()->Global(); 4972 CHECK_EQ(info.Holder(), global->Get(v8_str("o1"))); 4973 if (name->Equals(v8_str("p1"))) { 4974 CHECK_EQ(info.This(), global->Get(v8_str("o1"))); 4975 } else if (name->Equals(v8_str("p2"))) { 4976 CHECK_EQ(info.This(), global->Get(v8_str("o2"))); 4977 } else if (name->Equals(v8_str("p3"))) { 4978 CHECK_EQ(info.This(), global->Get(v8_str("o3"))); 4979 } else if (name->Equals(v8_str("p4"))) { 4980 CHECK_EQ(info.This(), global->Get(v8_str("o4"))); 4981 } 4982 return v8::Undefined(); 4983} 4984 4985 4986static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) { 4987 ApiTestFuzzer::Fuzz(); 4988 LocalContext context; 4989 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 4990 CompileRun( 4991 "o1.__proto__ = { };" 4992 "var o2 = { __proto__: o1 };" 4993 "var o3 = { __proto__: o2 };" 4994 "var o4 = { __proto__: o3 };" 4995 "for (var i = 0; i < 10; i++) o4.p4;" 4996 "for (var i = 0; i < 10; i++) o3.p3;" 4997 "for (var i = 0; i < 10; i++) o2.p2;" 4998 "for (var i = 0; i < 10; i++) o1.p1;"); 4999} 5000 5001 5002static v8::Handle<Value> PGetter2(Local<String> name, 5003 const AccessorInfo& info) { 5004 ApiTestFuzzer::Fuzz(); 5005 p_getter_count2++; 5006 v8::Handle<v8::Object> global = Context::GetCurrent()->Global(); 5007 CHECK_EQ(info.Holder(), global->Get(v8_str("o1"))); 5008 if (name->Equals(v8_str("p1"))) { 5009 CHECK_EQ(info.This(), global->Get(v8_str("o1"))); 5010 } else if (name->Equals(v8_str("p2"))) { 5011 CHECK_EQ(info.This(), global->Get(v8_str("o2"))); 5012 } else if (name->Equals(v8_str("p3"))) { 5013 CHECK_EQ(info.This(), global->Get(v8_str("o3"))); 5014 } else if (name->Equals(v8_str("p4"))) { 5015 CHECK_EQ(info.This(), global->Get(v8_str("o4"))); 5016 } 5017 return v8::Undefined(); 5018} 5019 5020 5021THREADED_TEST(GetterHolders) { 5022 v8::HandleScope scope; 5023 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 5024 obj->SetAccessor(v8_str("p1"), PGetter); 5025 obj->SetAccessor(v8_str("p2"), PGetter); 5026 obj->SetAccessor(v8_str("p3"), PGetter); 5027 obj->SetAccessor(v8_str("p4"), PGetter); 5028 p_getter_count = 0; 5029 RunHolderTest(obj); 5030 CHECK_EQ(40, p_getter_count); 5031} 5032 5033 5034THREADED_TEST(PreInterceptorHolders) { 5035 v8::HandleScope scope; 5036 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 5037 obj->SetNamedPropertyHandler(PGetter2); 5038 p_getter_count2 = 0; 5039 RunHolderTest(obj); 5040 CHECK_EQ(40, p_getter_count2); 5041} 5042 5043 5044THREADED_TEST(ObjectInstantiation) { 5045 v8::HandleScope scope; 5046 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 5047 templ->SetAccessor(v8_str("t"), PGetter2); 5048 LocalContext context; 5049 context->Global()->Set(v8_str("o"), templ->NewInstance()); 5050 for (int i = 0; i < 100; i++) { 5051 v8::HandleScope inner_scope; 5052 v8::Handle<v8::Object> obj = templ->NewInstance(); 5053 CHECK_NE(obj, context->Global()->Get(v8_str("o"))); 5054 context->Global()->Set(v8_str("o2"), obj); 5055 v8::Handle<Value> value = 5056 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run(); 5057 CHECK_EQ(v8::True(), value); 5058 context->Global()->Set(v8_str("o"), obj); 5059 } 5060} 5061 5062 5063static int StrCmp16(uint16_t* a, uint16_t* b) { 5064 while (true) { 5065 if (*a == 0 && *b == 0) return 0; 5066 if (*a != *b) return 0 + *a - *b; 5067 a++; 5068 b++; 5069 } 5070} 5071 5072 5073static int StrNCmp16(uint16_t* a, uint16_t* b, int n) { 5074 while (true) { 5075 if (n-- == 0) return 0; 5076 if (*a == 0 && *b == 0) return 0; 5077 if (*a != *b) return 0 + *a - *b; 5078 a++; 5079 b++; 5080 } 5081} 5082 5083 5084THREADED_TEST(StringWrite) { 5085 v8::HandleScope scope; 5086 v8::Handle<String> str = v8_str("abcde"); 5087 // abc<Icelandic eth><Unicode snowman>. 5088 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203"); 5089 5090 CHECK_EQ(5, str2->Length()); 5091 5092 char buf[100]; 5093 char utf8buf[100]; 5094 uint16_t wbuf[100]; 5095 int len; 5096 int charlen; 5097 5098 memset(utf8buf, 0x1, sizeof(utf8buf)); 5099 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen); 5100 CHECK_EQ(9, len); 5101 CHECK_EQ(5, charlen); 5102 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 5103 5104 memset(utf8buf, 0x1, sizeof(utf8buf)); 5105 len = str2->WriteUtf8(utf8buf, 8, &charlen); 5106 CHECK_EQ(8, len); 5107 CHECK_EQ(5, charlen); 5108 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9)); 5109 5110 memset(utf8buf, 0x1, sizeof(utf8buf)); 5111 len = str2->WriteUtf8(utf8buf, 7, &charlen); 5112 CHECK_EQ(5, len); 5113 CHECK_EQ(4, charlen); 5114 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 5115 5116 memset(utf8buf, 0x1, sizeof(utf8buf)); 5117 len = str2->WriteUtf8(utf8buf, 6, &charlen); 5118 CHECK_EQ(5, len); 5119 CHECK_EQ(4, charlen); 5120 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 5121 5122 memset(utf8buf, 0x1, sizeof(utf8buf)); 5123 len = str2->WriteUtf8(utf8buf, 5, &charlen); 5124 CHECK_EQ(5, len); 5125 CHECK_EQ(4, charlen); 5126 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 5127 5128 memset(utf8buf, 0x1, sizeof(utf8buf)); 5129 len = str2->WriteUtf8(utf8buf, 4, &charlen); 5130 CHECK_EQ(3, len); 5131 CHECK_EQ(3, charlen); 5132 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 5133 5134 memset(utf8buf, 0x1, sizeof(utf8buf)); 5135 len = str2->WriteUtf8(utf8buf, 3, &charlen); 5136 CHECK_EQ(3, len); 5137 CHECK_EQ(3, charlen); 5138 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 5139 5140 memset(utf8buf, 0x1, sizeof(utf8buf)); 5141 len = str2->WriteUtf8(utf8buf, 2, &charlen); 5142 CHECK_EQ(2, len); 5143 CHECK_EQ(2, charlen); 5144 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3)); 5145 5146 memset(buf, 0x1, sizeof(buf)); 5147 memset(wbuf, 0x1, sizeof(wbuf)); 5148 len = str->WriteAscii(buf); 5149 CHECK_EQ(5, len); 5150 len = str->Write(wbuf); 5151 CHECK_EQ(5, len); 5152 CHECK_EQ(0, strcmp("abcde", buf)); 5153 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 5154 CHECK_EQ(0, StrCmp16(answer1, wbuf)); 5155 5156 memset(buf, 0x1, sizeof(buf)); 5157 memset(wbuf, 0x1, sizeof(wbuf)); 5158 len = str->WriteAscii(buf, 0, 4); 5159 CHECK_EQ(4, len); 5160 len = str->Write(wbuf, 0, 4); 5161 CHECK_EQ(4, len); 5162 CHECK_EQ(0, strncmp("abcd\1", buf, 5)); 5163 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101}; 5164 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5)); 5165 5166 memset(buf, 0x1, sizeof(buf)); 5167 memset(wbuf, 0x1, sizeof(wbuf)); 5168 len = str->WriteAscii(buf, 0, 5); 5169 CHECK_EQ(5, len); 5170 len = str->Write(wbuf, 0, 5); 5171 CHECK_EQ(5, len); 5172 CHECK_EQ(0, strncmp("abcde\1", buf, 6)); 5173 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101}; 5174 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6)); 5175 5176 memset(buf, 0x1, sizeof(buf)); 5177 memset(wbuf, 0x1, sizeof(wbuf)); 5178 len = str->WriteAscii(buf, 0, 6); 5179 CHECK_EQ(5, len); 5180 len = str->Write(wbuf, 0, 6); 5181 CHECK_EQ(5, len); 5182 CHECK_EQ(0, strcmp("abcde", buf)); 5183 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 5184 CHECK_EQ(0, StrCmp16(answer4, wbuf)); 5185 5186 memset(buf, 0x1, sizeof(buf)); 5187 memset(wbuf, 0x1, sizeof(wbuf)); 5188 len = str->WriteAscii(buf, 4, -1); 5189 CHECK_EQ(1, len); 5190 len = str->Write(wbuf, 4, -1); 5191 CHECK_EQ(1, len); 5192 CHECK_EQ(0, strcmp("e", buf)); 5193 uint16_t answer5[] = {'e', '\0'}; 5194 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 5195 5196 memset(buf, 0x1, sizeof(buf)); 5197 memset(wbuf, 0x1, sizeof(wbuf)); 5198 len = str->WriteAscii(buf, 4, 6); 5199 CHECK_EQ(1, len); 5200 len = str->Write(wbuf, 4, 6); 5201 CHECK_EQ(1, len); 5202 CHECK_EQ(0, strcmp("e", buf)); 5203 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 5204 5205 memset(buf, 0x1, sizeof(buf)); 5206 memset(wbuf, 0x1, sizeof(wbuf)); 5207 len = str->WriteAscii(buf, 4, 1); 5208 CHECK_EQ(1, len); 5209 len = str->Write(wbuf, 4, 1); 5210 CHECK_EQ(1, len); 5211 CHECK_EQ(0, strncmp("e\1", buf, 2)); 5212 uint16_t answer6[] = {'e', 0x101}; 5213 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2)); 5214 5215 memset(buf, 0x1, sizeof(buf)); 5216 memset(wbuf, 0x1, sizeof(wbuf)); 5217 len = str->WriteAscii(buf, 3, 1); 5218 CHECK_EQ(1, len); 5219 len = str->Write(wbuf, 3, 1); 5220 CHECK_EQ(1, len); 5221 CHECK_EQ(0, strncmp("d\1", buf, 2)); 5222 uint16_t answer7[] = {'d', 0x101}; 5223 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2)); 5224} 5225 5226 5227THREADED_TEST(ToArrayIndex) { 5228 v8::HandleScope scope; 5229 LocalContext context; 5230 5231 v8::Handle<String> str = v8_str("42"); 5232 v8::Handle<v8::Uint32> index = str->ToArrayIndex(); 5233 CHECK(!index.IsEmpty()); 5234 CHECK_EQ(42.0, index->Uint32Value()); 5235 str = v8_str("42asdf"); 5236 index = str->ToArrayIndex(); 5237 CHECK(index.IsEmpty()); 5238 str = v8_str("-42"); 5239 index = str->ToArrayIndex(); 5240 CHECK(index.IsEmpty()); 5241 str = v8_str("4294967295"); 5242 index = str->ToArrayIndex(); 5243 CHECK(!index.IsEmpty()); 5244 CHECK_EQ(4294967295.0, index->Uint32Value()); 5245 v8::Handle<v8::Number> num = v8::Number::New(1); 5246 index = num->ToArrayIndex(); 5247 CHECK(!index.IsEmpty()); 5248 CHECK_EQ(1.0, index->Uint32Value()); 5249 num = v8::Number::New(-1); 5250 index = num->ToArrayIndex(); 5251 CHECK(index.IsEmpty()); 5252 v8::Handle<v8::Object> obj = v8::Object::New(); 5253 index = obj->ToArrayIndex(); 5254 CHECK(index.IsEmpty()); 5255} 5256 5257 5258THREADED_TEST(ErrorConstruction) { 5259 v8::HandleScope scope; 5260 LocalContext context; 5261 5262 v8::Handle<String> foo = v8_str("foo"); 5263 v8::Handle<String> message = v8_str("message"); 5264 v8::Handle<Value> range_error = v8::Exception::RangeError(foo); 5265 CHECK(range_error->IsObject()); 5266 v8::Handle<v8::Object> range_obj = range_error.As<v8::Object>(); 5267 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo)); 5268 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo); 5269 CHECK(reference_error->IsObject()); 5270 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo)); 5271 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo); 5272 CHECK(syntax_error->IsObject()); 5273 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo)); 5274 v8::Handle<Value> type_error = v8::Exception::TypeError(foo); 5275 CHECK(type_error->IsObject()); 5276 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo)); 5277 v8::Handle<Value> error = v8::Exception::Error(foo); 5278 CHECK(error->IsObject()); 5279 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo)); 5280} 5281 5282 5283static v8::Handle<Value> YGetter(Local<String> name, const AccessorInfo& info) { 5284 ApiTestFuzzer::Fuzz(); 5285 return v8_num(10); 5286} 5287 5288 5289static void YSetter(Local<String> name, 5290 Local<Value> value, 5291 const AccessorInfo& info) { 5292 if (info.This()->Has(name)) { 5293 info.This()->Delete(name); 5294 } 5295 info.This()->Set(name, value); 5296} 5297 5298 5299THREADED_TEST(DeleteAccessor) { 5300 v8::HandleScope scope; 5301 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 5302 obj->SetAccessor(v8_str("y"), YGetter, YSetter); 5303 LocalContext context; 5304 v8::Handle<v8::Object> holder = obj->NewInstance(); 5305 context->Global()->Set(v8_str("holder"), holder); 5306 v8::Handle<Value> result = CompileRun( 5307 "holder.y = 11; holder.y = 12; holder.y"); 5308 CHECK_EQ(12, result->Uint32Value()); 5309} 5310 5311 5312THREADED_TEST(TypeSwitch) { 5313 v8::HandleScope scope; 5314 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(); 5315 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(); 5316 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(); 5317 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 }; 5318 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs); 5319 LocalContext context; 5320 v8::Handle<v8::Object> obj0 = v8::Object::New(); 5321 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance(); 5322 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance(); 5323 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance(); 5324 for (int i = 0; i < 10; i++) { 5325 CHECK_EQ(0, type_switch->match(obj0)); 5326 CHECK_EQ(1, type_switch->match(obj1)); 5327 CHECK_EQ(2, type_switch->match(obj2)); 5328 CHECK_EQ(3, type_switch->match(obj3)); 5329 CHECK_EQ(3, type_switch->match(obj3)); 5330 CHECK_EQ(2, type_switch->match(obj2)); 5331 CHECK_EQ(1, type_switch->match(obj1)); 5332 CHECK_EQ(0, type_switch->match(obj0)); 5333 } 5334} 5335 5336 5337// For use within the TestSecurityHandler() test. 5338static bool g_security_callback_result = false; 5339static bool NamedSecurityTestCallback(Local<v8::Object> global, 5340 Local<Value> name, 5341 v8::AccessType type, 5342 Local<Value> data) { 5343 // Always allow read access. 5344 if (type == v8::ACCESS_GET) 5345 return true; 5346 5347 // Sometimes allow other access. 5348 return g_security_callback_result; 5349} 5350 5351 5352static bool IndexedSecurityTestCallback(Local<v8::Object> global, 5353 uint32_t key, 5354 v8::AccessType type, 5355 Local<Value> data) { 5356 // Always allow read access. 5357 if (type == v8::ACCESS_GET) 5358 return true; 5359 5360 // Sometimes allow other access. 5361 return g_security_callback_result; 5362} 5363 5364 5365static int trouble_nesting = 0; 5366static v8::Handle<Value> TroubleCallback(const v8::Arguments& args) { 5367 ApiTestFuzzer::Fuzz(); 5368 trouble_nesting++; 5369 5370 // Call a JS function that throws an uncaught exception. 5371 Local<v8::Object> arg_this = Context::GetCurrent()->Global(); 5372 Local<Value> trouble_callee = (trouble_nesting == 3) ? 5373 arg_this->Get(v8_str("trouble_callee")) : 5374 arg_this->Get(v8_str("trouble_caller")); 5375 CHECK(trouble_callee->IsFunction()); 5376 return Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL); 5377} 5378 5379 5380static int report_count = 0; 5381static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>, 5382 v8::Handle<Value>) { 5383 report_count++; 5384} 5385 5386 5387// Counts uncaught exceptions, but other tests running in parallel 5388// also have uncaught exceptions. 5389TEST(ApiUncaughtException) { 5390 report_count = 0; 5391 v8::HandleScope scope; 5392 LocalContext env; 5393 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener); 5394 5395 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback); 5396 v8::Local<v8::Object> global = env->Global(); 5397 global->Set(v8_str("trouble"), fun->GetFunction()); 5398 5399 Script::Compile(v8_str("function trouble_callee() {" 5400 " var x = null;" 5401 " return x.foo;" 5402 "};" 5403 "function trouble_caller() {" 5404 " trouble();" 5405 "};"))->Run(); 5406 Local<Value> trouble = global->Get(v8_str("trouble")); 5407 CHECK(trouble->IsFunction()); 5408 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee")); 5409 CHECK(trouble_callee->IsFunction()); 5410 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller")); 5411 CHECK(trouble_caller->IsFunction()); 5412 Function::Cast(*trouble_caller)->Call(global, 0, NULL); 5413 CHECK_EQ(1, report_count); 5414 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener); 5415} 5416 5417static const char* script_resource_name = "ExceptionInNativeScript.js"; 5418static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message, 5419 v8::Handle<Value>) { 5420 v8::Handle<v8::Value> name_val = message->GetScriptResourceName(); 5421 CHECK(!name_val.IsEmpty() && name_val->IsString()); 5422 v8::String::AsciiValue name(message->GetScriptResourceName()); 5423 CHECK_EQ(script_resource_name, *name); 5424 CHECK_EQ(3, message->GetLineNumber()); 5425 v8::String::AsciiValue source_line(message->GetSourceLine()); 5426 CHECK_EQ(" new o.foo();", *source_line); 5427} 5428 5429TEST(ExceptionInNativeScript) { 5430 v8::HandleScope scope; 5431 LocalContext env; 5432 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener); 5433 5434 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback); 5435 v8::Local<v8::Object> global = env->Global(); 5436 global->Set(v8_str("trouble"), fun->GetFunction()); 5437 5438 Script::Compile(v8_str("function trouble() {\n" 5439 " var o = {};\n" 5440 " new o.foo();\n" 5441 "};"), v8::String::New(script_resource_name))->Run(); 5442 Local<Value> trouble = global->Get(v8_str("trouble")); 5443 CHECK(trouble->IsFunction()); 5444 Function::Cast(*trouble)->Call(global, 0, NULL); 5445 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener); 5446} 5447 5448 5449TEST(CompilationErrorUsingTryCatchHandler) { 5450 v8::HandleScope scope; 5451 LocalContext env; 5452 v8::TryCatch try_catch; 5453 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile.")); 5454 CHECK_NE(NULL, *try_catch.Exception()); 5455 CHECK(try_catch.HasCaught()); 5456} 5457 5458 5459TEST(TryCatchFinallyUsingTryCatchHandler) { 5460 v8::HandleScope scope; 5461 LocalContext env; 5462 v8::TryCatch try_catch; 5463 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run(); 5464 CHECK(!try_catch.HasCaught()); 5465 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run(); 5466 CHECK(try_catch.HasCaught()); 5467 try_catch.Reset(); 5468 Script::Compile(v8_str("(function() {" 5469 "try { throw ''; } finally { return; }" 5470 "})()"))->Run(); 5471 CHECK(!try_catch.HasCaught()); 5472 Script::Compile(v8_str("(function()" 5473 " { try { throw ''; } finally { throw 0; }" 5474 "})()"))->Run(); 5475 CHECK(try_catch.HasCaught()); 5476} 5477 5478 5479// SecurityHandler can't be run twice 5480TEST(SecurityHandler) { 5481 v8::HandleScope scope0; 5482 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 5483 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback, 5484 IndexedSecurityTestCallback); 5485 // Create an environment 5486 v8::Persistent<Context> context0 = 5487 Context::New(NULL, global_template); 5488 context0->Enter(); 5489 5490 v8::Handle<v8::Object> global0 = context0->Global(); 5491 v8::Handle<Script> script0 = v8_compile("foo = 111"); 5492 script0->Run(); 5493 global0->Set(v8_str("0"), v8_num(999)); 5494 v8::Handle<Value> foo0 = global0->Get(v8_str("foo")); 5495 CHECK_EQ(111, foo0->Int32Value()); 5496 v8::Handle<Value> z0 = global0->Get(v8_str("0")); 5497 CHECK_EQ(999, z0->Int32Value()); 5498 5499 // Create another environment, should fail security checks. 5500 v8::HandleScope scope1; 5501 5502 v8::Persistent<Context> context1 = 5503 Context::New(NULL, global_template); 5504 context1->Enter(); 5505 5506 v8::Handle<v8::Object> global1 = context1->Global(); 5507 global1->Set(v8_str("othercontext"), global0); 5508 // This set will fail the security check. 5509 v8::Handle<Script> script1 = 5510 v8_compile("othercontext.foo = 222; othercontext[0] = 888;"); 5511 script1->Run(); 5512 // This read will pass the security check. 5513 v8::Handle<Value> foo1 = global0->Get(v8_str("foo")); 5514 CHECK_EQ(111, foo1->Int32Value()); 5515 // This read will pass the security check. 5516 v8::Handle<Value> z1 = global0->Get(v8_str("0")); 5517 CHECK_EQ(999, z1->Int32Value()); 5518 5519 // Create another environment, should pass security checks. 5520 { g_security_callback_result = true; // allow security handler to pass. 5521 v8::HandleScope scope2; 5522 LocalContext context2; 5523 v8::Handle<v8::Object> global2 = context2->Global(); 5524 global2->Set(v8_str("othercontext"), global0); 5525 v8::Handle<Script> script2 = 5526 v8_compile("othercontext.foo = 333; othercontext[0] = 888;"); 5527 script2->Run(); 5528 v8::Handle<Value> foo2 = global0->Get(v8_str("foo")); 5529 CHECK_EQ(333, foo2->Int32Value()); 5530 v8::Handle<Value> z2 = global0->Get(v8_str("0")); 5531 CHECK_EQ(888, z2->Int32Value()); 5532 } 5533 5534 context1->Exit(); 5535 context1.Dispose(); 5536 5537 context0->Exit(); 5538 context0.Dispose(); 5539} 5540 5541 5542THREADED_TEST(SecurityChecks) { 5543 v8::HandleScope handle_scope; 5544 LocalContext env1; 5545 v8::Persistent<Context> env2 = Context::New(); 5546 5547 Local<Value> foo = v8_str("foo"); 5548 Local<Value> bar = v8_str("bar"); 5549 5550 // Set to the same domain. 5551 env1->SetSecurityToken(foo); 5552 5553 // Create a function in env1. 5554 Script::Compile(v8_str("spy=function(){return spy;}"))->Run(); 5555 Local<Value> spy = env1->Global()->Get(v8_str("spy")); 5556 CHECK(spy->IsFunction()); 5557 5558 // Create another function accessing global objects. 5559 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run(); 5560 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2")); 5561 CHECK(spy2->IsFunction()); 5562 5563 // Switch to env2 in the same domain and invoke spy on env2. 5564 { 5565 env2->SetSecurityToken(foo); 5566 // Enter env2 5567 Context::Scope scope_env2(env2); 5568 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL); 5569 CHECK(result->IsFunction()); 5570 } 5571 5572 { 5573 env2->SetSecurityToken(bar); 5574 Context::Scope scope_env2(env2); 5575 5576 // Call cross_domain_call, it should throw an exception 5577 v8::TryCatch try_catch; 5578 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL); 5579 CHECK(try_catch.HasCaught()); 5580 } 5581 5582 env2.Dispose(); 5583} 5584 5585 5586// Regression test case for issue 1183439. 5587THREADED_TEST(SecurityChecksForPrototypeChain) { 5588 v8::HandleScope scope; 5589 LocalContext current; 5590 v8::Persistent<Context> other = Context::New(); 5591 5592 // Change context to be able to get to the Object function in the 5593 // other context without hitting the security checks. 5594 v8::Local<Value> other_object; 5595 { Context::Scope scope(other); 5596 other_object = other->Global()->Get(v8_str("Object")); 5597 other->Global()->Set(v8_num(42), v8_num(87)); 5598 } 5599 5600 current->Global()->Set(v8_str("other"), other->Global()); 5601 CHECK(v8_compile("other")->Run()->Equals(other->Global())); 5602 5603 // Make sure the security check fails here and we get an undefined 5604 // result instead of getting the Object function. Repeat in a loop 5605 // to make sure to exercise the IC code. 5606 v8::Local<Script> access_other0 = v8_compile("other.Object"); 5607 v8::Local<Script> access_other1 = v8_compile("other[42]"); 5608 for (int i = 0; i < 5; i++) { 5609 CHECK(!access_other0->Run()->Equals(other_object)); 5610 CHECK(access_other0->Run()->IsUndefined()); 5611 CHECK(!access_other1->Run()->Equals(v8_num(87))); 5612 CHECK(access_other1->Run()->IsUndefined()); 5613 } 5614 5615 // Create an object that has 'other' in its prototype chain and make 5616 // sure we cannot access the Object function indirectly through 5617 // that. Repeat in a loop to make sure to exercise the IC code. 5618 v8_compile("function F() { };" 5619 "F.prototype = other;" 5620 "var f = new F();")->Run(); 5621 v8::Local<Script> access_f0 = v8_compile("f.Object"); 5622 v8::Local<Script> access_f1 = v8_compile("f[42]"); 5623 for (int j = 0; j < 5; j++) { 5624 CHECK(!access_f0->Run()->Equals(other_object)); 5625 CHECK(access_f0->Run()->IsUndefined()); 5626 CHECK(!access_f1->Run()->Equals(v8_num(87))); 5627 CHECK(access_f1->Run()->IsUndefined()); 5628 } 5629 5630 // Now it gets hairy: Set the prototype for the other global object 5631 // to be the current global object. The prototype chain for 'f' now 5632 // goes through 'other' but ends up in the current global object. 5633 { Context::Scope scope(other); 5634 other->Global()->Set(v8_str("__proto__"), current->Global()); 5635 } 5636 // Set a named and an index property on the current global 5637 // object. To force the lookup to go through the other global object, 5638 // the properties must not exist in the other global object. 5639 current->Global()->Set(v8_str("foo"), v8_num(100)); 5640 current->Global()->Set(v8_num(99), v8_num(101)); 5641 // Try to read the properties from f and make sure that the access 5642 // gets stopped by the security checks on the other global object. 5643 Local<Script> access_f2 = v8_compile("f.foo"); 5644 Local<Script> access_f3 = v8_compile("f[99]"); 5645 for (int k = 0; k < 5; k++) { 5646 CHECK(!access_f2->Run()->Equals(v8_num(100))); 5647 CHECK(access_f2->Run()->IsUndefined()); 5648 CHECK(!access_f3->Run()->Equals(v8_num(101))); 5649 CHECK(access_f3->Run()->IsUndefined()); 5650 } 5651 other.Dispose(); 5652} 5653 5654 5655THREADED_TEST(CrossDomainDelete) { 5656 v8::HandleScope handle_scope; 5657 LocalContext env1; 5658 v8::Persistent<Context> env2 = Context::New(); 5659 5660 Local<Value> foo = v8_str("foo"); 5661 Local<Value> bar = v8_str("bar"); 5662 5663 // Set to the same domain. 5664 env1->SetSecurityToken(foo); 5665 env2->SetSecurityToken(foo); 5666 5667 env1->Global()->Set(v8_str("prop"), v8_num(3)); 5668 env2->Global()->Set(v8_str("env1"), env1->Global()); 5669 5670 // Change env2 to a different domain and delete env1.prop. 5671 env2->SetSecurityToken(bar); 5672 { 5673 Context::Scope scope_env2(env2); 5674 Local<Value> result = 5675 Script::Compile(v8_str("delete env1.prop"))->Run(); 5676 CHECK(result->IsFalse()); 5677 } 5678 5679 // Check that env1.prop still exists. 5680 Local<Value> v = env1->Global()->Get(v8_str("prop")); 5681 CHECK(v->IsNumber()); 5682 CHECK_EQ(3, v->Int32Value()); 5683 5684 env2.Dispose(); 5685} 5686 5687 5688THREADED_TEST(CrossDomainIsPropertyEnumerable) { 5689 v8::HandleScope handle_scope; 5690 LocalContext env1; 5691 v8::Persistent<Context> env2 = Context::New(); 5692 5693 Local<Value> foo = v8_str("foo"); 5694 Local<Value> bar = v8_str("bar"); 5695 5696 // Set to the same domain. 5697 env1->SetSecurityToken(foo); 5698 env2->SetSecurityToken(foo); 5699 5700 env1->Global()->Set(v8_str("prop"), v8_num(3)); 5701 env2->Global()->Set(v8_str("env1"), env1->Global()); 5702 5703 // env1.prop is enumerable in env2. 5704 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')"); 5705 { 5706 Context::Scope scope_env2(env2); 5707 Local<Value> result = Script::Compile(test)->Run(); 5708 CHECK(result->IsTrue()); 5709 } 5710 5711 // Change env2 to a different domain and test again. 5712 env2->SetSecurityToken(bar); 5713 { 5714 Context::Scope scope_env2(env2); 5715 Local<Value> result = Script::Compile(test)->Run(); 5716 CHECK(result->IsFalse()); 5717 } 5718 5719 env2.Dispose(); 5720} 5721 5722 5723THREADED_TEST(CrossDomainForIn) { 5724 v8::HandleScope handle_scope; 5725 LocalContext env1; 5726 v8::Persistent<Context> env2 = Context::New(); 5727 5728 Local<Value> foo = v8_str("foo"); 5729 Local<Value> bar = v8_str("bar"); 5730 5731 // Set to the same domain. 5732 env1->SetSecurityToken(foo); 5733 env2->SetSecurityToken(foo); 5734 5735 env1->Global()->Set(v8_str("prop"), v8_num(3)); 5736 env2->Global()->Set(v8_str("env1"), env1->Global()); 5737 5738 // Change env2 to a different domain and set env1's global object 5739 // as the __proto__ of an object in env2 and enumerate properties 5740 // in for-in. It shouldn't enumerate properties on env1's global 5741 // object. 5742 env2->SetSecurityToken(bar); 5743 { 5744 Context::Scope scope_env2(env2); 5745 Local<Value> result = 5746 CompileRun("(function(){var obj = {'__proto__':env1};" 5747 "for (var p in obj)" 5748 " if (p == 'prop') return false;" 5749 "return true;})()"); 5750 CHECK(result->IsTrue()); 5751 } 5752 env2.Dispose(); 5753} 5754 5755 5756TEST(ContextDetachGlobal) { 5757 v8::HandleScope handle_scope; 5758 LocalContext env1; 5759 v8::Persistent<Context> env2 = Context::New(); 5760 5761 Local<v8::Object> global1 = env1->Global(); 5762 5763 Local<Value> foo = v8_str("foo"); 5764 5765 // Set to the same domain. 5766 env1->SetSecurityToken(foo); 5767 env2->SetSecurityToken(foo); 5768 5769 // Enter env2 5770 env2->Enter(); 5771 5772 // Create a function in env2 and add a reference to it in env1. 5773 Local<v8::Object> global2 = env2->Global(); 5774 global2->Set(v8_str("prop"), v8::Integer::New(1)); 5775 CompileRun("function getProp() {return prop;}"); 5776 5777 env1->Global()->Set(v8_str("getProp"), 5778 global2->Get(v8_str("getProp"))); 5779 5780 // Detach env2's global, and reuse the global object of env2 5781 env2->Exit(); 5782 env2->DetachGlobal(); 5783 // env2 has a new global object. 5784 CHECK(!env2->Global()->Equals(global2)); 5785 5786 v8::Persistent<Context> env3 = 5787 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2); 5788 env3->SetSecurityToken(v8_str("bar")); 5789 env3->Enter(); 5790 5791 Local<v8::Object> global3 = env3->Global(); 5792 CHECK_EQ(global2, global3); 5793 CHECK(global3->Get(v8_str("prop"))->IsUndefined()); 5794 CHECK(global3->Get(v8_str("getProp"))->IsUndefined()); 5795 global3->Set(v8_str("prop"), v8::Integer::New(-1)); 5796 global3->Set(v8_str("prop2"), v8::Integer::New(2)); 5797 env3->Exit(); 5798 5799 // Call getProp in env1, and it should return the value 1 5800 { 5801 Local<Value> get_prop = global1->Get(v8_str("getProp")); 5802 CHECK(get_prop->IsFunction()); 5803 v8::TryCatch try_catch; 5804 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL); 5805 CHECK(!try_catch.HasCaught()); 5806 CHECK_EQ(1, r->Int32Value()); 5807 } 5808 5809 // Check that env3 is not accessible from env1 5810 { 5811 Local<Value> r = global3->Get(v8_str("prop2")); 5812 CHECK(r->IsUndefined()); 5813 } 5814 5815 env2.Dispose(); 5816 env3.Dispose(); 5817} 5818 5819 5820TEST(DetachAndReattachGlobal) { 5821 v8::HandleScope scope; 5822 LocalContext env1; 5823 5824 // Create second environment. 5825 v8::Persistent<Context> env2 = Context::New(); 5826 5827 Local<Value> foo = v8_str("foo"); 5828 5829 // Set same security token for env1 and env2. 5830 env1->SetSecurityToken(foo); 5831 env2->SetSecurityToken(foo); 5832 5833 // Create a property on the global object in env2. 5834 { 5835 v8::Context::Scope scope(env2); 5836 env2->Global()->Set(v8_str("p"), v8::Integer::New(42)); 5837 } 5838 5839 // Create a reference to env2 global from env1 global. 5840 env1->Global()->Set(v8_str("other"), env2->Global()); 5841 5842 // Check that we have access to other.p in env2 from env1. 5843 Local<Value> result = CompileRun("other.p"); 5844 CHECK(result->IsInt32()); 5845 CHECK_EQ(42, result->Int32Value()); 5846 5847 // Hold on to global from env2 and detach global from env2. 5848 Local<v8::Object> global2 = env2->Global(); 5849 env2->DetachGlobal(); 5850 5851 // Check that the global has been detached. No other.p property can 5852 // be found. 5853 result = CompileRun("other.p"); 5854 CHECK(result->IsUndefined()); 5855 5856 // Reuse global2 for env3. 5857 v8::Persistent<Context> env3 = 5858 Context::New(0, v8::Handle<v8::ObjectTemplate>(), global2); 5859 CHECK_EQ(global2, env3->Global()); 5860 5861 // Start by using the same security token for env3 as for env1 and env2. 5862 env3->SetSecurityToken(foo); 5863 5864 // Create a property on the global object in env3. 5865 { 5866 v8::Context::Scope scope(env3); 5867 env3->Global()->Set(v8_str("p"), v8::Integer::New(24)); 5868 } 5869 5870 // Check that other.p is now the property in env3 and that we have access. 5871 result = CompileRun("other.p"); 5872 CHECK(result->IsInt32()); 5873 CHECK_EQ(24, result->Int32Value()); 5874 5875 // Change security token for env3 to something different from env1 and env2. 5876 env3->SetSecurityToken(v8_str("bar")); 5877 5878 // Check that we do not have access to other.p in env1. |other| is now 5879 // the global object for env3 which has a different security token, 5880 // so access should be blocked. 5881 result = CompileRun("other.p"); 5882 CHECK(result->IsUndefined()); 5883 5884 // Detach the global for env3 and reattach it to env2. 5885 env3->DetachGlobal(); 5886 env2->ReattachGlobal(global2); 5887 5888 // Check that we have access to other.p again in env1. |other| is now 5889 // the global object for env2 which has the same security token as env1. 5890 result = CompileRun("other.p"); 5891 CHECK(result->IsInt32()); 5892 CHECK_EQ(42, result->Int32Value()); 5893 5894 env2.Dispose(); 5895 env3.Dispose(); 5896} 5897 5898 5899static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false }; 5900static bool NamedAccessBlocker(Local<v8::Object> global, 5901 Local<Value> name, 5902 v8::AccessType type, 5903 Local<Value> data) { 5904 return Context::GetCurrent()->Global()->Equals(global) || 5905 allowed_access_type[type]; 5906} 5907 5908 5909static bool IndexedAccessBlocker(Local<v8::Object> global, 5910 uint32_t key, 5911 v8::AccessType type, 5912 Local<Value> data) { 5913 return Context::GetCurrent()->Global()->Equals(global) || 5914 allowed_access_type[type]; 5915} 5916 5917 5918static int g_echo_value = -1; 5919static v8::Handle<Value> EchoGetter(Local<String> name, 5920 const AccessorInfo& info) { 5921 return v8_num(g_echo_value); 5922} 5923 5924 5925static void EchoSetter(Local<String> name, 5926 Local<Value> value, 5927 const AccessorInfo&) { 5928 if (value->IsNumber()) 5929 g_echo_value = value->Int32Value(); 5930} 5931 5932 5933static v8::Handle<Value> UnreachableGetter(Local<String> name, 5934 const AccessorInfo& info) { 5935 CHECK(false); // This function should not be called.. 5936 return v8::Undefined(); 5937} 5938 5939 5940static void UnreachableSetter(Local<String>, Local<Value>, 5941 const AccessorInfo&) { 5942 CHECK(false); // This function should nto be called. 5943} 5944 5945 5946TEST(AccessControl) { 5947 v8::HandleScope handle_scope; 5948 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 5949 5950 global_template->SetAccessCheckCallbacks(NamedAccessBlocker, 5951 IndexedAccessBlocker); 5952 5953 // Add an accessor accessible by cross-domain JS code. 5954 global_template->SetAccessor( 5955 v8_str("accessible_prop"), 5956 EchoGetter, EchoSetter, 5957 v8::Handle<Value>(), 5958 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 5959 5960 // Add an accessor that is not accessible by cross-domain JS code. 5961 global_template->SetAccessor(v8_str("blocked_prop"), 5962 UnreachableGetter, UnreachableSetter, 5963 v8::Handle<Value>(), 5964 v8::DEFAULT); 5965 5966 // Create an environment 5967 v8::Persistent<Context> context0 = Context::New(NULL, global_template); 5968 context0->Enter(); 5969 5970 v8::Handle<v8::Object> global0 = context0->Global(); 5971 5972 // Define a property with JS getter and setter. 5973 CompileRun( 5974 "function getter() { return 'getter'; };\n" 5975 "function setter() { return 'setter'; }\n" 5976 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})"); 5977 5978 Local<Value> getter = global0->Get(v8_str("getter")); 5979 Local<Value> setter = global0->Get(v8_str("setter")); 5980 5981 // And define normal element. 5982 global0->Set(239, v8_str("239")); 5983 5984 // Define an element with JS getter and setter. 5985 CompileRun( 5986 "function el_getter() { return 'el_getter'; };\n" 5987 "function el_setter() { return 'el_setter'; };\n" 5988 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});"); 5989 5990 Local<Value> el_getter = global0->Get(v8_str("el_getter")); 5991 Local<Value> el_setter = global0->Get(v8_str("el_setter")); 5992 5993 v8::HandleScope scope1; 5994 5995 v8::Persistent<Context> context1 = Context::New(); 5996 context1->Enter(); 5997 5998 v8::Handle<v8::Object> global1 = context1->Global(); 5999 global1->Set(v8_str("other"), global0); 6000 6001 // Access blocked property. 6002 CompileRun("other.blocked_prop = 1"); 6003 6004 ExpectUndefined("other.blocked_prop"); 6005 ExpectUndefined( 6006 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')"); 6007 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')"); 6008 6009 // Enable ACCESS_HAS 6010 allowed_access_type[v8::ACCESS_HAS] = true; 6011 ExpectUndefined("other.blocked_prop"); 6012 // ... and now we can get the descriptor... 6013 ExpectUndefined( 6014 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value"); 6015 // ... and enumerate the property. 6016 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')"); 6017 allowed_access_type[v8::ACCESS_HAS] = false; 6018 6019 // Access blocked element. 6020 CompileRun("other[239] = 1"); 6021 6022 ExpectUndefined("other[239]"); 6023 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')"); 6024 ExpectFalse("propertyIsEnumerable.call(other, '239')"); 6025 6026 // Enable ACCESS_HAS 6027 allowed_access_type[v8::ACCESS_HAS] = true; 6028 ExpectUndefined("other[239]"); 6029 // ... and now we can get the descriptor... 6030 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value"); 6031 // ... and enumerate the property. 6032 ExpectTrue("propertyIsEnumerable.call(other, '239')"); 6033 allowed_access_type[v8::ACCESS_HAS] = false; 6034 6035 // Access a property with JS accessor. 6036 CompileRun("other.js_accessor_p = 2"); 6037 6038 ExpectUndefined("other.js_accessor_p"); 6039 ExpectUndefined( 6040 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')"); 6041 6042 // Enable ACCESS_HAS. 6043 allowed_access_type[v8::ACCESS_HAS] = true; 6044 ExpectUndefined("other.js_accessor_p"); 6045 ExpectUndefined( 6046 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get"); 6047 ExpectUndefined( 6048 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set"); 6049 ExpectUndefined( 6050 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 6051 allowed_access_type[v8::ACCESS_HAS] = false; 6052 6053 // Enable both ACCESS_HAS and ACCESS_GET. 6054 allowed_access_type[v8::ACCESS_HAS] = true; 6055 allowed_access_type[v8::ACCESS_GET] = true; 6056 6057 ExpectString("other.js_accessor_p", "getter"); 6058 ExpectObject( 6059 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter); 6060 ExpectUndefined( 6061 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set"); 6062 ExpectUndefined( 6063 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 6064 6065 allowed_access_type[v8::ACCESS_GET] = false; 6066 allowed_access_type[v8::ACCESS_HAS] = false; 6067 6068 // Enable both ACCESS_HAS and ACCESS_SET. 6069 allowed_access_type[v8::ACCESS_HAS] = true; 6070 allowed_access_type[v8::ACCESS_SET] = true; 6071 6072 ExpectUndefined("other.js_accessor_p"); 6073 ExpectUndefined( 6074 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get"); 6075 ExpectObject( 6076 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter); 6077 ExpectUndefined( 6078 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 6079 6080 allowed_access_type[v8::ACCESS_SET] = false; 6081 allowed_access_type[v8::ACCESS_HAS] = false; 6082 6083 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET. 6084 allowed_access_type[v8::ACCESS_HAS] = true; 6085 allowed_access_type[v8::ACCESS_GET] = true; 6086 allowed_access_type[v8::ACCESS_SET] = true; 6087 6088 ExpectString("other.js_accessor_p", "getter"); 6089 ExpectObject( 6090 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter); 6091 ExpectObject( 6092 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter); 6093 ExpectUndefined( 6094 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 6095 6096 allowed_access_type[v8::ACCESS_SET] = false; 6097 allowed_access_type[v8::ACCESS_GET] = false; 6098 allowed_access_type[v8::ACCESS_HAS] = false; 6099 6100 // Access an element with JS accessor. 6101 CompileRun("other[42] = 2"); 6102 6103 ExpectUndefined("other[42]"); 6104 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')"); 6105 6106 // Enable ACCESS_HAS. 6107 allowed_access_type[v8::ACCESS_HAS] = true; 6108 ExpectUndefined("other[42]"); 6109 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get"); 6110 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set"); 6111 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 6112 allowed_access_type[v8::ACCESS_HAS] = false; 6113 6114 // Enable both ACCESS_HAS and ACCESS_GET. 6115 allowed_access_type[v8::ACCESS_HAS] = true; 6116 allowed_access_type[v8::ACCESS_GET] = true; 6117 6118 ExpectString("other[42]", "el_getter"); 6119 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); 6120 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set"); 6121 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 6122 6123 allowed_access_type[v8::ACCESS_GET] = false; 6124 allowed_access_type[v8::ACCESS_HAS] = false; 6125 6126 // Enable both ACCESS_HAS and ACCESS_SET. 6127 allowed_access_type[v8::ACCESS_HAS] = true; 6128 allowed_access_type[v8::ACCESS_SET] = true; 6129 6130 ExpectUndefined("other[42]"); 6131 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get"); 6132 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); 6133 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 6134 6135 allowed_access_type[v8::ACCESS_SET] = false; 6136 allowed_access_type[v8::ACCESS_HAS] = false; 6137 6138 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET. 6139 allowed_access_type[v8::ACCESS_HAS] = true; 6140 allowed_access_type[v8::ACCESS_GET] = true; 6141 allowed_access_type[v8::ACCESS_SET] = true; 6142 6143 ExpectString("other[42]", "el_getter"); 6144 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); 6145 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); 6146 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 6147 6148 allowed_access_type[v8::ACCESS_SET] = false; 6149 allowed_access_type[v8::ACCESS_GET] = false; 6150 allowed_access_type[v8::ACCESS_HAS] = false; 6151 6152 v8::Handle<Value> value; 6153 6154 // Access accessible property 6155 value = CompileRun("other.accessible_prop = 3"); 6156 CHECK(value->IsNumber()); 6157 CHECK_EQ(3, value->Int32Value()); 6158 CHECK_EQ(3, g_echo_value); 6159 6160 value = CompileRun("other.accessible_prop"); 6161 CHECK(value->IsNumber()); 6162 CHECK_EQ(3, value->Int32Value()); 6163 6164 value = CompileRun( 6165 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value"); 6166 CHECK(value->IsNumber()); 6167 CHECK_EQ(3, value->Int32Value()); 6168 6169 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')"); 6170 CHECK(value->IsTrue()); 6171 6172 // Enumeration doesn't enumerate accessors from inaccessible objects in 6173 // the prototype chain even if the accessors are in themselves accessible. 6174 value = 6175 CompileRun("(function(){var obj = {'__proto__':other};" 6176 "for (var p in obj)" 6177 " if (p == 'accessible_prop' || p == 'blocked_prop') {" 6178 " return false;" 6179 " }" 6180 "return true;})()"); 6181 CHECK(value->IsTrue()); 6182 6183 context1->Exit(); 6184 context0->Exit(); 6185 context1.Dispose(); 6186 context0.Dispose(); 6187} 6188 6189 6190TEST(AccessControlES5) { 6191 v8::HandleScope handle_scope; 6192 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 6193 6194 global_template->SetAccessCheckCallbacks(NamedAccessBlocker, 6195 IndexedAccessBlocker); 6196 6197 // Add accessible accessor. 6198 global_template->SetAccessor( 6199 v8_str("accessible_prop"), 6200 EchoGetter, EchoSetter, 6201 v8::Handle<Value>(), 6202 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 6203 6204 6205 // Add an accessor that is not accessible by cross-domain JS code. 6206 global_template->SetAccessor(v8_str("blocked_prop"), 6207 UnreachableGetter, UnreachableSetter, 6208 v8::Handle<Value>(), 6209 v8::DEFAULT); 6210 6211 // Create an environment 6212 v8::Persistent<Context> context0 = Context::New(NULL, global_template); 6213 context0->Enter(); 6214 6215 v8::Handle<v8::Object> global0 = context0->Global(); 6216 6217 v8::Persistent<Context> context1 = Context::New(); 6218 context1->Enter(); 6219 v8::Handle<v8::Object> global1 = context1->Global(); 6220 global1->Set(v8_str("other"), global0); 6221 6222 // Regression test for issue 1154. 6223 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1"); 6224 6225 ExpectUndefined("other.blocked_prop"); 6226 6227 // Regression test for issue 1027. 6228 CompileRun("Object.defineProperty(\n" 6229 " other, 'blocked_prop', {configurable: false})"); 6230 ExpectUndefined("other.blocked_prop"); 6231 ExpectUndefined( 6232 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')"); 6233 6234 // Regression test for issue 1171. 6235 ExpectTrue("Object.isExtensible(other)"); 6236 CompileRun("Object.preventExtensions(other)"); 6237 ExpectTrue("Object.isExtensible(other)"); 6238 6239 // Object.seal and Object.freeze. 6240 CompileRun("Object.freeze(other)"); 6241 ExpectTrue("Object.isExtensible(other)"); 6242 6243 CompileRun("Object.seal(other)"); 6244 ExpectTrue("Object.isExtensible(other)"); 6245 6246 // Regression test for issue 1250. 6247 // Make sure that we can set the accessible accessors value using normal 6248 // assignment. 6249 CompileRun("other.accessible_prop = 42"); 6250 CHECK_EQ(42, g_echo_value); 6251 6252 v8::Handle<Value> value; 6253 // We follow Safari in ignoring assignments to host object accessors. 6254 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})"); 6255 value = CompileRun("other.accessible_prop == 42"); 6256 CHECK(value->IsTrue()); 6257} 6258 6259 6260static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global, 6261 Local<Value> name, 6262 v8::AccessType type, 6263 Local<Value> data) { 6264 return false; 6265} 6266 6267 6268static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global, 6269 uint32_t key, 6270 v8::AccessType type, 6271 Local<Value> data) { 6272 return false; 6273} 6274 6275 6276THREADED_TEST(AccessControlGetOwnPropertyNames) { 6277 v8::HandleScope handle_scope; 6278 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(); 6279 6280 obj_template->Set(v8_str("x"), v8::Integer::New(42)); 6281 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker, 6282 GetOwnPropertyNamesIndexedBlocker); 6283 6284 // Create an environment 6285 v8::Persistent<Context> context0 = Context::New(NULL, obj_template); 6286 context0->Enter(); 6287 6288 v8::Handle<v8::Object> global0 = context0->Global(); 6289 6290 v8::HandleScope scope1; 6291 6292 v8::Persistent<Context> context1 = Context::New(); 6293 context1->Enter(); 6294 6295 v8::Handle<v8::Object> global1 = context1->Global(); 6296 global1->Set(v8_str("other"), global0); 6297 global1->Set(v8_str("object"), obj_template->NewInstance()); 6298 6299 v8::Handle<Value> value; 6300 6301 // Attempt to get the property names of the other global object and 6302 // of an object that requires access checks. Accessing the other 6303 // global object should be blocked by access checks on the global 6304 // proxy object. Accessing the object that requires access checks 6305 // is blocked by the access checks on the object itself. 6306 value = CompileRun("Object.getOwnPropertyNames(other).length == 0"); 6307 CHECK(value->IsTrue()); 6308 6309 value = CompileRun("Object.getOwnPropertyNames(object).length == 0"); 6310 CHECK(value->IsTrue()); 6311 6312 context1->Exit(); 6313 context0->Exit(); 6314 context1.Dispose(); 6315 context0.Dispose(); 6316} 6317 6318 6319static v8::Handle<v8::Array> NamedPropertyEnumerator(const AccessorInfo& info) { 6320 v8::Handle<v8::Array> result = v8::Array::New(1); 6321 result->Set(0, v8_str("x")); 6322 return result; 6323} 6324 6325 6326THREADED_TEST(GetOwnPropertyNamesWithInterceptor) { 6327 v8::HandleScope handle_scope; 6328 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(); 6329 6330 obj_template->Set(v8_str("x"), v8::Integer::New(42)); 6331 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL, 6332 NamedPropertyEnumerator); 6333 6334 LocalContext context; 6335 v8::Handle<v8::Object> global = context->Global(); 6336 global->Set(v8_str("object"), obj_template->NewInstance()); 6337 6338 v8::Handle<Value> value = 6339 CompileRun("Object.getOwnPropertyNames(object).join(',')"); 6340 CHECK_EQ(v8_str("x"), value); 6341} 6342 6343 6344static v8::Handle<Value> ConstTenGetter(Local<String> name, 6345 const AccessorInfo& info) { 6346 return v8_num(10); 6347} 6348 6349 6350THREADED_TEST(CrossDomainAccessors) { 6351 v8::HandleScope handle_scope; 6352 6353 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(); 6354 6355 v8::Handle<v8::ObjectTemplate> global_template = 6356 func_template->InstanceTemplate(); 6357 6358 v8::Handle<v8::ObjectTemplate> proto_template = 6359 func_template->PrototypeTemplate(); 6360 6361 // Add an accessor to proto that's accessible by cross-domain JS code. 6362 proto_template->SetAccessor(v8_str("accessible"), 6363 ConstTenGetter, 0, 6364 v8::Handle<Value>(), 6365 v8::ALL_CAN_READ); 6366 6367 // Add an accessor that is not accessible by cross-domain JS code. 6368 global_template->SetAccessor(v8_str("unreachable"), 6369 UnreachableGetter, 0, 6370 v8::Handle<Value>(), 6371 v8::DEFAULT); 6372 6373 v8::Persistent<Context> context0 = Context::New(NULL, global_template); 6374 context0->Enter(); 6375 6376 Local<v8::Object> global = context0->Global(); 6377 // Add a normal property that shadows 'accessible' 6378 global->Set(v8_str("accessible"), v8_num(11)); 6379 6380 // Enter a new context. 6381 v8::HandleScope scope1; 6382 v8::Persistent<Context> context1 = Context::New(); 6383 context1->Enter(); 6384 6385 v8::Handle<v8::Object> global1 = context1->Global(); 6386 global1->Set(v8_str("other"), global); 6387 6388 // Should return 10, instead of 11 6389 v8::Handle<Value> value = v8_compile("other.accessible")->Run(); 6390 CHECK(value->IsNumber()); 6391 CHECK_EQ(10, value->Int32Value()); 6392 6393 value = v8_compile("other.unreachable")->Run(); 6394 CHECK(value->IsUndefined()); 6395 6396 context1->Exit(); 6397 context0->Exit(); 6398 context1.Dispose(); 6399 context0.Dispose(); 6400} 6401 6402 6403static int named_access_count = 0; 6404static int indexed_access_count = 0; 6405 6406static bool NamedAccessCounter(Local<v8::Object> global, 6407 Local<Value> name, 6408 v8::AccessType type, 6409 Local<Value> data) { 6410 named_access_count++; 6411 return true; 6412} 6413 6414 6415static bool IndexedAccessCounter(Local<v8::Object> global, 6416 uint32_t key, 6417 v8::AccessType type, 6418 Local<Value> data) { 6419 indexed_access_count++; 6420 return true; 6421} 6422 6423 6424// This one is too easily disturbed by other tests. 6425TEST(AccessControlIC) { 6426 named_access_count = 0; 6427 indexed_access_count = 0; 6428 6429 v8::HandleScope handle_scope; 6430 6431 // Create an environment. 6432 v8::Persistent<Context> context0 = Context::New(); 6433 context0->Enter(); 6434 6435 // Create an object that requires access-check functions to be 6436 // called for cross-domain access. 6437 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(); 6438 object_template->SetAccessCheckCallbacks(NamedAccessCounter, 6439 IndexedAccessCounter); 6440 Local<v8::Object> object = object_template->NewInstance(); 6441 6442 v8::HandleScope scope1; 6443 6444 // Create another environment. 6445 v8::Persistent<Context> context1 = Context::New(); 6446 context1->Enter(); 6447 6448 // Make easy access to the object from the other environment. 6449 v8::Handle<v8::Object> global1 = context1->Global(); 6450 global1->Set(v8_str("obj"), object); 6451 6452 v8::Handle<Value> value; 6453 6454 // Check that the named access-control function is called every time. 6455 CompileRun("function testProp(obj) {" 6456 " for (var i = 0; i < 10; i++) obj.prop = 1;" 6457 " for (var j = 0; j < 10; j++) obj.prop;" 6458 " return obj.prop" 6459 "}"); 6460 value = CompileRun("testProp(obj)"); 6461 CHECK(value->IsNumber()); 6462 CHECK_EQ(1, value->Int32Value()); 6463 CHECK_EQ(21, named_access_count); 6464 6465 // Check that the named access-control function is called every time. 6466 CompileRun("var p = 'prop';" 6467 "function testKeyed(obj) {" 6468 " for (var i = 0; i < 10; i++) obj[p] = 1;" 6469 " for (var j = 0; j < 10; j++) obj[p];" 6470 " return obj[p];" 6471 "}"); 6472 // Use obj which requires access checks. No inline caching is used 6473 // in that case. 6474 value = CompileRun("testKeyed(obj)"); 6475 CHECK(value->IsNumber()); 6476 CHECK_EQ(1, value->Int32Value()); 6477 CHECK_EQ(42, named_access_count); 6478 // Force the inline caches into generic state and try again. 6479 CompileRun("testKeyed({ a: 0 })"); 6480 CompileRun("testKeyed({ b: 0 })"); 6481 value = CompileRun("testKeyed(obj)"); 6482 CHECK(value->IsNumber()); 6483 CHECK_EQ(1, value->Int32Value()); 6484 CHECK_EQ(63, named_access_count); 6485 6486 // Check that the indexed access-control function is called every time. 6487 CompileRun("function testIndexed(obj) {" 6488 " for (var i = 0; i < 10; i++) obj[0] = 1;" 6489 " for (var j = 0; j < 10; j++) obj[0];" 6490 " return obj[0]" 6491 "}"); 6492 value = CompileRun("testIndexed(obj)"); 6493 CHECK(value->IsNumber()); 6494 CHECK_EQ(1, value->Int32Value()); 6495 CHECK_EQ(21, indexed_access_count); 6496 // Force the inline caches into generic state. 6497 CompileRun("testIndexed(new Array(1))"); 6498 // Test that the indexed access check is called. 6499 value = CompileRun("testIndexed(obj)"); 6500 CHECK(value->IsNumber()); 6501 CHECK_EQ(1, value->Int32Value()); 6502 CHECK_EQ(42, indexed_access_count); 6503 6504 // Check that the named access check is called when invoking 6505 // functions on an object that requires access checks. 6506 CompileRun("obj.f = function() {}"); 6507 CompileRun("function testCallNormal(obj) {" 6508 " for (var i = 0; i < 10; i++) obj.f();" 6509 "}"); 6510 CompileRun("testCallNormal(obj)"); 6511 CHECK_EQ(74, named_access_count); 6512 6513 // Force obj into slow case. 6514 value = CompileRun("delete obj.prop"); 6515 CHECK(value->BooleanValue()); 6516 // Force inline caches into dictionary probing mode. 6517 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);"); 6518 // Test that the named access check is called. 6519 value = CompileRun("testProp(obj);"); 6520 CHECK(value->IsNumber()); 6521 CHECK_EQ(1, value->Int32Value()); 6522 CHECK_EQ(96, named_access_count); 6523 6524 // Force the call inline cache into dictionary probing mode. 6525 CompileRun("o.f = function() {}; testCallNormal(o)"); 6526 // Test that the named access check is still called for each 6527 // invocation of the function. 6528 value = CompileRun("testCallNormal(obj)"); 6529 CHECK_EQ(106, named_access_count); 6530 6531 context1->Exit(); 6532 context0->Exit(); 6533 context1.Dispose(); 6534 context0.Dispose(); 6535} 6536 6537 6538static bool NamedAccessFlatten(Local<v8::Object> global, 6539 Local<Value> name, 6540 v8::AccessType type, 6541 Local<Value> data) { 6542 char buf[100]; 6543 int len; 6544 6545 CHECK(name->IsString()); 6546 6547 memset(buf, 0x1, sizeof(buf)); 6548 len = name.As<String>()->WriteAscii(buf); 6549 CHECK_EQ(4, len); 6550 6551 uint16_t buf2[100]; 6552 6553 memset(buf, 0x1, sizeof(buf)); 6554 len = name.As<String>()->Write(buf2); 6555 CHECK_EQ(4, len); 6556 6557 return true; 6558} 6559 6560 6561static bool IndexedAccessFlatten(Local<v8::Object> global, 6562 uint32_t key, 6563 v8::AccessType type, 6564 Local<Value> data) { 6565 return true; 6566} 6567 6568 6569// Regression test. In access checks, operations that may cause 6570// garbage collection are not allowed. It used to be the case that 6571// using the Write operation on a string could cause a garbage 6572// collection due to flattening of the string. This is no longer the 6573// case. 6574THREADED_TEST(AccessControlFlatten) { 6575 named_access_count = 0; 6576 indexed_access_count = 0; 6577 6578 v8::HandleScope handle_scope; 6579 6580 // Create an environment. 6581 v8::Persistent<Context> context0 = Context::New(); 6582 context0->Enter(); 6583 6584 // Create an object that requires access-check functions to be 6585 // called for cross-domain access. 6586 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(); 6587 object_template->SetAccessCheckCallbacks(NamedAccessFlatten, 6588 IndexedAccessFlatten); 6589 Local<v8::Object> object = object_template->NewInstance(); 6590 6591 v8::HandleScope scope1; 6592 6593 // Create another environment. 6594 v8::Persistent<Context> context1 = Context::New(); 6595 context1->Enter(); 6596 6597 // Make easy access to the object from the other environment. 6598 v8::Handle<v8::Object> global1 = context1->Global(); 6599 global1->Set(v8_str("obj"), object); 6600 6601 v8::Handle<Value> value; 6602 6603 value = v8_compile("var p = 'as' + 'df';")->Run(); 6604 value = v8_compile("obj[p];")->Run(); 6605 6606 context1->Exit(); 6607 context0->Exit(); 6608 context1.Dispose(); 6609 context0.Dispose(); 6610} 6611 6612 6613static v8::Handle<Value> AccessControlNamedGetter( 6614 Local<String>, const AccessorInfo&) { 6615 return v8::Integer::New(42); 6616} 6617 6618 6619static v8::Handle<Value> AccessControlNamedSetter( 6620 Local<String>, Local<Value> value, const AccessorInfo&) { 6621 return value; 6622} 6623 6624 6625static v8::Handle<Value> AccessControlIndexedGetter( 6626 uint32_t index, 6627 const AccessorInfo& info) { 6628 return v8_num(42); 6629} 6630 6631 6632static v8::Handle<Value> AccessControlIndexedSetter( 6633 uint32_t, Local<Value> value, const AccessorInfo&) { 6634 return value; 6635} 6636 6637 6638THREADED_TEST(AccessControlInterceptorIC) { 6639 named_access_count = 0; 6640 indexed_access_count = 0; 6641 6642 v8::HandleScope handle_scope; 6643 6644 // Create an environment. 6645 v8::Persistent<Context> context0 = Context::New(); 6646 context0->Enter(); 6647 6648 // Create an object that requires access-check functions to be 6649 // called for cross-domain access. The object also has interceptors 6650 // interceptor. 6651 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(); 6652 object_template->SetAccessCheckCallbacks(NamedAccessCounter, 6653 IndexedAccessCounter); 6654 object_template->SetNamedPropertyHandler(AccessControlNamedGetter, 6655 AccessControlNamedSetter); 6656 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter, 6657 AccessControlIndexedSetter); 6658 Local<v8::Object> object = object_template->NewInstance(); 6659 6660 v8::HandleScope scope1; 6661 6662 // Create another environment. 6663 v8::Persistent<Context> context1 = Context::New(); 6664 context1->Enter(); 6665 6666 // Make easy access to the object from the other environment. 6667 v8::Handle<v8::Object> global1 = context1->Global(); 6668 global1->Set(v8_str("obj"), object); 6669 6670 v8::Handle<Value> value; 6671 6672 // Check that the named access-control function is called every time 6673 // eventhough there is an interceptor on the object. 6674 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run(); 6675 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;" 6676 "obj.x")->Run(); 6677 CHECK(value->IsNumber()); 6678 CHECK_EQ(42, value->Int32Value()); 6679 CHECK_EQ(21, named_access_count); 6680 6681 value = v8_compile("var p = 'x';")->Run(); 6682 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run(); 6683 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];" 6684 "obj[p]")->Run(); 6685 CHECK(value->IsNumber()); 6686 CHECK_EQ(42, value->Int32Value()); 6687 CHECK_EQ(42, named_access_count); 6688 6689 // Check that the indexed access-control function is called every 6690 // time eventhough there is an interceptor on the object. 6691 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run(); 6692 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];" 6693 "obj[0]")->Run(); 6694 CHECK(value->IsNumber()); 6695 CHECK_EQ(42, value->Int32Value()); 6696 CHECK_EQ(21, indexed_access_count); 6697 6698 context1->Exit(); 6699 context0->Exit(); 6700 context1.Dispose(); 6701 context0.Dispose(); 6702} 6703 6704 6705THREADED_TEST(Version) { 6706 v8::V8::GetVersion(); 6707} 6708 6709 6710static v8::Handle<Value> InstanceFunctionCallback(const v8::Arguments& args) { 6711 ApiTestFuzzer::Fuzz(); 6712 return v8_num(12); 6713} 6714 6715 6716THREADED_TEST(InstanceProperties) { 6717 v8::HandleScope handle_scope; 6718 LocalContext context; 6719 6720 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 6721 Local<ObjectTemplate> instance = t->InstanceTemplate(); 6722 6723 instance->Set(v8_str("x"), v8_num(42)); 6724 instance->Set(v8_str("f"), 6725 v8::FunctionTemplate::New(InstanceFunctionCallback)); 6726 6727 Local<Value> o = t->GetFunction()->NewInstance(); 6728 6729 context->Global()->Set(v8_str("i"), o); 6730 Local<Value> value = Script::Compile(v8_str("i.x"))->Run(); 6731 CHECK_EQ(42, value->Int32Value()); 6732 6733 value = Script::Compile(v8_str("i.f()"))->Run(); 6734 CHECK_EQ(12, value->Int32Value()); 6735} 6736 6737 6738static v8::Handle<Value> 6739GlobalObjectInstancePropertiesGet(Local<String> key, const AccessorInfo&) { 6740 ApiTestFuzzer::Fuzz(); 6741 return v8::Handle<Value>(); 6742} 6743 6744 6745THREADED_TEST(GlobalObjectInstanceProperties) { 6746 v8::HandleScope handle_scope; 6747 6748 Local<Value> global_object; 6749 6750 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 6751 t->InstanceTemplate()->SetNamedPropertyHandler( 6752 GlobalObjectInstancePropertiesGet); 6753 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 6754 instance_template->Set(v8_str("x"), v8_num(42)); 6755 instance_template->Set(v8_str("f"), 6756 v8::FunctionTemplate::New(InstanceFunctionCallback)); 6757 6758 // The script to check how Crankshaft compiles missing global function 6759 // invocations. function g is not defined and should throw on call. 6760 const char* script = 6761 "function wrapper(call) {" 6762 " var x = 0, y = 1;" 6763 " for (var i = 0; i < 1000; i++) {" 6764 " x += i * 100;" 6765 " y += i * 100;" 6766 " }" 6767 " if (call) g();" 6768 "}" 6769 "for (var i = 0; i < 17; i++) wrapper(false);" 6770 "var thrown = 0;" 6771 "try { wrapper(true); } catch (e) { thrown = 1; };" 6772 "thrown"; 6773 6774 { 6775 LocalContext env(NULL, instance_template); 6776 // Hold on to the global object so it can be used again in another 6777 // environment initialization. 6778 global_object = env->Global(); 6779 6780 Local<Value> value = Script::Compile(v8_str("x"))->Run(); 6781 CHECK_EQ(42, value->Int32Value()); 6782 value = Script::Compile(v8_str("f()"))->Run(); 6783 CHECK_EQ(12, value->Int32Value()); 6784 value = Script::Compile(v8_str(script))->Run(); 6785 CHECK_EQ(1, value->Int32Value()); 6786 } 6787 6788 { 6789 // Create new environment reusing the global object. 6790 LocalContext env(NULL, instance_template, global_object); 6791 Local<Value> value = Script::Compile(v8_str("x"))->Run(); 6792 CHECK_EQ(42, value->Int32Value()); 6793 value = Script::Compile(v8_str("f()"))->Run(); 6794 CHECK_EQ(12, value->Int32Value()); 6795 value = Script::Compile(v8_str(script))->Run(); 6796 CHECK_EQ(1, value->Int32Value()); 6797 } 6798} 6799 6800 6801THREADED_TEST(CallKnownGlobalReceiver) { 6802 v8::HandleScope handle_scope; 6803 6804 Local<Value> global_object; 6805 6806 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 6807 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 6808 6809 // The script to check that we leave global object not 6810 // global object proxy on stack when we deoptimize from inside 6811 // arguments evaluation. 6812 // To provoke error we need to both force deoptimization 6813 // from arguments evaluation and to force CallIC to take 6814 // CallIC_Miss code path that can't cope with global proxy. 6815 const char* script = 6816 "function bar(x, y) { try { } finally { } }" 6817 "function baz(x) { try { } finally { } }" 6818 "function bom(x) { try { } finally { } }" 6819 "function foo(x) { bar([x], bom(2)); }" 6820 "for (var i = 0; i < 10000; i++) foo(1);" 6821 "foo"; 6822 6823 Local<Value> foo; 6824 { 6825 LocalContext env(NULL, instance_template); 6826 // Hold on to the global object so it can be used again in another 6827 // environment initialization. 6828 global_object = env->Global(); 6829 foo = Script::Compile(v8_str(script))->Run(); 6830 } 6831 6832 { 6833 // Create new environment reusing the global object. 6834 LocalContext env(NULL, instance_template, global_object); 6835 env->Global()->Set(v8_str("foo"), foo); 6836 Local<Value> value = Script::Compile(v8_str("foo()"))->Run(); 6837 } 6838} 6839 6840 6841static v8::Handle<Value> ShadowFunctionCallback(const v8::Arguments& args) { 6842 ApiTestFuzzer::Fuzz(); 6843 return v8_num(42); 6844} 6845 6846 6847static int shadow_y; 6848static int shadow_y_setter_call_count; 6849static int shadow_y_getter_call_count; 6850 6851 6852static void ShadowYSetter(Local<String>, Local<Value>, const AccessorInfo&) { 6853 shadow_y_setter_call_count++; 6854 shadow_y = 42; 6855} 6856 6857 6858static v8::Handle<Value> ShadowYGetter(Local<String> name, 6859 const AccessorInfo& info) { 6860 ApiTestFuzzer::Fuzz(); 6861 shadow_y_getter_call_count++; 6862 return v8_num(shadow_y); 6863} 6864 6865 6866static v8::Handle<Value> ShadowIndexedGet(uint32_t index, 6867 const AccessorInfo& info) { 6868 return v8::Handle<Value>(); 6869} 6870 6871 6872static v8::Handle<Value> ShadowNamedGet(Local<String> key, 6873 const AccessorInfo&) { 6874 return v8::Handle<Value>(); 6875} 6876 6877 6878THREADED_TEST(ShadowObject) { 6879 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0; 6880 v8::HandleScope handle_scope; 6881 6882 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(); 6883 LocalContext context(NULL, global_template); 6884 6885 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 6886 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet); 6887 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet); 6888 Local<ObjectTemplate> proto = t->PrototypeTemplate(); 6889 Local<ObjectTemplate> instance = t->InstanceTemplate(); 6890 6891 // Only allow calls of f on instances of t. 6892 Local<v8::Signature> signature = v8::Signature::New(t); 6893 proto->Set(v8_str("f"), 6894 v8::FunctionTemplate::New(ShadowFunctionCallback, 6895 Local<Value>(), 6896 signature)); 6897 proto->Set(v8_str("x"), v8_num(12)); 6898 6899 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter); 6900 6901 Local<Value> o = t->GetFunction()->NewInstance(); 6902 context->Global()->Set(v8_str("__proto__"), o); 6903 6904 Local<Value> value = 6905 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run(); 6906 CHECK(value->IsBoolean()); 6907 CHECK(!value->BooleanValue()); 6908 6909 value = Script::Compile(v8_str("x"))->Run(); 6910 CHECK_EQ(12, value->Int32Value()); 6911 6912 value = Script::Compile(v8_str("f()"))->Run(); 6913 CHECK_EQ(42, value->Int32Value()); 6914 6915 Script::Compile(v8_str("y = 42"))->Run(); 6916 CHECK_EQ(1, shadow_y_setter_call_count); 6917 value = Script::Compile(v8_str("y"))->Run(); 6918 CHECK_EQ(1, shadow_y_getter_call_count); 6919 CHECK_EQ(42, value->Int32Value()); 6920} 6921 6922 6923THREADED_TEST(HiddenPrototype) { 6924 v8::HandleScope handle_scope; 6925 LocalContext context; 6926 6927 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(); 6928 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 6929 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(); 6930 t1->SetHiddenPrototype(true); 6931 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 6932 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(); 6933 t2->SetHiddenPrototype(true); 6934 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 6935 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(); 6936 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 6937 6938 Local<v8::Object> o0 = t0->GetFunction()->NewInstance(); 6939 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 6940 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 6941 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 6942 6943 // Setting the prototype on an object skips hidden prototypes. 6944 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 6945 o0->Set(v8_str("__proto__"), o1); 6946 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 6947 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 6948 o0->Set(v8_str("__proto__"), o2); 6949 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 6950 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 6951 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 6952 o0->Set(v8_str("__proto__"), o3); 6953 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 6954 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 6955 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 6956 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value()); 6957 6958 // Getting the prototype of o0 should get the first visible one 6959 // which is o3. Therefore, z should not be defined on the prototype 6960 // object. 6961 Local<Value> proto = o0->Get(v8_str("__proto__")); 6962 CHECK(proto->IsObject()); 6963 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined()); 6964} 6965 6966 6967THREADED_TEST(SetPrototype) { 6968 v8::HandleScope handle_scope; 6969 LocalContext context; 6970 6971 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(); 6972 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 6973 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(); 6974 t1->SetHiddenPrototype(true); 6975 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 6976 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(); 6977 t2->SetHiddenPrototype(true); 6978 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 6979 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(); 6980 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 6981 6982 Local<v8::Object> o0 = t0->GetFunction()->NewInstance(); 6983 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 6984 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 6985 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 6986 6987 // Setting the prototype on an object does not skip hidden prototypes. 6988 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 6989 CHECK(o0->SetPrototype(o1)); 6990 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 6991 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 6992 CHECK(o1->SetPrototype(o2)); 6993 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 6994 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 6995 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 6996 CHECK(o2->SetPrototype(o3)); 6997 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 6998 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 6999 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 7000 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value()); 7001 7002 // Getting the prototype of o0 should get the first visible one 7003 // which is o3. Therefore, z should not be defined on the prototype 7004 // object. 7005 Local<Value> proto = o0->Get(v8_str("__proto__")); 7006 CHECK(proto->IsObject()); 7007 CHECK_EQ(proto.As<v8::Object>(), o3); 7008 7009 // However, Object::GetPrototype ignores hidden prototype. 7010 Local<Value> proto0 = o0->GetPrototype(); 7011 CHECK(proto0->IsObject()); 7012 CHECK_EQ(proto0.As<v8::Object>(), o1); 7013 7014 Local<Value> proto1 = o1->GetPrototype(); 7015 CHECK(proto1->IsObject()); 7016 CHECK_EQ(proto1.As<v8::Object>(), o2); 7017 7018 Local<Value> proto2 = o2->GetPrototype(); 7019 CHECK(proto2->IsObject()); 7020 CHECK_EQ(proto2.As<v8::Object>(), o3); 7021} 7022 7023 7024THREADED_TEST(SetPrototypeProperties) { 7025 v8::HandleScope handle_scope; 7026 LocalContext context; 7027 7028 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(); 7029 t1->SetPrototypeAttributes(v8::DontDelete); 7030 context->Global()->Set(v8_str("func1"), t1->GetFunction()); 7031 CHECK(CompileRun( 7032 "(function() {" 7033 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');" 7034 " return (descriptor['writable'] == true) &&" 7035 " (descriptor['enumerable'] == true) &&" 7036 " (descriptor['configurable'] == false);" 7037 "})()")->BooleanValue()); 7038 7039 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(); 7040 t2->SetPrototypeAttributes(v8::DontEnum); 7041 context->Global()->Set(v8_str("func2"), t2->GetFunction()); 7042 CHECK(CompileRun( 7043 "(function() {" 7044 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');" 7045 " return (descriptor['writable'] == true) &&" 7046 " (descriptor['enumerable'] == false) &&" 7047 " (descriptor['configurable'] == true);" 7048 "})()")->BooleanValue()); 7049 7050 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(); 7051 t3->SetPrototypeAttributes(v8::ReadOnly); 7052 context->Global()->Set(v8_str("func3"), t3->GetFunction()); 7053 CHECK(CompileRun( 7054 "(function() {" 7055 " descriptor = Object.getOwnPropertyDescriptor(func3, 'prototype');" 7056 " return (descriptor['writable'] == false) &&" 7057 " (descriptor['enumerable'] == true) &&" 7058 " (descriptor['configurable'] == true);" 7059 "})()")->BooleanValue()); 7060 7061 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(); 7062 t4->SetPrototypeAttributes(v8::ReadOnly | v8::DontEnum | v8::DontDelete); 7063 context->Global()->Set(v8_str("func4"), t4->GetFunction()); 7064 CHECK(CompileRun( 7065 "(function() {" 7066 " descriptor = Object.getOwnPropertyDescriptor(func4, 'prototype');" 7067 " return (descriptor['writable'] == false) &&" 7068 " (descriptor['enumerable'] == false) &&" 7069 " (descriptor['configurable'] == false);" 7070 "})()")->BooleanValue()); 7071} 7072 7073 7074THREADED_TEST(SetPrototypeThrows) { 7075 v8::HandleScope handle_scope; 7076 LocalContext context; 7077 7078 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 7079 7080 Local<v8::Object> o0 = t->GetFunction()->NewInstance(); 7081 Local<v8::Object> o1 = t->GetFunction()->NewInstance(); 7082 7083 CHECK(o0->SetPrototype(o1)); 7084 // If setting the prototype leads to the cycle, SetPrototype should 7085 // return false and keep VM in sane state. 7086 v8::TryCatch try_catch; 7087 CHECK(!o1->SetPrototype(o0)); 7088 CHECK(!try_catch.HasCaught()); 7089 ASSERT(!i::Isolate::Current()->has_pending_exception()); 7090 7091 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value()); 7092} 7093 7094 7095THREADED_TEST(GetterSetterExceptions) { 7096 v8::HandleScope handle_scope; 7097 LocalContext context; 7098 CompileRun( 7099 "function Foo() { };" 7100 "function Throw() { throw 5; };" 7101 "var x = { };" 7102 "x.__defineSetter__('set', Throw);" 7103 "x.__defineGetter__('get', Throw);"); 7104 Local<v8::Object> x = 7105 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x"))); 7106 v8::TryCatch try_catch; 7107 x->Set(v8_str("set"), v8::Integer::New(8)); 7108 x->Get(v8_str("get")); 7109 x->Set(v8_str("set"), v8::Integer::New(8)); 7110 x->Get(v8_str("get")); 7111 x->Set(v8_str("set"), v8::Integer::New(8)); 7112 x->Get(v8_str("get")); 7113 x->Set(v8_str("set"), v8::Integer::New(8)); 7114 x->Get(v8_str("get")); 7115} 7116 7117 7118THREADED_TEST(Constructor) { 7119 v8::HandleScope handle_scope; 7120 LocalContext context; 7121 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 7122 templ->SetClassName(v8_str("Fun")); 7123 Local<Function> cons = templ->GetFunction(); 7124 context->Global()->Set(v8_str("Fun"), cons); 7125 Local<v8::Object> inst = cons->NewInstance(); 7126 i::Handle<i::JSObject> obj = v8::Utils::OpenHandle(*inst); 7127 Local<Value> value = CompileRun("(new Fun()).constructor === Fun"); 7128 CHECK(value->BooleanValue()); 7129} 7130 7131 7132static Handle<Value> ConstructorCallback(const Arguments& args) { 7133 ApiTestFuzzer::Fuzz(); 7134 Local<Object> This; 7135 7136 if (args.IsConstructCall()) { 7137 Local<Object> Holder = args.Holder(); 7138 This = Object::New(); 7139 Local<Value> proto = Holder->GetPrototype(); 7140 if (proto->IsObject()) { 7141 This->SetPrototype(proto); 7142 } 7143 } else { 7144 This = args.This(); 7145 } 7146 7147 This->Set(v8_str("a"), args[0]); 7148 return This; 7149} 7150 7151 7152static Handle<Value> FakeConstructorCallback(const Arguments& args) { 7153 ApiTestFuzzer::Fuzz(); 7154 return args[0]; 7155} 7156 7157 7158THREADED_TEST(ConstructorForObject) { 7159 v8::HandleScope handle_scope; 7160 LocalContext context; 7161 7162 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 7163 instance_template->SetCallAsFunctionHandler(ConstructorCallback); 7164 Local<Object> instance = instance_template->NewInstance(); 7165 context->Global()->Set(v8_str("obj"), instance); 7166 v8::TryCatch try_catch; 7167 Local<Value> value; 7168 CHECK(!try_catch.HasCaught()); 7169 7170 // Call the Object's constructor with a 32-bit signed integer. 7171 value = CompileRun("(function() { var o = new obj(28); return o.a; })()"); 7172 CHECK(!try_catch.HasCaught()); 7173 CHECK(value->IsInt32()); 7174 CHECK_EQ(28, value->Int32Value()); 7175 7176 Local<Value> args1[] = { v8_num(28) }; 7177 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1); 7178 CHECK(value_obj1->IsObject()); 7179 Local<Object> object1 = Local<Object>::Cast(value_obj1); 7180 value = object1->Get(v8_str("a")); 7181 CHECK(value->IsInt32()); 7182 CHECK(!try_catch.HasCaught()); 7183 CHECK_EQ(28, value->Int32Value()); 7184 7185 // Call the Object's constructor with a String. 7186 value = CompileRun( 7187 "(function() { var o = new obj('tipli'); return o.a; })()"); 7188 CHECK(!try_catch.HasCaught()); 7189 CHECK(value->IsString()); 7190 String::AsciiValue string_value1(value->ToString()); 7191 CHECK_EQ("tipli", *string_value1); 7192 7193 Local<Value> args2[] = { v8_str("tipli") }; 7194 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2); 7195 CHECK(value_obj2->IsObject()); 7196 Local<Object> object2 = Local<Object>::Cast(value_obj2); 7197 value = object2->Get(v8_str("a")); 7198 CHECK(!try_catch.HasCaught()); 7199 CHECK(value->IsString()); 7200 String::AsciiValue string_value2(value->ToString()); 7201 CHECK_EQ("tipli", *string_value2); 7202 7203 // Call the Object's constructor with a Boolean. 7204 value = CompileRun("(function() { var o = new obj(true); return o.a; })()"); 7205 CHECK(!try_catch.HasCaught()); 7206 CHECK(value->IsBoolean()); 7207 CHECK_EQ(true, value->BooleanValue()); 7208 7209 Handle<Value> args3[] = { v8::Boolean::New(true) }; 7210 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3); 7211 CHECK(value_obj3->IsObject()); 7212 Local<Object> object3 = Local<Object>::Cast(value_obj3); 7213 value = object3->Get(v8_str("a")); 7214 CHECK(!try_catch.HasCaught()); 7215 CHECK(value->IsBoolean()); 7216 CHECK_EQ(true, value->BooleanValue()); 7217 7218 // Call the Object's constructor with undefined. 7219 Handle<Value> args4[] = { v8::Undefined() }; 7220 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4); 7221 CHECK(value_obj4->IsObject()); 7222 Local<Object> object4 = Local<Object>::Cast(value_obj4); 7223 value = object4->Get(v8_str("a")); 7224 CHECK(!try_catch.HasCaught()); 7225 CHECK(value->IsUndefined()); 7226 7227 // Call the Object's constructor with null. 7228 Handle<Value> args5[] = { v8::Null() }; 7229 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5); 7230 CHECK(value_obj5->IsObject()); 7231 Local<Object> object5 = Local<Object>::Cast(value_obj5); 7232 value = object5->Get(v8_str("a")); 7233 CHECK(!try_catch.HasCaught()); 7234 CHECK(value->IsNull()); 7235 } 7236 7237 // Check exception handling when there is no constructor set for the Object. 7238 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 7239 Local<Object> instance = instance_template->NewInstance(); 7240 context->Global()->Set(v8_str("obj2"), instance); 7241 v8::TryCatch try_catch; 7242 Local<Value> value; 7243 CHECK(!try_catch.HasCaught()); 7244 7245 value = CompileRun("new obj2(28)"); 7246 CHECK(try_catch.HasCaught()); 7247 String::AsciiValue exception_value1(try_catch.Exception()); 7248 CHECK_EQ("TypeError: object is not a function", *exception_value1); 7249 try_catch.Reset(); 7250 7251 Local<Value> args[] = { v8_num(29) }; 7252 value = instance->CallAsConstructor(1, args); 7253 CHECK(try_catch.HasCaught()); 7254 String::AsciiValue exception_value2(try_catch.Exception()); 7255 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2); 7256 try_catch.Reset(); 7257 } 7258 7259 // Check the case when constructor throws exception. 7260 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 7261 instance_template->SetCallAsFunctionHandler(ThrowValue); 7262 Local<Object> instance = instance_template->NewInstance(); 7263 context->Global()->Set(v8_str("obj3"), instance); 7264 v8::TryCatch try_catch; 7265 Local<Value> value; 7266 CHECK(!try_catch.HasCaught()); 7267 7268 value = CompileRun("new obj3(22)"); 7269 CHECK(try_catch.HasCaught()); 7270 String::AsciiValue exception_value1(try_catch.Exception()); 7271 CHECK_EQ("22", *exception_value1); 7272 try_catch.Reset(); 7273 7274 Local<Value> args[] = { v8_num(23) }; 7275 value = instance->CallAsConstructor(1, args); 7276 CHECK(try_catch.HasCaught()); 7277 String::AsciiValue exception_value2(try_catch.Exception()); 7278 CHECK_EQ("23", *exception_value2); 7279 try_catch.Reset(); 7280 } 7281 7282 // Check whether constructor returns with an object or non-object. 7283 { Local<FunctionTemplate> function_template = 7284 FunctionTemplate::New(FakeConstructorCallback); 7285 Local<Function> function = function_template->GetFunction(); 7286 Local<Object> instance1 = function; 7287 context->Global()->Set(v8_str("obj4"), instance1); 7288 v8::TryCatch try_catch; 7289 Local<Value> value; 7290 CHECK(!try_catch.HasCaught()); 7291 7292 CHECK(instance1->IsObject()); 7293 CHECK(instance1->IsFunction()); 7294 7295 value = CompileRun("new obj4(28)"); 7296 CHECK(!try_catch.HasCaught()); 7297 CHECK(value->IsObject()); 7298 7299 Local<Value> args1[] = { v8_num(28) }; 7300 value = instance1->CallAsConstructor(1, args1); 7301 CHECK(!try_catch.HasCaught()); 7302 CHECK(value->IsObject()); 7303 7304 Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 7305 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback); 7306 Local<Object> instance2 = instance_template->NewInstance(); 7307 context->Global()->Set(v8_str("obj5"), instance2); 7308 CHECK(!try_catch.HasCaught()); 7309 7310 CHECK(instance2->IsObject()); 7311 CHECK(!instance2->IsFunction()); 7312 7313 value = CompileRun("new obj5(28)"); 7314 CHECK(!try_catch.HasCaught()); 7315 CHECK(!value->IsObject()); 7316 7317 Local<Value> args2[] = { v8_num(28) }; 7318 value = instance2->CallAsConstructor(1, args2); 7319 CHECK(!try_catch.HasCaught()); 7320 CHECK(!value->IsObject()); 7321 } 7322} 7323 7324 7325THREADED_TEST(FunctionDescriptorException) { 7326 v8::HandleScope handle_scope; 7327 LocalContext context; 7328 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 7329 templ->SetClassName(v8_str("Fun")); 7330 Local<Function> cons = templ->GetFunction(); 7331 context->Global()->Set(v8_str("Fun"), cons); 7332 Local<Value> value = CompileRun( 7333 "function test() {" 7334 " try {" 7335 " (new Fun()).blah()" 7336 " } catch (e) {" 7337 " var str = String(e);" 7338 " if (str.indexOf('TypeError') == -1) return 1;" 7339 " if (str.indexOf('[object Fun]') != -1) return 2;" 7340 " if (str.indexOf('#<Fun>') == -1) return 3;" 7341 " return 0;" 7342 " }" 7343 " return 4;" 7344 "}" 7345 "test();"); 7346 CHECK_EQ(0, value->Int32Value()); 7347} 7348 7349 7350THREADED_TEST(EvalAliasedDynamic) { 7351 v8::HandleScope scope; 7352 LocalContext current; 7353 7354 // Tests where aliased eval can only be resolved dynamically. 7355 Local<Script> script = 7356 Script::Compile(v8_str("function f(x) { " 7357 " var foo = 2;" 7358 " with (x) { return eval('foo'); }" 7359 "}" 7360 "foo = 0;" 7361 "result1 = f(new Object());" 7362 "result2 = f(this);" 7363 "var x = new Object();" 7364 "x.eval = function(x) { return 1; };" 7365 "result3 = f(x);")); 7366 script->Run(); 7367 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value()); 7368 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value()); 7369 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value()); 7370 7371 v8::TryCatch try_catch; 7372 script = 7373 Script::Compile(v8_str("function f(x) { " 7374 " var bar = 2;" 7375 " with (x) { return eval('bar'); }" 7376 "}" 7377 "f(this)")); 7378 script->Run(); 7379 CHECK(try_catch.HasCaught()); 7380 try_catch.Reset(); 7381} 7382 7383 7384THREADED_TEST(CrossEval) { 7385 v8::HandleScope scope; 7386 LocalContext other; 7387 LocalContext current; 7388 7389 Local<String> token = v8_str("<security token>"); 7390 other->SetSecurityToken(token); 7391 current->SetSecurityToken(token); 7392 7393 // Setup reference from current to other. 7394 current->Global()->Set(v8_str("other"), other->Global()); 7395 7396 // Check that new variables are introduced in other context. 7397 Local<Script> script = 7398 Script::Compile(v8_str("other.eval('var foo = 1234')")); 7399 script->Run(); 7400 Local<Value> foo = other->Global()->Get(v8_str("foo")); 7401 CHECK_EQ(1234, foo->Int32Value()); 7402 CHECK(!current->Global()->Has(v8_str("foo"))); 7403 7404 // Check that writing to non-existing properties introduces them in 7405 // the other context. 7406 script = 7407 Script::Compile(v8_str("other.eval('na = 1234')")); 7408 script->Run(); 7409 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value()); 7410 CHECK(!current->Global()->Has(v8_str("na"))); 7411 7412 // Check that global variables in current context are not visible in other 7413 // context. 7414 v8::TryCatch try_catch; 7415 script = 7416 Script::Compile(v8_str("var bar = 42; other.eval('bar');")); 7417 Local<Value> result = script->Run(); 7418 CHECK(try_catch.HasCaught()); 7419 try_catch.Reset(); 7420 7421 // Check that local variables in current context are not visible in other 7422 // context. 7423 script = 7424 Script::Compile(v8_str("(function() { " 7425 " var baz = 87;" 7426 " return other.eval('baz');" 7427 "})();")); 7428 result = script->Run(); 7429 CHECK(try_catch.HasCaught()); 7430 try_catch.Reset(); 7431 7432 // Check that global variables in the other environment are visible 7433 // when evaluting code. 7434 other->Global()->Set(v8_str("bis"), v8_num(1234)); 7435 script = Script::Compile(v8_str("other.eval('bis')")); 7436 CHECK_EQ(1234, script->Run()->Int32Value()); 7437 CHECK(!try_catch.HasCaught()); 7438 7439 // Check that the 'this' pointer points to the global object evaluating 7440 // code. 7441 other->Global()->Set(v8_str("t"), other->Global()); 7442 script = Script::Compile(v8_str("other.eval('this == t')")); 7443 result = script->Run(); 7444 CHECK(result->IsTrue()); 7445 CHECK(!try_catch.HasCaught()); 7446 7447 // Check that variables introduced in with-statement are not visible in 7448 // other context. 7449 script = 7450 Script::Compile(v8_str("with({x:2}){other.eval('x')}")); 7451 result = script->Run(); 7452 CHECK(try_catch.HasCaught()); 7453 try_catch.Reset(); 7454 7455 // Check that you cannot use 'eval.call' with another object than the 7456 // current global object. 7457 script = 7458 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')")); 7459 result = script->Run(); 7460 CHECK(try_catch.HasCaught()); 7461} 7462 7463 7464// Test that calling eval in a context which has been detached from 7465// its global throws an exception. This behavior is consistent with 7466// other JavaScript implementations. 7467THREADED_TEST(EvalInDetachedGlobal) { 7468 v8::HandleScope scope; 7469 7470 v8::Persistent<Context> context0 = Context::New(); 7471 v8::Persistent<Context> context1 = Context::New(); 7472 7473 // Setup function in context0 that uses eval from context0. 7474 context0->Enter(); 7475 v8::Handle<v8::Value> fun = 7476 CompileRun("var x = 42;" 7477 "(function() {" 7478 " var e = eval;" 7479 " return function(s) { return e(s); }" 7480 "})()"); 7481 context0->Exit(); 7482 7483 // Put the function into context1 and call it before and after 7484 // detaching the global. Before detaching, the call succeeds and 7485 // after detaching and exception is thrown. 7486 context1->Enter(); 7487 context1->Global()->Set(v8_str("fun"), fun); 7488 v8::Handle<v8::Value> x_value = CompileRun("fun('x')"); 7489 CHECK_EQ(42, x_value->Int32Value()); 7490 context0->DetachGlobal(); 7491 v8::TryCatch catcher; 7492 x_value = CompileRun("fun('x')"); 7493 CHECK(x_value.IsEmpty()); 7494 CHECK(catcher.HasCaught()); 7495 context1->Exit(); 7496 7497 context1.Dispose(); 7498 context0.Dispose(); 7499} 7500 7501 7502THREADED_TEST(CrossLazyLoad) { 7503 v8::HandleScope scope; 7504 LocalContext other; 7505 LocalContext current; 7506 7507 Local<String> token = v8_str("<security token>"); 7508 other->SetSecurityToken(token); 7509 current->SetSecurityToken(token); 7510 7511 // Setup reference from current to other. 7512 current->Global()->Set(v8_str("other"), other->Global()); 7513 7514 // Trigger lazy loading in other context. 7515 Local<Script> script = 7516 Script::Compile(v8_str("other.eval('new Date(42)')")); 7517 Local<Value> value = script->Run(); 7518 CHECK_EQ(42.0, value->NumberValue()); 7519} 7520 7521 7522static v8::Handle<Value> call_as_function(const v8::Arguments& args) { 7523 ApiTestFuzzer::Fuzz(); 7524 if (args.IsConstructCall()) { 7525 if (args[0]->IsInt32()) { 7526 return v8_num(-args[0]->Int32Value()); 7527 } 7528 } 7529 7530 return args[0]; 7531} 7532 7533 7534// Test that a call handler can be set for objects which will allow 7535// non-function objects created through the API to be called as 7536// functions. 7537THREADED_TEST(CallAsFunction) { 7538 v8::HandleScope scope; 7539 LocalContext context; 7540 7541 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 7542 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 7543 instance_template->SetCallAsFunctionHandler(call_as_function); 7544 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 7545 context->Global()->Set(v8_str("obj"), instance); 7546 v8::TryCatch try_catch; 7547 Local<Value> value; 7548 CHECK(!try_catch.HasCaught()); 7549 7550 value = CompileRun("obj(42)"); 7551 CHECK(!try_catch.HasCaught()); 7552 CHECK_EQ(42, value->Int32Value()); 7553 7554 value = CompileRun("(function(o){return o(49)})(obj)"); 7555 CHECK(!try_catch.HasCaught()); 7556 CHECK_EQ(49, value->Int32Value()); 7557 7558 // test special case of call as function 7559 value = CompileRun("[obj]['0'](45)"); 7560 CHECK(!try_catch.HasCaught()); 7561 CHECK_EQ(45, value->Int32Value()); 7562 7563 value = CompileRun("obj.call = Function.prototype.call;" 7564 "obj.call(null, 87)"); 7565 CHECK(!try_catch.HasCaught()); 7566 CHECK_EQ(87, value->Int32Value()); 7567 7568 // Regression tests for bug #1116356: Calling call through call/apply 7569 // must work for non-function receivers. 7570 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; 7571 value = CompileRun(apply_99); 7572 CHECK(!try_catch.HasCaught()); 7573 CHECK_EQ(99, value->Int32Value()); 7574 7575 const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; 7576 value = CompileRun(call_17); 7577 CHECK(!try_catch.HasCaught()); 7578 CHECK_EQ(17, value->Int32Value()); 7579 7580 // Check that the call-as-function handler can be called through 7581 // new. 7582 value = CompileRun("new obj(43)"); 7583 CHECK(!try_catch.HasCaught()); 7584 CHECK_EQ(-43, value->Int32Value()); 7585 7586 // Check that the call-as-function handler can be called through 7587 // the API. 7588 v8::Handle<Value> args[] = { v8_num(28) }; 7589 value = instance->CallAsFunction(instance, 1, args); 7590 CHECK(!try_catch.HasCaught()); 7591 CHECK_EQ(28, value->Int32Value()); 7592 } 7593 7594 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 7595 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 7596 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 7597 context->Global()->Set(v8_str("obj2"), instance); 7598 v8::TryCatch try_catch; 7599 Local<Value> value; 7600 CHECK(!try_catch.HasCaught()); 7601 7602 // Call an object without call-as-function handler through the JS 7603 value = CompileRun("obj2(28)"); 7604 CHECK(value.IsEmpty()); 7605 CHECK(try_catch.HasCaught()); 7606 String::AsciiValue exception_value1(try_catch.Exception()); 7607 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function", 7608 *exception_value1); 7609 try_catch.Reset(); 7610 7611 // Call an object without call-as-function handler through the API 7612 value = CompileRun("obj2(28)"); 7613 v8::Handle<Value> args[] = { v8_num(28) }; 7614 value = instance->CallAsFunction(instance, 1, args); 7615 CHECK(value.IsEmpty()); 7616 CHECK(try_catch.HasCaught()); 7617 String::AsciiValue exception_value2(try_catch.Exception()); 7618 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2); 7619 try_catch.Reset(); 7620 } 7621 7622 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 7623 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 7624 instance_template->SetCallAsFunctionHandler(ThrowValue); 7625 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 7626 context->Global()->Set(v8_str("obj3"), instance); 7627 v8::TryCatch try_catch; 7628 Local<Value> value; 7629 CHECK(!try_catch.HasCaught()); 7630 7631 // Catch the exception which is thrown by call-as-function handler 7632 value = CompileRun("obj3(22)"); 7633 CHECK(try_catch.HasCaught()); 7634 String::AsciiValue exception_value1(try_catch.Exception()); 7635 CHECK_EQ("22", *exception_value1); 7636 try_catch.Reset(); 7637 7638 v8::Handle<Value> args[] = { v8_num(23) }; 7639 value = instance->CallAsFunction(instance, 1, args); 7640 CHECK(try_catch.HasCaught()); 7641 String::AsciiValue exception_value2(try_catch.Exception()); 7642 CHECK_EQ("23", *exception_value2); 7643 try_catch.Reset(); 7644 } 7645} 7646 7647 7648// Check whether a non-function object is callable. 7649THREADED_TEST(CallableObject) { 7650 v8::HandleScope scope; 7651 LocalContext context; 7652 7653 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 7654 instance_template->SetCallAsFunctionHandler(call_as_function); 7655 Local<Object> instance = instance_template->NewInstance(); 7656 v8::TryCatch try_catch; 7657 7658 CHECK(instance->IsCallable()); 7659 CHECK(!try_catch.HasCaught()); 7660 } 7661 7662 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 7663 Local<Object> instance = instance_template->NewInstance(); 7664 v8::TryCatch try_catch; 7665 7666 CHECK(!instance->IsCallable()); 7667 CHECK(!try_catch.HasCaught()); 7668 } 7669 7670 { Local<FunctionTemplate> function_template = 7671 FunctionTemplate::New(call_as_function); 7672 Local<Function> function = function_template->GetFunction(); 7673 Local<Object> instance = function; 7674 v8::TryCatch try_catch; 7675 7676 CHECK(instance->IsCallable()); 7677 CHECK(!try_catch.HasCaught()); 7678 } 7679 7680 { Local<FunctionTemplate> function_template = FunctionTemplate::New(); 7681 Local<Function> function = function_template->GetFunction(); 7682 Local<Object> instance = function; 7683 v8::TryCatch try_catch; 7684 7685 CHECK(instance->IsCallable()); 7686 CHECK(!try_catch.HasCaught()); 7687 } 7688} 7689 7690 7691static int CountHandles() { 7692 return v8::HandleScope::NumberOfHandles(); 7693} 7694 7695 7696static int Recurse(int depth, int iterations) { 7697 v8::HandleScope scope; 7698 if (depth == 0) return CountHandles(); 7699 for (int i = 0; i < iterations; i++) { 7700 Local<v8::Number> n = v8::Integer::New(42); 7701 } 7702 return Recurse(depth - 1, iterations); 7703} 7704 7705 7706THREADED_TEST(HandleIteration) { 7707 static const int kIterations = 500; 7708 static const int kNesting = 200; 7709 CHECK_EQ(0, CountHandles()); 7710 { 7711 v8::HandleScope scope1; 7712 CHECK_EQ(0, CountHandles()); 7713 for (int i = 0; i < kIterations; i++) { 7714 Local<v8::Number> n = v8::Integer::New(42); 7715 CHECK_EQ(i + 1, CountHandles()); 7716 } 7717 7718 CHECK_EQ(kIterations, CountHandles()); 7719 { 7720 v8::HandleScope scope2; 7721 for (int j = 0; j < kIterations; j++) { 7722 Local<v8::Number> n = v8::Integer::New(42); 7723 CHECK_EQ(j + 1 + kIterations, CountHandles()); 7724 } 7725 } 7726 CHECK_EQ(kIterations, CountHandles()); 7727 } 7728 CHECK_EQ(0, CountHandles()); 7729 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations)); 7730} 7731 7732 7733static v8::Handle<Value> InterceptorHasOwnPropertyGetter( 7734 Local<String> name, 7735 const AccessorInfo& info) { 7736 ApiTestFuzzer::Fuzz(); 7737 return v8::Handle<Value>(); 7738} 7739 7740 7741THREADED_TEST(InterceptorHasOwnProperty) { 7742 v8::HandleScope scope; 7743 LocalContext context; 7744 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 7745 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 7746 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter); 7747 Local<Function> function = fun_templ->GetFunction(); 7748 context->Global()->Set(v8_str("constructor"), function); 7749 v8::Handle<Value> value = CompileRun( 7750 "var o = new constructor();" 7751 "o.hasOwnProperty('ostehaps');"); 7752 CHECK_EQ(false, value->BooleanValue()); 7753 value = CompileRun( 7754 "o.ostehaps = 42;" 7755 "o.hasOwnProperty('ostehaps');"); 7756 CHECK_EQ(true, value->BooleanValue()); 7757 value = CompileRun( 7758 "var p = new constructor();" 7759 "p.hasOwnProperty('ostehaps');"); 7760 CHECK_EQ(false, value->BooleanValue()); 7761} 7762 7763 7764static v8::Handle<Value> InterceptorHasOwnPropertyGetterGC( 7765 Local<String> name, 7766 const AccessorInfo& info) { 7767 ApiTestFuzzer::Fuzz(); 7768 HEAP->CollectAllGarbage(false); 7769 return v8::Handle<Value>(); 7770} 7771 7772 7773THREADED_TEST(InterceptorHasOwnPropertyCausingGC) { 7774 v8::HandleScope scope; 7775 LocalContext context; 7776 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 7777 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 7778 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC); 7779 Local<Function> function = fun_templ->GetFunction(); 7780 context->Global()->Set(v8_str("constructor"), function); 7781 // Let's first make some stuff so we can be sure to get a good GC. 7782 CompileRun( 7783 "function makestr(size) {" 7784 " switch (size) {" 7785 " case 1: return 'f';" 7786 " case 2: return 'fo';" 7787 " case 3: return 'foo';" 7788 " }" 7789 " return makestr(size >> 1) + makestr((size + 1) >> 1);" 7790 "}" 7791 "var x = makestr(12345);" 7792 "x = makestr(31415);" 7793 "x = makestr(23456);"); 7794 v8::Handle<Value> value = CompileRun( 7795 "var o = new constructor();" 7796 "o.__proto__ = new String(x);" 7797 "o.hasOwnProperty('ostehaps');"); 7798 CHECK_EQ(false, value->BooleanValue()); 7799} 7800 7801 7802typedef v8::Handle<Value> (*NamedPropertyGetter)(Local<String> property, 7803 const AccessorInfo& info); 7804 7805 7806static void CheckInterceptorLoadIC(NamedPropertyGetter getter, 7807 const char* source, 7808 int expected) { 7809 v8::HandleScope scope; 7810 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 7811 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data")); 7812 LocalContext context; 7813 context->Global()->Set(v8_str("o"), templ->NewInstance()); 7814 v8::Handle<Value> value = CompileRun(source); 7815 CHECK_EQ(expected, value->Int32Value()); 7816} 7817 7818 7819static v8::Handle<Value> InterceptorLoadICGetter(Local<String> name, 7820 const AccessorInfo& info) { 7821 ApiTestFuzzer::Fuzz(); 7822 CHECK_EQ(v8_str("data"), info.Data()); 7823 CHECK_EQ(v8_str("x"), name); 7824 return v8::Integer::New(42); 7825} 7826 7827 7828// This test should hit the load IC for the interceptor case. 7829THREADED_TEST(InterceptorLoadIC) { 7830 CheckInterceptorLoadIC(InterceptorLoadICGetter, 7831 "var result = 0;" 7832 "for (var i = 0; i < 1000; i++) {" 7833 " result = o.x;" 7834 "}", 7835 42); 7836} 7837 7838 7839// Below go several tests which verify that JITing for various 7840// configurations of interceptor and explicit fields works fine 7841// (those cases are special cased to get better performance). 7842 7843static v8::Handle<Value> InterceptorLoadXICGetter(Local<String> name, 7844 const AccessorInfo& info) { 7845 ApiTestFuzzer::Fuzz(); 7846 return v8_str("x")->Equals(name) 7847 ? v8::Integer::New(42) : v8::Handle<v8::Value>(); 7848} 7849 7850 7851THREADED_TEST(InterceptorLoadICWithFieldOnHolder) { 7852 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 7853 "var result = 0;" 7854 "o.y = 239;" 7855 "for (var i = 0; i < 1000; i++) {" 7856 " result = o.y;" 7857 "}", 7858 239); 7859} 7860 7861 7862THREADED_TEST(InterceptorLoadICWithSubstitutedProto) { 7863 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 7864 "var result = 0;" 7865 "o.__proto__ = { 'y': 239 };" 7866 "for (var i = 0; i < 1000; i++) {" 7867 " result = o.y + o.x;" 7868 "}", 7869 239 + 42); 7870} 7871 7872 7873THREADED_TEST(InterceptorLoadICWithPropertyOnProto) { 7874 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 7875 "var result = 0;" 7876 "o.__proto__.y = 239;" 7877 "for (var i = 0; i < 1000; i++) {" 7878 " result = o.y + o.x;" 7879 "}", 7880 239 + 42); 7881} 7882 7883 7884THREADED_TEST(InterceptorLoadICUndefined) { 7885 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 7886 "var result = 0;" 7887 "for (var i = 0; i < 1000; i++) {" 7888 " result = (o.y == undefined) ? 239 : 42;" 7889 "}", 7890 239); 7891} 7892 7893 7894THREADED_TEST(InterceptorLoadICWithOverride) { 7895 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 7896 "fst = new Object(); fst.__proto__ = o;" 7897 "snd = new Object(); snd.__proto__ = fst;" 7898 "var result1 = 0;" 7899 "for (var i = 0; i < 1000; i++) {" 7900 " result1 = snd.x;" 7901 "}" 7902 "fst.x = 239;" 7903 "var result = 0;" 7904 "for (var i = 0; i < 1000; i++) {" 7905 " result = snd.x;" 7906 "}" 7907 "result + result1", 7908 239 + 42); 7909} 7910 7911 7912// Test the case when we stored field into 7913// a stub, but interceptor produced value on its own. 7914THREADED_TEST(InterceptorLoadICFieldNotNeeded) { 7915 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 7916 "proto = new Object();" 7917 "o.__proto__ = proto;" 7918 "proto.x = 239;" 7919 "for (var i = 0; i < 1000; i++) {" 7920 " o.x;" 7921 // Now it should be ICed and keep a reference to x defined on proto 7922 "}" 7923 "var result = 0;" 7924 "for (var i = 0; i < 1000; i++) {" 7925 " result += o.x;" 7926 "}" 7927 "result;", 7928 42 * 1000); 7929} 7930 7931 7932// Test the case when we stored field into 7933// a stub, but it got invalidated later on. 7934THREADED_TEST(InterceptorLoadICInvalidatedField) { 7935 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 7936 "proto1 = new Object();" 7937 "proto2 = new Object();" 7938 "o.__proto__ = proto1;" 7939 "proto1.__proto__ = proto2;" 7940 "proto2.y = 239;" 7941 "for (var i = 0; i < 1000; i++) {" 7942 " o.y;" 7943 // Now it should be ICed and keep a reference to y defined on proto2 7944 "}" 7945 "proto1.y = 42;" 7946 "var result = 0;" 7947 "for (var i = 0; i < 1000; i++) {" 7948 " result += o.y;" 7949 "}" 7950 "result;", 7951 42 * 1000); 7952} 7953 7954 7955static int interceptor_load_not_handled_calls = 0; 7956static v8::Handle<Value> InterceptorLoadNotHandled(Local<String> name, 7957 const AccessorInfo& info) { 7958 ++interceptor_load_not_handled_calls; 7959 return v8::Handle<v8::Value>(); 7960} 7961 7962 7963// Test how post-interceptor lookups are done in the non-cacheable 7964// case: the interceptor should not be invoked during this lookup. 7965THREADED_TEST(InterceptorLoadICPostInterceptor) { 7966 interceptor_load_not_handled_calls = 0; 7967 CheckInterceptorLoadIC(InterceptorLoadNotHandled, 7968 "receiver = new Object();" 7969 "receiver.__proto__ = o;" 7970 "proto = new Object();" 7971 "/* Make proto a slow-case object. */" 7972 "for (var i = 0; i < 1000; i++) {" 7973 " proto[\"xxxxxxxx\" + i] = [];" 7974 "}" 7975 "proto.x = 17;" 7976 "o.__proto__ = proto;" 7977 "var result = 0;" 7978 "for (var i = 0; i < 1000; i++) {" 7979 " result += receiver.x;" 7980 "}" 7981 "result;", 7982 17 * 1000); 7983 CHECK_EQ(1000, interceptor_load_not_handled_calls); 7984} 7985 7986 7987// Test the case when we stored field into 7988// a stub, but it got invalidated later on due to override on 7989// global object which is between interceptor and fields' holders. 7990THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) { 7991 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 7992 "o.__proto__ = this;" // set a global to be a proto of o. 7993 "this.__proto__.y = 239;" 7994 "for (var i = 0; i < 10; i++) {" 7995 " if (o.y != 239) throw 'oops: ' + o.y;" 7996 // Now it should be ICed and keep a reference to y defined on field_holder. 7997 "}" 7998 "this.y = 42;" // Assign on a global. 7999 "var result = 0;" 8000 "for (var i = 0; i < 10; i++) {" 8001 " result += o.y;" 8002 "}" 8003 "result;", 8004 42 * 10); 8005} 8006 8007 8008static void SetOnThis(Local<String> name, 8009 Local<Value> value, 8010 const AccessorInfo& info) { 8011 info.This()->ForceSet(name, value); 8012} 8013 8014 8015THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) { 8016 v8::HandleScope scope; 8017 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8018 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 8019 templ->SetAccessor(v8_str("y"), Return239); 8020 LocalContext context; 8021 context->Global()->Set(v8_str("o"), templ->NewInstance()); 8022 8023 // Check the case when receiver and interceptor's holder 8024 // are the same objects. 8025 v8::Handle<Value> value = CompileRun( 8026 "var result = 0;" 8027 "for (var i = 0; i < 7; i++) {" 8028 " result = o.y;" 8029 "}"); 8030 CHECK_EQ(239, value->Int32Value()); 8031 8032 // Check the case when interceptor's holder is in proto chain 8033 // of receiver. 8034 value = CompileRun( 8035 "r = { __proto__: o };" 8036 "var result = 0;" 8037 "for (var i = 0; i < 7; i++) {" 8038 " result = r.y;" 8039 "}"); 8040 CHECK_EQ(239, value->Int32Value()); 8041} 8042 8043 8044THREADED_TEST(InterceptorLoadICWithCallbackOnProto) { 8045 v8::HandleScope scope; 8046 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 8047 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 8048 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(); 8049 templ_p->SetAccessor(v8_str("y"), Return239); 8050 8051 LocalContext context; 8052 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 8053 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 8054 8055 // Check the case when receiver and interceptor's holder 8056 // are the same objects. 8057 v8::Handle<Value> value = CompileRun( 8058 "o.__proto__ = p;" 8059 "var result = 0;" 8060 "for (var i = 0; i < 7; i++) {" 8061 " result = o.x + o.y;" 8062 "}"); 8063 CHECK_EQ(239 + 42, value->Int32Value()); 8064 8065 // Check the case when interceptor's holder is in proto chain 8066 // of receiver. 8067 value = CompileRun( 8068 "r = { __proto__: o };" 8069 "var result = 0;" 8070 "for (var i = 0; i < 7; i++) {" 8071 " result = r.x + r.y;" 8072 "}"); 8073 CHECK_EQ(239 + 42, value->Int32Value()); 8074} 8075 8076 8077THREADED_TEST(InterceptorLoadICForCallbackWithOverride) { 8078 v8::HandleScope scope; 8079 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8080 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 8081 templ->SetAccessor(v8_str("y"), Return239); 8082 8083 LocalContext context; 8084 context->Global()->Set(v8_str("o"), templ->NewInstance()); 8085 8086 v8::Handle<Value> value = CompileRun( 8087 "fst = new Object(); fst.__proto__ = o;" 8088 "snd = new Object(); snd.__proto__ = fst;" 8089 "var result1 = 0;" 8090 "for (var i = 0; i < 7; i++) {" 8091 " result1 = snd.x;" 8092 "}" 8093 "fst.x = 239;" 8094 "var result = 0;" 8095 "for (var i = 0; i < 7; i++) {" 8096 " result = snd.x;" 8097 "}" 8098 "result + result1"); 8099 CHECK_EQ(239 + 42, value->Int32Value()); 8100} 8101 8102 8103// Test the case when we stored callback into 8104// a stub, but interceptor produced value on its own. 8105THREADED_TEST(InterceptorLoadICCallbackNotNeeded) { 8106 v8::HandleScope scope; 8107 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 8108 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 8109 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(); 8110 templ_p->SetAccessor(v8_str("y"), Return239); 8111 8112 LocalContext context; 8113 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 8114 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 8115 8116 v8::Handle<Value> value = CompileRun( 8117 "o.__proto__ = p;" 8118 "for (var i = 0; i < 7; i++) {" 8119 " o.x;" 8120 // Now it should be ICed and keep a reference to x defined on p 8121 "}" 8122 "var result = 0;" 8123 "for (var i = 0; i < 7; i++) {" 8124 " result += o.x;" 8125 "}" 8126 "result"); 8127 CHECK_EQ(42 * 7, value->Int32Value()); 8128} 8129 8130 8131// Test the case when we stored callback into 8132// a stub, but it got invalidated later on. 8133THREADED_TEST(InterceptorLoadICInvalidatedCallback) { 8134 v8::HandleScope scope; 8135 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 8136 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 8137 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(); 8138 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis); 8139 8140 LocalContext context; 8141 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 8142 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 8143 8144 v8::Handle<Value> value = CompileRun( 8145 "inbetween = new Object();" 8146 "o.__proto__ = inbetween;" 8147 "inbetween.__proto__ = p;" 8148 "for (var i = 0; i < 10; i++) {" 8149 " o.y;" 8150 // Now it should be ICed and keep a reference to y defined on p 8151 "}" 8152 "inbetween.y = 42;" 8153 "var result = 0;" 8154 "for (var i = 0; i < 10; i++) {" 8155 " result += o.y;" 8156 "}" 8157 "result"); 8158 CHECK_EQ(42 * 10, value->Int32Value()); 8159} 8160 8161 8162// Test the case when we stored callback into 8163// a stub, but it got invalidated later on due to override on 8164// global object which is between interceptor and callbacks' holders. 8165THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) { 8166 v8::HandleScope scope; 8167 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 8168 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 8169 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(); 8170 templ_p->SetAccessor(v8_str("y"), Return239, SetOnThis); 8171 8172 LocalContext context; 8173 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 8174 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 8175 8176 v8::Handle<Value> value = CompileRun( 8177 "o.__proto__ = this;" 8178 "this.__proto__ = p;" 8179 "for (var i = 0; i < 10; i++) {" 8180 " if (o.y != 239) throw 'oops: ' + o.y;" 8181 // Now it should be ICed and keep a reference to y defined on p 8182 "}" 8183 "this.y = 42;" 8184 "var result = 0;" 8185 "for (var i = 0; i < 10; i++) {" 8186 " result += o.y;" 8187 "}" 8188 "result"); 8189 CHECK_EQ(42 * 10, value->Int32Value()); 8190} 8191 8192 8193static v8::Handle<Value> InterceptorLoadICGetter0(Local<String> name, 8194 const AccessorInfo& info) { 8195 ApiTestFuzzer::Fuzz(); 8196 CHECK(v8_str("x")->Equals(name)); 8197 return v8::Integer::New(0); 8198} 8199 8200 8201THREADED_TEST(InterceptorReturningZero) { 8202 CheckInterceptorLoadIC(InterceptorLoadICGetter0, 8203 "o.x == undefined ? 1 : 0", 8204 0); 8205} 8206 8207 8208static v8::Handle<Value> InterceptorStoreICSetter( 8209 Local<String> key, Local<Value> value, const AccessorInfo&) { 8210 CHECK(v8_str("x")->Equals(key)); 8211 CHECK_EQ(42, value->Int32Value()); 8212 return value; 8213} 8214 8215 8216// This test should hit the store IC for the interceptor case. 8217THREADED_TEST(InterceptorStoreIC) { 8218 v8::HandleScope scope; 8219 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8220 templ->SetNamedPropertyHandler(InterceptorLoadICGetter, 8221 InterceptorStoreICSetter, 8222 0, 0, 0, v8_str("data")); 8223 LocalContext context; 8224 context->Global()->Set(v8_str("o"), templ->NewInstance()); 8225 v8::Handle<Value> value = CompileRun( 8226 "for (var i = 0; i < 1000; i++) {" 8227 " o.x = 42;" 8228 "}"); 8229} 8230 8231 8232THREADED_TEST(InterceptorStoreICWithNoSetter) { 8233 v8::HandleScope scope; 8234 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8235 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 8236 LocalContext context; 8237 context->Global()->Set(v8_str("o"), templ->NewInstance()); 8238 v8::Handle<Value> value = CompileRun( 8239 "for (var i = 0; i < 1000; i++) {" 8240 " o.y = 239;" 8241 "}" 8242 "42 + o.y"); 8243 CHECK_EQ(239 + 42, value->Int32Value()); 8244} 8245 8246 8247 8248 8249v8::Handle<Value> call_ic_function; 8250v8::Handle<Value> call_ic_function2; 8251v8::Handle<Value> call_ic_function3; 8252 8253static v8::Handle<Value> InterceptorCallICGetter(Local<String> name, 8254 const AccessorInfo& info) { 8255 ApiTestFuzzer::Fuzz(); 8256 CHECK(v8_str("x")->Equals(name)); 8257 return call_ic_function; 8258} 8259 8260 8261// This test should hit the call IC for the interceptor case. 8262THREADED_TEST(InterceptorCallIC) { 8263 v8::HandleScope scope; 8264 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8265 templ->SetNamedPropertyHandler(InterceptorCallICGetter); 8266 LocalContext context; 8267 context->Global()->Set(v8_str("o"), templ->NewInstance()); 8268 call_ic_function = 8269 v8_compile("function f(x) { return x + 1; }; f")->Run(); 8270 v8::Handle<Value> value = CompileRun( 8271 "var result = 0;" 8272 "for (var i = 0; i < 1000; i++) {" 8273 " result = o.x(41);" 8274 "}"); 8275 CHECK_EQ(42, value->Int32Value()); 8276} 8277 8278 8279// This test checks that if interceptor doesn't provide 8280// a value, we can fetch regular value. 8281THREADED_TEST(InterceptorCallICSeesOthers) { 8282 v8::HandleScope scope; 8283 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8284 templ->SetNamedPropertyHandler(NoBlockGetterX); 8285 LocalContext context; 8286 context->Global()->Set(v8_str("o"), templ->NewInstance()); 8287 v8::Handle<Value> value = CompileRun( 8288 "o.x = function f(x) { return x + 1; };" 8289 "var result = 0;" 8290 "for (var i = 0; i < 7; i++) {" 8291 " result = o.x(41);" 8292 "}"); 8293 CHECK_EQ(42, value->Int32Value()); 8294} 8295 8296 8297static v8::Handle<Value> call_ic_function4; 8298static v8::Handle<Value> InterceptorCallICGetter4(Local<String> name, 8299 const AccessorInfo& info) { 8300 ApiTestFuzzer::Fuzz(); 8301 CHECK(v8_str("x")->Equals(name)); 8302 return call_ic_function4; 8303} 8304 8305 8306// This test checks that if interceptor provides a function, 8307// even if we cached shadowed variant, interceptor's function 8308// is invoked 8309THREADED_TEST(InterceptorCallICCacheableNotNeeded) { 8310 v8::HandleScope scope; 8311 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8312 templ->SetNamedPropertyHandler(InterceptorCallICGetter4); 8313 LocalContext context; 8314 context->Global()->Set(v8_str("o"), templ->NewInstance()); 8315 call_ic_function4 = 8316 v8_compile("function f(x) { return x - 1; }; f")->Run(); 8317 v8::Handle<Value> value = CompileRun( 8318 "o.__proto__.x = function(x) { return x + 1; };" 8319 "var result = 0;" 8320 "for (var i = 0; i < 1000; i++) {" 8321 " result = o.x(42);" 8322 "}"); 8323 CHECK_EQ(41, value->Int32Value()); 8324} 8325 8326 8327// Test the case when we stored cacheable lookup into 8328// a stub, but it got invalidated later on 8329THREADED_TEST(InterceptorCallICInvalidatedCacheable) { 8330 v8::HandleScope scope; 8331 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8332 templ->SetNamedPropertyHandler(NoBlockGetterX); 8333 LocalContext context; 8334 context->Global()->Set(v8_str("o"), templ->NewInstance()); 8335 v8::Handle<Value> value = CompileRun( 8336 "proto1 = new Object();" 8337 "proto2 = new Object();" 8338 "o.__proto__ = proto1;" 8339 "proto1.__proto__ = proto2;" 8340 "proto2.y = function(x) { return x + 1; };" 8341 // Invoke it many times to compile a stub 8342 "for (var i = 0; i < 7; i++) {" 8343 " o.y(42);" 8344 "}" 8345 "proto1.y = function(x) { return x - 1; };" 8346 "var result = 0;" 8347 "for (var i = 0; i < 7; i++) {" 8348 " result += o.y(42);" 8349 "}"); 8350 CHECK_EQ(41 * 7, value->Int32Value()); 8351} 8352 8353 8354static v8::Handle<Value> call_ic_function5; 8355static v8::Handle<Value> InterceptorCallICGetter5(Local<String> name, 8356 const AccessorInfo& info) { 8357 ApiTestFuzzer::Fuzz(); 8358 if (v8_str("x")->Equals(name)) 8359 return call_ic_function5; 8360 else 8361 return Local<Value>(); 8362} 8363 8364 8365// This test checks that if interceptor doesn't provide a function, 8366// cached constant function is used 8367THREADED_TEST(InterceptorCallICConstantFunctionUsed) { 8368 v8::HandleScope scope; 8369 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8370 templ->SetNamedPropertyHandler(NoBlockGetterX); 8371 LocalContext context; 8372 context->Global()->Set(v8_str("o"), templ->NewInstance()); 8373 v8::Handle<Value> value = CompileRun( 8374 "function inc(x) { return x + 1; };" 8375 "inc(1);" 8376 "o.x = inc;" 8377 "var result = 0;" 8378 "for (var i = 0; i < 1000; i++) {" 8379 " result = o.x(42);" 8380 "}"); 8381 CHECK_EQ(43, value->Int32Value()); 8382} 8383 8384 8385// This test checks that if interceptor provides a function, 8386// even if we cached constant function, interceptor's function 8387// is invoked 8388THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) { 8389 v8::HandleScope scope; 8390 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8391 templ->SetNamedPropertyHandler(InterceptorCallICGetter5); 8392 LocalContext context; 8393 context->Global()->Set(v8_str("o"), templ->NewInstance()); 8394 call_ic_function5 = 8395 v8_compile("function f(x) { return x - 1; }; f")->Run(); 8396 v8::Handle<Value> value = CompileRun( 8397 "function inc(x) { return x + 1; };" 8398 "inc(1);" 8399 "o.x = inc;" 8400 "var result = 0;" 8401 "for (var i = 0; i < 1000; i++) {" 8402 " result = o.x(42);" 8403 "}"); 8404 CHECK_EQ(41, value->Int32Value()); 8405} 8406 8407 8408// Test the case when we stored constant function into 8409// a stub, but it got invalidated later on 8410THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) { 8411 v8::HandleScope scope; 8412 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8413 templ->SetNamedPropertyHandler(NoBlockGetterX); 8414 LocalContext context; 8415 context->Global()->Set(v8_str("o"), templ->NewInstance()); 8416 v8::Handle<Value> value = CompileRun( 8417 "function inc(x) { return x + 1; };" 8418 "inc(1);" 8419 "proto1 = new Object();" 8420 "proto2 = new Object();" 8421 "o.__proto__ = proto1;" 8422 "proto1.__proto__ = proto2;" 8423 "proto2.y = inc;" 8424 // Invoke it many times to compile a stub 8425 "for (var i = 0; i < 7; i++) {" 8426 " o.y(42);" 8427 "}" 8428 "proto1.y = function(x) { return x - 1; };" 8429 "var result = 0;" 8430 "for (var i = 0; i < 7; i++) {" 8431 " result += o.y(42);" 8432 "}"); 8433 CHECK_EQ(41 * 7, value->Int32Value()); 8434} 8435 8436 8437// Test the case when we stored constant function into 8438// a stub, but it got invalidated later on due to override on 8439// global object which is between interceptor and constant function' holders. 8440THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) { 8441 v8::HandleScope scope; 8442 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8443 templ->SetNamedPropertyHandler(NoBlockGetterX); 8444 LocalContext context; 8445 context->Global()->Set(v8_str("o"), templ->NewInstance()); 8446 v8::Handle<Value> value = CompileRun( 8447 "function inc(x) { return x + 1; };" 8448 "inc(1);" 8449 "o.__proto__ = this;" 8450 "this.__proto__.y = inc;" 8451 // Invoke it many times to compile a stub 8452 "for (var i = 0; i < 7; i++) {" 8453 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);" 8454 "}" 8455 "this.y = function(x) { return x - 1; };" 8456 "var result = 0;" 8457 "for (var i = 0; i < 7; i++) {" 8458 " result += o.y(42);" 8459 "}"); 8460 CHECK_EQ(41 * 7, value->Int32Value()); 8461} 8462 8463 8464// Test the case when actual function to call sits on global object. 8465THREADED_TEST(InterceptorCallICCachedFromGlobal) { 8466 v8::HandleScope scope; 8467 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 8468 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 8469 8470 LocalContext context; 8471 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 8472 8473 v8::Handle<Value> value = CompileRun( 8474 "try {" 8475 " o.__proto__ = this;" 8476 " for (var i = 0; i < 10; i++) {" 8477 " var v = o.parseFloat('239');" 8478 " if (v != 239) throw v;" 8479 // Now it should be ICed and keep a reference to parseFloat. 8480 " }" 8481 " var result = 0;" 8482 " for (var i = 0; i < 10; i++) {" 8483 " result += o.parseFloat('239');" 8484 " }" 8485 " result" 8486 "} catch(e) {" 8487 " e" 8488 "};"); 8489 CHECK_EQ(239 * 10, value->Int32Value()); 8490} 8491 8492static v8::Handle<Value> InterceptorCallICFastApi(Local<String> name, 8493 const AccessorInfo& info) { 8494 ApiTestFuzzer::Fuzz(); 8495 int* call_count = reinterpret_cast<int*>(v8::External::Unwrap(info.Data())); 8496 ++(*call_count); 8497 if ((*call_count) % 20 == 0) { 8498 HEAP->CollectAllGarbage(true); 8499 } 8500 return v8::Handle<Value>(); 8501} 8502 8503static v8::Handle<Value> FastApiCallback_TrivialSignature( 8504 const v8::Arguments& args) { 8505 ApiTestFuzzer::Fuzz(); 8506 CHECK_EQ(args.This(), args.Holder()); 8507 CHECK(args.Data()->Equals(v8_str("method_data"))); 8508 return v8::Integer::New(args[0]->Int32Value() + 1); 8509} 8510 8511static v8::Handle<Value> FastApiCallback_SimpleSignature( 8512 const v8::Arguments& args) { 8513 ApiTestFuzzer::Fuzz(); 8514 CHECK_EQ(args.This()->GetPrototype(), args.Holder()); 8515 CHECK(args.Data()->Equals(v8_str("method_data"))); 8516 // Note, we're using HasRealNamedProperty instead of Has to avoid 8517 // invoking the interceptor again. 8518 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo"))); 8519 return v8::Integer::New(args[0]->Int32Value() + 1); 8520} 8521 8522// Helper to maximize the odds of object moving. 8523static void GenerateSomeGarbage() { 8524 CompileRun( 8525 "var garbage;" 8526 "for (var i = 0; i < 1000; i++) {" 8527 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];" 8528 "}" 8529 "garbage = undefined;"); 8530} 8531 8532 8533v8::Handle<v8::Value> DirectApiCallback(const v8::Arguments& args) { 8534 static int count = 0; 8535 if (count++ % 3 == 0) { 8536 HEAP-> CollectAllGarbage(true); // This should move the stub 8537 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed 8538 } 8539 return v8::Handle<v8::Value>(); 8540} 8541 8542 8543THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) { 8544 v8::HandleScope scope; 8545 LocalContext context; 8546 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New(); 8547 nativeobject_templ->Set("callback", 8548 v8::FunctionTemplate::New(DirectApiCallback)); 8549 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance(); 8550 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj); 8551 // call the api function multiple times to ensure direct call stub creation. 8552 CompileRun( 8553 "function f() {" 8554 " for (var i = 1; i <= 30; i++) {" 8555 " nativeobject.callback();" 8556 " }" 8557 "}" 8558 "f();"); 8559} 8560 8561 8562v8::Handle<v8::Value> ThrowingDirectApiCallback(const v8::Arguments& args) { 8563 return v8::ThrowException(v8_str("g")); 8564} 8565 8566 8567THREADED_TEST(CallICFastApi_DirectCall_Throw) { 8568 v8::HandleScope scope; 8569 LocalContext context; 8570 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New(); 8571 nativeobject_templ->Set("callback", 8572 v8::FunctionTemplate::New(ThrowingDirectApiCallback)); 8573 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance(); 8574 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj); 8575 // call the api function multiple times to ensure direct call stub creation. 8576 v8::Handle<Value> result = CompileRun( 8577 "var result = '';" 8578 "function f() {" 8579 " for (var i = 1; i <= 5; i++) {" 8580 " try { nativeobject.callback(); } catch (e) { result += e; }" 8581 " }" 8582 "}" 8583 "f(); result;"); 8584 CHECK_EQ(v8_str("ggggg"), result); 8585} 8586 8587 8588v8::Handle<v8::Value> DirectGetterCallback(Local<String> name, 8589 const v8::AccessorInfo& info) { 8590 if (++p_getter_count % 3 == 0) { 8591 HEAP->CollectAllGarbage(true); 8592 GenerateSomeGarbage(); 8593 } 8594 return v8::Handle<v8::Value>(); 8595} 8596 8597 8598THREADED_TEST(LoadICFastApi_DirectCall_GCMoveStub) { 8599 v8::HandleScope scope; 8600 LocalContext context; 8601 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(); 8602 obj->SetAccessor(v8_str("p1"), DirectGetterCallback); 8603 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 8604 p_getter_count = 0; 8605 CompileRun( 8606 "function f() {" 8607 " for (var i = 0; i < 30; i++) o1.p1;" 8608 "}" 8609 "f();"); 8610 CHECK_EQ(30, p_getter_count); 8611} 8612 8613 8614v8::Handle<v8::Value> ThrowingDirectGetterCallback( 8615 Local<String> name, const v8::AccessorInfo& info) { 8616 return v8::ThrowException(v8_str("g")); 8617} 8618 8619 8620THREADED_TEST(LoadICFastApi_DirectCall_Throw) { 8621 v8::HandleScope scope; 8622 LocalContext context; 8623 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(); 8624 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback); 8625 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 8626 v8::Handle<Value> result = CompileRun( 8627 "var result = '';" 8628 "for (var i = 0; i < 5; i++) {" 8629 " try { o1.p1; } catch (e) { result += e; }" 8630 "}" 8631 "result;"); 8632 CHECK_EQ(v8_str("ggggg"), result); 8633} 8634 8635 8636THREADED_TEST(InterceptorCallICFastApi_TrivialSignature) { 8637 int interceptor_call_count = 0; 8638 v8::HandleScope scope; 8639 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 8640 v8::Handle<v8::FunctionTemplate> method_templ = 8641 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature, 8642 v8_str("method_data"), 8643 v8::Handle<v8::Signature>()); 8644 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 8645 proto_templ->Set(v8_str("method"), method_templ); 8646 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 8647 templ->SetNamedPropertyHandler(InterceptorCallICFastApi, 8648 NULL, NULL, NULL, NULL, 8649 v8::External::Wrap(&interceptor_call_count)); 8650 LocalContext context; 8651 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 8652 GenerateSomeGarbage(); 8653 context->Global()->Set(v8_str("o"), fun->NewInstance()); 8654 v8::Handle<Value> value = CompileRun( 8655 "var result = 0;" 8656 "for (var i = 0; i < 100; i++) {" 8657 " result = o.method(41);" 8658 "}"); 8659 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 8660 CHECK_EQ(100, interceptor_call_count); 8661} 8662 8663THREADED_TEST(InterceptorCallICFastApi_SimpleSignature) { 8664 int interceptor_call_count = 0; 8665 v8::HandleScope scope; 8666 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 8667 v8::Handle<v8::FunctionTemplate> method_templ = 8668 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 8669 v8_str("method_data"), 8670 v8::Signature::New(fun_templ)); 8671 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 8672 proto_templ->Set(v8_str("method"), method_templ); 8673 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 8674 templ->SetNamedPropertyHandler(InterceptorCallICFastApi, 8675 NULL, NULL, NULL, NULL, 8676 v8::External::Wrap(&interceptor_call_count)); 8677 LocalContext context; 8678 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 8679 GenerateSomeGarbage(); 8680 context->Global()->Set(v8_str("o"), fun->NewInstance()); 8681 v8::Handle<Value> value = CompileRun( 8682 "o.foo = 17;" 8683 "var receiver = {};" 8684 "receiver.__proto__ = o;" 8685 "var result = 0;" 8686 "for (var i = 0; i < 100; i++) {" 8687 " result = receiver.method(41);" 8688 "}"); 8689 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 8690 CHECK_EQ(100, interceptor_call_count); 8691} 8692 8693THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) { 8694 int interceptor_call_count = 0; 8695 v8::HandleScope scope; 8696 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 8697 v8::Handle<v8::FunctionTemplate> method_templ = 8698 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 8699 v8_str("method_data"), 8700 v8::Signature::New(fun_templ)); 8701 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 8702 proto_templ->Set(v8_str("method"), method_templ); 8703 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 8704 templ->SetNamedPropertyHandler(InterceptorCallICFastApi, 8705 NULL, NULL, NULL, NULL, 8706 v8::External::Wrap(&interceptor_call_count)); 8707 LocalContext context; 8708 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 8709 GenerateSomeGarbage(); 8710 context->Global()->Set(v8_str("o"), fun->NewInstance()); 8711 v8::Handle<Value> value = CompileRun( 8712 "o.foo = 17;" 8713 "var receiver = {};" 8714 "receiver.__proto__ = o;" 8715 "var result = 0;" 8716 "var saved_result = 0;" 8717 "for (var i = 0; i < 100; i++) {" 8718 " result = receiver.method(41);" 8719 " if (i == 50) {" 8720 " saved_result = result;" 8721 " receiver = {method: function(x) { return x - 1 }};" 8722 " }" 8723 "}"); 8724 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 8725 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 8726 CHECK_GE(interceptor_call_count, 50); 8727} 8728 8729THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) { 8730 int interceptor_call_count = 0; 8731 v8::HandleScope scope; 8732 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 8733 v8::Handle<v8::FunctionTemplate> method_templ = 8734 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 8735 v8_str("method_data"), 8736 v8::Signature::New(fun_templ)); 8737 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 8738 proto_templ->Set(v8_str("method"), method_templ); 8739 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 8740 templ->SetNamedPropertyHandler(InterceptorCallICFastApi, 8741 NULL, NULL, NULL, NULL, 8742 v8::External::Wrap(&interceptor_call_count)); 8743 LocalContext context; 8744 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 8745 GenerateSomeGarbage(); 8746 context->Global()->Set(v8_str("o"), fun->NewInstance()); 8747 v8::Handle<Value> value = CompileRun( 8748 "o.foo = 17;" 8749 "var receiver = {};" 8750 "receiver.__proto__ = o;" 8751 "var result = 0;" 8752 "var saved_result = 0;" 8753 "for (var i = 0; i < 100; i++) {" 8754 " result = receiver.method(41);" 8755 " if (i == 50) {" 8756 " saved_result = result;" 8757 " o.method = function(x) { return x - 1 };" 8758 " }" 8759 "}"); 8760 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 8761 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 8762 CHECK_GE(interceptor_call_count, 50); 8763} 8764 8765THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) { 8766 int interceptor_call_count = 0; 8767 v8::HandleScope scope; 8768 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 8769 v8::Handle<v8::FunctionTemplate> method_templ = 8770 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 8771 v8_str("method_data"), 8772 v8::Signature::New(fun_templ)); 8773 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 8774 proto_templ->Set(v8_str("method"), method_templ); 8775 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 8776 templ->SetNamedPropertyHandler(InterceptorCallICFastApi, 8777 NULL, NULL, NULL, NULL, 8778 v8::External::Wrap(&interceptor_call_count)); 8779 LocalContext context; 8780 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 8781 GenerateSomeGarbage(); 8782 context->Global()->Set(v8_str("o"), fun->NewInstance()); 8783 v8::TryCatch try_catch; 8784 v8::Handle<Value> value = CompileRun( 8785 "o.foo = 17;" 8786 "var receiver = {};" 8787 "receiver.__proto__ = o;" 8788 "var result = 0;" 8789 "var saved_result = 0;" 8790 "for (var i = 0; i < 100; i++) {" 8791 " result = receiver.method(41);" 8792 " if (i == 50) {" 8793 " saved_result = result;" 8794 " receiver = 333;" 8795 " }" 8796 "}"); 8797 CHECK(try_catch.HasCaught()); 8798 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"), 8799 try_catch.Exception()->ToString()); 8800 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 8801 CHECK_GE(interceptor_call_count, 50); 8802} 8803 8804THREADED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) { 8805 int interceptor_call_count = 0; 8806 v8::HandleScope scope; 8807 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 8808 v8::Handle<v8::FunctionTemplate> method_templ = 8809 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 8810 v8_str("method_data"), 8811 v8::Signature::New(fun_templ)); 8812 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 8813 proto_templ->Set(v8_str("method"), method_templ); 8814 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 8815 templ->SetNamedPropertyHandler(InterceptorCallICFastApi, 8816 NULL, NULL, NULL, NULL, 8817 v8::External::Wrap(&interceptor_call_count)); 8818 LocalContext context; 8819 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 8820 GenerateSomeGarbage(); 8821 context->Global()->Set(v8_str("o"), fun->NewInstance()); 8822 v8::TryCatch try_catch; 8823 v8::Handle<Value> value = CompileRun( 8824 "o.foo = 17;" 8825 "var receiver = {};" 8826 "receiver.__proto__ = o;" 8827 "var result = 0;" 8828 "var saved_result = 0;" 8829 "for (var i = 0; i < 100; i++) {" 8830 " result = receiver.method(41);" 8831 " if (i == 50) {" 8832 " saved_result = result;" 8833 " receiver = {method: receiver.method};" 8834 " }" 8835 "}"); 8836 CHECK(try_catch.HasCaught()); 8837 CHECK_EQ(v8_str("TypeError: Illegal invocation"), 8838 try_catch.Exception()->ToString()); 8839 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 8840 CHECK_GE(interceptor_call_count, 50); 8841} 8842 8843THREADED_TEST(CallICFastApi_TrivialSignature) { 8844 v8::HandleScope scope; 8845 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 8846 v8::Handle<v8::FunctionTemplate> method_templ = 8847 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature, 8848 v8_str("method_data"), 8849 v8::Handle<v8::Signature>()); 8850 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 8851 proto_templ->Set(v8_str("method"), method_templ); 8852 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 8853 LocalContext context; 8854 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 8855 GenerateSomeGarbage(); 8856 context->Global()->Set(v8_str("o"), fun->NewInstance()); 8857 v8::Handle<Value> value = CompileRun( 8858 "var result = 0;" 8859 "for (var i = 0; i < 100; i++) {" 8860 " result = o.method(41);" 8861 "}"); 8862 8863 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 8864} 8865 8866THREADED_TEST(CallICFastApi_SimpleSignature) { 8867 v8::HandleScope scope; 8868 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 8869 v8::Handle<v8::FunctionTemplate> method_templ = 8870 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 8871 v8_str("method_data"), 8872 v8::Signature::New(fun_templ)); 8873 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 8874 proto_templ->Set(v8_str("method"), method_templ); 8875 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 8876 LocalContext context; 8877 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 8878 GenerateSomeGarbage(); 8879 context->Global()->Set(v8_str("o"), fun->NewInstance()); 8880 v8::Handle<Value> value = CompileRun( 8881 "o.foo = 17;" 8882 "var receiver = {};" 8883 "receiver.__proto__ = o;" 8884 "var result = 0;" 8885 "for (var i = 0; i < 100; i++) {" 8886 " result = receiver.method(41);" 8887 "}"); 8888 8889 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 8890} 8891 8892THREADED_TEST(CallICFastApi_SimpleSignature_Miss1) { 8893 v8::HandleScope scope; 8894 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 8895 v8::Handle<v8::FunctionTemplate> method_templ = 8896 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 8897 v8_str("method_data"), 8898 v8::Signature::New(fun_templ)); 8899 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 8900 proto_templ->Set(v8_str("method"), method_templ); 8901 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 8902 LocalContext context; 8903 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 8904 GenerateSomeGarbage(); 8905 context->Global()->Set(v8_str("o"), fun->NewInstance()); 8906 v8::Handle<Value> value = CompileRun( 8907 "o.foo = 17;" 8908 "var receiver = {};" 8909 "receiver.__proto__ = o;" 8910 "var result = 0;" 8911 "var saved_result = 0;" 8912 "for (var i = 0; i < 100; i++) {" 8913 " result = receiver.method(41);" 8914 " if (i == 50) {" 8915 " saved_result = result;" 8916 " receiver = {method: function(x) { return x - 1 }};" 8917 " }" 8918 "}"); 8919 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 8920 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 8921} 8922 8923THREADED_TEST(CallICFastApi_SimpleSignature_Miss2) { 8924 v8::HandleScope scope; 8925 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 8926 v8::Handle<v8::FunctionTemplate> method_templ = 8927 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 8928 v8_str("method_data"), 8929 v8::Signature::New(fun_templ)); 8930 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 8931 proto_templ->Set(v8_str("method"), method_templ); 8932 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 8933 LocalContext context; 8934 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 8935 GenerateSomeGarbage(); 8936 context->Global()->Set(v8_str("o"), fun->NewInstance()); 8937 v8::TryCatch try_catch; 8938 v8::Handle<Value> value = CompileRun( 8939 "o.foo = 17;" 8940 "var receiver = {};" 8941 "receiver.__proto__ = o;" 8942 "var result = 0;" 8943 "var saved_result = 0;" 8944 "for (var i = 0; i < 100; i++) {" 8945 " result = receiver.method(41);" 8946 " if (i == 50) {" 8947 " saved_result = result;" 8948 " receiver = 333;" 8949 " }" 8950 "}"); 8951 CHECK(try_catch.HasCaught()); 8952 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"), 8953 try_catch.Exception()->ToString()); 8954 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 8955} 8956 8957 8958v8::Handle<Value> keyed_call_ic_function; 8959 8960static v8::Handle<Value> InterceptorKeyedCallICGetter( 8961 Local<String> name, const AccessorInfo& info) { 8962 ApiTestFuzzer::Fuzz(); 8963 if (v8_str("x")->Equals(name)) { 8964 return keyed_call_ic_function; 8965 } 8966 return v8::Handle<Value>(); 8967} 8968 8969 8970// Test the case when we stored cacheable lookup into 8971// a stub, but the function name changed (to another cacheable function). 8972THREADED_TEST(InterceptorKeyedCallICKeyChange1) { 8973 v8::HandleScope scope; 8974 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8975 templ->SetNamedPropertyHandler(NoBlockGetterX); 8976 LocalContext context; 8977 context->Global()->Set(v8_str("o"), templ->NewInstance()); 8978 v8::Handle<Value> value = CompileRun( 8979 "proto = new Object();" 8980 "proto.y = function(x) { return x + 1; };" 8981 "proto.z = function(x) { return x - 1; };" 8982 "o.__proto__ = proto;" 8983 "var result = 0;" 8984 "var method = 'y';" 8985 "for (var i = 0; i < 10; i++) {" 8986 " if (i == 5) { method = 'z'; };" 8987 " result += o[method](41);" 8988 "}"); 8989 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 8990} 8991 8992 8993// Test the case when we stored cacheable lookup into 8994// a stub, but the function name changed (and the new function is present 8995// both before and after the interceptor in the prototype chain). 8996THREADED_TEST(InterceptorKeyedCallICKeyChange2) { 8997 v8::HandleScope scope; 8998 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 8999 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter); 9000 LocalContext context; 9001 context->Global()->Set(v8_str("proto1"), templ->NewInstance()); 9002 keyed_call_ic_function = 9003 v8_compile("function f(x) { return x - 1; }; f")->Run(); 9004 v8::Handle<Value> value = CompileRun( 9005 "o = new Object();" 9006 "proto2 = new Object();" 9007 "o.y = function(x) { return x + 1; };" 9008 "proto2.y = function(x) { return x + 2; };" 9009 "o.__proto__ = proto1;" 9010 "proto1.__proto__ = proto2;" 9011 "var result = 0;" 9012 "var method = 'x';" 9013 "for (var i = 0; i < 10; i++) {" 9014 " if (i == 5) { method = 'y'; };" 9015 " result += o[method](41);" 9016 "}"); 9017 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 9018} 9019 9020 9021// Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit 9022// on the global object. 9023THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) { 9024 v8::HandleScope scope; 9025 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 9026 templ->SetNamedPropertyHandler(NoBlockGetterX); 9027 LocalContext context; 9028 context->Global()->Set(v8_str("o"), templ->NewInstance()); 9029 v8::Handle<Value> value = CompileRun( 9030 "function inc(x) { return x + 1; };" 9031 "inc(1);" 9032 "function dec(x) { return x - 1; };" 9033 "dec(1);" 9034 "o.__proto__ = this;" 9035 "this.__proto__.x = inc;" 9036 "this.__proto__.y = dec;" 9037 "var result = 0;" 9038 "var method = 'x';" 9039 "for (var i = 0; i < 10; i++) {" 9040 " if (i == 5) { method = 'y'; };" 9041 " result += o[method](41);" 9042 "}"); 9043 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 9044} 9045 9046 9047// Test the case when actual function to call sits on global object. 9048THREADED_TEST(InterceptorKeyedCallICFromGlobal) { 9049 v8::HandleScope scope; 9050 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 9051 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 9052 LocalContext context; 9053 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 9054 9055 v8::Handle<Value> value = CompileRun( 9056 "function len(x) { return x.length; };" 9057 "o.__proto__ = this;" 9058 "var m = 'parseFloat';" 9059 "var result = 0;" 9060 "for (var i = 0; i < 10; i++) {" 9061 " if (i == 5) {" 9062 " m = 'len';" 9063 " saved_result = result;" 9064 " };" 9065 " result = o[m]('239');" 9066 "}"); 9067 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value()); 9068 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 9069} 9070 9071// Test the map transition before the interceptor. 9072THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) { 9073 v8::HandleScope scope; 9074 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 9075 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 9076 LocalContext context; 9077 context->Global()->Set(v8_str("proto"), templ_o->NewInstance()); 9078 9079 v8::Handle<Value> value = CompileRun( 9080 "var o = new Object();" 9081 "o.__proto__ = proto;" 9082 "o.method = function(x) { return x + 1; };" 9083 "var m = 'method';" 9084 "var result = 0;" 9085 "for (var i = 0; i < 10; i++) {" 9086 " if (i == 5) { o.method = function(x) { return x - 1; }; };" 9087 " result += o[m](41);" 9088 "}"); 9089 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 9090} 9091 9092 9093// Test the map transition after the interceptor. 9094THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) { 9095 v8::HandleScope scope; 9096 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 9097 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 9098 LocalContext context; 9099 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 9100 9101 v8::Handle<Value> value = CompileRun( 9102 "var proto = new Object();" 9103 "o.__proto__ = proto;" 9104 "proto.method = function(x) { return x + 1; };" 9105 "var m = 'method';" 9106 "var result = 0;" 9107 "for (var i = 0; i < 10; i++) {" 9108 " if (i == 5) { proto.method = function(x) { return x - 1; }; };" 9109 " result += o[m](41);" 9110 "}"); 9111 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 9112} 9113 9114 9115static int interceptor_call_count = 0; 9116 9117static v8::Handle<Value> InterceptorICRefErrorGetter(Local<String> name, 9118 const AccessorInfo& info) { 9119 ApiTestFuzzer::Fuzz(); 9120 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) { 9121 return call_ic_function2; 9122 } 9123 return v8::Handle<Value>(); 9124} 9125 9126 9127// This test should hit load and call ICs for the interceptor case. 9128// Once in a while, the interceptor will reply that a property was not 9129// found in which case we should get a reference error. 9130THREADED_TEST(InterceptorICReferenceErrors) { 9131 v8::HandleScope scope; 9132 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 9133 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter); 9134 LocalContext context(0, templ, v8::Handle<Value>()); 9135 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run(); 9136 v8::Handle<Value> value = CompileRun( 9137 "function f() {" 9138 " for (var i = 0; i < 1000; i++) {" 9139 " try { x; } catch(e) { return true; }" 9140 " }" 9141 " return false;" 9142 "};" 9143 "f();"); 9144 CHECK_EQ(true, value->BooleanValue()); 9145 interceptor_call_count = 0; 9146 value = CompileRun( 9147 "function g() {" 9148 " for (var i = 0; i < 1000; i++) {" 9149 " try { x(42); } catch(e) { return true; }" 9150 " }" 9151 " return false;" 9152 "};" 9153 "g();"); 9154 CHECK_EQ(true, value->BooleanValue()); 9155} 9156 9157 9158static int interceptor_ic_exception_get_count = 0; 9159 9160static v8::Handle<Value> InterceptorICExceptionGetter( 9161 Local<String> name, 9162 const AccessorInfo& info) { 9163 ApiTestFuzzer::Fuzz(); 9164 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) { 9165 return call_ic_function3; 9166 } 9167 if (interceptor_ic_exception_get_count == 20) { 9168 return v8::ThrowException(v8_num(42)); 9169 } 9170 // Do not handle get for properties other than x. 9171 return v8::Handle<Value>(); 9172} 9173 9174// Test interceptor load/call IC where the interceptor throws an 9175// exception once in a while. 9176THREADED_TEST(InterceptorICGetterExceptions) { 9177 interceptor_ic_exception_get_count = 0; 9178 v8::HandleScope scope; 9179 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 9180 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter); 9181 LocalContext context(0, templ, v8::Handle<Value>()); 9182 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run(); 9183 v8::Handle<Value> value = CompileRun( 9184 "function f() {" 9185 " for (var i = 0; i < 100; i++) {" 9186 " try { x; } catch(e) { return true; }" 9187 " }" 9188 " return false;" 9189 "};" 9190 "f();"); 9191 CHECK_EQ(true, value->BooleanValue()); 9192 interceptor_ic_exception_get_count = 0; 9193 value = CompileRun( 9194 "function f() {" 9195 " for (var i = 0; i < 100; i++) {" 9196 " try { x(42); } catch(e) { return true; }" 9197 " }" 9198 " return false;" 9199 "};" 9200 "f();"); 9201 CHECK_EQ(true, value->BooleanValue()); 9202} 9203 9204 9205static int interceptor_ic_exception_set_count = 0; 9206 9207static v8::Handle<Value> InterceptorICExceptionSetter( 9208 Local<String> key, Local<Value> value, const AccessorInfo&) { 9209 ApiTestFuzzer::Fuzz(); 9210 if (++interceptor_ic_exception_set_count > 20) { 9211 return v8::ThrowException(v8_num(42)); 9212 } 9213 // Do not actually handle setting. 9214 return v8::Handle<Value>(); 9215} 9216 9217// Test interceptor store IC where the interceptor throws an exception 9218// once in a while. 9219THREADED_TEST(InterceptorICSetterExceptions) { 9220 interceptor_ic_exception_set_count = 0; 9221 v8::HandleScope scope; 9222 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 9223 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter); 9224 LocalContext context(0, templ, v8::Handle<Value>()); 9225 v8::Handle<Value> value = CompileRun( 9226 "function f() {" 9227 " for (var i = 0; i < 100; i++) {" 9228 " try { x = 42; } catch(e) { return true; }" 9229 " }" 9230 " return false;" 9231 "};" 9232 "f();"); 9233 CHECK_EQ(true, value->BooleanValue()); 9234} 9235 9236 9237// Test that we ignore null interceptors. 9238THREADED_TEST(NullNamedInterceptor) { 9239 v8::HandleScope scope; 9240 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 9241 templ->SetNamedPropertyHandler(0); 9242 LocalContext context; 9243 templ->Set("x", v8_num(42)); 9244 v8::Handle<v8::Object> obj = templ->NewInstance(); 9245 context->Global()->Set(v8_str("obj"), obj); 9246 v8::Handle<Value> value = CompileRun("obj.x"); 9247 CHECK(value->IsInt32()); 9248 CHECK_EQ(42, value->Int32Value()); 9249} 9250 9251 9252// Test that we ignore null interceptors. 9253THREADED_TEST(NullIndexedInterceptor) { 9254 v8::HandleScope scope; 9255 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 9256 templ->SetIndexedPropertyHandler(0); 9257 LocalContext context; 9258 templ->Set("42", v8_num(42)); 9259 v8::Handle<v8::Object> obj = templ->NewInstance(); 9260 context->Global()->Set(v8_str("obj"), obj); 9261 v8::Handle<Value> value = CompileRun("obj[42]"); 9262 CHECK(value->IsInt32()); 9263 CHECK_EQ(42, value->Int32Value()); 9264} 9265 9266 9267THREADED_TEST(NamedPropertyHandlerGetterAttributes) { 9268 v8::HandleScope scope; 9269 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 9270 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter); 9271 LocalContext env; 9272 env->Global()->Set(v8_str("obj"), 9273 templ->GetFunction()->NewInstance()); 9274 ExpectTrue("obj.x === 42"); 9275 ExpectTrue("!obj.propertyIsEnumerable('x')"); 9276} 9277 9278 9279static Handle<Value> ThrowingGetter(Local<String> name, 9280 const AccessorInfo& info) { 9281 ApiTestFuzzer::Fuzz(); 9282 ThrowException(Handle<Value>()); 9283 return Undefined(); 9284} 9285 9286 9287THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) { 9288 HandleScope scope; 9289 LocalContext context; 9290 9291 Local<FunctionTemplate> templ = FunctionTemplate::New(); 9292 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate(); 9293 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter); 9294 9295 Local<Object> instance = templ->GetFunction()->NewInstance(); 9296 9297 Local<Object> another = Object::New(); 9298 another->SetPrototype(instance); 9299 9300 Local<Object> with_js_getter = CompileRun( 9301 "o = {};\n" 9302 "o.__defineGetter__('f', function() { throw undefined; });\n" 9303 "o\n").As<Object>(); 9304 CHECK(!with_js_getter.IsEmpty()); 9305 9306 TryCatch try_catch; 9307 9308 Local<Value> result = instance->GetRealNamedProperty(v8_str("f")); 9309 CHECK(try_catch.HasCaught()); 9310 try_catch.Reset(); 9311 CHECK(result.IsEmpty()); 9312 9313 result = another->GetRealNamedProperty(v8_str("f")); 9314 CHECK(try_catch.HasCaught()); 9315 try_catch.Reset(); 9316 CHECK(result.IsEmpty()); 9317 9318 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f")); 9319 CHECK(try_catch.HasCaught()); 9320 try_catch.Reset(); 9321 CHECK(result.IsEmpty()); 9322 9323 result = another->Get(v8_str("f")); 9324 CHECK(try_catch.HasCaught()); 9325 try_catch.Reset(); 9326 CHECK(result.IsEmpty()); 9327 9328 result = with_js_getter->GetRealNamedProperty(v8_str("f")); 9329 CHECK(try_catch.HasCaught()); 9330 try_catch.Reset(); 9331 CHECK(result.IsEmpty()); 9332 9333 result = with_js_getter->Get(v8_str("f")); 9334 CHECK(try_catch.HasCaught()); 9335 try_catch.Reset(); 9336 CHECK(result.IsEmpty()); 9337} 9338 9339 9340static Handle<Value> ThrowingCallbackWithTryCatch(const Arguments& args) { 9341 TryCatch try_catch; 9342 // Verboseness is important: it triggers message delivery which can call into 9343 // external code. 9344 try_catch.SetVerbose(true); 9345 CompileRun("throw 'from JS';"); 9346 CHECK(try_catch.HasCaught()); 9347 CHECK(!i::Isolate::Current()->has_pending_exception()); 9348 CHECK(!i::Isolate::Current()->has_scheduled_exception()); 9349 return Undefined(); 9350} 9351 9352 9353static int call_depth; 9354 9355 9356static void WithTryCatch(Handle<Message> message, Handle<Value> data) { 9357 TryCatch try_catch; 9358} 9359 9360 9361static void ThrowFromJS(Handle<Message> message, Handle<Value> data) { 9362 if (--call_depth) CompileRun("throw 'ThrowInJS';"); 9363} 9364 9365 9366static void ThrowViaApi(Handle<Message> message, Handle<Value> data) { 9367 if (--call_depth) ThrowException(v8_str("ThrowViaApi")); 9368} 9369 9370 9371static void WebKitLike(Handle<Message> message, Handle<Value> data) { 9372 Handle<String> errorMessageString = message->Get(); 9373 CHECK(!errorMessageString.IsEmpty()); 9374 message->GetStackTrace(); 9375 message->GetScriptResourceName(); 9376} 9377 9378THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) { 9379 HandleScope scope; 9380 LocalContext context; 9381 9382 Local<Function> func = 9383 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction(); 9384 context->Global()->Set(v8_str("func"), func); 9385 9386 MessageCallback callbacks[] = 9387 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch }; 9388 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) { 9389 MessageCallback callback = callbacks[i]; 9390 if (callback != NULL) { 9391 V8::AddMessageListener(callback); 9392 } 9393 // Some small number to control number of times message handler should 9394 // throw an exception. 9395 call_depth = 5; 9396 ExpectFalse( 9397 "var thrown = false;\n" 9398 "try { func(); } catch(e) { thrown = true; }\n" 9399 "thrown\n"); 9400 if (callback != NULL) { 9401 V8::RemoveMessageListeners(callback); 9402 } 9403 } 9404} 9405 9406 9407static v8::Handle<Value> ParentGetter(Local<String> name, 9408 const AccessorInfo& info) { 9409 ApiTestFuzzer::Fuzz(); 9410 return v8_num(1); 9411} 9412 9413 9414static v8::Handle<Value> ChildGetter(Local<String> name, 9415 const AccessorInfo& info) { 9416 ApiTestFuzzer::Fuzz(); 9417 return v8_num(42); 9418} 9419 9420 9421THREADED_TEST(Overriding) { 9422 v8::HandleScope scope; 9423 LocalContext context; 9424 9425 // Parent template. 9426 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(); 9427 Local<ObjectTemplate> parent_instance_templ = 9428 parent_templ->InstanceTemplate(); 9429 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter); 9430 9431 // Template that inherits from the parent template. 9432 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(); 9433 Local<ObjectTemplate> child_instance_templ = 9434 child_templ->InstanceTemplate(); 9435 child_templ->Inherit(parent_templ); 9436 // Override 'f'. The child version of 'f' should get called for child 9437 // instances. 9438 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter); 9439 // Add 'g' twice. The 'g' added last should get called for instances. 9440 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter); 9441 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter); 9442 9443 // Add 'h' as an accessor to the proto template with ReadOnly attributes 9444 // so 'h' can be shadowed on the instance object. 9445 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate(); 9446 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0, 9447 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly); 9448 9449 // Add 'i' as an accessor to the instance template with ReadOnly attributes 9450 // but the attribute does not have effect because it is duplicated with 9451 // NULL setter. 9452 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0, 9453 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly); 9454 9455 9456 9457 // Instantiate the child template. 9458 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance(); 9459 9460 // Check that the child function overrides the parent one. 9461 context->Global()->Set(v8_str("o"), instance); 9462 Local<Value> value = v8_compile("o.f")->Run(); 9463 // Check that the 'g' that was added last is hit. 9464 CHECK_EQ(42, value->Int32Value()); 9465 value = v8_compile("o.g")->Run(); 9466 CHECK_EQ(42, value->Int32Value()); 9467 9468 // Check 'h' can be shadowed. 9469 value = v8_compile("o.h = 3; o.h")->Run(); 9470 CHECK_EQ(3, value->Int32Value()); 9471 9472 // Check 'i' is cannot be shadowed or changed. 9473 value = v8_compile("o.i = 3; o.i")->Run(); 9474 CHECK_EQ(42, value->Int32Value()); 9475} 9476 9477 9478static v8::Handle<Value> IsConstructHandler(const v8::Arguments& args) { 9479 ApiTestFuzzer::Fuzz(); 9480 if (args.IsConstructCall()) { 9481 return v8::Boolean::New(true); 9482 } 9483 return v8::Boolean::New(false); 9484} 9485 9486 9487THREADED_TEST(IsConstructCall) { 9488 v8::HandleScope scope; 9489 9490 // Function template with call handler. 9491 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 9492 templ->SetCallHandler(IsConstructHandler); 9493 9494 LocalContext context; 9495 9496 context->Global()->Set(v8_str("f"), templ->GetFunction()); 9497 Local<Value> value = v8_compile("f()")->Run(); 9498 CHECK(!value->BooleanValue()); 9499 value = v8_compile("new f()")->Run(); 9500 CHECK(value->BooleanValue()); 9501} 9502 9503 9504THREADED_TEST(ObjectProtoToString) { 9505 v8::HandleScope scope; 9506 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 9507 templ->SetClassName(v8_str("MyClass")); 9508 9509 LocalContext context; 9510 9511 Local<String> customized_tostring = v8_str("customized toString"); 9512 9513 // Replace Object.prototype.toString 9514 v8_compile("Object.prototype.toString = function() {" 9515 " return 'customized toString';" 9516 "}")->Run(); 9517 9518 // Normal ToString call should call replaced Object.prototype.toString 9519 Local<v8::Object> instance = templ->GetFunction()->NewInstance(); 9520 Local<String> value = instance->ToString(); 9521 CHECK(value->IsString() && value->Equals(customized_tostring)); 9522 9523 // ObjectProtoToString should not call replace toString function. 9524 value = instance->ObjectProtoToString(); 9525 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]"))); 9526 9527 // Check global 9528 value = context->Global()->ObjectProtoToString(); 9529 CHECK(value->IsString() && value->Equals(v8_str("[object global]"))); 9530 9531 // Check ordinary object 9532 Local<Value> object = v8_compile("new Object()")->Run(); 9533 value = object.As<v8::Object>()->ObjectProtoToString(); 9534 CHECK(value->IsString() && value->Equals(v8_str("[object Object]"))); 9535} 9536 9537 9538THREADED_TEST(ObjectGetConstructorName) { 9539 v8::HandleScope scope; 9540 LocalContext context; 9541 v8_compile("function Parent() {};" 9542 "function Child() {};" 9543 "Child.prototype = new Parent();" 9544 "var outer = { inner: function() { } };" 9545 "var p = new Parent();" 9546 "var c = new Child();" 9547 "var x = new outer.inner();")->Run(); 9548 9549 Local<v8::Value> p = context->Global()->Get(v8_str("p")); 9550 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals( 9551 v8_str("Parent"))); 9552 9553 Local<v8::Value> c = context->Global()->Get(v8_str("c")); 9554 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals( 9555 v8_str("Child"))); 9556 9557 Local<v8::Value> x = context->Global()->Get(v8_str("x")); 9558 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals( 9559 v8_str("outer.inner"))); 9560} 9561 9562 9563bool ApiTestFuzzer::fuzzing_ = false; 9564i::Semaphore* ApiTestFuzzer::all_tests_done_= 9565 i::OS::CreateSemaphore(0); 9566int ApiTestFuzzer::active_tests_; 9567int ApiTestFuzzer::tests_being_run_; 9568int ApiTestFuzzer::current_; 9569 9570 9571// We are in a callback and want to switch to another thread (if we 9572// are currently running the thread fuzzing test). 9573void ApiTestFuzzer::Fuzz() { 9574 if (!fuzzing_) return; 9575 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_; 9576 test->ContextSwitch(); 9577} 9578 9579 9580// Let the next thread go. Since it is also waiting on the V8 lock it may 9581// not start immediately. 9582bool ApiTestFuzzer::NextThread() { 9583 int test_position = GetNextTestNumber(); 9584 const char* test_name = RegisterThreadedTest::nth(current_)->name(); 9585 if (test_position == current_) { 9586 if (kLogThreading) 9587 printf("Stay with %s\n", test_name); 9588 return false; 9589 } 9590 if (kLogThreading) { 9591 printf("Switch from %s to %s\n", 9592 test_name, 9593 RegisterThreadedTest::nth(test_position)->name()); 9594 } 9595 current_ = test_position; 9596 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal(); 9597 return true; 9598} 9599 9600 9601void ApiTestFuzzer::Run() { 9602 // When it is our turn... 9603 gate_->Wait(); 9604 { 9605 // ... get the V8 lock and start running the test. 9606 v8::Locker locker; 9607 CallTest(); 9608 } 9609 // This test finished. 9610 active_ = false; 9611 active_tests_--; 9612 // If it was the last then signal that fact. 9613 if (active_tests_ == 0) { 9614 all_tests_done_->Signal(); 9615 } else { 9616 // Otherwise select a new test and start that. 9617 NextThread(); 9618 } 9619} 9620 9621 9622static unsigned linear_congruential_generator; 9623 9624 9625void ApiTestFuzzer::Setup(PartOfTest part) { 9626 linear_congruential_generator = i::FLAG_testing_prng_seed; 9627 fuzzing_ = true; 9628 int count = RegisterThreadedTest::count(); 9629 int start = count * part / (LAST_PART + 1); 9630 int end = (count * (part + 1) / (LAST_PART + 1)) - 1; 9631 active_tests_ = tests_being_run_ = end - start + 1; 9632 for (int i = 0; i < tests_being_run_; i++) { 9633 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start); 9634 } 9635 for (int i = 0; i < active_tests_; i++) { 9636 RegisterThreadedTest::nth(i)->fuzzer_->Start(); 9637 } 9638} 9639 9640 9641static void CallTestNumber(int test_number) { 9642 (RegisterThreadedTest::nth(test_number)->callback())(); 9643} 9644 9645 9646void ApiTestFuzzer::RunAllTests() { 9647 // Set off the first test. 9648 current_ = -1; 9649 NextThread(); 9650 // Wait till they are all done. 9651 all_tests_done_->Wait(); 9652} 9653 9654 9655int ApiTestFuzzer::GetNextTestNumber() { 9656 int next_test; 9657 do { 9658 next_test = (linear_congruential_generator >> 16) % tests_being_run_; 9659 linear_congruential_generator *= 1664525u; 9660 linear_congruential_generator += 1013904223u; 9661 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_); 9662 return next_test; 9663} 9664 9665 9666void ApiTestFuzzer::ContextSwitch() { 9667 // If the new thread is the same as the current thread there is nothing to do. 9668 if (NextThread()) { 9669 // Now it can start. 9670 v8::Unlocker unlocker; 9671 // Wait till someone starts us again. 9672 gate_->Wait(); 9673 // And we're off. 9674 } 9675} 9676 9677 9678void ApiTestFuzzer::TearDown() { 9679 fuzzing_ = false; 9680 for (int i = 0; i < RegisterThreadedTest::count(); i++) { 9681 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_; 9682 if (fuzzer != NULL) fuzzer->Join(); 9683 } 9684} 9685 9686 9687// Lets not be needlessly self-referential. 9688TEST(Threading) { 9689 ApiTestFuzzer::Setup(ApiTestFuzzer::FIRST_PART); 9690 ApiTestFuzzer::RunAllTests(); 9691 ApiTestFuzzer::TearDown(); 9692} 9693 9694TEST(Threading2) { 9695 ApiTestFuzzer::Setup(ApiTestFuzzer::SECOND_PART); 9696 ApiTestFuzzer::RunAllTests(); 9697 ApiTestFuzzer::TearDown(); 9698} 9699 9700TEST(Threading3) { 9701 ApiTestFuzzer::Setup(ApiTestFuzzer::THIRD_PART); 9702 ApiTestFuzzer::RunAllTests(); 9703 ApiTestFuzzer::TearDown(); 9704} 9705 9706TEST(Threading4) { 9707 ApiTestFuzzer::Setup(ApiTestFuzzer::FOURTH_PART); 9708 ApiTestFuzzer::RunAllTests(); 9709 ApiTestFuzzer::TearDown(); 9710} 9711 9712void ApiTestFuzzer::CallTest() { 9713 if (kLogThreading) 9714 printf("Start test %d\n", test_number_); 9715 CallTestNumber(test_number_); 9716 if (kLogThreading) 9717 printf("End test %d\n", test_number_); 9718} 9719 9720 9721static v8::Handle<Value> ThrowInJS(const v8::Arguments& args) { 9722 CHECK(v8::Locker::IsLocked()); 9723 ApiTestFuzzer::Fuzz(); 9724 v8::Unlocker unlocker; 9725 const char* code = "throw 7;"; 9726 { 9727 v8::Locker nested_locker; 9728 v8::HandleScope scope; 9729 v8::Handle<Value> exception; 9730 { v8::TryCatch try_catch; 9731 v8::Handle<Value> value = CompileRun(code); 9732 CHECK(value.IsEmpty()); 9733 CHECK(try_catch.HasCaught()); 9734 // Make sure to wrap the exception in a new handle because 9735 // the handle returned from the TryCatch is destroyed 9736 // when the TryCatch is destroyed. 9737 exception = Local<Value>::New(try_catch.Exception()); 9738 } 9739 return v8::ThrowException(exception); 9740 } 9741} 9742 9743 9744static v8::Handle<Value> ThrowInJSNoCatch(const v8::Arguments& args) { 9745 CHECK(v8::Locker::IsLocked()); 9746 ApiTestFuzzer::Fuzz(); 9747 v8::Unlocker unlocker; 9748 const char* code = "throw 7;"; 9749 { 9750 v8::Locker nested_locker; 9751 v8::HandleScope scope; 9752 v8::Handle<Value> value = CompileRun(code); 9753 CHECK(value.IsEmpty()); 9754 return v8_str("foo"); 9755 } 9756} 9757 9758 9759// These are locking tests that don't need to be run again 9760// as part of the locking aggregation tests. 9761TEST(NestedLockers) { 9762 v8::Locker locker; 9763 CHECK(v8::Locker::IsLocked()); 9764 v8::HandleScope scope; 9765 LocalContext env; 9766 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS); 9767 Local<Function> fun = fun_templ->GetFunction(); 9768 env->Global()->Set(v8_str("throw_in_js"), fun); 9769 Local<Script> script = v8_compile("(function () {" 9770 " try {" 9771 " throw_in_js();" 9772 " return 42;" 9773 " } catch (e) {" 9774 " return e * 13;" 9775 " }" 9776 "})();"); 9777 CHECK_EQ(91, script->Run()->Int32Value()); 9778} 9779 9780 9781// These are locking tests that don't need to be run again 9782// as part of the locking aggregation tests. 9783TEST(NestedLockersNoTryCatch) { 9784 v8::Locker locker; 9785 v8::HandleScope scope; 9786 LocalContext env; 9787 Local<v8::FunctionTemplate> fun_templ = 9788 v8::FunctionTemplate::New(ThrowInJSNoCatch); 9789 Local<Function> fun = fun_templ->GetFunction(); 9790 env->Global()->Set(v8_str("throw_in_js"), fun); 9791 Local<Script> script = v8_compile("(function () {" 9792 " try {" 9793 " throw_in_js();" 9794 " return 42;" 9795 " } catch (e) {" 9796 " return e * 13;" 9797 " }" 9798 "})();"); 9799 CHECK_EQ(91, script->Run()->Int32Value()); 9800} 9801 9802 9803THREADED_TEST(RecursiveLocking) { 9804 v8::Locker locker; 9805 { 9806 v8::Locker locker2; 9807 CHECK(v8::Locker::IsLocked()); 9808 } 9809} 9810 9811 9812static v8::Handle<Value> UnlockForAMoment(const v8::Arguments& args) { 9813 ApiTestFuzzer::Fuzz(); 9814 v8::Unlocker unlocker; 9815 return v8::Undefined(); 9816} 9817 9818 9819THREADED_TEST(LockUnlockLock) { 9820 { 9821 v8::Locker locker; 9822 v8::HandleScope scope; 9823 LocalContext env; 9824 Local<v8::FunctionTemplate> fun_templ = 9825 v8::FunctionTemplate::New(UnlockForAMoment); 9826 Local<Function> fun = fun_templ->GetFunction(); 9827 env->Global()->Set(v8_str("unlock_for_a_moment"), fun); 9828 Local<Script> script = v8_compile("(function () {" 9829 " unlock_for_a_moment();" 9830 " return 42;" 9831 "})();"); 9832 CHECK_EQ(42, script->Run()->Int32Value()); 9833 } 9834 { 9835 v8::Locker locker; 9836 v8::HandleScope scope; 9837 LocalContext env; 9838 Local<v8::FunctionTemplate> fun_templ = 9839 v8::FunctionTemplate::New(UnlockForAMoment); 9840 Local<Function> fun = fun_templ->GetFunction(); 9841 env->Global()->Set(v8_str("unlock_for_a_moment"), fun); 9842 Local<Script> script = v8_compile("(function () {" 9843 " unlock_for_a_moment();" 9844 " return 42;" 9845 "})();"); 9846 CHECK_EQ(42, script->Run()->Int32Value()); 9847 } 9848} 9849 9850 9851static int GetGlobalObjectsCount() { 9852 int count = 0; 9853 i::HeapIterator it; 9854 for (i::HeapObject* object = it.next(); object != NULL; object = it.next()) 9855 if (object->IsJSGlobalObject()) count++; 9856 return count; 9857} 9858 9859 9860static void CheckSurvivingGlobalObjectsCount(int expected) { 9861 // We need to collect all garbage twice to be sure that everything 9862 // has been collected. This is because inline caches are cleared in 9863 // the first garbage collection but some of the maps have already 9864 // been marked at that point. Therefore some of the maps are not 9865 // collected until the second garbage collection. 9866 HEAP->global_context_map(); 9867 HEAP->CollectAllGarbage(false); 9868 HEAP->CollectAllGarbage(false); 9869 int count = GetGlobalObjectsCount(); 9870#ifdef DEBUG 9871 if (count != expected) HEAP->TracePathToGlobal(); 9872#endif 9873 CHECK_EQ(expected, count); 9874} 9875 9876 9877TEST(DontLeakGlobalObjects) { 9878 // Regression test for issues 1139850 and 1174891. 9879 9880 v8::V8::Initialize(); 9881 9882 for (int i = 0; i < 5; i++) { 9883 { v8::HandleScope scope; 9884 LocalContext context; 9885 } 9886 CheckSurvivingGlobalObjectsCount(0); 9887 9888 { v8::HandleScope scope; 9889 LocalContext context; 9890 v8_compile("Date")->Run(); 9891 } 9892 CheckSurvivingGlobalObjectsCount(0); 9893 9894 { v8::HandleScope scope; 9895 LocalContext context; 9896 v8_compile("/aaa/")->Run(); 9897 } 9898 CheckSurvivingGlobalObjectsCount(0); 9899 9900 { v8::HandleScope scope; 9901 const char* extension_list[] = { "v8/gc" }; 9902 v8::ExtensionConfiguration extensions(1, extension_list); 9903 LocalContext context(&extensions); 9904 v8_compile("gc();")->Run(); 9905 } 9906 CheckSurvivingGlobalObjectsCount(0); 9907 } 9908} 9909 9910 9911v8::Persistent<v8::Object> some_object; 9912v8::Persistent<v8::Object> bad_handle; 9913 9914void NewPersistentHandleCallback(v8::Persistent<v8::Value> handle, void*) { 9915 v8::HandleScope scope; 9916 bad_handle = v8::Persistent<v8::Object>::New(some_object); 9917 handle.Dispose(); 9918} 9919 9920 9921THREADED_TEST(NewPersistentHandleFromWeakCallback) { 9922 LocalContext context; 9923 9924 v8::Persistent<v8::Object> handle1, handle2; 9925 { 9926 v8::HandleScope scope; 9927 some_object = v8::Persistent<v8::Object>::New(v8::Object::New()); 9928 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New()); 9929 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New()); 9930 } 9931 // Note: order is implementation dependent alas: currently 9932 // global handle nodes are processed by PostGarbageCollectionProcessing 9933 // in reverse allocation order, so if second allocated handle is deleted, 9934 // weak callback of the first handle would be able to 'reallocate' it. 9935 handle1.MakeWeak(NULL, NewPersistentHandleCallback); 9936 handle2.Dispose(); 9937 HEAP->CollectAllGarbage(false); 9938} 9939 9940 9941v8::Persistent<v8::Object> to_be_disposed; 9942 9943void DisposeAndForceGcCallback(v8::Persistent<v8::Value> handle, void*) { 9944 to_be_disposed.Dispose(); 9945 HEAP->CollectAllGarbage(false); 9946 handle.Dispose(); 9947} 9948 9949 9950THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) { 9951 LocalContext context; 9952 9953 v8::Persistent<v8::Object> handle1, handle2; 9954 { 9955 v8::HandleScope scope; 9956 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New()); 9957 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New()); 9958 } 9959 handle1.MakeWeak(NULL, DisposeAndForceGcCallback); 9960 to_be_disposed = handle2; 9961 HEAP->CollectAllGarbage(false); 9962} 9963 9964void DisposingCallback(v8::Persistent<v8::Value> handle, void*) { 9965 handle.Dispose(); 9966} 9967 9968void HandleCreatingCallback(v8::Persistent<v8::Value> handle, void*) { 9969 v8::HandleScope scope; 9970 v8::Persistent<v8::Object>::New(v8::Object::New()); 9971 handle.Dispose(); 9972} 9973 9974 9975THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) { 9976 LocalContext context; 9977 9978 v8::Persistent<v8::Object> handle1, handle2, handle3; 9979 { 9980 v8::HandleScope scope; 9981 handle3 = v8::Persistent<v8::Object>::New(v8::Object::New()); 9982 handle2 = v8::Persistent<v8::Object>::New(v8::Object::New()); 9983 handle1 = v8::Persistent<v8::Object>::New(v8::Object::New()); 9984 } 9985 handle2.MakeWeak(NULL, DisposingCallback); 9986 handle3.MakeWeak(NULL, HandleCreatingCallback); 9987 HEAP->CollectAllGarbage(false); 9988} 9989 9990 9991THREADED_TEST(CheckForCrossContextObjectLiterals) { 9992 v8::V8::Initialize(); 9993 9994 const int nof = 2; 9995 const char* sources[nof] = { 9996 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }", 9997 "Object()" 9998 }; 9999 10000 for (int i = 0; i < nof; i++) { 10001 const char* source = sources[i]; 10002 { v8::HandleScope scope; 10003 LocalContext context; 10004 CompileRun(source); 10005 } 10006 { v8::HandleScope scope; 10007 LocalContext context; 10008 CompileRun(source); 10009 } 10010 } 10011} 10012 10013 10014static v8::Handle<Value> NestedScope(v8::Persistent<Context> env) { 10015 v8::HandleScope inner; 10016 env->Enter(); 10017 v8::Handle<Value> three = v8_num(3); 10018 v8::Handle<Value> value = inner.Close(three); 10019 env->Exit(); 10020 return value; 10021} 10022 10023 10024THREADED_TEST(NestedHandleScopeAndContexts) { 10025 v8::HandleScope outer; 10026 v8::Persistent<Context> env = Context::New(); 10027 env->Enter(); 10028 v8::Handle<Value> value = NestedScope(env); 10029 v8::Handle<String> str = value->ToString(); 10030 env->Exit(); 10031 env.Dispose(); 10032} 10033 10034 10035THREADED_TEST(ExternalAllocatedMemory) { 10036 v8::HandleScope outer; 10037 v8::Persistent<Context> env = Context::New(); 10038 const int kSize = 1024*1024; 10039 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(kSize), kSize); 10040 CHECK_EQ(v8::V8::AdjustAmountOfExternalAllocatedMemory(-kSize), 0); 10041} 10042 10043 10044THREADED_TEST(DisposeEnteredContext) { 10045 v8::HandleScope scope; 10046 LocalContext outer; 10047 { v8::Persistent<v8::Context> inner = v8::Context::New(); 10048 inner->Enter(); 10049 inner.Dispose(); 10050 inner.Clear(); 10051 inner->Exit(); 10052 } 10053} 10054 10055 10056// Regression test for issue 54, object templates with internal fields 10057// but no accessors or interceptors did not get their internal field 10058// count set on instances. 10059THREADED_TEST(Regress54) { 10060 v8::HandleScope outer; 10061 LocalContext context; 10062 static v8::Persistent<v8::ObjectTemplate> templ; 10063 if (templ.IsEmpty()) { 10064 v8::HandleScope inner; 10065 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New(); 10066 local->SetInternalFieldCount(1); 10067 templ = v8::Persistent<v8::ObjectTemplate>::New(inner.Close(local)); 10068 } 10069 v8::Handle<v8::Object> result = templ->NewInstance(); 10070 CHECK_EQ(1, result->InternalFieldCount()); 10071} 10072 10073 10074// If part of the threaded tests, this test makes ThreadingTest fail 10075// on mac. 10076TEST(CatchStackOverflow) { 10077 v8::HandleScope scope; 10078 LocalContext context; 10079 v8::TryCatch try_catch; 10080 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New( 10081 "function f() {" 10082 " return f();" 10083 "}" 10084 "" 10085 "f();")); 10086 v8::Handle<v8::Value> result = script->Run(); 10087 CHECK(result.IsEmpty()); 10088} 10089 10090 10091static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script, 10092 const char* resource_name, 10093 int line_offset) { 10094 v8::HandleScope scope; 10095 v8::TryCatch try_catch; 10096 v8::Handle<v8::Value> result = script->Run(); 10097 CHECK(result.IsEmpty()); 10098 CHECK(try_catch.HasCaught()); 10099 v8::Handle<v8::Message> message = try_catch.Message(); 10100 CHECK(!message.IsEmpty()); 10101 CHECK_EQ(10 + line_offset, message->GetLineNumber()); 10102 CHECK_EQ(91, message->GetStartPosition()); 10103 CHECK_EQ(92, message->GetEndPosition()); 10104 CHECK_EQ(2, message->GetStartColumn()); 10105 CHECK_EQ(3, message->GetEndColumn()); 10106 v8::String::AsciiValue line(message->GetSourceLine()); 10107 CHECK_EQ(" throw 'nirk';", *line); 10108 v8::String::AsciiValue name(message->GetScriptResourceName()); 10109 CHECK_EQ(resource_name, *name); 10110} 10111 10112 10113THREADED_TEST(TryCatchSourceInfo) { 10114 v8::HandleScope scope; 10115 LocalContext context; 10116 v8::Handle<v8::String> source = v8::String::New( 10117 "function Foo() {\n" 10118 " return Bar();\n" 10119 "}\n" 10120 "\n" 10121 "function Bar() {\n" 10122 " return Baz();\n" 10123 "}\n" 10124 "\n" 10125 "function Baz() {\n" 10126 " throw 'nirk';\n" 10127 "}\n" 10128 "\n" 10129 "Foo();\n"); 10130 10131 const char* resource_name; 10132 v8::Handle<v8::Script> script; 10133 resource_name = "test.js"; 10134 script = v8::Script::Compile(source, v8::String::New(resource_name)); 10135 CheckTryCatchSourceInfo(script, resource_name, 0); 10136 10137 resource_name = "test1.js"; 10138 v8::ScriptOrigin origin1(v8::String::New(resource_name)); 10139 script = v8::Script::Compile(source, &origin1); 10140 CheckTryCatchSourceInfo(script, resource_name, 0); 10141 10142 resource_name = "test2.js"; 10143 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7)); 10144 script = v8::Script::Compile(source, &origin2); 10145 CheckTryCatchSourceInfo(script, resource_name, 7); 10146} 10147 10148 10149THREADED_TEST(CompilationCache) { 10150 v8::HandleScope scope; 10151 LocalContext context; 10152 v8::Handle<v8::String> source0 = v8::String::New("1234"); 10153 v8::Handle<v8::String> source1 = v8::String::New("1234"); 10154 v8::Handle<v8::Script> script0 = 10155 v8::Script::Compile(source0, v8::String::New("test.js")); 10156 v8::Handle<v8::Script> script1 = 10157 v8::Script::Compile(source1, v8::String::New("test.js")); 10158 v8::Handle<v8::Script> script2 = 10159 v8::Script::Compile(source0); // different origin 10160 CHECK_EQ(1234, script0->Run()->Int32Value()); 10161 CHECK_EQ(1234, script1->Run()->Int32Value()); 10162 CHECK_EQ(1234, script2->Run()->Int32Value()); 10163} 10164 10165 10166static v8::Handle<Value> FunctionNameCallback(const v8::Arguments& args) { 10167 ApiTestFuzzer::Fuzz(); 10168 return v8_num(42); 10169} 10170 10171 10172THREADED_TEST(CallbackFunctionName) { 10173 v8::HandleScope scope; 10174 LocalContext context; 10175 Local<ObjectTemplate> t = ObjectTemplate::New(); 10176 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback)); 10177 context->Global()->Set(v8_str("obj"), t->NewInstance()); 10178 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name"); 10179 CHECK(value->IsString()); 10180 v8::String::AsciiValue name(value); 10181 CHECK_EQ("asdf", *name); 10182} 10183 10184 10185THREADED_TEST(DateAccess) { 10186 v8::HandleScope scope; 10187 LocalContext context; 10188 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0); 10189 CHECK(date->IsDate()); 10190 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->NumberValue()); 10191} 10192 10193 10194void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) { 10195 v8::Handle<v8::Object> obj = val.As<v8::Object>(); 10196 v8::Handle<v8::Array> props = obj->GetPropertyNames(); 10197 CHECK_EQ(elmc, props->Length()); 10198 for (int i = 0; i < elmc; i++) { 10199 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i))); 10200 CHECK_EQ(elmv[i], *elm); 10201 } 10202} 10203 10204 10205void CheckOwnProperties(v8::Handle<v8::Value> val, 10206 int elmc, 10207 const char* elmv[]) { 10208 v8::Handle<v8::Object> obj = val.As<v8::Object>(); 10209 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames(); 10210 CHECK_EQ(elmc, props->Length()); 10211 for (int i = 0; i < elmc; i++) { 10212 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i))); 10213 CHECK_EQ(elmv[i], *elm); 10214 } 10215} 10216 10217 10218THREADED_TEST(PropertyEnumeration) { 10219 v8::HandleScope scope; 10220 LocalContext context; 10221 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New( 10222 "var result = [];" 10223 "result[0] = {};" 10224 "result[1] = {a: 1, b: 2};" 10225 "result[2] = [1, 2, 3];" 10226 "var proto = {x: 1, y: 2, z: 3};" 10227 "var x = { __proto__: proto, w: 0, z: 1 };" 10228 "result[3] = x;" 10229 "result;"))->Run(); 10230 v8::Handle<v8::Array> elms = obj.As<v8::Array>(); 10231 CHECK_EQ(4, elms->Length()); 10232 int elmc0 = 0; 10233 const char** elmv0 = NULL; 10234 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0); 10235 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0); 10236 int elmc1 = 2; 10237 const char* elmv1[] = {"a", "b"}; 10238 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1); 10239 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1); 10240 int elmc2 = 3; 10241 const char* elmv2[] = {"0", "1", "2"}; 10242 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2); 10243 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2); 10244 int elmc3 = 4; 10245 const char* elmv3[] = {"w", "z", "x", "y"}; 10246 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3); 10247 int elmc4 = 2; 10248 const char* elmv4[] = {"w", "z"}; 10249 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4); 10250} 10251 10252THREADED_TEST(PropertyEnumeration2) { 10253 v8::HandleScope scope; 10254 LocalContext context; 10255 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New( 10256 "var result = [];" 10257 "result[0] = {};" 10258 "result[1] = {a: 1, b: 2};" 10259 "result[2] = [1, 2, 3];" 10260 "var proto = {x: 1, y: 2, z: 3};" 10261 "var x = { __proto__: proto, w: 0, z: 1 };" 10262 "result[3] = x;" 10263 "result;"))->Run(); 10264 v8::Handle<v8::Array> elms = obj.As<v8::Array>(); 10265 CHECK_EQ(4, elms->Length()); 10266 int elmc0 = 0; 10267 const char** elmv0 = NULL; 10268 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0); 10269 10270 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0)); 10271 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames(); 10272 CHECK_EQ(0, props->Length()); 10273 for (uint32_t i = 0; i < props->Length(); i++) { 10274 printf("p[%d]\n", i); 10275 } 10276} 10277 10278static bool NamedSetAccessBlocker(Local<v8::Object> obj, 10279 Local<Value> name, 10280 v8::AccessType type, 10281 Local<Value> data) { 10282 return type != v8::ACCESS_SET; 10283} 10284 10285 10286static bool IndexedSetAccessBlocker(Local<v8::Object> obj, 10287 uint32_t key, 10288 v8::AccessType type, 10289 Local<Value> data) { 10290 return type != v8::ACCESS_SET; 10291} 10292 10293 10294THREADED_TEST(DisableAccessChecksWhileConfiguring) { 10295 v8::HandleScope scope; 10296 LocalContext context; 10297 Local<ObjectTemplate> templ = ObjectTemplate::New(); 10298 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker, 10299 IndexedSetAccessBlocker); 10300 templ->Set(v8_str("x"), v8::True()); 10301 Local<v8::Object> instance = templ->NewInstance(); 10302 context->Global()->Set(v8_str("obj"), instance); 10303 Local<Value> value = CompileRun("obj.x"); 10304 CHECK(value->BooleanValue()); 10305} 10306 10307 10308static bool NamedGetAccessBlocker(Local<v8::Object> obj, 10309 Local<Value> name, 10310 v8::AccessType type, 10311 Local<Value> data) { 10312 return false; 10313} 10314 10315 10316static bool IndexedGetAccessBlocker(Local<v8::Object> obj, 10317 uint32_t key, 10318 v8::AccessType type, 10319 Local<Value> data) { 10320 return false; 10321} 10322 10323 10324 10325THREADED_TEST(AccessChecksReenabledCorrectly) { 10326 v8::HandleScope scope; 10327 LocalContext context; 10328 Local<ObjectTemplate> templ = ObjectTemplate::New(); 10329 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker, 10330 IndexedGetAccessBlocker); 10331 templ->Set(v8_str("a"), v8_str("a")); 10332 // Add more than 8 (see kMaxFastProperties) properties 10333 // so that the constructor will force copying map. 10334 // Cannot sprintf, gcc complains unsafety. 10335 char buf[4]; 10336 for (char i = '0'; i <= '9' ; i++) { 10337 buf[0] = i; 10338 for (char j = '0'; j <= '9'; j++) { 10339 buf[1] = j; 10340 for (char k = '0'; k <= '9'; k++) { 10341 buf[2] = k; 10342 buf[3] = 0; 10343 templ->Set(v8_str(buf), v8::Number::New(k)); 10344 } 10345 } 10346 } 10347 10348 Local<v8::Object> instance_1 = templ->NewInstance(); 10349 context->Global()->Set(v8_str("obj_1"), instance_1); 10350 10351 Local<Value> value_1 = CompileRun("obj_1.a"); 10352 CHECK(value_1->IsUndefined()); 10353 10354 Local<v8::Object> instance_2 = templ->NewInstance(); 10355 context->Global()->Set(v8_str("obj_2"), instance_2); 10356 10357 Local<Value> value_2 = CompileRun("obj_2.a"); 10358 CHECK(value_2->IsUndefined()); 10359} 10360 10361 10362// This tests that access check information remains on the global 10363// object template when creating contexts. 10364THREADED_TEST(AccessControlRepeatedContextCreation) { 10365 v8::HandleScope handle_scope; 10366 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 10367 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker, 10368 IndexedSetAccessBlocker); 10369 i::Handle<i::ObjectTemplateInfo> internal_template = 10370 v8::Utils::OpenHandle(*global_template); 10371 CHECK(!internal_template->constructor()->IsUndefined()); 10372 i::Handle<i::FunctionTemplateInfo> constructor( 10373 i::FunctionTemplateInfo::cast(internal_template->constructor())); 10374 CHECK(!constructor->access_check_info()->IsUndefined()); 10375 v8::Persistent<Context> context0 = Context::New(NULL, global_template); 10376 CHECK(!constructor->access_check_info()->IsUndefined()); 10377} 10378 10379 10380THREADED_TEST(TurnOnAccessCheck) { 10381 v8::HandleScope handle_scope; 10382 10383 // Create an environment with access check to the global object disabled by 10384 // default. 10385 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 10386 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker, 10387 IndexedGetAccessBlocker, 10388 v8::Handle<v8::Value>(), 10389 false); 10390 v8::Persistent<Context> context = Context::New(NULL, global_template); 10391 Context::Scope context_scope(context); 10392 10393 // Set up a property and a number of functions. 10394 context->Global()->Set(v8_str("a"), v8_num(1)); 10395 CompileRun("function f1() {return a;}" 10396 "function f2() {return a;}" 10397 "function g1() {return h();}" 10398 "function g2() {return h();}" 10399 "function h() {return 1;}"); 10400 Local<Function> f1 = 10401 Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); 10402 Local<Function> f2 = 10403 Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); 10404 Local<Function> g1 = 10405 Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); 10406 Local<Function> g2 = 10407 Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); 10408 Local<Function> h = 10409 Local<Function>::Cast(context->Global()->Get(v8_str("h"))); 10410 10411 // Get the global object. 10412 v8::Handle<v8::Object> global = context->Global(); 10413 10414 // Call f1 one time and f2 a number of times. This will ensure that f1 still 10415 // uses the runtime system to retreive property a whereas f2 uses global load 10416 // inline cache. 10417 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1))); 10418 for (int i = 0; i < 4; i++) { 10419 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1))); 10420 } 10421 10422 // Same for g1 and g2. 10423 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1))); 10424 for (int i = 0; i < 4; i++) { 10425 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1))); 10426 } 10427 10428 // Detach the global and turn on access check. 10429 context->DetachGlobal(); 10430 context->Global()->TurnOnAccessCheck(); 10431 10432 // Failing access check to property get results in undefined. 10433 CHECK(f1->Call(global, 0, NULL)->IsUndefined()); 10434 CHECK(f2->Call(global, 0, NULL)->IsUndefined()); 10435 10436 // Failing access check to function call results in exception. 10437 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 10438 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 10439 10440 // No failing access check when just returning a constant. 10441 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1))); 10442} 10443 10444 10445v8::Handle<v8::String> a; 10446v8::Handle<v8::String> h; 10447 10448static bool NamedGetAccessBlockAandH(Local<v8::Object> obj, 10449 Local<Value> name, 10450 v8::AccessType type, 10451 Local<Value> data) { 10452 return !(name->Equals(a) || name->Equals(h)); 10453} 10454 10455 10456THREADED_TEST(TurnOnAccessCheckAndRecompile) { 10457 v8::HandleScope handle_scope; 10458 10459 // Create an environment with access check to the global object disabled by 10460 // default. When the registered access checker will block access to properties 10461 // a and h 10462 a = v8_str("a"); 10463 h = v8_str("h"); 10464 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 10465 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH, 10466 IndexedGetAccessBlocker, 10467 v8::Handle<v8::Value>(), 10468 false); 10469 v8::Persistent<Context> context = Context::New(NULL, global_template); 10470 Context::Scope context_scope(context); 10471 10472 // Set up a property and a number of functions. 10473 context->Global()->Set(v8_str("a"), v8_num(1)); 10474 static const char* source = "function f1() {return a;}" 10475 "function f2() {return a;}" 10476 "function g1() {return h();}" 10477 "function g2() {return h();}" 10478 "function h() {return 1;}"; 10479 10480 CompileRun(source); 10481 Local<Function> f1; 10482 Local<Function> f2; 10483 Local<Function> g1; 10484 Local<Function> g2; 10485 Local<Function> h; 10486 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); 10487 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); 10488 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); 10489 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); 10490 h = Local<Function>::Cast(context->Global()->Get(v8_str("h"))); 10491 10492 // Get the global object. 10493 v8::Handle<v8::Object> global = context->Global(); 10494 10495 // Call f1 one time and f2 a number of times. This will ensure that f1 still 10496 // uses the runtime system to retreive property a whereas f2 uses global load 10497 // inline cache. 10498 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1))); 10499 for (int i = 0; i < 4; i++) { 10500 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1))); 10501 } 10502 10503 // Same for g1 and g2. 10504 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1))); 10505 for (int i = 0; i < 4; i++) { 10506 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1))); 10507 } 10508 10509 // Detach the global and turn on access check now blocking access to property 10510 // a and function h. 10511 context->DetachGlobal(); 10512 context->Global()->TurnOnAccessCheck(); 10513 10514 // Failing access check to property get results in undefined. 10515 CHECK(f1->Call(global, 0, NULL)->IsUndefined()); 10516 CHECK(f2->Call(global, 0, NULL)->IsUndefined()); 10517 10518 // Failing access check to function call results in exception. 10519 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 10520 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 10521 10522 // No failing access check when just returning a constant. 10523 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1))); 10524 10525 // Now compile the source again. And get the newly compiled functions, except 10526 // for h for which access is blocked. 10527 CompileRun(source); 10528 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); 10529 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); 10530 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); 10531 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); 10532 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined()); 10533 10534 // Failing access check to property get results in undefined. 10535 CHECK(f1->Call(global, 0, NULL)->IsUndefined()); 10536 CHECK(f2->Call(global, 0, NULL)->IsUndefined()); 10537 10538 // Failing access check to function call results in exception. 10539 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 10540 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 10541} 10542 10543 10544// This test verifies that pre-compilation (aka preparsing) can be called 10545// without initializing the whole VM. Thus we cannot run this test in a 10546// multi-threaded setup. 10547TEST(PreCompile) { 10548 // TODO(155): This test would break without the initialization of V8. This is 10549 // a workaround for now to make this test not fail. 10550 v8::V8::Initialize(); 10551 const char* script = "function foo(a) { return a+1; }"; 10552 v8::ScriptData* sd = 10553 v8::ScriptData::PreCompile(script, i::StrLength(script)); 10554 CHECK_NE(sd->Length(), 0); 10555 CHECK_NE(sd->Data(), NULL); 10556 CHECK(!sd->HasError()); 10557 delete sd; 10558} 10559 10560 10561TEST(PreCompileWithError) { 10562 v8::V8::Initialize(); 10563 const char* script = "function foo(a) { return 1 * * 2; }"; 10564 v8::ScriptData* sd = 10565 v8::ScriptData::PreCompile(script, i::StrLength(script)); 10566 CHECK(sd->HasError()); 10567 delete sd; 10568} 10569 10570 10571TEST(Regress31661) { 10572 v8::V8::Initialize(); 10573 const char* script = " The Definintive Guide"; 10574 v8::ScriptData* sd = 10575 v8::ScriptData::PreCompile(script, i::StrLength(script)); 10576 CHECK(sd->HasError()); 10577 delete sd; 10578} 10579 10580 10581// Tests that ScriptData can be serialized and deserialized. 10582TEST(PreCompileSerialization) { 10583 v8::V8::Initialize(); 10584 const char* script = "function foo(a) { return a+1; }"; 10585 v8::ScriptData* sd = 10586 v8::ScriptData::PreCompile(script, i::StrLength(script)); 10587 10588 // Serialize. 10589 int serialized_data_length = sd->Length(); 10590 char* serialized_data = i::NewArray<char>(serialized_data_length); 10591 memcpy(serialized_data, sd->Data(), serialized_data_length); 10592 10593 // Deserialize. 10594 v8::ScriptData* deserialized_sd = 10595 v8::ScriptData::New(serialized_data, serialized_data_length); 10596 10597 // Verify that the original is the same as the deserialized. 10598 CHECK_EQ(sd->Length(), deserialized_sd->Length()); 10599 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length())); 10600 CHECK_EQ(sd->HasError(), deserialized_sd->HasError()); 10601 10602 delete sd; 10603 delete deserialized_sd; 10604} 10605 10606 10607// Attempts to deserialize bad data. 10608TEST(PreCompileDeserializationError) { 10609 v8::V8::Initialize(); 10610 const char* data = "DONT CARE"; 10611 int invalid_size = 3; 10612 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size); 10613 10614 CHECK_EQ(0, sd->Length()); 10615 10616 delete sd; 10617} 10618 10619 10620// Attempts to deserialize bad data. 10621TEST(PreCompileInvalidPreparseDataError) { 10622 v8::V8::Initialize(); 10623 v8::HandleScope scope; 10624 LocalContext context; 10625 10626 const char* script = "function foo(){ return 5;}\n" 10627 "function bar(){ return 6 + 7;} foo();"; 10628 v8::ScriptData* sd = 10629 v8::ScriptData::PreCompile(script, i::StrLength(script)); 10630 CHECK(!sd->HasError()); 10631 // ScriptDataImpl private implementation details 10632 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize; 10633 const int kFunctionEntrySize = i::FunctionEntry::kSize; 10634 const int kFunctionEntryStartOffset = 0; 10635 const int kFunctionEntryEndOffset = 1; 10636 unsigned* sd_data = 10637 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data())); 10638 10639 // Overwrite function bar's end position with 0. 10640 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0; 10641 v8::TryCatch try_catch; 10642 10643 Local<String> source = String::New(script); 10644 Local<Script> compiled_script = Script::New(source, NULL, sd); 10645 CHECK(try_catch.HasCaught()); 10646 String::AsciiValue exception_value(try_catch.Message()->Get()); 10647 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar", 10648 *exception_value); 10649 10650 try_catch.Reset(); 10651 10652 // Overwrite function bar's start position with 200. The function entry 10653 // will not be found when searching for it by position and we should fall 10654 // back on eager compilation. 10655 sd = v8::ScriptData::PreCompile(script, i::StrLength(script)); 10656 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data())); 10657 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] = 10658 200; 10659 compiled_script = Script::New(source, NULL, sd); 10660 CHECK(!try_catch.HasCaught()); 10661 10662 delete sd; 10663} 10664 10665 10666// Verifies that the Handle<String> and const char* versions of the API produce 10667// the same results (at least for one trivial case). 10668TEST(PreCompileAPIVariationsAreSame) { 10669 v8::V8::Initialize(); 10670 v8::HandleScope scope; 10671 10672 const char* cstring = "function foo(a) { return a+1; }"; 10673 10674 v8::ScriptData* sd_from_cstring = 10675 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring)); 10676 10677 TestAsciiResource* resource = new TestAsciiResource(cstring); 10678 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile( 10679 v8::String::NewExternal(resource)); 10680 10681 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile( 10682 v8::String::New(cstring)); 10683 10684 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length()); 10685 CHECK_EQ(0, memcmp(sd_from_cstring->Data(), 10686 sd_from_external_string->Data(), 10687 sd_from_cstring->Length())); 10688 10689 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length()); 10690 CHECK_EQ(0, memcmp(sd_from_cstring->Data(), 10691 sd_from_string->Data(), 10692 sd_from_cstring->Length())); 10693 10694 10695 delete sd_from_cstring; 10696 delete sd_from_external_string; 10697 delete sd_from_string; 10698} 10699 10700 10701// This tests that we do not allow dictionary load/call inline caches 10702// to use functions that have not yet been compiled. The potential 10703// problem of loading a function that has not yet been compiled can 10704// arise because we share code between contexts via the compilation 10705// cache. 10706THREADED_TEST(DictionaryICLoadedFunction) { 10707 v8::HandleScope scope; 10708 // Test LoadIC. 10709 for (int i = 0; i < 2; i++) { 10710 LocalContext context; 10711 context->Global()->Set(v8_str("tmp"), v8::True()); 10712 context->Global()->Delete(v8_str("tmp")); 10713 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');"); 10714 } 10715 // Test CallIC. 10716 for (int i = 0; i < 2; i++) { 10717 LocalContext context; 10718 context->Global()->Set(v8_str("tmp"), v8::True()); 10719 context->Global()->Delete(v8_str("tmp")); 10720 CompileRun("for (var j = 0; j < 10; j++) RegExp('')"); 10721 } 10722} 10723 10724 10725// Test that cross-context new calls use the context of the callee to 10726// create the new JavaScript object. 10727THREADED_TEST(CrossContextNew) { 10728 v8::HandleScope scope; 10729 v8::Persistent<Context> context0 = Context::New(); 10730 v8::Persistent<Context> context1 = Context::New(); 10731 10732 // Allow cross-domain access. 10733 Local<String> token = v8_str("<security token>"); 10734 context0->SetSecurityToken(token); 10735 context1->SetSecurityToken(token); 10736 10737 // Set an 'x' property on the Object prototype and define a 10738 // constructor function in context0. 10739 context0->Enter(); 10740 CompileRun("Object.prototype.x = 42; function C() {};"); 10741 context0->Exit(); 10742 10743 // Call the constructor function from context0 and check that the 10744 // result has the 'x' property. 10745 context1->Enter(); 10746 context1->Global()->Set(v8_str("other"), context0->Global()); 10747 Local<Value> value = CompileRun("var instance = new other.C(); instance.x"); 10748 CHECK(value->IsInt32()); 10749 CHECK_EQ(42, value->Int32Value()); 10750 context1->Exit(); 10751 10752 // Dispose the contexts to allow them to be garbage collected. 10753 context0.Dispose(); 10754 context1.Dispose(); 10755} 10756 10757 10758class RegExpInterruptTest { 10759 public: 10760 RegExpInterruptTest() : block_(NULL) {} 10761 ~RegExpInterruptTest() { delete block_; } 10762 void RunTest() { 10763 block_ = i::OS::CreateSemaphore(0); 10764 gc_count_ = 0; 10765 gc_during_regexp_ = 0; 10766 regexp_success_ = false; 10767 gc_success_ = false; 10768 GCThread gc_thread(this); 10769 gc_thread.Start(); 10770 v8::Locker::StartPreemption(1); 10771 10772 LongRunningRegExp(); 10773 { 10774 v8::Unlocker unlock; 10775 gc_thread.Join(); 10776 } 10777 v8::Locker::StopPreemption(); 10778 CHECK(regexp_success_); 10779 CHECK(gc_success_); 10780 } 10781 10782 private: 10783 // Number of garbage collections required. 10784 static const int kRequiredGCs = 5; 10785 10786 class GCThread : public i::Thread { 10787 public: 10788 explicit GCThread(RegExpInterruptTest* test) 10789 : Thread("GCThread"), test_(test) {} 10790 virtual void Run() { 10791 test_->CollectGarbage(); 10792 } 10793 private: 10794 RegExpInterruptTest* test_; 10795 }; 10796 10797 void CollectGarbage() { 10798 block_->Wait(); 10799 while (gc_during_regexp_ < kRequiredGCs) { 10800 { 10801 v8::Locker lock; 10802 // TODO(lrn): Perhaps create some garbage before collecting. 10803 HEAP->CollectAllGarbage(false); 10804 gc_count_++; 10805 } 10806 i::OS::Sleep(1); 10807 } 10808 gc_success_ = true; 10809 } 10810 10811 void LongRunningRegExp() { 10812 block_->Signal(); // Enable garbage collection thread on next preemption. 10813 int rounds = 0; 10814 while (gc_during_regexp_ < kRequiredGCs) { 10815 int gc_before = gc_count_; 10816 { 10817 // Match 15-30 "a"'s against 14 and a "b". 10818 const char* c_source = 10819 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" 10820 ".exec('aaaaaaaaaaaaaaab') === null"; 10821 Local<String> source = String::New(c_source); 10822 Local<Script> script = Script::Compile(source); 10823 Local<Value> result = script->Run(); 10824 if (!result->BooleanValue()) { 10825 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit. 10826 return; 10827 } 10828 } 10829 { 10830 // Match 15-30 "a"'s against 15 and a "b". 10831 const char* c_source = 10832 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" 10833 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'"; 10834 Local<String> source = String::New(c_source); 10835 Local<Script> script = Script::Compile(source); 10836 Local<Value> result = script->Run(); 10837 if (!result->BooleanValue()) { 10838 gc_during_regexp_ = kRequiredGCs; 10839 return; 10840 } 10841 } 10842 int gc_after = gc_count_; 10843 gc_during_regexp_ += gc_after - gc_before; 10844 rounds++; 10845 i::OS::Sleep(1); 10846 } 10847 regexp_success_ = true; 10848 } 10849 10850 i::Semaphore* block_; 10851 int gc_count_; 10852 int gc_during_regexp_; 10853 bool regexp_success_; 10854 bool gc_success_; 10855}; 10856 10857 10858// Test that a regular expression execution can be interrupted and 10859// survive a garbage collection. 10860TEST(RegExpInterruption) { 10861 v8::Locker lock; 10862 v8::V8::Initialize(); 10863 v8::HandleScope scope; 10864 Local<Context> local_env; 10865 { 10866 LocalContext env; 10867 local_env = env.local(); 10868 } 10869 10870 // Local context should still be live. 10871 CHECK(!local_env.IsEmpty()); 10872 local_env->Enter(); 10873 10874 // Should complete without problems. 10875 RegExpInterruptTest().RunTest(); 10876 10877 local_env->Exit(); 10878} 10879 10880 10881class ApplyInterruptTest { 10882 public: 10883 ApplyInterruptTest() : block_(NULL) {} 10884 ~ApplyInterruptTest() { delete block_; } 10885 void RunTest() { 10886 block_ = i::OS::CreateSemaphore(0); 10887 gc_count_ = 0; 10888 gc_during_apply_ = 0; 10889 apply_success_ = false; 10890 gc_success_ = false; 10891 GCThread gc_thread(this); 10892 gc_thread.Start(); 10893 v8::Locker::StartPreemption(1); 10894 10895 LongRunningApply(); 10896 { 10897 v8::Unlocker unlock; 10898 gc_thread.Join(); 10899 } 10900 v8::Locker::StopPreemption(); 10901 CHECK(apply_success_); 10902 CHECK(gc_success_); 10903 } 10904 10905 private: 10906 // Number of garbage collections required. 10907 static const int kRequiredGCs = 2; 10908 10909 class GCThread : public i::Thread { 10910 public: 10911 explicit GCThread(ApplyInterruptTest* test) 10912 : Thread("GCThread"), test_(test) {} 10913 virtual void Run() { 10914 test_->CollectGarbage(); 10915 } 10916 private: 10917 ApplyInterruptTest* test_; 10918 }; 10919 10920 void CollectGarbage() { 10921 block_->Wait(); 10922 while (gc_during_apply_ < kRequiredGCs) { 10923 { 10924 v8::Locker lock; 10925 HEAP->CollectAllGarbage(false); 10926 gc_count_++; 10927 } 10928 i::OS::Sleep(1); 10929 } 10930 gc_success_ = true; 10931 } 10932 10933 void LongRunningApply() { 10934 block_->Signal(); 10935 int rounds = 0; 10936 while (gc_during_apply_ < kRequiredGCs) { 10937 int gc_before = gc_count_; 10938 { 10939 const char* c_source = 10940 "function do_very_little(bar) {" 10941 " this.foo = bar;" 10942 "}" 10943 "for (var i = 0; i < 100000; i++) {" 10944 " do_very_little.apply(this, ['bar']);" 10945 "}"; 10946 Local<String> source = String::New(c_source); 10947 Local<Script> script = Script::Compile(source); 10948 Local<Value> result = script->Run(); 10949 // Check that no exception was thrown. 10950 CHECK(!result.IsEmpty()); 10951 } 10952 int gc_after = gc_count_; 10953 gc_during_apply_ += gc_after - gc_before; 10954 rounds++; 10955 } 10956 apply_success_ = true; 10957 } 10958 10959 i::Semaphore* block_; 10960 int gc_count_; 10961 int gc_during_apply_; 10962 bool apply_success_; 10963 bool gc_success_; 10964}; 10965 10966 10967// Test that nothing bad happens if we get a preemption just when we were 10968// about to do an apply(). 10969TEST(ApplyInterruption) { 10970 v8::Locker lock; 10971 v8::V8::Initialize(); 10972 v8::HandleScope scope; 10973 Local<Context> local_env; 10974 { 10975 LocalContext env; 10976 local_env = env.local(); 10977 } 10978 10979 // Local context should still be live. 10980 CHECK(!local_env.IsEmpty()); 10981 local_env->Enter(); 10982 10983 // Should complete without problems. 10984 ApplyInterruptTest().RunTest(); 10985 10986 local_env->Exit(); 10987} 10988 10989 10990// Verify that we can clone an object 10991TEST(ObjectClone) { 10992 v8::HandleScope scope; 10993 LocalContext env; 10994 10995 const char* sample = 10996 "var rv = {};" \ 10997 "rv.alpha = 'hello';" \ 10998 "rv.beta = 123;" \ 10999 "rv;"; 11000 11001 // Create an object, verify basics. 11002 Local<Value> val = CompileRun(sample); 11003 CHECK(val->IsObject()); 11004 Local<v8::Object> obj = val.As<v8::Object>(); 11005 obj->Set(v8_str("gamma"), v8_str("cloneme")); 11006 11007 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha"))); 11008 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta"))); 11009 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma"))); 11010 11011 // Clone it. 11012 Local<v8::Object> clone = obj->Clone(); 11013 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha"))); 11014 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta"))); 11015 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma"))); 11016 11017 // Set a property on the clone, verify each object. 11018 clone->Set(v8_str("beta"), v8::Integer::New(456)); 11019 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta"))); 11020 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta"))); 11021} 11022 11023 11024class AsciiVectorResource : public v8::String::ExternalAsciiStringResource { 11025 public: 11026 explicit AsciiVectorResource(i::Vector<const char> vector) 11027 : data_(vector) {} 11028 virtual ~AsciiVectorResource() {} 11029 virtual size_t length() const { return data_.length(); } 11030 virtual const char* data() const { return data_.start(); } 11031 private: 11032 i::Vector<const char> data_; 11033}; 11034 11035 11036class UC16VectorResource : public v8::String::ExternalStringResource { 11037 public: 11038 explicit UC16VectorResource(i::Vector<const i::uc16> vector) 11039 : data_(vector) {} 11040 virtual ~UC16VectorResource() {} 11041 virtual size_t length() const { return data_.length(); } 11042 virtual const i::uc16* data() const { return data_.start(); } 11043 private: 11044 i::Vector<const i::uc16> data_; 11045}; 11046 11047 11048static void MorphAString(i::String* string, 11049 AsciiVectorResource* ascii_resource, 11050 UC16VectorResource* uc16_resource) { 11051 CHECK(i::StringShape(string).IsExternal()); 11052 if (string->IsAsciiRepresentation()) { 11053 // Check old map is not symbol or long. 11054 CHECK(string->map() == HEAP->external_ascii_string_map()); 11055 // Morph external string to be TwoByte string. 11056 string->set_map(HEAP->external_string_map()); 11057 i::ExternalTwoByteString* morphed = 11058 i::ExternalTwoByteString::cast(string); 11059 morphed->set_resource(uc16_resource); 11060 } else { 11061 // Check old map is not symbol or long. 11062 CHECK(string->map() == HEAP->external_string_map()); 11063 // Morph external string to be ASCII string. 11064 string->set_map(HEAP->external_ascii_string_map()); 11065 i::ExternalAsciiString* morphed = 11066 i::ExternalAsciiString::cast(string); 11067 morphed->set_resource(ascii_resource); 11068 } 11069} 11070 11071 11072// Test that we can still flatten a string if the components it is built up 11073// from have been turned into 16 bit strings in the mean time. 11074THREADED_TEST(MorphCompositeStringTest) { 11075 const char* c_string = "Now is the time for all good men" 11076 " to come to the aid of the party"; 11077 uint16_t* two_byte_string = AsciiToTwoByteString(c_string); 11078 { 11079 v8::HandleScope scope; 11080 LocalContext env; 11081 AsciiVectorResource ascii_resource( 11082 i::Vector<const char>(c_string, i::StrLength(c_string))); 11083 UC16VectorResource uc16_resource( 11084 i::Vector<const uint16_t>(two_byte_string, 11085 i::StrLength(c_string))); 11086 11087 Local<String> lhs(v8::Utils::ToLocal( 11088 FACTORY->NewExternalStringFromAscii(&ascii_resource))); 11089 Local<String> rhs(v8::Utils::ToLocal( 11090 FACTORY->NewExternalStringFromAscii(&ascii_resource))); 11091 11092 env->Global()->Set(v8_str("lhs"), lhs); 11093 env->Global()->Set(v8_str("rhs"), rhs); 11094 11095 CompileRun( 11096 "var cons = lhs + rhs;" 11097 "var slice = lhs.substring(1, lhs.length - 1);" 11098 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);"); 11099 11100 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource); 11101 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource); 11102 11103 // Now do some stuff to make sure the strings are flattened, etc. 11104 CompileRun( 11105 "/[^a-z]/.test(cons);" 11106 "/[^a-z]/.test(slice);" 11107 "/[^a-z]/.test(slice_on_cons);"); 11108 const char* expected_cons = 11109 "Now is the time for all good men to come to the aid of the party" 11110 "Now is the time for all good men to come to the aid of the party"; 11111 const char* expected_slice = 11112 "ow is the time for all good men to come to the aid of the part"; 11113 const char* expected_slice_on_cons = 11114 "ow is the time for all good men to come to the aid of the party" 11115 "Now is the time for all good men to come to the aid of the part"; 11116 CHECK_EQ(String::New(expected_cons), 11117 env->Global()->Get(v8_str("cons"))); 11118 CHECK_EQ(String::New(expected_slice), 11119 env->Global()->Get(v8_str("slice"))); 11120 CHECK_EQ(String::New(expected_slice_on_cons), 11121 env->Global()->Get(v8_str("slice_on_cons"))); 11122 } 11123 i::DeleteArray(two_byte_string); 11124} 11125 11126 11127TEST(CompileExternalTwoByteSource) { 11128 v8::HandleScope scope; 11129 LocalContext context; 11130 11131 // This is a very short list of sources, which currently is to check for a 11132 // regression caused by r2703. 11133 const char* ascii_sources[] = { 11134 "0.5", 11135 "-0.5", // This mainly testes PushBack in the Scanner. 11136 "--0.5", // This mainly testes PushBack in the Scanner. 11137 NULL 11138 }; 11139 11140 // Compile the sources as external two byte strings. 11141 for (int i = 0; ascii_sources[i] != NULL; i++) { 11142 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]); 11143 UC16VectorResource uc16_resource( 11144 i::Vector<const uint16_t>(two_byte_string, 11145 i::StrLength(ascii_sources[i]))); 11146 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource); 11147 v8::Script::Compile(source); 11148 i::DeleteArray(two_byte_string); 11149 } 11150} 11151 11152 11153class RegExpStringModificationTest { 11154 public: 11155 RegExpStringModificationTest() 11156 : block_(i::OS::CreateSemaphore(0)), 11157 morphs_(0), 11158 morphs_during_regexp_(0), 11159 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)), 11160 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {} 11161 ~RegExpStringModificationTest() { delete block_; } 11162 void RunTest() { 11163 regexp_success_ = false; 11164 morph_success_ = false; 11165 11166 // Initialize the contents of two_byte_content_ to be a uc16 representation 11167 // of "aaaaaaaaaaaaaab". 11168 for (int i = 0; i < 14; i++) { 11169 two_byte_content_[i] = 'a'; 11170 } 11171 two_byte_content_[14] = 'b'; 11172 11173 // Create the input string for the regexp - the one we are going to change 11174 // properties of. 11175 input_ = FACTORY->NewExternalStringFromAscii(&ascii_resource_); 11176 11177 // Inject the input as a global variable. 11178 i::Handle<i::String> input_name = 11179 FACTORY->NewStringFromAscii(i::Vector<const char>("input", 5)); 11180 i::Isolate::Current()->global_context()->global()->SetProperty( 11181 *input_name, 11182 *input_, 11183 NONE, 11184 i::kNonStrictMode)->ToObjectChecked(); 11185 11186 MorphThread morph_thread(this); 11187 morph_thread.Start(); 11188 v8::Locker::StartPreemption(1); 11189 LongRunningRegExp(); 11190 { 11191 v8::Unlocker unlock; 11192 morph_thread.Join(); 11193 } 11194 v8::Locker::StopPreemption(); 11195 CHECK(regexp_success_); 11196 CHECK(morph_success_); 11197 } 11198 11199 private: 11200 // Number of string modifications required. 11201 static const int kRequiredModifications = 5; 11202 static const int kMaxModifications = 100; 11203 11204 class MorphThread : public i::Thread { 11205 public: 11206 explicit MorphThread(RegExpStringModificationTest* test) 11207 : Thread("MorphThread"), test_(test) {} 11208 virtual void Run() { 11209 test_->MorphString(); 11210 } 11211 private: 11212 RegExpStringModificationTest* test_; 11213 }; 11214 11215 void MorphString() { 11216 block_->Wait(); 11217 while (morphs_during_regexp_ < kRequiredModifications && 11218 morphs_ < kMaxModifications) { 11219 { 11220 v8::Locker lock; 11221 // Swap string between ascii and two-byte representation. 11222 i::String* string = *input_; 11223 MorphAString(string, &ascii_resource_, &uc16_resource_); 11224 morphs_++; 11225 } 11226 i::OS::Sleep(1); 11227 } 11228 morph_success_ = true; 11229 } 11230 11231 void LongRunningRegExp() { 11232 block_->Signal(); // Enable morphing thread on next preemption. 11233 while (morphs_during_regexp_ < kRequiredModifications && 11234 morphs_ < kMaxModifications) { 11235 int morphs_before = morphs_; 11236 { 11237 v8::HandleScope scope; 11238 // Match 15-30 "a"'s against 14 and a "b". 11239 const char* c_source = 11240 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" 11241 ".exec(input) === null"; 11242 Local<String> source = String::New(c_source); 11243 Local<Script> script = Script::Compile(source); 11244 Local<Value> result = script->Run(); 11245 CHECK(result->IsTrue()); 11246 } 11247 int morphs_after = morphs_; 11248 morphs_during_regexp_ += morphs_after - morphs_before; 11249 } 11250 regexp_success_ = true; 11251 } 11252 11253 i::uc16 two_byte_content_[15]; 11254 i::Semaphore* block_; 11255 int morphs_; 11256 int morphs_during_regexp_; 11257 bool regexp_success_; 11258 bool morph_success_; 11259 i::Handle<i::String> input_; 11260 AsciiVectorResource ascii_resource_; 11261 UC16VectorResource uc16_resource_; 11262}; 11263 11264 11265// Test that a regular expression execution can be interrupted and 11266// the string changed without failing. 11267TEST(RegExpStringModification) { 11268 v8::Locker lock; 11269 v8::V8::Initialize(); 11270 v8::HandleScope scope; 11271 Local<Context> local_env; 11272 { 11273 LocalContext env; 11274 local_env = env.local(); 11275 } 11276 11277 // Local context should still be live. 11278 CHECK(!local_env.IsEmpty()); 11279 local_env->Enter(); 11280 11281 // Should complete without problems. 11282 RegExpStringModificationTest().RunTest(); 11283 11284 local_env->Exit(); 11285} 11286 11287 11288// Test that we can set a property on the global object even if there 11289// is a read-only property in the prototype chain. 11290TEST(ReadOnlyPropertyInGlobalProto) { 11291 v8::HandleScope scope; 11292 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 11293 LocalContext context(0, templ); 11294 v8::Handle<v8::Object> global = context->Global(); 11295 v8::Handle<v8::Object> global_proto = 11296 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__"))); 11297 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly); 11298 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly); 11299 // Check without 'eval' or 'with'. 11300 v8::Handle<v8::Value> res = 11301 CompileRun("function f() { x = 42; return x; }; f()"); 11302 // Check with 'eval'. 11303 res = CompileRun("function f() { eval('1'); y = 42; return y; }; f()"); 11304 CHECK_EQ(v8::Integer::New(42), res); 11305 // Check with 'with'. 11306 res = CompileRun("function f() { with (this) { y = 42 }; return y; }; f()"); 11307 CHECK_EQ(v8::Integer::New(42), res); 11308} 11309 11310static int force_set_set_count = 0; 11311static int force_set_get_count = 0; 11312bool pass_on_get = false; 11313 11314static v8::Handle<v8::Value> ForceSetGetter(v8::Local<v8::String> name, 11315 const v8::AccessorInfo& info) { 11316 force_set_get_count++; 11317 if (pass_on_get) { 11318 return v8::Handle<v8::Value>(); 11319 } else { 11320 return v8::Int32::New(3); 11321 } 11322} 11323 11324static void ForceSetSetter(v8::Local<v8::String> name, 11325 v8::Local<v8::Value> value, 11326 const v8::AccessorInfo& info) { 11327 force_set_set_count++; 11328} 11329 11330static v8::Handle<v8::Value> ForceSetInterceptSetter( 11331 v8::Local<v8::String> name, 11332 v8::Local<v8::Value> value, 11333 const v8::AccessorInfo& info) { 11334 force_set_set_count++; 11335 return v8::Undefined(); 11336} 11337 11338TEST(ForceSet) { 11339 force_set_get_count = 0; 11340 force_set_set_count = 0; 11341 pass_on_get = false; 11342 11343 v8::HandleScope scope; 11344 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 11345 v8::Handle<v8::String> access_property = v8::String::New("a"); 11346 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter); 11347 LocalContext context(NULL, templ); 11348 v8::Handle<v8::Object> global = context->Global(); 11349 11350 // Ordinary properties 11351 v8::Handle<v8::String> simple_property = v8::String::New("p"); 11352 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly); 11353 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 11354 // This should fail because the property is read-only 11355 global->Set(simple_property, v8::Int32::New(5)); 11356 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 11357 // This should succeed even though the property is read-only 11358 global->ForceSet(simple_property, v8::Int32::New(6)); 11359 CHECK_EQ(6, global->Get(simple_property)->Int32Value()); 11360 11361 // Accessors 11362 CHECK_EQ(0, force_set_set_count); 11363 CHECK_EQ(0, force_set_get_count); 11364 CHECK_EQ(3, global->Get(access_property)->Int32Value()); 11365 // CHECK_EQ the property shouldn't override it, just call the setter 11366 // which in this case does nothing. 11367 global->Set(access_property, v8::Int32::New(7)); 11368 CHECK_EQ(3, global->Get(access_property)->Int32Value()); 11369 CHECK_EQ(1, force_set_set_count); 11370 CHECK_EQ(2, force_set_get_count); 11371 // Forcing the property to be set should override the accessor without 11372 // calling it 11373 global->ForceSet(access_property, v8::Int32::New(8)); 11374 CHECK_EQ(8, global->Get(access_property)->Int32Value()); 11375 CHECK_EQ(1, force_set_set_count); 11376 CHECK_EQ(2, force_set_get_count); 11377} 11378 11379TEST(ForceSetWithInterceptor) { 11380 force_set_get_count = 0; 11381 force_set_set_count = 0; 11382 pass_on_get = false; 11383 11384 v8::HandleScope scope; 11385 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 11386 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter); 11387 LocalContext context(NULL, templ); 11388 v8::Handle<v8::Object> global = context->Global(); 11389 11390 v8::Handle<v8::String> some_property = v8::String::New("a"); 11391 CHECK_EQ(0, force_set_set_count); 11392 CHECK_EQ(0, force_set_get_count); 11393 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 11394 // Setting the property shouldn't override it, just call the setter 11395 // which in this case does nothing. 11396 global->Set(some_property, v8::Int32::New(7)); 11397 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 11398 CHECK_EQ(1, force_set_set_count); 11399 CHECK_EQ(2, force_set_get_count); 11400 // Getting the property when the interceptor returns an empty handle 11401 // should yield undefined, since the property isn't present on the 11402 // object itself yet. 11403 pass_on_get = true; 11404 CHECK(global->Get(some_property)->IsUndefined()); 11405 CHECK_EQ(1, force_set_set_count); 11406 CHECK_EQ(3, force_set_get_count); 11407 // Forcing the property to be set should cause the value to be 11408 // set locally without calling the interceptor. 11409 global->ForceSet(some_property, v8::Int32::New(8)); 11410 CHECK_EQ(8, global->Get(some_property)->Int32Value()); 11411 CHECK_EQ(1, force_set_set_count); 11412 CHECK_EQ(4, force_set_get_count); 11413 // Reenabling the interceptor should cause it to take precedence over 11414 // the property 11415 pass_on_get = false; 11416 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 11417 CHECK_EQ(1, force_set_set_count); 11418 CHECK_EQ(5, force_set_get_count); 11419 // The interceptor should also work for other properties 11420 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value()); 11421 CHECK_EQ(1, force_set_set_count); 11422 CHECK_EQ(6, force_set_get_count); 11423} 11424 11425 11426THREADED_TEST(ForceDelete) { 11427 v8::HandleScope scope; 11428 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 11429 LocalContext context(NULL, templ); 11430 v8::Handle<v8::Object> global = context->Global(); 11431 11432 // Ordinary properties 11433 v8::Handle<v8::String> simple_property = v8::String::New("p"); 11434 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete); 11435 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 11436 // This should fail because the property is dont-delete. 11437 CHECK(!global->Delete(simple_property)); 11438 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 11439 // This should succeed even though the property is dont-delete. 11440 CHECK(global->ForceDelete(simple_property)); 11441 CHECK(global->Get(simple_property)->IsUndefined()); 11442} 11443 11444 11445static int force_delete_interceptor_count = 0; 11446static bool pass_on_delete = false; 11447 11448 11449static v8::Handle<v8::Boolean> ForceDeleteDeleter( 11450 v8::Local<v8::String> name, 11451 const v8::AccessorInfo& info) { 11452 force_delete_interceptor_count++; 11453 if (pass_on_delete) { 11454 return v8::Handle<v8::Boolean>(); 11455 } else { 11456 return v8::True(); 11457 } 11458} 11459 11460 11461THREADED_TEST(ForceDeleteWithInterceptor) { 11462 force_delete_interceptor_count = 0; 11463 pass_on_delete = false; 11464 11465 v8::HandleScope scope; 11466 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 11467 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter); 11468 LocalContext context(NULL, templ); 11469 v8::Handle<v8::Object> global = context->Global(); 11470 11471 v8::Handle<v8::String> some_property = v8::String::New("a"); 11472 global->Set(some_property, v8::Integer::New(42), v8::DontDelete); 11473 11474 // Deleting a property should get intercepted and nothing should 11475 // happen. 11476 CHECK_EQ(0, force_delete_interceptor_count); 11477 CHECK(global->Delete(some_property)); 11478 CHECK_EQ(1, force_delete_interceptor_count); 11479 CHECK_EQ(42, global->Get(some_property)->Int32Value()); 11480 // Deleting the property when the interceptor returns an empty 11481 // handle should not delete the property since it is DontDelete. 11482 pass_on_delete = true; 11483 CHECK(!global->Delete(some_property)); 11484 CHECK_EQ(2, force_delete_interceptor_count); 11485 CHECK_EQ(42, global->Get(some_property)->Int32Value()); 11486 // Forcing the property to be deleted should delete the value 11487 // without calling the interceptor. 11488 CHECK(global->ForceDelete(some_property)); 11489 CHECK(global->Get(some_property)->IsUndefined()); 11490 CHECK_EQ(2, force_delete_interceptor_count); 11491} 11492 11493 11494// Make sure that forcing a delete invalidates any IC stubs, so we 11495// don't read the hole value. 11496THREADED_TEST(ForceDeleteIC) { 11497 v8::HandleScope scope; 11498 LocalContext context; 11499 // Create a DontDelete variable on the global object. 11500 CompileRun("this.__proto__ = { foo: 'horse' };" 11501 "var foo = 'fish';" 11502 "function f() { return foo.length; }"); 11503 // Initialize the IC for foo in f. 11504 CompileRun("for (var i = 0; i < 4; i++) f();"); 11505 // Make sure the value of foo is correct before the deletion. 11506 CHECK_EQ(4, CompileRun("f()")->Int32Value()); 11507 // Force the deletion of foo. 11508 CHECK(context->Global()->ForceDelete(v8_str("foo"))); 11509 // Make sure the value for foo is read from the prototype, and that 11510 // we don't get in trouble with reading the deleted cell value 11511 // sentinel. 11512 CHECK_EQ(5, CompileRun("f()")->Int32Value()); 11513} 11514 11515 11516v8::Persistent<Context> calling_context0; 11517v8::Persistent<Context> calling_context1; 11518v8::Persistent<Context> calling_context2; 11519 11520 11521// Check that the call to the callback is initiated in 11522// calling_context2, the directly calling context is calling_context1 11523// and the callback itself is in calling_context0. 11524static v8::Handle<Value> GetCallingContextCallback(const v8::Arguments& args) { 11525 ApiTestFuzzer::Fuzz(); 11526 CHECK(Context::GetCurrent() == calling_context0); 11527 CHECK(Context::GetCalling() == calling_context1); 11528 CHECK(Context::GetEntered() == calling_context2); 11529 return v8::Integer::New(42); 11530} 11531 11532 11533THREADED_TEST(GetCallingContext) { 11534 v8::HandleScope scope; 11535 11536 calling_context0 = Context::New(); 11537 calling_context1 = Context::New(); 11538 calling_context2 = Context::New(); 11539 11540 // Allow cross-domain access. 11541 Local<String> token = v8_str("<security token>"); 11542 calling_context0->SetSecurityToken(token); 11543 calling_context1->SetSecurityToken(token); 11544 calling_context2->SetSecurityToken(token); 11545 11546 // Create an object with a C++ callback in context0. 11547 calling_context0->Enter(); 11548 Local<v8::FunctionTemplate> callback_templ = 11549 v8::FunctionTemplate::New(GetCallingContextCallback); 11550 calling_context0->Global()->Set(v8_str("callback"), 11551 callback_templ->GetFunction()); 11552 calling_context0->Exit(); 11553 11554 // Expose context0 in context1 and setup a function that calls the 11555 // callback function. 11556 calling_context1->Enter(); 11557 calling_context1->Global()->Set(v8_str("context0"), 11558 calling_context0->Global()); 11559 CompileRun("function f() { context0.callback() }"); 11560 calling_context1->Exit(); 11561 11562 // Expose context1 in context2 and call the callback function in 11563 // context0 indirectly through f in context1. 11564 calling_context2->Enter(); 11565 calling_context2->Global()->Set(v8_str("context1"), 11566 calling_context1->Global()); 11567 CompileRun("context1.f()"); 11568 calling_context2->Exit(); 11569 11570 // Dispose the contexts to allow them to be garbage collected. 11571 calling_context0.Dispose(); 11572 calling_context1.Dispose(); 11573 calling_context2.Dispose(); 11574 calling_context0.Clear(); 11575 calling_context1.Clear(); 11576 calling_context2.Clear(); 11577} 11578 11579 11580// Check that a variable declaration with no explicit initialization 11581// value does not shadow an existing property in the prototype chain. 11582// 11583// This is consistent with Firefox and Safari. 11584// 11585// See http://crbug.com/12548. 11586THREADED_TEST(InitGlobalVarInProtoChain) { 11587 v8::HandleScope scope; 11588 LocalContext context; 11589 // Introduce a variable in the prototype chain. 11590 CompileRun("__proto__.x = 42"); 11591 v8::Handle<v8::Value> result = CompileRun("var x; x"); 11592 CHECK(!result->IsUndefined()); 11593 CHECK_EQ(42, result->Int32Value()); 11594} 11595 11596 11597// Regression test for issue 398. 11598// If a function is added to an object, creating a constant function 11599// field, and the result is cloned, replacing the constant function on the 11600// original should not affect the clone. 11601// See http://code.google.com/p/v8/issues/detail?id=398 11602THREADED_TEST(ReplaceConstantFunction) { 11603 v8::HandleScope scope; 11604 LocalContext context; 11605 v8::Handle<v8::Object> obj = v8::Object::New(); 11606 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New(); 11607 v8::Handle<v8::String> foo_string = v8::String::New("foo"); 11608 obj->Set(foo_string, func_templ->GetFunction()); 11609 v8::Handle<v8::Object> obj_clone = obj->Clone(); 11610 obj_clone->Set(foo_string, v8::String::New("Hello")); 11611 CHECK(!obj->Get(foo_string)->IsUndefined()); 11612} 11613 11614 11615// Regression test for http://crbug.com/16276. 11616THREADED_TEST(Regress16276) { 11617 v8::HandleScope scope; 11618 LocalContext context; 11619 // Force the IC in f to be a dictionary load IC. 11620 CompileRun("function f(obj) { return obj.x; }\n" 11621 "var obj = { x: { foo: 42 }, y: 87 };\n" 11622 "var x = obj.x;\n" 11623 "delete obj.y;\n" 11624 "for (var i = 0; i < 5; i++) f(obj);"); 11625 // Detach the global object to make 'this' refer directly to the 11626 // global object (not the proxy), and make sure that the dictionary 11627 // load IC doesn't mess up loading directly from the global object. 11628 context->DetachGlobal(); 11629 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value()); 11630} 11631 11632 11633THREADED_TEST(PixelArray) { 11634 v8::HandleScope scope; 11635 LocalContext context; 11636 const int kElementCount = 260; 11637 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount)); 11638 i::Handle<i::ExternalPixelArray> pixels = 11639 i::Handle<i::ExternalPixelArray>::cast( 11640 FACTORY->NewExternalArray(kElementCount, 11641 v8::kExternalPixelArray, 11642 pixel_data)); 11643 HEAP->CollectAllGarbage(false); // Force GC to trigger verification. 11644 for (int i = 0; i < kElementCount; i++) { 11645 pixels->set(i, i % 256); 11646 } 11647 HEAP->CollectAllGarbage(false); // Force GC to trigger verification. 11648 for (int i = 0; i < kElementCount; i++) { 11649 CHECK_EQ(i % 256, pixels->get(i)); 11650 CHECK_EQ(i % 256, pixel_data[i]); 11651 } 11652 11653 v8::Handle<v8::Object> obj = v8::Object::New(); 11654 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 11655 // Set the elements to be the pixels. 11656 // jsobj->set_elements(*pixels); 11657 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount); 11658 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); 11659 obj->Set(v8_str("field"), v8::Int32::New(1503)); 11660 context->Global()->Set(v8_str("pixels"), obj); 11661 v8::Handle<v8::Value> result = CompileRun("pixels.field"); 11662 CHECK_EQ(1503, result->Int32Value()); 11663 result = CompileRun("pixels[1]"); 11664 CHECK_EQ(1, result->Int32Value()); 11665 11666 result = CompileRun("var sum = 0;" 11667 "for (var i = 0; i < 8; i++) {" 11668 " sum += pixels[i] = pixels[i] = -i;" 11669 "}" 11670 "sum;"); 11671 CHECK_EQ(-28, result->Int32Value()); 11672 11673 result = CompileRun("var sum = 0;" 11674 "for (var i = 0; i < 8; i++) {" 11675 " sum += pixels[i] = pixels[i] = 0;" 11676 "}" 11677 "sum;"); 11678 CHECK_EQ(0, result->Int32Value()); 11679 11680 result = CompileRun("var sum = 0;" 11681 "for (var i = 0; i < 8; i++) {" 11682 " sum += pixels[i] = pixels[i] = 255;" 11683 "}" 11684 "sum;"); 11685 CHECK_EQ(8 * 255, result->Int32Value()); 11686 11687 result = CompileRun("var sum = 0;" 11688 "for (var i = 0; i < 8; i++) {" 11689 " sum += pixels[i] = pixels[i] = 256 + i;" 11690 "}" 11691 "sum;"); 11692 CHECK_EQ(2076, result->Int32Value()); 11693 11694 result = CompileRun("var sum = 0;" 11695 "for (var i = 0; i < 8; i++) {" 11696 " sum += pixels[i] = pixels[i] = i;" 11697 "}" 11698 "sum;"); 11699 CHECK_EQ(28, result->Int32Value()); 11700 11701 result = CompileRun("var sum = 0;" 11702 "for (var i = 0; i < 8; i++) {" 11703 " sum += pixels[i];" 11704 "}" 11705 "sum;"); 11706 CHECK_EQ(28, result->Int32Value()); 11707 11708 i::Handle<i::Smi> value(i::Smi::FromInt(2)); 11709 i::SetElement(jsobj, 1, value, i::kNonStrictMode); 11710 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); 11711 *value.location() = i::Smi::FromInt(256); 11712 i::SetElement(jsobj, 1, value, i::kNonStrictMode); 11713 CHECK_EQ(255, 11714 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); 11715 *value.location() = i::Smi::FromInt(-1); 11716 i::SetElement(jsobj, 1, value, i::kNonStrictMode); 11717 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); 11718 11719 result = CompileRun("for (var i = 0; i < 8; i++) {" 11720 " pixels[i] = (i * 65) - 109;" 11721 "}" 11722 "pixels[1] + pixels[6];"); 11723 CHECK_EQ(255, result->Int32Value()); 11724 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value()); 11725 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); 11726 CHECK_EQ(21, 11727 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value()); 11728 CHECK_EQ(86, 11729 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value()); 11730 CHECK_EQ(151, 11731 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value()); 11732 CHECK_EQ(216, 11733 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value()); 11734 CHECK_EQ(255, 11735 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value()); 11736 CHECK_EQ(255, 11737 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value()); 11738 result = CompileRun("var sum = 0;" 11739 "for (var i = 0; i < 8; i++) {" 11740 " sum += pixels[i];" 11741 "}" 11742 "sum;"); 11743 CHECK_EQ(984, result->Int32Value()); 11744 11745 result = CompileRun("for (var i = 0; i < 8; i++) {" 11746 " pixels[i] = (i * 1.1);" 11747 "}" 11748 "pixels[1] + pixels[6];"); 11749 CHECK_EQ(8, result->Int32Value()); 11750 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value()); 11751 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); 11752 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value()); 11753 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value()); 11754 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value()); 11755 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value()); 11756 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value()); 11757 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value()); 11758 11759 result = CompileRun("for (var i = 0; i < 8; i++) {" 11760 " pixels[7] = undefined;" 11761 "}" 11762 "pixels[7];"); 11763 CHECK_EQ(0, result->Int32Value()); 11764 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value()); 11765 11766 result = CompileRun("for (var i = 0; i < 8; i++) {" 11767 " pixels[6] = '2.3';" 11768 "}" 11769 "pixels[6];"); 11770 CHECK_EQ(2, result->Int32Value()); 11771 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value()); 11772 11773 result = CompileRun("for (var i = 0; i < 8; i++) {" 11774 " pixels[5] = NaN;" 11775 "}" 11776 "pixels[5];"); 11777 CHECK_EQ(0, result->Int32Value()); 11778 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value()); 11779 11780 result = CompileRun("for (var i = 0; i < 8; i++) {" 11781 " pixels[8] = Infinity;" 11782 "}" 11783 "pixels[8];"); 11784 CHECK_EQ(255, result->Int32Value()); 11785 CHECK_EQ(255, 11786 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value()); 11787 11788 result = CompileRun("for (var i = 0; i < 8; i++) {" 11789 " pixels[9] = -Infinity;" 11790 "}" 11791 "pixels[9];"); 11792 CHECK_EQ(0, result->Int32Value()); 11793 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value()); 11794 11795 result = CompileRun("pixels[3] = 33;" 11796 "delete pixels[3];" 11797 "pixels[3];"); 11798 CHECK_EQ(33, result->Int32Value()); 11799 11800 result = CompileRun("pixels[0] = 10; pixels[1] = 11;" 11801 "pixels[2] = 12; pixels[3] = 13;" 11802 "pixels.__defineGetter__('2'," 11803 "function() { return 120; });" 11804 "pixels[2];"); 11805 CHECK_EQ(12, result->Int32Value()); 11806 11807 result = CompileRun("var js_array = new Array(40);" 11808 "js_array[0] = 77;" 11809 "js_array;"); 11810 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 11811 11812 result = CompileRun("pixels[1] = 23;" 11813 "pixels.__proto__ = [];" 11814 "js_array.__proto__ = pixels;" 11815 "js_array.concat(pixels);"); 11816 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 11817 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value()); 11818 11819 result = CompileRun("pixels[1] = 23;"); 11820 CHECK_EQ(23, result->Int32Value()); 11821 11822 // Test for index greater than 255. Regression test for: 11823 // http://code.google.com/p/chromium/issues/detail?id=26337. 11824 result = CompileRun("pixels[256] = 255;"); 11825 CHECK_EQ(255, result->Int32Value()); 11826 result = CompileRun("var i = 0;" 11827 "for (var j = 0; j < 8; j++) { i = pixels[256]; }" 11828 "i"); 11829 CHECK_EQ(255, result->Int32Value()); 11830 11831 // Make sure that pixel array ICs recognize when a non-pixel array 11832 // is passed to it. 11833 result = CompileRun("function pa_load(p) {" 11834 " var sum = 0;" 11835 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 11836 " return sum;" 11837 "}" 11838 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 11839 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }" 11840 "just_ints = new Object();" 11841 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 11842 "for (var i = 0; i < 10; ++i) {" 11843 " result = pa_load(just_ints);" 11844 "}" 11845 "result"); 11846 CHECK_EQ(32640, result->Int32Value()); 11847 11848 // Make sure that pixel array ICs recognize out-of-bound accesses. 11849 result = CompileRun("function pa_load(p, start) {" 11850 " var sum = 0;" 11851 " for (var j = start; j < 256; j++) { sum += p[j]; }" 11852 " return sum;" 11853 "}" 11854 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 11855 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }" 11856 "for (var i = 0; i < 10; ++i) {" 11857 " result = pa_load(pixels,-10);" 11858 "}" 11859 "result"); 11860 CHECK_EQ(0, result->Int32Value()); 11861 11862 // Make sure that generic ICs properly handles a pixel array. 11863 result = CompileRun("function pa_load(p) {" 11864 " var sum = 0;" 11865 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 11866 " return sum;" 11867 "}" 11868 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 11869 "just_ints = new Object();" 11870 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 11871 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }" 11872 "for (var i = 0; i < 10; ++i) {" 11873 " result = pa_load(pixels);" 11874 "}" 11875 "result"); 11876 CHECK_EQ(32640, result->Int32Value()); 11877 11878 // Make sure that generic load ICs recognize out-of-bound accesses in 11879 // pixel arrays. 11880 result = CompileRun("function pa_load(p, start) {" 11881 " var sum = 0;" 11882 " for (var j = start; j < 256; j++) { sum += p[j]; }" 11883 " return sum;" 11884 "}" 11885 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 11886 "just_ints = new Object();" 11887 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 11888 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }" 11889 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }" 11890 "for (var i = 0; i < 10; ++i) {" 11891 " result = pa_load(pixels,-10);" 11892 "}" 11893 "result"); 11894 CHECK_EQ(0, result->Int32Value()); 11895 11896 // Make sure that generic ICs properly handles other types than pixel 11897 // arrays (that the inlined fast pixel array test leaves the right information 11898 // in the right registers). 11899 result = CompileRun("function pa_load(p) {" 11900 " var sum = 0;" 11901 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 11902 " return sum;" 11903 "}" 11904 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 11905 "just_ints = new Object();" 11906 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 11907 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }" 11908 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }" 11909 "sparse_array = new Object();" 11910 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }" 11911 "sparse_array[1000000] = 3;" 11912 "for (var i = 0; i < 10; ++i) {" 11913 " result = pa_load(sparse_array);" 11914 "}" 11915 "result"); 11916 CHECK_EQ(32640, result->Int32Value()); 11917 11918 // Make sure that pixel array store ICs clamp values correctly. 11919 result = CompileRun("function pa_store(p) {" 11920 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }" 11921 "}" 11922 "pa_store(pixels);" 11923 "var sum = 0;" 11924 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 11925 "sum"); 11926 CHECK_EQ(48896, result->Int32Value()); 11927 11928 // Make sure that pixel array stores correctly handle accesses outside 11929 // of the pixel array.. 11930 result = CompileRun("function pa_store(p,start) {" 11931 " for (var j = 0; j < 256; j++) {" 11932 " p[j+start] = j * 2;" 11933 " }" 11934 "}" 11935 "pa_store(pixels,0);" 11936 "pa_store(pixels,-128);" 11937 "var sum = 0;" 11938 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 11939 "sum"); 11940 CHECK_EQ(65280, result->Int32Value()); 11941 11942 // Make sure that the generic store stub correctly handle accesses outside 11943 // of the pixel array.. 11944 result = CompileRun("function pa_store(p,start) {" 11945 " for (var j = 0; j < 256; j++) {" 11946 " p[j+start] = j * 2;" 11947 " }" 11948 "}" 11949 "pa_store(pixels,0);" 11950 "just_ints = new Object();" 11951 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 11952 "pa_store(just_ints, 0);" 11953 "pa_store(pixels,-128);" 11954 "var sum = 0;" 11955 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 11956 "sum"); 11957 CHECK_EQ(65280, result->Int32Value()); 11958 11959 // Make sure that the generic keyed store stub clamps pixel array values 11960 // correctly. 11961 result = CompileRun("function pa_store(p) {" 11962 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }" 11963 "}" 11964 "pa_store(pixels);" 11965 "just_ints = new Object();" 11966 "pa_store(just_ints);" 11967 "pa_store(pixels);" 11968 "var sum = 0;" 11969 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 11970 "sum"); 11971 CHECK_EQ(48896, result->Int32Value()); 11972 11973 // Make sure that pixel array loads are optimized by crankshaft. 11974 result = CompileRun("function pa_load(p) {" 11975 " var sum = 0;" 11976 " for (var i=0; i<256; ++i) {" 11977 " sum += p[i];" 11978 " }" 11979 " return sum; " 11980 "}" 11981 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 11982 "for (var i = 0; i < 5000; ++i) {" 11983 " result = pa_load(pixels);" 11984 "}" 11985 "result"); 11986 CHECK_EQ(32640, result->Int32Value()); 11987 11988 // Make sure that pixel array stores are optimized by crankshaft. 11989 result = CompileRun("function pa_init(p) {" 11990 "for (var i = 0; i < 256; ++i) { p[i] = i; }" 11991 "}" 11992 "function pa_load(p) {" 11993 " var sum = 0;" 11994 " for (var i=0; i<256; ++i) {" 11995 " sum += p[i];" 11996 " }" 11997 " return sum; " 11998 "}" 11999 "for (var i = 0; i < 5000; ++i) {" 12000 " pa_init(pixels);" 12001 "}" 12002 "result = pa_load(pixels);" 12003 "result"); 12004 CHECK_EQ(32640, result->Int32Value()); 12005 12006 free(pixel_data); 12007} 12008 12009 12010THREADED_TEST(PixelArrayInfo) { 12011 v8::HandleScope scope; 12012 LocalContext context; 12013 for (int size = 0; size < 100; size += 10) { 12014 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size)); 12015 v8::Handle<v8::Object> obj = v8::Object::New(); 12016 obj->SetIndexedPropertiesToPixelData(pixel_data, size); 12017 CHECK(obj->HasIndexedPropertiesInPixelData()); 12018 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData()); 12019 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength()); 12020 free(pixel_data); 12021 } 12022} 12023 12024 12025static v8::Handle<Value> NotHandledIndexedPropertyGetter( 12026 uint32_t index, 12027 const AccessorInfo& info) { 12028 ApiTestFuzzer::Fuzz(); 12029 return v8::Handle<Value>(); 12030} 12031 12032 12033static v8::Handle<Value> NotHandledIndexedPropertySetter( 12034 uint32_t index, 12035 Local<Value> value, 12036 const AccessorInfo& info) { 12037 ApiTestFuzzer::Fuzz(); 12038 return v8::Handle<Value>(); 12039} 12040 12041 12042THREADED_TEST(PixelArrayWithInterceptor) { 12043 v8::HandleScope scope; 12044 LocalContext context; 12045 const int kElementCount = 260; 12046 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount)); 12047 i::Handle<i::ExternalPixelArray> pixels = 12048 i::Handle<i::ExternalPixelArray>::cast( 12049 FACTORY->NewExternalArray(kElementCount, 12050 v8::kExternalPixelArray, 12051 pixel_data)); 12052 for (int i = 0; i < kElementCount; i++) { 12053 pixels->set(i, i % 256); 12054 } 12055 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 12056 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter, 12057 NotHandledIndexedPropertySetter); 12058 v8::Handle<v8::Object> obj = templ->NewInstance(); 12059 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount); 12060 context->Global()->Set(v8_str("pixels"), obj); 12061 v8::Handle<v8::Value> result = CompileRun("pixels[1]"); 12062 CHECK_EQ(1, result->Int32Value()); 12063 result = CompileRun("var sum = 0;" 12064 "for (var i = 0; i < 8; i++) {" 12065 " sum += pixels[i] = pixels[i] = -i;" 12066 "}" 12067 "sum;"); 12068 CHECK_EQ(-28, result->Int32Value()); 12069 result = CompileRun("pixels.hasOwnProperty('1')"); 12070 CHECK(result->BooleanValue()); 12071 free(pixel_data); 12072} 12073 12074 12075static int ExternalArrayElementSize(v8::ExternalArrayType array_type) { 12076 switch (array_type) { 12077 case v8::kExternalByteArray: 12078 case v8::kExternalUnsignedByteArray: 12079 case v8::kExternalPixelArray: 12080 return 1; 12081 break; 12082 case v8::kExternalShortArray: 12083 case v8::kExternalUnsignedShortArray: 12084 return 2; 12085 break; 12086 case v8::kExternalIntArray: 12087 case v8::kExternalUnsignedIntArray: 12088 case v8::kExternalFloatArray: 12089 return 4; 12090 break; 12091 case v8::kExternalDoubleArray: 12092 return 8; 12093 break; 12094 default: 12095 UNREACHABLE(); 12096 return -1; 12097 } 12098 UNREACHABLE(); 12099 return -1; 12100} 12101 12102 12103template <class ExternalArrayClass, class ElementType> 12104static void ExternalArrayTestHelper(v8::ExternalArrayType array_type, 12105 int64_t low, 12106 int64_t high) { 12107 v8::HandleScope scope; 12108 LocalContext context; 12109 const int kElementCount = 40; 12110 int element_size = ExternalArrayElementSize(array_type); 12111 ElementType* array_data = 12112 static_cast<ElementType*>(malloc(kElementCount * element_size)); 12113 i::Handle<ExternalArrayClass> array = 12114 i::Handle<ExternalArrayClass>::cast( 12115 FACTORY->NewExternalArray(kElementCount, array_type, array_data)); 12116 HEAP->CollectAllGarbage(false); // Force GC to trigger verification. 12117 for (int i = 0; i < kElementCount; i++) { 12118 array->set(i, static_cast<ElementType>(i)); 12119 } 12120 HEAP->CollectAllGarbage(false); // Force GC to trigger verification. 12121 for (int i = 0; i < kElementCount; i++) { 12122 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array->get(i))); 12123 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i])); 12124 } 12125 12126 v8::Handle<v8::Object> obj = v8::Object::New(); 12127 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 12128 // Set the elements to be the external array. 12129 obj->SetIndexedPropertiesToExternalArrayData(array_data, 12130 array_type, 12131 kElementCount); 12132 CHECK_EQ( 12133 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number())); 12134 obj->Set(v8_str("field"), v8::Int32::New(1503)); 12135 context->Global()->Set(v8_str("ext_array"), obj); 12136 v8::Handle<v8::Value> result = CompileRun("ext_array.field"); 12137 CHECK_EQ(1503, result->Int32Value()); 12138 result = CompileRun("ext_array[1]"); 12139 CHECK_EQ(1, result->Int32Value()); 12140 12141 // Check pass through of assigned smis 12142 result = CompileRun("var sum = 0;" 12143 "for (var i = 0; i < 8; i++) {" 12144 " sum += ext_array[i] = ext_array[i] = -i;" 12145 "}" 12146 "sum;"); 12147 CHECK_EQ(-28, result->Int32Value()); 12148 12149 // Check assigned smis 12150 result = CompileRun("for (var i = 0; i < 8; i++) {" 12151 " ext_array[i] = i;" 12152 "}" 12153 "var sum = 0;" 12154 "for (var i = 0; i < 8; i++) {" 12155 " sum += ext_array[i];" 12156 "}" 12157 "sum;"); 12158 CHECK_EQ(28, result->Int32Value()); 12159 12160 // Check assigned smis in reverse order 12161 result = CompileRun("for (var i = 8; --i >= 0; ) {" 12162 " ext_array[i] = i;" 12163 "}" 12164 "var sum = 0;" 12165 "for (var i = 0; i < 8; i++) {" 12166 " sum += ext_array[i];" 12167 "}" 12168 "sum;"); 12169 CHECK_EQ(28, result->Int32Value()); 12170 12171 // Check pass through of assigned HeapNumbers 12172 result = CompileRun("var sum = 0;" 12173 "for (var i = 0; i < 16; i+=2) {" 12174 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);" 12175 "}" 12176 "sum;"); 12177 CHECK_EQ(-28, result->Int32Value()); 12178 12179 // Check assigned HeapNumbers 12180 result = CompileRun("for (var i = 0; i < 16; i+=2) {" 12181 " ext_array[i] = (i * 0.5);" 12182 "}" 12183 "var sum = 0;" 12184 "for (var i = 0; i < 16; i+=2) {" 12185 " sum += ext_array[i];" 12186 "}" 12187 "sum;"); 12188 CHECK_EQ(28, result->Int32Value()); 12189 12190 // Check assigned HeapNumbers in reverse order 12191 result = CompileRun("for (var i = 14; i >= 0; i-=2) {" 12192 " ext_array[i] = (i * 0.5);" 12193 "}" 12194 "var sum = 0;" 12195 "for (var i = 0; i < 16; i+=2) {" 12196 " sum += ext_array[i];" 12197 "}" 12198 "sum;"); 12199 CHECK_EQ(28, result->Int32Value()); 12200 12201 i::ScopedVector<char> test_buf(1024); 12202 12203 // Check legal boundary conditions. 12204 // The repeated loads and stores ensure the ICs are exercised. 12205 const char* boundary_program = 12206 "var res = 0;" 12207 "for (var i = 0; i < 16; i++) {" 12208 " ext_array[i] = %lld;" 12209 " if (i > 8) {" 12210 " res = ext_array[i];" 12211 " }" 12212 "}" 12213 "res;"; 12214 i::OS::SNPrintF(test_buf, 12215 boundary_program, 12216 low); 12217 result = CompileRun(test_buf.start()); 12218 CHECK_EQ(low, result->IntegerValue()); 12219 12220 i::OS::SNPrintF(test_buf, 12221 boundary_program, 12222 high); 12223 result = CompileRun(test_buf.start()); 12224 CHECK_EQ(high, result->IntegerValue()); 12225 12226 // Check misprediction of type in IC. 12227 result = CompileRun("var tmp_array = ext_array;" 12228 "var sum = 0;" 12229 "for (var i = 0; i < 8; i++) {" 12230 " tmp_array[i] = i;" 12231 " sum += tmp_array[i];" 12232 " if (i == 4) {" 12233 " tmp_array = {};" 12234 " }" 12235 "}" 12236 "sum;"); 12237 HEAP->CollectAllGarbage(false); // Force GC to trigger verification. 12238 CHECK_EQ(28, result->Int32Value()); 12239 12240 // Make sure out-of-range loads do not throw. 12241 i::OS::SNPrintF(test_buf, 12242 "var caught_exception = false;" 12243 "try {" 12244 " ext_array[%d];" 12245 "} catch (e) {" 12246 " caught_exception = true;" 12247 "}" 12248 "caught_exception;", 12249 kElementCount); 12250 result = CompileRun(test_buf.start()); 12251 CHECK_EQ(false, result->BooleanValue()); 12252 12253 // Make sure out-of-range stores do not throw. 12254 i::OS::SNPrintF(test_buf, 12255 "var caught_exception = false;" 12256 "try {" 12257 " ext_array[%d] = 1;" 12258 "} catch (e) {" 12259 " caught_exception = true;" 12260 "}" 12261 "caught_exception;", 12262 kElementCount); 12263 result = CompileRun(test_buf.start()); 12264 CHECK_EQ(false, result->BooleanValue()); 12265 12266 // Check other boundary conditions, values and operations. 12267 result = CompileRun("for (var i = 0; i < 8; i++) {" 12268 " ext_array[7] = undefined;" 12269 "}" 12270 "ext_array[7];"); 12271 CHECK_EQ(0, result->Int32Value()); 12272 CHECK_EQ( 12273 0, static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number())); 12274 12275 result = CompileRun("for (var i = 0; i < 8; i++) {" 12276 " ext_array[6] = '2.3';" 12277 "}" 12278 "ext_array[6];"); 12279 CHECK_EQ(2, result->Int32Value()); 12280 CHECK_EQ( 12281 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number())); 12282 12283 if (array_type != v8::kExternalFloatArray && 12284 array_type != v8::kExternalDoubleArray) { 12285 // Though the specification doesn't state it, be explicit about 12286 // converting NaNs and +/-Infinity to zero. 12287 result = CompileRun("for (var i = 0; i < 8; i++) {" 12288 " ext_array[i] = 5;" 12289 "}" 12290 "for (var i = 0; i < 8; i++) {" 12291 " ext_array[i] = NaN;" 12292 "}" 12293 "ext_array[5];"); 12294 CHECK_EQ(0, result->Int32Value()); 12295 CHECK_EQ(0, 12296 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value()); 12297 12298 result = CompileRun("for (var i = 0; i < 8; i++) {" 12299 " ext_array[i] = 5;" 12300 "}" 12301 "for (var i = 0; i < 8; i++) {" 12302 " ext_array[i] = Infinity;" 12303 "}" 12304 "ext_array[5];"); 12305 int expected_value = 12306 (array_type == v8::kExternalPixelArray) ? 255 : 0; 12307 CHECK_EQ(expected_value, result->Int32Value()); 12308 CHECK_EQ(expected_value, 12309 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value()); 12310 12311 result = CompileRun("for (var i = 0; i < 8; i++) {" 12312 " ext_array[i] = 5;" 12313 "}" 12314 "for (var i = 0; i < 8; i++) {" 12315 " ext_array[i] = -Infinity;" 12316 "}" 12317 "ext_array[5];"); 12318 CHECK_EQ(0, result->Int32Value()); 12319 CHECK_EQ(0, 12320 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value()); 12321 12322 // Check truncation behavior of integral arrays. 12323 const char* unsigned_data = 12324 "var source_data = [0.6, 10.6];" 12325 "var expected_results = [0, 10];"; 12326 const char* signed_data = 12327 "var source_data = [0.6, 10.6, -0.6, -10.6];" 12328 "var expected_results = [0, 10, 0, -10];"; 12329 const char* pixel_data = 12330 "var source_data = [0.6, 10.6];" 12331 "var expected_results = [1, 11];"; 12332 bool is_unsigned = 12333 (array_type == v8::kExternalUnsignedByteArray || 12334 array_type == v8::kExternalUnsignedShortArray || 12335 array_type == v8::kExternalUnsignedIntArray); 12336 bool is_pixel_data = array_type == v8::kExternalPixelArray; 12337 12338 i::OS::SNPrintF(test_buf, 12339 "%s" 12340 "var all_passed = true;" 12341 "for (var i = 0; i < source_data.length; i++) {" 12342 " for (var j = 0; j < 8; j++) {" 12343 " ext_array[j] = source_data[i];" 12344 " }" 12345 " all_passed = all_passed &&" 12346 " (ext_array[5] == expected_results[i]);" 12347 "}" 12348 "all_passed;", 12349 (is_unsigned ? 12350 unsigned_data : 12351 (is_pixel_data ? pixel_data : signed_data))); 12352 result = CompileRun(test_buf.start()); 12353 CHECK_EQ(true, result->BooleanValue()); 12354 } 12355 12356 for (int i = 0; i < kElementCount; i++) { 12357 array->set(i, static_cast<ElementType>(i)); 12358 } 12359 // Test complex assignments 12360 result = CompileRun("function ee_op_test_complex_func(sum) {" 12361 " for (var i = 0; i < 40; ++i) {" 12362 " sum += (ext_array[i] += 1);" 12363 " sum += (ext_array[i] -= 1);" 12364 " } " 12365 " return sum;" 12366 "}" 12367 "sum=0;" 12368 "for (var i=0;i<10000;++i) {" 12369 " sum=ee_op_test_complex_func(sum);" 12370 "}" 12371 "sum;"); 12372 CHECK_EQ(16000000, result->Int32Value()); 12373 12374 // Test count operations 12375 result = CompileRun("function ee_op_test_count_func(sum) {" 12376 " for (var i = 0; i < 40; ++i) {" 12377 " sum += (++ext_array[i]);" 12378 " sum += (--ext_array[i]);" 12379 " } " 12380 " return sum;" 12381 "}" 12382 "sum=0;" 12383 "for (var i=0;i<10000;++i) {" 12384 " sum=ee_op_test_count_func(sum);" 12385 "}" 12386 "sum;"); 12387 CHECK_EQ(16000000, result->Int32Value()); 12388 12389 result = CompileRun("ext_array[3] = 33;" 12390 "delete ext_array[3];" 12391 "ext_array[3];"); 12392 CHECK_EQ(33, result->Int32Value()); 12393 12394 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;" 12395 "ext_array[2] = 12; ext_array[3] = 13;" 12396 "ext_array.__defineGetter__('2'," 12397 "function() { return 120; });" 12398 "ext_array[2];"); 12399 CHECK_EQ(12, result->Int32Value()); 12400 12401 result = CompileRun("var js_array = new Array(40);" 12402 "js_array[0] = 77;" 12403 "js_array;"); 12404 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 12405 12406 result = CompileRun("ext_array[1] = 23;" 12407 "ext_array.__proto__ = [];" 12408 "js_array.__proto__ = ext_array;" 12409 "js_array.concat(ext_array);"); 12410 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 12411 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value()); 12412 12413 result = CompileRun("ext_array[1] = 23;"); 12414 CHECK_EQ(23, result->Int32Value()); 12415 12416 // Test more complex manipulations which cause eax to contain values 12417 // that won't be completely overwritten by loads from the arrays. 12418 // This catches bugs in the instructions used for the KeyedLoadIC 12419 // for byte and word types. 12420 { 12421 const int kXSize = 300; 12422 const int kYSize = 300; 12423 const int kLargeElementCount = kXSize * kYSize * 4; 12424 ElementType* large_array_data = 12425 static_cast<ElementType*>(malloc(kLargeElementCount * element_size)); 12426 i::Handle<ExternalArrayClass> large_array = 12427 i::Handle<ExternalArrayClass>::cast( 12428 FACTORY->NewExternalArray(kLargeElementCount, 12429 array_type, 12430 array_data)); 12431 v8::Handle<v8::Object> large_obj = v8::Object::New(); 12432 // Set the elements to be the external array. 12433 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data, 12434 array_type, 12435 kLargeElementCount); 12436 context->Global()->Set(v8_str("large_array"), large_obj); 12437 // Initialize contents of a few rows. 12438 for (int x = 0; x < 300; x++) { 12439 int row = 0; 12440 int offset = row * 300 * 4; 12441 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 12442 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 12443 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 12444 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 12445 row = 150; 12446 offset = row * 300 * 4; 12447 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 12448 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 12449 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 12450 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 12451 row = 298; 12452 offset = row * 300 * 4; 12453 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 12454 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 12455 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 12456 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 12457 } 12458 // The goal of the code below is to make "offset" large enough 12459 // that the computation of the index (which goes into eax) has 12460 // high bits set which will not be overwritten by a byte or short 12461 // load. 12462 result = CompileRun("var failed = false;" 12463 "var offset = 0;" 12464 "for (var i = 0; i < 300; i++) {" 12465 " if (large_array[4 * i] != 127 ||" 12466 " large_array[4 * i + 1] != 0 ||" 12467 " large_array[4 * i + 2] != 0 ||" 12468 " large_array[4 * i + 3] != 127) {" 12469 " failed = true;" 12470 " }" 12471 "}" 12472 "offset = 150 * 300 * 4;" 12473 "for (var i = 0; i < 300; i++) {" 12474 " if (large_array[offset + 4 * i] != 127 ||" 12475 " large_array[offset + 4 * i + 1] != 0 ||" 12476 " large_array[offset + 4 * i + 2] != 0 ||" 12477 " large_array[offset + 4 * i + 3] != 127) {" 12478 " failed = true;" 12479 " }" 12480 "}" 12481 "offset = 298 * 300 * 4;" 12482 "for (var i = 0; i < 300; i++) {" 12483 " if (large_array[offset + 4 * i] != 127 ||" 12484 " large_array[offset + 4 * i + 1] != 0 ||" 12485 " large_array[offset + 4 * i + 2] != 0 ||" 12486 " large_array[offset + 4 * i + 3] != 127) {" 12487 " failed = true;" 12488 " }" 12489 "}" 12490 "!failed;"); 12491 CHECK_EQ(true, result->BooleanValue()); 12492 free(large_array_data); 12493 } 12494 12495 // The "" property descriptor is overloaded to store information about 12496 // the external array. Ensure that setting and accessing the "" property 12497 // works (it should overwrite the information cached about the external 12498 // array in the DescriptorArray) in various situations. 12499 result = CompileRun("ext_array[''] = 23; ext_array['']"); 12500 CHECK_EQ(23, result->Int32Value()); 12501 12502 // Property "" set after the external array is associated with the object. 12503 { 12504 v8::Handle<v8::Object> obj2 = v8::Object::New(); 12505 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256)); 12506 obj2->Set(v8_str(""), v8::Int32::New(1503)); 12507 // Set the elements to be the external array. 12508 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 12509 array_type, 12510 kElementCount); 12511 context->Global()->Set(v8_str("ext_array"), obj2); 12512 result = CompileRun("ext_array['']"); 12513 CHECK_EQ(1503, result->Int32Value()); 12514 } 12515 12516 // Property "" set after the external array is associated with the object. 12517 { 12518 v8::Handle<v8::Object> obj2 = v8::Object::New(); 12519 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256)); 12520 // Set the elements to be the external array. 12521 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 12522 array_type, 12523 kElementCount); 12524 obj2->Set(v8_str(""), v8::Int32::New(1503)); 12525 context->Global()->Set(v8_str("ext_array"), obj2); 12526 result = CompileRun("ext_array['']"); 12527 CHECK_EQ(1503, result->Int32Value()); 12528 } 12529 12530 // Should reuse the map from previous test. 12531 { 12532 v8::Handle<v8::Object> obj2 = v8::Object::New(); 12533 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256)); 12534 // Set the elements to be the external array. Should re-use the map 12535 // from previous test. 12536 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 12537 array_type, 12538 kElementCount); 12539 context->Global()->Set(v8_str("ext_array"), obj2); 12540 result = CompileRun("ext_array['']"); 12541 } 12542 12543 // Property "" is a constant function that shouldn't not be interfered with 12544 // when an external array is set. 12545 { 12546 v8::Handle<v8::Object> obj2 = v8::Object::New(); 12547 // Start 12548 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256)); 12549 12550 // Add a constant function to an object. 12551 context->Global()->Set(v8_str("ext_array"), obj2); 12552 result = CompileRun("ext_array[''] = function() {return 1503;};" 12553 "ext_array['']();"); 12554 12555 // Add an external array transition to the same map that 12556 // has the constant transition. 12557 v8::Handle<v8::Object> obj3 = v8::Object::New(); 12558 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256)); 12559 obj3->SetIndexedPropertiesToExternalArrayData(array_data, 12560 array_type, 12561 kElementCount); 12562 context->Global()->Set(v8_str("ext_array"), obj3); 12563 } 12564 12565 // If a external array transition is in the map, it should get clobbered 12566 // by a constant function. 12567 { 12568 // Add an external array transition. 12569 v8::Handle<v8::Object> obj3 = v8::Object::New(); 12570 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256)); 12571 obj3->SetIndexedPropertiesToExternalArrayData(array_data, 12572 array_type, 12573 kElementCount); 12574 12575 // Add a constant function to the same map that just got an external array 12576 // transition. 12577 v8::Handle<v8::Object> obj2 = v8::Object::New(); 12578 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256)); 12579 context->Global()->Set(v8_str("ext_array"), obj2); 12580 result = CompileRun("ext_array[''] = function() {return 1503;};" 12581 "ext_array['']();"); 12582 } 12583 12584 free(array_data); 12585} 12586 12587 12588THREADED_TEST(ExternalByteArray) { 12589 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>( 12590 v8::kExternalByteArray, 12591 -128, 12592 127); 12593} 12594 12595 12596THREADED_TEST(ExternalUnsignedByteArray) { 12597 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>( 12598 v8::kExternalUnsignedByteArray, 12599 0, 12600 255); 12601} 12602 12603 12604THREADED_TEST(ExternalPixelArray) { 12605 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>( 12606 v8::kExternalPixelArray, 12607 0, 12608 255); 12609} 12610 12611 12612THREADED_TEST(ExternalShortArray) { 12613 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>( 12614 v8::kExternalShortArray, 12615 -32768, 12616 32767); 12617} 12618 12619 12620THREADED_TEST(ExternalUnsignedShortArray) { 12621 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>( 12622 v8::kExternalUnsignedShortArray, 12623 0, 12624 65535); 12625} 12626 12627 12628THREADED_TEST(ExternalIntArray) { 12629 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>( 12630 v8::kExternalIntArray, 12631 INT_MIN, // -2147483648 12632 INT_MAX); // 2147483647 12633} 12634 12635 12636THREADED_TEST(ExternalUnsignedIntArray) { 12637 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>( 12638 v8::kExternalUnsignedIntArray, 12639 0, 12640 UINT_MAX); // 4294967295 12641} 12642 12643 12644THREADED_TEST(ExternalFloatArray) { 12645 ExternalArrayTestHelper<i::ExternalFloatArray, float>( 12646 v8::kExternalFloatArray, 12647 -500, 12648 500); 12649} 12650 12651 12652THREADED_TEST(ExternalDoubleArray) { 12653 ExternalArrayTestHelper<i::ExternalDoubleArray, double>( 12654 v8::kExternalDoubleArray, 12655 -500, 12656 500); 12657} 12658 12659 12660THREADED_TEST(ExternalArrays) { 12661 TestExternalByteArray(); 12662 TestExternalUnsignedByteArray(); 12663 TestExternalShortArray(); 12664 TestExternalUnsignedShortArray(); 12665 TestExternalIntArray(); 12666 TestExternalUnsignedIntArray(); 12667 TestExternalFloatArray(); 12668} 12669 12670 12671void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) { 12672 v8::HandleScope scope; 12673 LocalContext context; 12674 for (int size = 0; size < 100; size += 10) { 12675 int element_size = ExternalArrayElementSize(array_type); 12676 void* external_data = malloc(size * element_size); 12677 v8::Handle<v8::Object> obj = v8::Object::New(); 12678 obj->SetIndexedPropertiesToExternalArrayData( 12679 external_data, array_type, size); 12680 CHECK(obj->HasIndexedPropertiesInExternalArrayData()); 12681 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData()); 12682 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType()); 12683 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength()); 12684 free(external_data); 12685 } 12686} 12687 12688 12689THREADED_TEST(ExternalArrayInfo) { 12690 ExternalArrayInfoTestHelper(v8::kExternalByteArray); 12691 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray); 12692 ExternalArrayInfoTestHelper(v8::kExternalShortArray); 12693 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray); 12694 ExternalArrayInfoTestHelper(v8::kExternalIntArray); 12695 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray); 12696 ExternalArrayInfoTestHelper(v8::kExternalFloatArray); 12697 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray); 12698 ExternalArrayInfoTestHelper(v8::kExternalPixelArray); 12699} 12700 12701 12702THREADED_TEST(ScriptContextDependence) { 12703 v8::HandleScope scope; 12704 LocalContext c1; 12705 const char *source = "foo"; 12706 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source)); 12707 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source)); 12708 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100)); 12709 CHECK_EQ(dep->Run()->Int32Value(), 100); 12710 CHECK_EQ(indep->Run()->Int32Value(), 100); 12711 LocalContext c2; 12712 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101)); 12713 CHECK_EQ(dep->Run()->Int32Value(), 100); 12714 CHECK_EQ(indep->Run()->Int32Value(), 101); 12715} 12716 12717 12718THREADED_TEST(StackTrace) { 12719 v8::HandleScope scope; 12720 LocalContext context; 12721 v8::TryCatch try_catch; 12722 const char *source = "function foo() { FAIL.FAIL; }; foo();"; 12723 v8::Handle<v8::String> src = v8::String::New(source); 12724 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test"); 12725 v8::Script::New(src, origin)->Run(); 12726 CHECK(try_catch.HasCaught()); 12727 v8::String::Utf8Value stack(try_catch.StackTrace()); 12728 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL); 12729} 12730 12731 12732// Checks that a StackFrame has certain expected values. 12733void checkStackFrame(const char* expected_script_name, 12734 const char* expected_func_name, int expected_line_number, 12735 int expected_column, bool is_eval, bool is_constructor, 12736 v8::Handle<v8::StackFrame> frame) { 12737 v8::HandleScope scope; 12738 v8::String::Utf8Value func_name(frame->GetFunctionName()); 12739 v8::String::Utf8Value script_name(frame->GetScriptName()); 12740 if (*script_name == NULL) { 12741 // The situation where there is no associated script, like for evals. 12742 CHECK(expected_script_name == NULL); 12743 } else { 12744 CHECK(strstr(*script_name, expected_script_name) != NULL); 12745 } 12746 CHECK(strstr(*func_name, expected_func_name) != NULL); 12747 CHECK_EQ(expected_line_number, frame->GetLineNumber()); 12748 CHECK_EQ(expected_column, frame->GetColumn()); 12749 CHECK_EQ(is_eval, frame->IsEval()); 12750 CHECK_EQ(is_constructor, frame->IsConstructor()); 12751} 12752 12753 12754v8::Handle<Value> AnalyzeStackInNativeCode(const v8::Arguments& args) { 12755 v8::HandleScope scope; 12756 const char* origin = "capture-stack-trace-test"; 12757 const int kOverviewTest = 1; 12758 const int kDetailedTest = 2; 12759 12760 ASSERT(args.Length() == 1); 12761 12762 int testGroup = args[0]->Int32Value(); 12763 if (testGroup == kOverviewTest) { 12764 v8::Handle<v8::StackTrace> stackTrace = 12765 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview); 12766 CHECK_EQ(4, stackTrace->GetFrameCount()); 12767 checkStackFrame(origin, "bar", 2, 10, false, false, 12768 stackTrace->GetFrame(0)); 12769 checkStackFrame(origin, "foo", 6, 3, false, false, 12770 stackTrace->GetFrame(1)); 12771 // This is the source string inside the eval which has the call to foo. 12772 checkStackFrame(NULL, "", 1, 5, false, false, 12773 stackTrace->GetFrame(2)); 12774 // The last frame is an anonymous function which has the initial eval call. 12775 checkStackFrame(origin, "", 8, 7, false, false, 12776 stackTrace->GetFrame(3)); 12777 12778 CHECK(stackTrace->AsArray()->IsArray()); 12779 } else if (testGroup == kDetailedTest) { 12780 v8::Handle<v8::StackTrace> stackTrace = 12781 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); 12782 CHECK_EQ(4, stackTrace->GetFrameCount()); 12783 checkStackFrame(origin, "bat", 4, 22, false, false, 12784 stackTrace->GetFrame(0)); 12785 checkStackFrame(origin, "baz", 8, 3, false, true, 12786 stackTrace->GetFrame(1)); 12787#ifdef ENABLE_DEBUGGER_SUPPORT 12788 bool is_eval = true; 12789#else // ENABLE_DEBUGGER_SUPPORT 12790 bool is_eval = false; 12791#endif // ENABLE_DEBUGGER_SUPPORT 12792 12793 // This is the source string inside the eval which has the call to baz. 12794 checkStackFrame(NULL, "", 1, 5, is_eval, false, 12795 stackTrace->GetFrame(2)); 12796 // The last frame is an anonymous function which has the initial eval call. 12797 checkStackFrame(origin, "", 10, 1, false, false, 12798 stackTrace->GetFrame(3)); 12799 12800 CHECK(stackTrace->AsArray()->IsArray()); 12801 } 12802 return v8::Undefined(); 12803} 12804 12805 12806// Tests the C++ StackTrace API. 12807// TODO(3074796): Reenable this as a THREADED_TEST once it passes. 12808// THREADED_TEST(CaptureStackTrace) { 12809TEST(CaptureStackTrace) { 12810 v8::HandleScope scope; 12811 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test"); 12812 Local<ObjectTemplate> templ = ObjectTemplate::New(); 12813 templ->Set(v8_str("AnalyzeStackInNativeCode"), 12814 v8::FunctionTemplate::New(AnalyzeStackInNativeCode)); 12815 LocalContext context(0, templ); 12816 12817 // Test getting OVERVIEW information. Should ignore information that is not 12818 // script name, function name, line number, and column offset. 12819 const char *overview_source = 12820 "function bar() {\n" 12821 " var y; AnalyzeStackInNativeCode(1);\n" 12822 "}\n" 12823 "function foo() {\n" 12824 "\n" 12825 " bar();\n" 12826 "}\n" 12827 "var x;eval('new foo();');"; 12828 v8::Handle<v8::String> overview_src = v8::String::New(overview_source); 12829 v8::Handle<Value> overview_result = 12830 v8::Script::New(overview_src, origin)->Run(); 12831 ASSERT(!overview_result.IsEmpty()); 12832 ASSERT(overview_result->IsObject()); 12833 12834 // Test getting DETAILED information. 12835 const char *detailed_source = 12836 "function bat() {AnalyzeStackInNativeCode(2);\n" 12837 "}\n" 12838 "\n" 12839 "function baz() {\n" 12840 " bat();\n" 12841 "}\n" 12842 "eval('new baz();');"; 12843 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source); 12844 // Make the script using a non-zero line and column offset. 12845 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3); 12846 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5); 12847 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset); 12848 v8::Handle<v8::Script> detailed_script( 12849 v8::Script::New(detailed_src, &detailed_origin)); 12850 v8::Handle<Value> detailed_result = detailed_script->Run(); 12851 ASSERT(!detailed_result.IsEmpty()); 12852 ASSERT(detailed_result->IsObject()); 12853} 12854 12855 12856static void StackTraceForUncaughtExceptionListener( 12857 v8::Handle<v8::Message> message, 12858 v8::Handle<Value>) { 12859 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 12860 CHECK_EQ(2, stack_trace->GetFrameCount()); 12861 checkStackFrame("origin", "foo", 2, 3, false, false, 12862 stack_trace->GetFrame(0)); 12863 checkStackFrame("origin", "bar", 5, 3, false, false, 12864 stack_trace->GetFrame(1)); 12865} 12866 12867TEST(CaptureStackTraceForUncaughtException) { 12868 report_count = 0; 12869 v8::HandleScope scope; 12870 LocalContext env; 12871 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener); 12872 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 12873 12874 Script::Compile(v8_str("function foo() {\n" 12875 " throw 1;\n" 12876 "};\n" 12877 "function bar() {\n" 12878 " foo();\n" 12879 "};"), 12880 v8_str("origin"))->Run(); 12881 v8::Local<v8::Object> global = env->Global(); 12882 Local<Value> trouble = global->Get(v8_str("bar")); 12883 CHECK(trouble->IsFunction()); 12884 Function::Cast(*trouble)->Call(global, 0, NULL); 12885 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 12886 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener); 12887} 12888 12889 12890TEST(CaptureStackTraceForUncaughtExceptionAndSetters) { 12891 v8::HandleScope scope; 12892 LocalContext env; 12893 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true, 12894 1024, 12895 v8::StackTrace::kDetailed); 12896 12897 CompileRun( 12898 "var setters = ['column', 'lineNumber', 'scriptName',\n" 12899 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n" 12900 " 'isConstructor'];\n" 12901 "for (var i = 0; i < setters.length; i++) {\n" 12902 " var prop = setters[i];\n" 12903 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n" 12904 "}\n"); 12905 CompileRun("throw 'exception';"); 12906 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 12907} 12908 12909 12910v8::Handle<Value> AnalyzeStackOfEvalWithSourceURL(const v8::Arguments& args) { 12911 v8::HandleScope scope; 12912 v8::Handle<v8::StackTrace> stackTrace = 12913 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); 12914 CHECK_EQ(5, stackTrace->GetFrameCount()); 12915 v8::Handle<v8::String> url = v8_str("eval_url"); 12916 for (int i = 0; i < 3; i++) { 12917 v8::Handle<v8::String> name = 12918 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 12919 CHECK(!name.IsEmpty()); 12920 CHECK_EQ(url, name); 12921 } 12922 return v8::Undefined(); 12923} 12924 12925 12926TEST(SourceURLInStackTrace) { 12927 v8::HandleScope scope; 12928 Local<ObjectTemplate> templ = ObjectTemplate::New(); 12929 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"), 12930 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL)); 12931 LocalContext context(0, templ); 12932 12933 const char *source = 12934 "function outer() {\n" 12935 "function bar() {\n" 12936 " AnalyzeStackOfEvalWithSourceURL();\n" 12937 "}\n" 12938 "function foo() {\n" 12939 "\n" 12940 " bar();\n" 12941 "}\n" 12942 "foo();\n" 12943 "}\n" 12944 "eval('(' + outer +')()//@ sourceURL=eval_url');"; 12945 CHECK(CompileRun(source)->IsUndefined()); 12946} 12947 12948 12949// Test that idle notification can be handled and eventually returns true. 12950THREADED_TEST(IdleNotification) { 12951 bool rv = false; 12952 for (int i = 0; i < 100; i++) { 12953 rv = v8::V8::IdleNotification(); 12954 if (rv) 12955 break; 12956 } 12957 CHECK(rv == true); 12958} 12959 12960 12961static uint32_t* stack_limit; 12962 12963static v8::Handle<Value> GetStackLimitCallback(const v8::Arguments& args) { 12964 stack_limit = reinterpret_cast<uint32_t*>( 12965 i::Isolate::Current()->stack_guard()->real_climit()); 12966 return v8::Undefined(); 12967} 12968 12969 12970// Uses the address of a local variable to determine the stack top now. 12971// Given a size, returns an address that is that far from the current 12972// top of stack. 12973static uint32_t* ComputeStackLimit(uint32_t size) { 12974 uint32_t* answer = &size - (size / sizeof(size)); 12975 // If the size is very large and the stack is very near the bottom of 12976 // memory then the calculation above may wrap around and give an address 12977 // that is above the (downwards-growing) stack. In that case we return 12978 // a very low address. 12979 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size)); 12980 return answer; 12981} 12982 12983 12984TEST(SetResourceConstraints) { 12985 static const int K = 1024; 12986 uint32_t* set_limit = ComputeStackLimit(128 * K); 12987 12988 // Set stack limit. 12989 v8::ResourceConstraints constraints; 12990 constraints.set_stack_limit(set_limit); 12991 CHECK(v8::SetResourceConstraints(&constraints)); 12992 12993 // Execute a script. 12994 v8::HandleScope scope; 12995 LocalContext env; 12996 Local<v8::FunctionTemplate> fun_templ = 12997 v8::FunctionTemplate::New(GetStackLimitCallback); 12998 Local<Function> fun = fun_templ->GetFunction(); 12999 env->Global()->Set(v8_str("get_stack_limit"), fun); 13000 CompileRun("get_stack_limit();"); 13001 13002 CHECK(stack_limit == set_limit); 13003} 13004 13005 13006TEST(SetResourceConstraintsInThread) { 13007 uint32_t* set_limit; 13008 { 13009 v8::Locker locker; 13010 static const int K = 1024; 13011 set_limit = ComputeStackLimit(128 * K); 13012 13013 // Set stack limit. 13014 v8::ResourceConstraints constraints; 13015 constraints.set_stack_limit(set_limit); 13016 CHECK(v8::SetResourceConstraints(&constraints)); 13017 13018 // Execute a script. 13019 v8::HandleScope scope; 13020 LocalContext env; 13021 Local<v8::FunctionTemplate> fun_templ = 13022 v8::FunctionTemplate::New(GetStackLimitCallback); 13023 Local<Function> fun = fun_templ->GetFunction(); 13024 env->Global()->Set(v8_str("get_stack_limit"), fun); 13025 CompileRun("get_stack_limit();"); 13026 13027 CHECK(stack_limit == set_limit); 13028 } 13029 { 13030 v8::Locker locker; 13031 CHECK(stack_limit == set_limit); 13032 } 13033} 13034 13035 13036THREADED_TEST(GetHeapStatistics) { 13037 v8::HandleScope scope; 13038 LocalContext c1; 13039 v8::HeapStatistics heap_statistics; 13040 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0); 13041 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0); 13042 v8::V8::GetHeapStatistics(&heap_statistics); 13043 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0); 13044 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0); 13045} 13046 13047 13048static double DoubleFromBits(uint64_t value) { 13049 double target; 13050 memcpy(&target, &value, sizeof(target)); 13051 return target; 13052} 13053 13054 13055static uint64_t DoubleToBits(double value) { 13056 uint64_t target; 13057 memcpy(&target, &value, sizeof(target)); 13058 return target; 13059} 13060 13061 13062static double DoubleToDateTime(double input) { 13063 double date_limit = 864e13; 13064 if (IsNaN(input) || input < -date_limit || input > date_limit) { 13065 return i::OS::nan_value(); 13066 } 13067 return (input < 0) ? -(floor(-input)) : floor(input); 13068} 13069 13070// We don't have a consistent way to write 64-bit constants syntactically, so we 13071// split them into two 32-bit constants and combine them programmatically. 13072static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) { 13073 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits); 13074} 13075 13076 13077THREADED_TEST(QuietSignalingNaNs) { 13078 v8::HandleScope scope; 13079 LocalContext context; 13080 v8::TryCatch try_catch; 13081 13082 // Special double values. 13083 double snan = DoubleFromBits(0x7ff00000, 0x00000001); 13084 double qnan = DoubleFromBits(0x7ff80000, 0x00000000); 13085 double infinity = DoubleFromBits(0x7ff00000, 0x00000000); 13086 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu); 13087 double min_normal = DoubleFromBits(0x00100000, 0x00000000); 13088 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu); 13089 double min_denormal = DoubleFromBits(0x00000000, 0x00000001); 13090 13091 // Date values are capped at +/-100000000 days (times 864e5 ms per day) 13092 // on either side of the epoch. 13093 double date_limit = 864e13; 13094 13095 double test_values[] = { 13096 snan, 13097 qnan, 13098 infinity, 13099 max_normal, 13100 date_limit + 1, 13101 date_limit, 13102 min_normal, 13103 max_denormal, 13104 min_denormal, 13105 0, 13106 -0, 13107 -min_denormal, 13108 -max_denormal, 13109 -min_normal, 13110 -date_limit, 13111 -date_limit - 1, 13112 -max_normal, 13113 -infinity, 13114 -qnan, 13115 -snan 13116 }; 13117 int num_test_values = 20; 13118 13119 for (int i = 0; i < num_test_values; i++) { 13120 double test_value = test_values[i]; 13121 13122 // Check that Number::New preserves non-NaNs and quiets SNaNs. 13123 v8::Handle<v8::Value> number = v8::Number::New(test_value); 13124 double stored_number = number->NumberValue(); 13125 if (!IsNaN(test_value)) { 13126 CHECK_EQ(test_value, stored_number); 13127 } else { 13128 uint64_t stored_bits = DoubleToBits(stored_number); 13129 // Check if quiet nan (bits 51..62 all set). 13130 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 13131 } 13132 13133 // Check that Date::New preserves non-NaNs in the date range and 13134 // quiets SNaNs. 13135 v8::Handle<v8::Value> date = v8::Date::New(test_value); 13136 double expected_stored_date = DoubleToDateTime(test_value); 13137 double stored_date = date->NumberValue(); 13138 if (!IsNaN(expected_stored_date)) { 13139 CHECK_EQ(expected_stored_date, stored_date); 13140 } else { 13141 uint64_t stored_bits = DoubleToBits(stored_date); 13142 // Check if quiet nan (bits 51..62 all set). 13143 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 13144 } 13145 } 13146} 13147 13148 13149static v8::Handle<Value> SpaghettiIncident(const v8::Arguments& args) { 13150 v8::HandleScope scope; 13151 v8::TryCatch tc; 13152 v8::Handle<v8::String> str = args[0]->ToString(); 13153 if (tc.HasCaught()) 13154 return tc.ReThrow(); 13155 return v8::Undefined(); 13156} 13157 13158 13159// Test that an exception can be propagated down through a spaghetti 13160// stack using ReThrow. 13161THREADED_TEST(SpaghettiStackReThrow) { 13162 v8::HandleScope scope; 13163 LocalContext context; 13164 context->Global()->Set( 13165 v8::String::New("s"), 13166 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction()); 13167 v8::TryCatch try_catch; 13168 CompileRun( 13169 "var i = 0;" 13170 "var o = {" 13171 " toString: function () {" 13172 " if (i == 10) {" 13173 " throw 'Hey!';" 13174 " } else {" 13175 " i++;" 13176 " return s(o);" 13177 " }" 13178 " }" 13179 "};" 13180 "s(o);"); 13181 CHECK(try_catch.HasCaught()); 13182 v8::String::Utf8Value value(try_catch.Exception()); 13183 CHECK_EQ(0, strcmp(*value, "Hey!")); 13184} 13185 13186 13187TEST(Regress528) { 13188 v8::V8::Initialize(); 13189 13190 v8::HandleScope scope; 13191 v8::Persistent<Context> context; 13192 v8::Persistent<Context> other_context; 13193 int gc_count; 13194 13195 // Create a context used to keep the code from aging in the compilation 13196 // cache. 13197 other_context = Context::New(); 13198 13199 // Context-dependent context data creates reference from the compilation 13200 // cache to the global object. 13201 const char* source_simple = "1"; 13202 context = Context::New(); 13203 { 13204 v8::HandleScope scope; 13205 13206 context->Enter(); 13207 Local<v8::String> obj = v8::String::New(""); 13208 context->SetData(obj); 13209 CompileRun(source_simple); 13210 context->Exit(); 13211 } 13212 context.Dispose(); 13213 for (gc_count = 1; gc_count < 10; gc_count++) { 13214 other_context->Enter(); 13215 CompileRun(source_simple); 13216 other_context->Exit(); 13217 HEAP->CollectAllGarbage(false); 13218 if (GetGlobalObjectsCount() == 1) break; 13219 } 13220 CHECK_GE(2, gc_count); 13221 CHECK_EQ(1, GetGlobalObjectsCount()); 13222 13223 // Eval in a function creates reference from the compilation cache to the 13224 // global object. 13225 const char* source_eval = "function f(){eval('1')}; f()"; 13226 context = Context::New(); 13227 { 13228 v8::HandleScope scope; 13229 13230 context->Enter(); 13231 CompileRun(source_eval); 13232 context->Exit(); 13233 } 13234 context.Dispose(); 13235 for (gc_count = 1; gc_count < 10; gc_count++) { 13236 other_context->Enter(); 13237 CompileRun(source_eval); 13238 other_context->Exit(); 13239 HEAP->CollectAllGarbage(false); 13240 if (GetGlobalObjectsCount() == 1) break; 13241 } 13242 CHECK_GE(2, gc_count); 13243 CHECK_EQ(1, GetGlobalObjectsCount()); 13244 13245 // Looking up the line number for an exception creates reference from the 13246 // compilation cache to the global object. 13247 const char* source_exception = "function f(){throw 1;} f()"; 13248 context = Context::New(); 13249 { 13250 v8::HandleScope scope; 13251 13252 context->Enter(); 13253 v8::TryCatch try_catch; 13254 CompileRun(source_exception); 13255 CHECK(try_catch.HasCaught()); 13256 v8::Handle<v8::Message> message = try_catch.Message(); 13257 CHECK(!message.IsEmpty()); 13258 CHECK_EQ(1, message->GetLineNumber()); 13259 context->Exit(); 13260 } 13261 context.Dispose(); 13262 for (gc_count = 1; gc_count < 10; gc_count++) { 13263 other_context->Enter(); 13264 CompileRun(source_exception); 13265 other_context->Exit(); 13266 HEAP->CollectAllGarbage(false); 13267 if (GetGlobalObjectsCount() == 1) break; 13268 } 13269 CHECK_GE(2, gc_count); 13270 CHECK_EQ(1, GetGlobalObjectsCount()); 13271 13272 other_context.Dispose(); 13273} 13274 13275 13276THREADED_TEST(ScriptOrigin) { 13277 v8::HandleScope scope; 13278 LocalContext env; 13279 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test")); 13280 v8::Handle<v8::String> script = v8::String::New( 13281 "function f() {}\n\nfunction g() {}"); 13282 v8::Script::Compile(script, &origin)->Run(); 13283 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 13284 env->Global()->Get(v8::String::New("f"))); 13285 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 13286 env->Global()->Get(v8::String::New("g"))); 13287 13288 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin(); 13289 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_f.ResourceName())); 13290 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value()); 13291 13292 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin(); 13293 CHECK_EQ("test", *v8::String::AsciiValue(script_origin_g.ResourceName())); 13294 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value()); 13295} 13296 13297 13298THREADED_TEST(ScriptLineNumber) { 13299 v8::HandleScope scope; 13300 LocalContext env; 13301 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test")); 13302 v8::Handle<v8::String> script = v8::String::New( 13303 "function f() {}\n\nfunction g() {}"); 13304 v8::Script::Compile(script, &origin)->Run(); 13305 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 13306 env->Global()->Get(v8::String::New("f"))); 13307 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 13308 env->Global()->Get(v8::String::New("g"))); 13309 CHECK_EQ(0, f->GetScriptLineNumber()); 13310 CHECK_EQ(2, g->GetScriptLineNumber()); 13311} 13312 13313 13314static v8::Handle<Value> GetterWhichReturns42(Local<String> name, 13315 const AccessorInfo& info) { 13316 return v8_num(42); 13317} 13318 13319 13320static void SetterWhichSetsYOnThisTo23(Local<String> name, 13321 Local<Value> value, 13322 const AccessorInfo& info) { 13323 info.This()->Set(v8_str("y"), v8_num(23)); 13324} 13325 13326 13327TEST(SetterOnConstructorPrototype) { 13328 v8::HandleScope scope; 13329 Local<ObjectTemplate> templ = ObjectTemplate::New(); 13330 templ->SetAccessor(v8_str("x"), 13331 GetterWhichReturns42, 13332 SetterWhichSetsYOnThisTo23); 13333 LocalContext context; 13334 context->Global()->Set(v8_str("P"), templ->NewInstance()); 13335 CompileRun("function C1() {" 13336 " this.x = 23;" 13337 "};" 13338 "C1.prototype = P;" 13339 "function C2() {" 13340 " this.x = 23" 13341 "};" 13342 "C2.prototype = { };" 13343 "C2.prototype.__proto__ = P;"); 13344 13345 v8::Local<v8::Script> script; 13346 script = v8::Script::Compile(v8_str("new C1();")); 13347 for (int i = 0; i < 10; i++) { 13348 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 13349 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value()); 13350 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value()); 13351 } 13352 13353 script = v8::Script::Compile(v8_str("new C2();")); 13354 for (int i = 0; i < 10; i++) { 13355 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run()); 13356 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value()); 13357 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value()); 13358 } 13359} 13360 13361 13362static v8::Handle<Value> NamedPropertyGetterWhichReturns42( 13363 Local<String> name, const AccessorInfo& info) { 13364 return v8_num(42); 13365} 13366 13367 13368static v8::Handle<Value> NamedPropertySetterWhichSetsYOnThisTo23( 13369 Local<String> name, Local<Value> value, const AccessorInfo& info) { 13370 if (name->Equals(v8_str("x"))) { 13371 info.This()->Set(v8_str("y"), v8_num(23)); 13372 } 13373 return v8::Handle<Value>(); 13374} 13375 13376 13377THREADED_TEST(InterceptorOnConstructorPrototype) { 13378 v8::HandleScope scope; 13379 Local<ObjectTemplate> templ = ObjectTemplate::New(); 13380 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42, 13381 NamedPropertySetterWhichSetsYOnThisTo23); 13382 LocalContext context; 13383 context->Global()->Set(v8_str("P"), templ->NewInstance()); 13384 CompileRun("function C1() {" 13385 " this.x = 23;" 13386 "};" 13387 "C1.prototype = P;" 13388 "function C2() {" 13389 " this.x = 23" 13390 "};" 13391 "C2.prototype = { };" 13392 "C2.prototype.__proto__ = P;"); 13393 13394 v8::Local<v8::Script> script; 13395 script = v8::Script::Compile(v8_str("new C1();")); 13396 for (int i = 0; i < 10; i++) { 13397 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 13398 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value()); 13399 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value()); 13400 } 13401 13402 script = v8::Script::Compile(v8_str("new C2();")); 13403 for (int i = 0; i < 10; i++) { 13404 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run()); 13405 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value()); 13406 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value()); 13407 } 13408} 13409 13410 13411TEST(Bug618) { 13412 const char* source = "function C1() {" 13413 " this.x = 23;" 13414 "};" 13415 "C1.prototype = P;"; 13416 13417 v8::HandleScope scope; 13418 LocalContext context; 13419 v8::Local<v8::Script> script; 13420 13421 // Use a simple object as prototype. 13422 v8::Local<v8::Object> prototype = v8::Object::New(); 13423 prototype->Set(v8_str("y"), v8_num(42)); 13424 context->Global()->Set(v8_str("P"), prototype); 13425 13426 // This compile will add the code to the compilation cache. 13427 CompileRun(source); 13428 13429 script = v8::Script::Compile(v8_str("new C1();")); 13430 // Allow enough iterations for the inobject slack tracking logic 13431 // to finalize instance size and install the fast construct stub. 13432 for (int i = 0; i < 256; i++) { 13433 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 13434 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value()); 13435 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value()); 13436 } 13437 13438 // Use an API object with accessors as prototype. 13439 Local<ObjectTemplate> templ = ObjectTemplate::New(); 13440 templ->SetAccessor(v8_str("x"), 13441 GetterWhichReturns42, 13442 SetterWhichSetsYOnThisTo23); 13443 context->Global()->Set(v8_str("P"), templ->NewInstance()); 13444 13445 // This compile will get the code from the compilation cache. 13446 CompileRun(source); 13447 13448 script = v8::Script::Compile(v8_str("new C1();")); 13449 for (int i = 0; i < 10; i++) { 13450 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 13451 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value()); 13452 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value()); 13453 } 13454} 13455 13456int prologue_call_count = 0; 13457int epilogue_call_count = 0; 13458int prologue_call_count_second = 0; 13459int epilogue_call_count_second = 0; 13460 13461void PrologueCallback(v8::GCType, v8::GCCallbackFlags) { 13462 ++prologue_call_count; 13463} 13464 13465void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) { 13466 ++epilogue_call_count; 13467} 13468 13469void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) { 13470 ++prologue_call_count_second; 13471} 13472 13473void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) { 13474 ++epilogue_call_count_second; 13475} 13476 13477TEST(GCCallbacks) { 13478 LocalContext context; 13479 13480 v8::V8::AddGCPrologueCallback(PrologueCallback); 13481 v8::V8::AddGCEpilogueCallback(EpilogueCallback); 13482 CHECK_EQ(0, prologue_call_count); 13483 CHECK_EQ(0, epilogue_call_count); 13484 HEAP->CollectAllGarbage(false); 13485 CHECK_EQ(1, prologue_call_count); 13486 CHECK_EQ(1, epilogue_call_count); 13487 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond); 13488 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond); 13489 HEAP->CollectAllGarbage(false); 13490 CHECK_EQ(2, prologue_call_count); 13491 CHECK_EQ(2, epilogue_call_count); 13492 CHECK_EQ(1, prologue_call_count_second); 13493 CHECK_EQ(1, epilogue_call_count_second); 13494 v8::V8::RemoveGCPrologueCallback(PrologueCallback); 13495 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback); 13496 HEAP->CollectAllGarbage(false); 13497 CHECK_EQ(2, prologue_call_count); 13498 CHECK_EQ(2, epilogue_call_count); 13499 CHECK_EQ(2, prologue_call_count_second); 13500 CHECK_EQ(2, epilogue_call_count_second); 13501 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond); 13502 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond); 13503 HEAP->CollectAllGarbage(false); 13504 CHECK_EQ(2, prologue_call_count); 13505 CHECK_EQ(2, epilogue_call_count); 13506 CHECK_EQ(2, prologue_call_count_second); 13507 CHECK_EQ(2, epilogue_call_count_second); 13508} 13509 13510 13511THREADED_TEST(AddToJSFunctionResultCache) { 13512 i::FLAG_allow_natives_syntax = true; 13513 v8::HandleScope scope; 13514 13515 LocalContext context; 13516 13517 const char* code = 13518 "(function() {" 13519 " var key0 = 'a';" 13520 " var key1 = 'b';" 13521 " var r0 = %_GetFromCache(0, key0);" 13522 " var r1 = %_GetFromCache(0, key1);" 13523 " var r0_ = %_GetFromCache(0, key0);" 13524 " if (r0 !== r0_)" 13525 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;" 13526 " var r1_ = %_GetFromCache(0, key1);" 13527 " if (r1 !== r1_)" 13528 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;" 13529 " return 'PASSED';" 13530 "})()"; 13531 HEAP->ClearJSFunctionResultCaches(); 13532 ExpectString(code, "PASSED"); 13533} 13534 13535 13536static const int k0CacheSize = 16; 13537 13538THREADED_TEST(FillJSFunctionResultCache) { 13539 i::FLAG_allow_natives_syntax = true; 13540 v8::HandleScope scope; 13541 13542 LocalContext context; 13543 13544 const char* code = 13545 "(function() {" 13546 " var k = 'a';" 13547 " var r = %_GetFromCache(0, k);" 13548 " for (var i = 0; i < 16; i++) {" 13549 " %_GetFromCache(0, 'a' + i);" 13550 " };" 13551 " if (r === %_GetFromCache(0, k))" 13552 " return 'FAILED: k0CacheSize is too small';" 13553 " return 'PASSED';" 13554 "})()"; 13555 HEAP->ClearJSFunctionResultCaches(); 13556 ExpectString(code, "PASSED"); 13557} 13558 13559 13560THREADED_TEST(RoundRobinGetFromCache) { 13561 i::FLAG_allow_natives_syntax = true; 13562 v8::HandleScope scope; 13563 13564 LocalContext context; 13565 13566 const char* code = 13567 "(function() {" 13568 " var keys = [];" 13569 " for (var i = 0; i < 16; i++) keys.push(i);" 13570 " var values = [];" 13571 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);" 13572 " for (var i = 0; i < 16; i++) {" 13573 " var v = %_GetFromCache(0, keys[i]);" 13574 " if (v !== values[i])" 13575 " return 'Wrong value for ' + " 13576 " keys[i] + ': ' + v + ' vs. ' + values[i];" 13577 " };" 13578 " return 'PASSED';" 13579 "})()"; 13580 HEAP->ClearJSFunctionResultCaches(); 13581 ExpectString(code, "PASSED"); 13582} 13583 13584 13585THREADED_TEST(ReverseGetFromCache) { 13586 i::FLAG_allow_natives_syntax = true; 13587 v8::HandleScope scope; 13588 13589 LocalContext context; 13590 13591 const char* code = 13592 "(function() {" 13593 " var keys = [];" 13594 " for (var i = 0; i < 16; i++) keys.push(i);" 13595 " var values = [];" 13596 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);" 13597 " for (var i = 15; i >= 16; i--) {" 13598 " var v = %_GetFromCache(0, keys[i]);" 13599 " if (v !== values[i])" 13600 " return 'Wrong value for ' + " 13601 " keys[i] + ': ' + v + ' vs. ' + values[i];" 13602 " };" 13603 " return 'PASSED';" 13604 "})()"; 13605 HEAP->ClearJSFunctionResultCaches(); 13606 ExpectString(code, "PASSED"); 13607} 13608 13609 13610THREADED_TEST(TestEviction) { 13611 i::FLAG_allow_natives_syntax = true; 13612 v8::HandleScope scope; 13613 13614 LocalContext context; 13615 13616 const char* code = 13617 "(function() {" 13618 " for (var i = 0; i < 2*16; i++) {" 13619 " %_GetFromCache(0, 'a' + i);" 13620 " };" 13621 " return 'PASSED';" 13622 "})()"; 13623 HEAP->ClearJSFunctionResultCaches(); 13624 ExpectString(code, "PASSED"); 13625} 13626 13627 13628THREADED_TEST(TwoByteStringInAsciiCons) { 13629 // See Chromium issue 47824. 13630 v8::HandleScope scope; 13631 13632 LocalContext context; 13633 const char* init_code = 13634 "var str1 = 'abelspendabel';" 13635 "var str2 = str1 + str1 + str1;" 13636 "str2;"; 13637 Local<Value> result = CompileRun(init_code); 13638 13639 CHECK(result->IsString()); 13640 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result)); 13641 int length = string->length(); 13642 CHECK(string->IsAsciiRepresentation()); 13643 13644 FlattenString(string); 13645 i::Handle<i::String> flat_string = FlattenGetString(string); 13646 13647 CHECK(string->IsAsciiRepresentation()); 13648 CHECK(flat_string->IsAsciiRepresentation()); 13649 13650 // Create external resource. 13651 uint16_t* uc16_buffer = new uint16_t[length + 1]; 13652 13653 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length); 13654 uc16_buffer[length] = 0; 13655 13656 TestResource resource(uc16_buffer); 13657 13658 flat_string->MakeExternal(&resource); 13659 13660 CHECK(flat_string->IsTwoByteRepresentation()); 13661 13662 // At this point, we should have a Cons string which is flat and ASCII, 13663 // with a first half that is a two-byte string (although it only contains 13664 // ASCII characters). This is a valid sequence of steps, and it can happen 13665 // in real pages. 13666 13667 CHECK(string->IsAsciiRepresentation()); 13668 i::ConsString* cons = i::ConsString::cast(*string); 13669 CHECK_EQ(0, cons->second()->length()); 13670 CHECK(cons->first()->IsTwoByteRepresentation()); 13671 13672 // Check that some string operations work. 13673 13674 // Atom RegExp. 13675 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;"); 13676 CHECK_EQ(6, reresult->Int32Value()); 13677 13678 // Nonatom RegExp. 13679 reresult = CompileRun("str2.match(/abe./g).length;"); 13680 CHECK_EQ(6, reresult->Int32Value()); 13681 13682 reresult = CompileRun("str2.search(/bel/g);"); 13683 CHECK_EQ(1, reresult->Int32Value()); 13684 13685 reresult = CompileRun("str2.search(/be./g);"); 13686 CHECK_EQ(1, reresult->Int32Value()); 13687 13688 ExpectTrue("/bel/g.test(str2);"); 13689 13690 ExpectTrue("/be./g.test(str2);"); 13691 13692 reresult = CompileRun("/bel/g.exec(str2);"); 13693 CHECK(!reresult->IsNull()); 13694 13695 reresult = CompileRun("/be./g.exec(str2);"); 13696 CHECK(!reresult->IsNull()); 13697 13698 ExpectString("str2.substring(2, 10);", "elspenda"); 13699 13700 ExpectString("str2.substring(2, 20);", "elspendabelabelspe"); 13701 13702 ExpectString("str2.charAt(2);", "e"); 13703 13704 reresult = CompileRun("str2.charCodeAt(2);"); 13705 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value()); 13706} 13707 13708 13709// Failed access check callback that performs a GC on each invocation. 13710void FailedAccessCheckCallbackGC(Local<v8::Object> target, 13711 v8::AccessType type, 13712 Local<v8::Value> data) { 13713 HEAP->CollectAllGarbage(true); 13714} 13715 13716 13717TEST(GCInFailedAccessCheckCallback) { 13718 // Install a failed access check callback that performs a GC on each 13719 // invocation. Then force the callback to be called from va 13720 13721 v8::V8::Initialize(); 13722 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC); 13723 13724 v8::HandleScope scope; 13725 13726 // Create an ObjectTemplate for global objects and install access 13727 // check callbacks that will block access. 13728 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 13729 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker, 13730 IndexedGetAccessBlocker, 13731 v8::Handle<v8::Value>(), 13732 false); 13733 13734 // Create a context and set an x property on it's global object. 13735 LocalContext context0(NULL, global_template); 13736 context0->Global()->Set(v8_str("x"), v8_num(42)); 13737 v8::Handle<v8::Object> global0 = context0->Global(); 13738 13739 // Create a context with a different security token so that the 13740 // failed access check callback will be called on each access. 13741 LocalContext context1(NULL, global_template); 13742 context1->Global()->Set(v8_str("other"), global0); 13743 13744 // Get property with failed access check. 13745 ExpectUndefined("other.x"); 13746 13747 // Get element with failed access check. 13748 ExpectUndefined("other[0]"); 13749 13750 // Set property with failed access check. 13751 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()"); 13752 CHECK(result->IsObject()); 13753 13754 // Set element with failed access check. 13755 result = CompileRun("other[0] = new Object()"); 13756 CHECK(result->IsObject()); 13757 13758 // Get property attribute with failed access check. 13759 ExpectFalse("\'x\' in other"); 13760 13761 // Get property attribute for element with failed access check. 13762 ExpectFalse("0 in other"); 13763 13764 // Delete property. 13765 ExpectFalse("delete other.x"); 13766 13767 // Delete element. 13768 CHECK_EQ(false, global0->Delete(0)); 13769 13770 // DefineAccessor. 13771 CHECK_EQ(false, 13772 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x"))); 13773 13774 // Define JavaScript accessor. 13775 ExpectUndefined("Object.prototype.__defineGetter__.call(" 13776 " other, \'x\', function() { return 42; })"); 13777 13778 // LookupAccessor. 13779 ExpectUndefined("Object.prototype.__lookupGetter__.call(" 13780 " other, \'x\')"); 13781 13782 // HasLocalElement. 13783 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')"); 13784 13785 CHECK_EQ(false, global0->HasRealIndexedProperty(0)); 13786 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x"))); 13787 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x"))); 13788 13789 // Reset the failed access check callback so it does not influence 13790 // the other tests. 13791 v8::V8::SetFailedAccessCheckCallbackFunction(NULL); 13792} 13793 13794TEST(DefaultIsolateGetCurrent) { 13795 CHECK(v8::Isolate::GetCurrent() != NULL); 13796 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 13797 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate()); 13798 printf("*** %s\n", "DefaultIsolateGetCurrent success"); 13799} 13800 13801TEST(IsolateNewDispose) { 13802 v8::Isolate* current_isolate = v8::Isolate::GetCurrent(); 13803 v8::Isolate* isolate = v8::Isolate::New(); 13804 CHECK(isolate != NULL); 13805 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate()); 13806 CHECK(current_isolate != isolate); 13807 CHECK(current_isolate == v8::Isolate::GetCurrent()); 13808 13809 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 13810 last_location = last_message = NULL; 13811 isolate->Dispose(); 13812 CHECK_EQ(last_location, NULL); 13813 CHECK_EQ(last_message, NULL); 13814} 13815 13816TEST(IsolateEnterExitDefault) { 13817 v8::HandleScope scope; 13818 LocalContext context; 13819 v8::Isolate* current_isolate = v8::Isolate::GetCurrent(); 13820 CHECK(current_isolate != NULL); // Default isolate. 13821 ExpectString("'hello'", "hello"); 13822 current_isolate->Enter(); 13823 ExpectString("'still working'", "still working"); 13824 current_isolate->Exit(); 13825 ExpectString("'still working 2'", "still working 2"); 13826 current_isolate->Exit(); 13827 // Default isolate is always, well, 'default current'. 13828 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate); 13829 // Still working since default isolate is auto-entering any thread 13830 // that has no isolate and attempts to execute V8 APIs. 13831 ExpectString("'still working 3'", "still working 3"); 13832} 13833 13834TEST(DisposeDefaultIsolate) { 13835 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 13836 13837 // Run some V8 code to trigger default isolate to become 'current'. 13838 v8::HandleScope scope; 13839 LocalContext context; 13840 ExpectString("'run some V8'", "run some V8"); 13841 13842 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 13843 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate()); 13844 last_location = last_message = NULL; 13845 isolate->Dispose(); 13846 // It is not possible to dispose default isolate via Isolate API. 13847 CHECK_NE(last_location, NULL); 13848 CHECK_NE(last_message, NULL); 13849} 13850 13851TEST(RunDefaultAndAnotherIsolate) { 13852 v8::HandleScope scope; 13853 LocalContext context; 13854 13855 // Enter new isolate. 13856 v8::Isolate* isolate = v8::Isolate::New(); 13857 CHECK(isolate); 13858 isolate->Enter(); 13859 { // Need this block because subsequent Exit() will deallocate Heap, 13860 // so we need all scope objects to be deconstructed when it happens. 13861 v8::HandleScope scope_new; 13862 LocalContext context_new; 13863 13864 // Run something in new isolate. 13865 CompileRun("var foo = 153;"); 13866 ExpectTrue("function f() { return foo == 153; }; f()"); 13867 } 13868 isolate->Exit(); 13869 13870 // This runs automatically in default isolate. 13871 // Variables in another isolate should be not available. 13872 ExpectTrue("function f() {" 13873 " try {" 13874 " foo;" 13875 " return false;" 13876 " } catch(e) {" 13877 " return true;" 13878 " }" 13879 "};" 13880 "var bar = 371;" 13881 "f()"); 13882 13883 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 13884 last_location = last_message = NULL; 13885 isolate->Dispose(); 13886 CHECK_EQ(last_location, NULL); 13887 CHECK_EQ(last_message, NULL); 13888 13889 // Check that default isolate still runs. 13890 ExpectTrue("function f() { return bar == 371; }; f()"); 13891} 13892 13893TEST(DisposeIsolateWhenInUse) { 13894 v8::Isolate* isolate = v8::Isolate::New(); 13895 CHECK(isolate); 13896 isolate->Enter(); 13897 v8::HandleScope scope; 13898 LocalContext context; 13899 // Run something in this isolate. 13900 ExpectTrue("true"); 13901 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 13902 last_location = last_message = NULL; 13903 // Still entered, should fail. 13904 isolate->Dispose(); 13905 CHECK_NE(last_location, NULL); 13906 CHECK_NE(last_message, NULL); 13907} 13908 13909TEST(RunTwoIsolatesOnSingleThread) { 13910 // Run isolate 1. 13911 v8::Isolate* isolate1 = v8::Isolate::New(); 13912 isolate1->Enter(); 13913 v8::Persistent<v8::Context> context1 = v8::Context::New(); 13914 13915 { 13916 v8::Context::Scope cscope(context1); 13917 v8::HandleScope scope; 13918 // Run something in new isolate. 13919 CompileRun("var foo = 'isolate 1';"); 13920 ExpectString("function f() { return foo; }; f()", "isolate 1"); 13921 } 13922 13923 // Run isolate 2. 13924 v8::Isolate* isolate2 = v8::Isolate::New(); 13925 v8::Persistent<v8::Context> context2; 13926 13927 { 13928 v8::Isolate::Scope iscope(isolate2); 13929 context2 = v8::Context::New(); 13930 v8::Context::Scope cscope(context2); 13931 v8::HandleScope scope; 13932 13933 // Run something in new isolate. 13934 CompileRun("var foo = 'isolate 2';"); 13935 ExpectString("function f() { return foo; }; f()", "isolate 2"); 13936 } 13937 13938 { 13939 v8::Context::Scope cscope(context1); 13940 v8::HandleScope scope; 13941 // Now again in isolate 1 13942 ExpectString("function f() { return foo; }; f()", "isolate 1"); 13943 } 13944 13945 isolate1->Exit(); 13946 13947 // Run some stuff in default isolate. 13948 v8::Persistent<v8::Context> context_default = v8::Context::New(); 13949 13950 { 13951 v8::Context::Scope cscope(context_default); 13952 v8::HandleScope scope; 13953 // Variables in other isolates should be not available, verify there 13954 // is an exception. 13955 ExpectTrue("function f() {" 13956 " try {" 13957 " foo;" 13958 " return false;" 13959 " } catch(e) {" 13960 " return true;" 13961 " }" 13962 "};" 13963 "var isDefaultIsolate = true;" 13964 "f()"); 13965 } 13966 13967 isolate1->Enter(); 13968 13969 { 13970 v8::Isolate::Scope iscope(isolate2); 13971 v8::Context::Scope cscope(context2); 13972 v8::HandleScope scope; 13973 ExpectString("function f() { return foo; }; f()", "isolate 2"); 13974 } 13975 13976 { 13977 v8::Context::Scope cscope(context1); 13978 v8::HandleScope scope; 13979 ExpectString("function f() { return foo; }; f()", "isolate 1"); 13980 } 13981 13982 { 13983 v8::Isolate::Scope iscope(isolate2); 13984 context2.Dispose(); 13985 } 13986 13987 context1.Dispose(); 13988 isolate1->Exit(); 13989 13990 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 13991 last_location = last_message = NULL; 13992 13993 isolate1->Dispose(); 13994 CHECK_EQ(last_location, NULL); 13995 CHECK_EQ(last_message, NULL); 13996 13997 isolate2->Dispose(); 13998 CHECK_EQ(last_location, NULL); 13999 CHECK_EQ(last_message, NULL); 14000 14001 // Check that default isolate still runs. 14002 { 14003 v8::Context::Scope cscope(context_default); 14004 v8::HandleScope scope; 14005 ExpectTrue("function f() { return isDefaultIsolate; }; f()"); 14006 } 14007} 14008 14009static int CalcFibonacci(v8::Isolate* isolate, int limit) { 14010 v8::Isolate::Scope isolate_scope(isolate); 14011 v8::HandleScope scope; 14012 LocalContext context; 14013 i::ScopedVector<char> code(1024); 14014 i::OS::SNPrintF(code, "function fib(n) {" 14015 " if (n <= 2) return 1;" 14016 " return fib(n-1) + fib(n-2);" 14017 "}" 14018 "fib(%d)", limit); 14019 Local<Value> value = CompileRun(code.start()); 14020 CHECK(value->IsNumber()); 14021 return static_cast<int>(value->NumberValue()); 14022} 14023 14024class IsolateThread : public v8::internal::Thread { 14025 public: 14026 IsolateThread(v8::Isolate* isolate, int fib_limit) 14027 : Thread("IsolateThread"), 14028 isolate_(isolate), 14029 fib_limit_(fib_limit), 14030 result_(0) { } 14031 14032 void Run() { 14033 result_ = CalcFibonacci(isolate_, fib_limit_); 14034 } 14035 14036 int result() { return result_; } 14037 14038 private: 14039 v8::Isolate* isolate_; 14040 int fib_limit_; 14041 int result_; 14042}; 14043 14044TEST(MultipleIsolatesOnIndividualThreads) { 14045 v8::Isolate* isolate1 = v8::Isolate::New(); 14046 v8::Isolate* isolate2 = v8::Isolate::New(); 14047 14048 IsolateThread thread1(isolate1, 21); 14049 IsolateThread thread2(isolate2, 12); 14050 14051 // Compute some fibonacci numbers on 3 threads in 3 isolates. 14052 thread1.Start(); 14053 thread2.Start(); 14054 14055 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21); 14056 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12); 14057 14058 thread1.Join(); 14059 thread2.Join(); 14060 14061 // Compare results. The actual fibonacci numbers for 12 and 21 are taken 14062 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number 14063 CHECK_EQ(result1, 10946); 14064 CHECK_EQ(result2, 144); 14065 CHECK_EQ(result1, thread1.result()); 14066 CHECK_EQ(result2, thread2.result()); 14067 14068 isolate1->Dispose(); 14069 isolate2->Dispose(); 14070} 14071 14072TEST(IsolateDifferentContexts) { 14073 v8::Isolate* isolate = v8::Isolate::New(); 14074 Persistent<v8::Context> context; 14075 { 14076 v8::Isolate::Scope isolate_scope(isolate); 14077 v8::HandleScope handle_scope; 14078 context = v8::Context::New(); 14079 v8::Context::Scope context_scope(context); 14080 Local<Value> v = CompileRun("2"); 14081 CHECK(v->IsNumber()); 14082 CHECK_EQ(2, static_cast<int>(v->NumberValue())); 14083 } 14084 { 14085 v8::Isolate::Scope isolate_scope(isolate); 14086 v8::HandleScope handle_scope; 14087 context = v8::Context::New(); 14088 v8::Context::Scope context_scope(context); 14089 Local<Value> v = CompileRun("22"); 14090 CHECK(v->IsNumber()); 14091 CHECK_EQ(22, static_cast<int>(v->NumberValue())); 14092 } 14093} 14094 14095class InitDefaultIsolateThread : public v8::internal::Thread { 14096 public: 14097 enum TestCase { 14098 IgnoreOOM, 14099 SetResourceConstraints, 14100 SetFatalHandler, 14101 SetCounterFunction, 14102 SetCreateHistogramFunction, 14103 SetAddHistogramSampleFunction 14104 }; 14105 14106 explicit InitDefaultIsolateThread(TestCase testCase) 14107 : Thread("InitDefaultIsolateThread"), 14108 testCase_(testCase), 14109 result_(false) { } 14110 14111 void Run() { 14112 switch (testCase_) { 14113 case IgnoreOOM: 14114 v8::V8::IgnoreOutOfMemoryException(); 14115 break; 14116 14117 case SetResourceConstraints: { 14118 static const int K = 1024; 14119 v8::ResourceConstraints constraints; 14120 constraints.set_max_young_space_size(256 * K); 14121 constraints.set_max_old_space_size(4 * K * K); 14122 v8::SetResourceConstraints(&constraints); 14123 break; 14124 } 14125 14126 case SetFatalHandler: 14127 v8::V8::SetFatalErrorHandler(NULL); 14128 break; 14129 14130 case SetCounterFunction: 14131 v8::V8::SetCounterFunction(NULL); 14132 break; 14133 14134 case SetCreateHistogramFunction: 14135 v8::V8::SetCreateHistogramFunction(NULL); 14136 break; 14137 14138 case SetAddHistogramSampleFunction: 14139 v8::V8::SetAddHistogramSampleFunction(NULL); 14140 break; 14141 } 14142 result_ = true; 14143 } 14144 14145 bool result() { return result_; } 14146 14147 private: 14148 TestCase testCase_; 14149 bool result_; 14150}; 14151 14152 14153static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) { 14154 InitDefaultIsolateThread thread(testCase); 14155 thread.Start(); 14156 thread.Join(); 14157 CHECK_EQ(thread.result(), true); 14158} 14159 14160TEST(InitializeDefaultIsolateOnSecondaryThread1) { 14161 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM); 14162} 14163 14164TEST(InitializeDefaultIsolateOnSecondaryThread2) { 14165 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints); 14166} 14167 14168TEST(InitializeDefaultIsolateOnSecondaryThread3) { 14169 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler); 14170} 14171 14172TEST(InitializeDefaultIsolateOnSecondaryThread4) { 14173 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction); 14174} 14175 14176TEST(InitializeDefaultIsolateOnSecondaryThread5) { 14177 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction); 14178} 14179 14180TEST(InitializeDefaultIsolateOnSecondaryThread6) { 14181 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction); 14182} 14183 14184 14185TEST(StringCheckMultipleContexts) { 14186 const char* code = 14187 "(function() { return \"a\".charAt(0); })()"; 14188 14189 { 14190 // Run the code twice in the first context to initialize the call IC. 14191 v8::HandleScope scope; 14192 LocalContext context1; 14193 ExpectString(code, "a"); 14194 ExpectString(code, "a"); 14195 } 14196 14197 { 14198 // Change the String.prototype in the second context and check 14199 // that the right function gets called. 14200 v8::HandleScope scope; 14201 LocalContext context2; 14202 CompileRun("String.prototype.charAt = function() { return \"not a\"; }"); 14203 ExpectString(code, "not a"); 14204 } 14205} 14206 14207 14208TEST(NumberCheckMultipleContexts) { 14209 const char* code = 14210 "(function() { return (42).toString(); })()"; 14211 14212 { 14213 // Run the code twice in the first context to initialize the call IC. 14214 v8::HandleScope scope; 14215 LocalContext context1; 14216 ExpectString(code, "42"); 14217 ExpectString(code, "42"); 14218 } 14219 14220 { 14221 // Change the Number.prototype in the second context and check 14222 // that the right function gets called. 14223 v8::HandleScope scope; 14224 LocalContext context2; 14225 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }"); 14226 ExpectString(code, "not 42"); 14227 } 14228} 14229 14230 14231TEST(BooleanCheckMultipleContexts) { 14232 const char* code = 14233 "(function() { return true.toString(); })()"; 14234 14235 { 14236 // Run the code twice in the first context to initialize the call IC. 14237 v8::HandleScope scope; 14238 LocalContext context1; 14239 ExpectString(code, "true"); 14240 ExpectString(code, "true"); 14241 } 14242 14243 { 14244 // Change the Boolean.prototype in the second context and check 14245 // that the right function gets called. 14246 v8::HandleScope scope; 14247 LocalContext context2; 14248 CompileRun("Boolean.prototype.toString = function() { return \"\"; }"); 14249 ExpectString(code, ""); 14250 } 14251} 14252 14253 14254TEST(DontDeleteCellLoadIC) { 14255 const char* function_code = 14256 "function readCell() { while (true) { return cell; } }"; 14257 14258 { 14259 // Run the code twice in the first context to initialize the load 14260 // IC for a don't delete cell. 14261 v8::HandleScope scope; 14262 LocalContext context1; 14263 CompileRun("var cell = \"first\";"); 14264 ExpectBoolean("delete cell", false); 14265 CompileRun(function_code); 14266 ExpectString("readCell()", "first"); 14267 ExpectString("readCell()", "first"); 14268 } 14269 14270 { 14271 // Use a deletable cell in the second context. 14272 v8::HandleScope scope; 14273 LocalContext context2; 14274 CompileRun("cell = \"second\";"); 14275 CompileRun(function_code); 14276 ExpectString("readCell()", "second"); 14277 ExpectBoolean("delete cell", true); 14278 ExpectString("(function() {" 14279 " try {" 14280 " return readCell();" 14281 " } catch(e) {" 14282 " return e.toString();" 14283 " }" 14284 "})()", 14285 "ReferenceError: cell is not defined"); 14286 CompileRun("cell = \"new_second\";"); 14287 HEAP->CollectAllGarbage(true); 14288 ExpectString("readCell()", "new_second"); 14289 ExpectString("readCell()", "new_second"); 14290 } 14291} 14292 14293 14294TEST(DontDeleteCellLoadICForceDelete) { 14295 const char* function_code = 14296 "function readCell() { while (true) { return cell; } }"; 14297 14298 // Run the code twice to initialize the load IC for a don't delete 14299 // cell. 14300 v8::HandleScope scope; 14301 LocalContext context; 14302 CompileRun("var cell = \"value\";"); 14303 ExpectBoolean("delete cell", false); 14304 CompileRun(function_code); 14305 ExpectString("readCell()", "value"); 14306 ExpectString("readCell()", "value"); 14307 14308 // Delete the cell using the API and check the inlined code works 14309 // correctly. 14310 CHECK(context->Global()->ForceDelete(v8_str("cell"))); 14311 ExpectString("(function() {" 14312 " try {" 14313 " return readCell();" 14314 " } catch(e) {" 14315 " return e.toString();" 14316 " }" 14317 "})()", 14318 "ReferenceError: cell is not defined"); 14319} 14320 14321 14322TEST(DontDeleteCellLoadICAPI) { 14323 const char* function_code = 14324 "function readCell() { while (true) { return cell; } }"; 14325 14326 // Run the code twice to initialize the load IC for a don't delete 14327 // cell created using the API. 14328 v8::HandleScope scope; 14329 LocalContext context; 14330 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete); 14331 ExpectBoolean("delete cell", false); 14332 CompileRun(function_code); 14333 ExpectString("readCell()", "value"); 14334 ExpectString("readCell()", "value"); 14335 14336 // Delete the cell using the API and check the inlined code works 14337 // correctly. 14338 CHECK(context->Global()->ForceDelete(v8_str("cell"))); 14339 ExpectString("(function() {" 14340 " try {" 14341 " return readCell();" 14342 " } catch(e) {" 14343 " return e.toString();" 14344 " }" 14345 "})()", 14346 "ReferenceError: cell is not defined"); 14347} 14348 14349 14350TEST(RegExp) { 14351 v8::HandleScope scope; 14352 LocalContext context; 14353 14354 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone); 14355 CHECK(re->IsRegExp()); 14356 CHECK(re->GetSource()->Equals(v8_str("foo"))); 14357 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone); 14358 14359 re = v8::RegExp::New(v8_str("bar"), 14360 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 14361 v8::RegExp::kGlobal)); 14362 CHECK(re->IsRegExp()); 14363 CHECK(re->GetSource()->Equals(v8_str("bar"))); 14364 CHECK_EQ(static_cast<int>(re->GetFlags()), 14365 v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal); 14366 14367 re = v8::RegExp::New(v8_str("baz"), 14368 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 14369 v8::RegExp::kMultiline)); 14370 CHECK(re->IsRegExp()); 14371 CHECK(re->GetSource()->Equals(v8_str("baz"))); 14372 CHECK_EQ(static_cast<int>(re->GetFlags()), 14373 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline); 14374 14375 re = CompileRun("/quux/").As<v8::RegExp>(); 14376 CHECK(re->IsRegExp()); 14377 CHECK(re->GetSource()->Equals(v8_str("quux"))); 14378 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone); 14379 14380 re = CompileRun("/quux/gm").As<v8::RegExp>(); 14381 CHECK(re->IsRegExp()); 14382 CHECK(re->GetSource()->Equals(v8_str("quux"))); 14383 CHECK_EQ(static_cast<int>(re->GetFlags()), 14384 v8::RegExp::kGlobal | v8::RegExp::kMultiline); 14385 14386 // Override the RegExp constructor and check the API constructor 14387 // still works. 14388 CompileRun("RegExp = function() {}"); 14389 14390 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone); 14391 CHECK(re->IsRegExp()); 14392 CHECK(re->GetSource()->Equals(v8_str("foobar"))); 14393 CHECK_EQ(re->GetFlags(), v8::RegExp::kNone); 14394 14395 re = v8::RegExp::New(v8_str("foobarbaz"), 14396 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 14397 v8::RegExp::kMultiline)); 14398 CHECK(re->IsRegExp()); 14399 CHECK(re->GetSource()->Equals(v8_str("foobarbaz"))); 14400 CHECK_EQ(static_cast<int>(re->GetFlags()), 14401 v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline); 14402 14403 context->Global()->Set(v8_str("re"), re); 14404 ExpectTrue("re.test('FoobarbaZ')"); 14405 14406 // RegExps are objects on which you can set properties. 14407 re->Set(v8_str("property"), v8::Integer::New(32)); 14408 v8::Handle<v8::Value> value = CompileRun("re.property"); 14409 ASSERT_EQ(32, value->Int32Value()); 14410 14411 v8::TryCatch try_catch; 14412 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone); 14413 CHECK(re.IsEmpty()); 14414 CHECK(try_catch.HasCaught()); 14415 context->Global()->Set(v8_str("ex"), try_catch.Exception()); 14416 ExpectTrue("ex instanceof SyntaxError"); 14417} 14418 14419 14420THREADED_TEST(Equals) { 14421 v8::HandleScope handleScope; 14422 LocalContext localContext; 14423 14424 v8::Handle<v8::Object> globalProxy = localContext->Global(); 14425 v8::Handle<Value> global = globalProxy->GetPrototype(); 14426 14427 CHECK(global->StrictEquals(global)); 14428 CHECK(!global->StrictEquals(globalProxy)); 14429 CHECK(!globalProxy->StrictEquals(global)); 14430 CHECK(globalProxy->StrictEquals(globalProxy)); 14431 14432 CHECK(global->Equals(global)); 14433 CHECK(!global->Equals(globalProxy)); 14434 CHECK(!globalProxy->Equals(global)); 14435 CHECK(globalProxy->Equals(globalProxy)); 14436} 14437 14438 14439static v8::Handle<v8::Value> Getter(v8::Local<v8::String> property, 14440 const v8::AccessorInfo& info ) { 14441 return v8_str("42!"); 14442} 14443 14444 14445static v8::Handle<v8::Array> Enumerator(const v8::AccessorInfo& info) { 14446 v8::Handle<v8::Array> result = v8::Array::New(); 14447 result->Set(0, v8_str("universalAnswer")); 14448 return result; 14449} 14450 14451 14452TEST(NamedEnumeratorAndForIn) { 14453 v8::HandleScope handle_scope; 14454 LocalContext context; 14455 v8::Context::Scope context_scope(context.local()); 14456 14457 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(); 14458 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator); 14459 context->Global()->Set(v8_str("o"), tmpl->NewInstance()); 14460 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 14461 "var result = []; for (var k in o) result.push(k); result")); 14462 CHECK_EQ(1, result->Length()); 14463 CHECK_EQ(v8_str("universalAnswer"), result->Get(0)); 14464} 14465 14466 14467TEST(DefinePropertyPostDetach) { 14468 v8::HandleScope scope; 14469 LocalContext context; 14470 v8::Handle<v8::Object> proxy = context->Global(); 14471 v8::Handle<v8::Function> define_property = 14472 CompileRun("(function() {" 14473 " Object.defineProperty(" 14474 " this," 14475 " 1," 14476 " { configurable: true, enumerable: true, value: 3 });" 14477 "})").As<Function>(); 14478 context->DetachGlobal(); 14479 define_property->Call(proxy, 0, NULL); 14480} 14481 14482 14483static void InstallContextId(v8::Handle<Context> context, int id) { 14484 Context::Scope scope(context); 14485 CompileRun("Object.prototype").As<Object>()-> 14486 Set(v8_str("context_id"), v8::Integer::New(id)); 14487} 14488 14489 14490static void CheckContextId(v8::Handle<Object> object, int expected) { 14491 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value()); 14492} 14493 14494 14495THREADED_TEST(CreationContext) { 14496 HandleScope handle_scope; 14497 Persistent<Context> context1 = Context::New(); 14498 InstallContextId(context1, 1); 14499 Persistent<Context> context2 = Context::New(); 14500 InstallContextId(context2, 2); 14501 Persistent<Context> context3 = Context::New(); 14502 InstallContextId(context3, 3); 14503 14504 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(); 14505 14506 Local<Object> object1; 14507 Local<Function> func1; 14508 { 14509 Context::Scope scope(context1); 14510 object1 = Object::New(); 14511 func1 = tmpl->GetFunction(); 14512 } 14513 14514 Local<Object> object2; 14515 Local<Function> func2; 14516 { 14517 Context::Scope scope(context2); 14518 object2 = Object::New(); 14519 func2 = tmpl->GetFunction(); 14520 } 14521 14522 Local<Object> instance1; 14523 Local<Object> instance2; 14524 14525 { 14526 Context::Scope scope(context3); 14527 instance1 = func1->NewInstance(); 14528 instance2 = func2->NewInstance(); 14529 } 14530 14531 CHECK(object1->CreationContext() == context1); 14532 CheckContextId(object1, 1); 14533 CHECK(func1->CreationContext() == context1); 14534 CheckContextId(func1, 1); 14535 CHECK(instance1->CreationContext() == context1); 14536 CheckContextId(instance1, 1); 14537 CHECK(object2->CreationContext() == context2); 14538 CheckContextId(object2, 2); 14539 CHECK(func2->CreationContext() == context2); 14540 CheckContextId(func2, 2); 14541 CHECK(instance2->CreationContext() == context2); 14542 CheckContextId(instance2, 2); 14543 14544 { 14545 Context::Scope scope(context1); 14546 CHECK(object1->CreationContext() == context1); 14547 CheckContextId(object1, 1); 14548 CHECK(func1->CreationContext() == context1); 14549 CheckContextId(func1, 1); 14550 CHECK(instance1->CreationContext() == context1); 14551 CheckContextId(instance1, 1); 14552 CHECK(object2->CreationContext() == context2); 14553 CheckContextId(object2, 2); 14554 CHECK(func2->CreationContext() == context2); 14555 CheckContextId(func2, 2); 14556 CHECK(instance2->CreationContext() == context2); 14557 CheckContextId(instance2, 2); 14558 } 14559 14560 { 14561 Context::Scope scope(context2); 14562 CHECK(object1->CreationContext() == context1); 14563 CheckContextId(object1, 1); 14564 CHECK(func1->CreationContext() == context1); 14565 CheckContextId(func1, 1); 14566 CHECK(instance1->CreationContext() == context1); 14567 CheckContextId(instance1, 1); 14568 CHECK(object2->CreationContext() == context2); 14569 CheckContextId(object2, 2); 14570 CHECK(func2->CreationContext() == context2); 14571 CheckContextId(func2, 2); 14572 CHECK(instance2->CreationContext() == context2); 14573 CheckContextId(instance2, 2); 14574 } 14575 14576 context1.Dispose(); 14577 context2.Dispose(); 14578 context3.Dispose(); 14579} 14580 14581 14582Handle<Value> HasOwnPropertyIndexedPropertyGetter(uint32_t index, 14583 const AccessorInfo& info) { 14584 if (index == 42) return v8_str("yes"); 14585 return Handle<v8::Integer>(); 14586} 14587 14588 14589Handle<Value> HasOwnPropertyNamedPropertyGetter(Local<String> property, 14590 const AccessorInfo& info) { 14591 if (property->Equals(v8_str("foo"))) return v8_str("yes"); 14592 return Handle<Value>(); 14593} 14594 14595 14596Handle<v8::Integer> HasOwnPropertyIndexedPropertyQuery( 14597 uint32_t index, const AccessorInfo& info) { 14598 if (index == 42) return v8_num(1).As<v8::Integer>(); 14599 return Handle<v8::Integer>(); 14600} 14601 14602 14603Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery( 14604 Local<String> property, const AccessorInfo& info) { 14605 if (property->Equals(v8_str("foo"))) return v8_num(1).As<v8::Integer>(); 14606 return Handle<v8::Integer>(); 14607} 14608 14609 14610Handle<v8::Integer> HasOwnPropertyNamedPropertyQuery2( 14611 Local<String> property, const AccessorInfo& info) { 14612 if (property->Equals(v8_str("bar"))) return v8_num(1).As<v8::Integer>(); 14613 return Handle<v8::Integer>(); 14614} 14615 14616 14617Handle<Value> HasOwnPropertyAccessorGetter(Local<String> property, 14618 const AccessorInfo& info) { 14619 return v8_str("yes"); 14620} 14621 14622 14623TEST(HasOwnProperty) { 14624 v8::HandleScope scope; 14625 LocalContext env; 14626 { // Check normal properties and defined getters. 14627 Handle<Value> value = CompileRun( 14628 "function Foo() {" 14629 " this.foo = 11;" 14630 " this.__defineGetter__('baz', function() { return 1; });" 14631 "};" 14632 "function Bar() { " 14633 " this.bar = 13;" 14634 " this.__defineGetter__('bla', function() { return 2; });" 14635 "};" 14636 "Bar.prototype = new Foo();" 14637 "new Bar();"); 14638 CHECK(value->IsObject()); 14639 Handle<Object> object = value->ToObject(); 14640 CHECK(object->Has(v8_str("foo"))); 14641 CHECK(!object->HasOwnProperty(v8_str("foo"))); 14642 CHECK(object->HasOwnProperty(v8_str("bar"))); 14643 CHECK(object->Has(v8_str("baz"))); 14644 CHECK(!object->HasOwnProperty(v8_str("baz"))); 14645 CHECK(object->HasOwnProperty(v8_str("bla"))); 14646 } 14647 { // Check named getter interceptors. 14648 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 14649 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter); 14650 Handle<Object> instance = templ->NewInstance(); 14651 CHECK(!instance->HasOwnProperty(v8_str("42"))); 14652 CHECK(instance->HasOwnProperty(v8_str("foo"))); 14653 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 14654 } 14655 { // Check indexed getter interceptors. 14656 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 14657 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter); 14658 Handle<Object> instance = templ->NewInstance(); 14659 CHECK(instance->HasOwnProperty(v8_str("42"))); 14660 CHECK(!instance->HasOwnProperty(v8_str("43"))); 14661 CHECK(!instance->HasOwnProperty(v8_str("foo"))); 14662 } 14663 { // Check named query interceptors. 14664 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 14665 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery); 14666 Handle<Object> instance = templ->NewInstance(); 14667 CHECK(instance->HasOwnProperty(v8_str("foo"))); 14668 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 14669 } 14670 { // Check indexed query interceptors. 14671 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 14672 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery); 14673 Handle<Object> instance = templ->NewInstance(); 14674 CHECK(instance->HasOwnProperty(v8_str("42"))); 14675 CHECK(!instance->HasOwnProperty(v8_str("41"))); 14676 } 14677 { // Check callbacks. 14678 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 14679 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter); 14680 Handle<Object> instance = templ->NewInstance(); 14681 CHECK(instance->HasOwnProperty(v8_str("foo"))); 14682 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 14683 } 14684 { // Check that query wins on disagreement. 14685 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 14686 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter, 14687 0, 14688 HasOwnPropertyNamedPropertyQuery2); 14689 Handle<Object> instance = templ->NewInstance(); 14690 CHECK(!instance->HasOwnProperty(v8_str("foo"))); 14691 CHECK(instance->HasOwnProperty(v8_str("bar"))); 14692 } 14693} 14694 14695 14696void CheckCodeGenerationAllowed() { 14697 Handle<Value> result = CompileRun("eval('42')"); 14698 CHECK_EQ(42, result->Int32Value()); 14699 result = CompileRun("(function(e) { return e('42'); })(eval)"); 14700 CHECK_EQ(42, result->Int32Value()); 14701 result = CompileRun("var f = new Function('return 42'); f()"); 14702 CHECK_EQ(42, result->Int32Value()); 14703} 14704 14705 14706void CheckCodeGenerationDisallowed() { 14707 TryCatch try_catch; 14708 14709 Handle<Value> result = CompileRun("eval('42')"); 14710 CHECK(result.IsEmpty()); 14711 CHECK(try_catch.HasCaught()); 14712 try_catch.Reset(); 14713 14714 result = CompileRun("(function(e) { return e('42'); })(eval)"); 14715 CHECK(result.IsEmpty()); 14716 CHECK(try_catch.HasCaught()); 14717 try_catch.Reset(); 14718 14719 result = CompileRun("var f = new Function('return 42'); f()"); 14720 CHECK(result.IsEmpty()); 14721 CHECK(try_catch.HasCaught()); 14722} 14723 14724 14725bool CodeGenerationAllowed(Local<Context> context) { 14726 ApiTestFuzzer::Fuzz(); 14727 return true; 14728} 14729 14730 14731bool CodeGenerationDisallowed(Local<Context> context) { 14732 ApiTestFuzzer::Fuzz(); 14733 return false; 14734} 14735 14736 14737THREADED_TEST(AllowCodeGenFromStrings) { 14738 v8::HandleScope scope; 14739 LocalContext context; 14740 14741 // eval and the Function constructor allowed by default. 14742 CheckCodeGenerationAllowed(); 14743 14744 // Disallow eval and the Function constructor. 14745 context->AllowCodeGenerationFromStrings(false); 14746 CheckCodeGenerationDisallowed(); 14747 14748 // Allow again. 14749 context->AllowCodeGenerationFromStrings(true); 14750 CheckCodeGenerationAllowed(); 14751 14752 // Disallow but setting a global callback that will allow the calls. 14753 context->AllowCodeGenerationFromStrings(false); 14754 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed); 14755 CheckCodeGenerationAllowed(); 14756 14757 // Set a callback that disallows the code generation. 14758 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed); 14759 CheckCodeGenerationDisallowed(); 14760} 14761 14762 14763static v8::Handle<Value> NonObjectThis(const v8::Arguments& args) { 14764 return v8::Undefined(); 14765} 14766 14767 14768THREADED_TEST(CallAPIFunctionOnNonObject) { 14769 v8::HandleScope scope; 14770 LocalContext context; 14771 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis); 14772 Handle<Function> function = templ->GetFunction(); 14773 context->Global()->Set(v8_str("f"), function); 14774 TryCatch try_catch; 14775 CompileRun("f.call(2)"); 14776} 14777 14778 14779// Regression test for issue 1470. 14780THREADED_TEST(ReadOnlyIndexedProperties) { 14781 v8::HandleScope scope; 14782 Local<ObjectTemplate> templ = ObjectTemplate::New(); 14783 14784 LocalContext context; 14785 Local<v8::Object> obj = templ->NewInstance(); 14786 context->Global()->Set(v8_str("obj"), obj); 14787 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly); 14788 obj->Set(v8_str("1"), v8_str("foobar")); 14789 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1"))); 14790 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly); 14791 obj->Set(v8_num(2), v8_str("foobar")); 14792 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2))); 14793 14794 // Test non-smi case. 14795 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly); 14796 obj->Set(v8_str("2000000000"), v8_str("foobar")); 14797 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000"))); 14798} 14799 14800 14801THREADED_TEST(Regress1516) { 14802 v8::HandleScope scope; 14803 14804 LocalContext context; 14805 { v8::HandleScope temp_scope; 14806 CompileRun("({'a': 0})"); 14807 } 14808 14809 int elements; 14810 { i::MapCache* map_cache = 14811 i::MapCache::cast(i::Isolate::Current()->context()->map_cache()); 14812 elements = map_cache->NumberOfElements(); 14813 CHECK_LE(1, elements); 14814 } 14815 14816 i::Isolate::Current()->heap()->CollectAllGarbage(true); 14817 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache(); 14818 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) { 14819 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache); 14820 CHECK_GT(elements, map_cache->NumberOfElements()); 14821 } 14822 } 14823} 14824 14825 14826static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global, 14827 Local<Value> name, 14828 v8::AccessType type, 14829 Local<Value> data) { 14830 // Only block read access to __proto__. 14831 if (type == v8::ACCESS_GET && 14832 name->IsString() && 14833 name->ToString()->Length() == 9 && 14834 name->ToString()->Utf8Length() == 9) { 14835 char buffer[10]; 14836 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer)); 14837 return strncmp(buffer, "__proto__", 9) != 0; 14838 } 14839 14840 return true; 14841} 14842 14843 14844THREADED_TEST(Regress93759) { 14845 HandleScope scope; 14846 14847 // Template for object with security check. 14848 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(); 14849 // We don't do indexing, so any callback can be used for that. 14850 no_proto_template->SetAccessCheckCallbacks( 14851 BlockProtoNamedSecurityTestCallback, 14852 IndexedSecurityTestCallback); 14853 14854 // Templates for objects with hidden prototypes and possibly security check. 14855 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New(); 14856 hidden_proto_template->SetHiddenPrototype(true); 14857 14858 Local<FunctionTemplate> protected_hidden_proto_template = 14859 v8::FunctionTemplate::New(); 14860 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks( 14861 BlockProtoNamedSecurityTestCallback, 14862 IndexedSecurityTestCallback); 14863 protected_hidden_proto_template->SetHiddenPrototype(true); 14864 14865 // Context for "foreign" objects used in test. 14866 Persistent<Context> context = v8::Context::New(); 14867 context->Enter(); 14868 14869 // Plain object, no security check. 14870 Local<Object> simple_object = Object::New(); 14871 14872 // Object with explicit security check. 14873 Local<Object> protected_object = 14874 no_proto_template->NewInstance(); 14875 14876 // JSGlobalProxy object, always have security check. 14877 Local<Object> proxy_object = 14878 context->Global(); 14879 14880 // Global object, the prototype of proxy_object. No security checks. 14881 Local<Object> global_object = 14882 proxy_object->GetPrototype()->ToObject(); 14883 14884 // Hidden prototype without security check. 14885 Local<Object> hidden_prototype = 14886 hidden_proto_template->GetFunction()->NewInstance(); 14887 Local<Object> object_with_hidden = 14888 Object::New(); 14889 object_with_hidden->SetPrototype(hidden_prototype); 14890 14891 // Hidden prototype with security check on the hidden prototype. 14892 Local<Object> protected_hidden_prototype = 14893 protected_hidden_proto_template->GetFunction()->NewInstance(); 14894 Local<Object> object_with_protected_hidden = 14895 Object::New(); 14896 object_with_protected_hidden->SetPrototype(protected_hidden_prototype); 14897 14898 context->Exit(); 14899 14900 // Template for object for second context. Values to test are put on it as 14901 // properties. 14902 Local<ObjectTemplate> global_template = ObjectTemplate::New(); 14903 global_template->Set(v8_str("simple"), simple_object); 14904 global_template->Set(v8_str("protected"), protected_object); 14905 global_template->Set(v8_str("global"), global_object); 14906 global_template->Set(v8_str("proxy"), proxy_object); 14907 global_template->Set(v8_str("hidden"), object_with_hidden); 14908 global_template->Set(v8_str("phidden"), object_with_protected_hidden); 14909 14910 LocalContext context2(NULL, global_template); 14911 14912 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)"); 14913 CHECK(result1->Equals(simple_object->GetPrototype())); 14914 14915 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)"); 14916 CHECK(result2->Equals(Undefined())); 14917 14918 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)"); 14919 CHECK(result3->Equals(global_object->GetPrototype())); 14920 14921 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)"); 14922 CHECK(result4->Equals(Undefined())); 14923 14924 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)"); 14925 CHECK(result5->Equals( 14926 object_with_hidden->GetPrototype()->ToObject()->GetPrototype())); 14927 14928 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)"); 14929 CHECK(result6->Equals(Undefined())); 14930 14931 context.Dispose(); 14932} 14933