1 // Copyright 2012 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 #ifndef WIN32 31 #include <signal.h> // kill 32 #include <unistd.h> // getpid 33 #endif // WIN32 34 #include <string> 35 #include <map> 36 37 #include "v8.h" 38 39 #include "api.h" 40 #include "arguments.h" 41 #include "cctest.h" 42 #include "compilation-cache.h" 43 #include "cpu-profiler.h" 44 #include "execution.h" 45 #include "isolate.h" 46 #include "objects.h" 47 #include "parser.h" 48 #include "platform.h" 49 #include "snapshot.h" 50 #include "unicode-inl.h" 51 #include "utils.h" 52 #include "vm-state.h" 53 54 static const bool kLogThreading = false; 55 56 using ::v8::AccessorInfo; 57 using ::v8::Arguments; 58 using ::v8::Boolean; 59 using ::v8::BooleanObject; 60 using ::v8::Context; 61 using ::v8::Extension; 62 using ::v8::Function; 63 using ::v8::FunctionTemplate; 64 using ::v8::Handle; 65 using ::v8::HandleScope; 66 using ::v8::Local; 67 using ::v8::Message; 68 using ::v8::MessageCallback; 69 using ::v8::Object; 70 using ::v8::ObjectTemplate; 71 using ::v8::Persistent; 72 using ::v8::Script; 73 using ::v8::StackTrace; 74 using ::v8::String; 75 using ::v8::TryCatch; 76 using ::v8::Undefined; 77 using ::v8::UniqueId; 78 using ::v8::V8; 79 using ::v8::Value; 80 81 82 #define THREADED_PROFILED_TEST(Name) \ 83 static void Test##Name(); \ 84 TEST(Name##WithProfiler) { \ 85 RunWithProfiler(&Test##Name); \ 86 } \ 87 THREADED_TEST(Name) 88 89 void RunWithProfiler(void (*test)()) { 90 LocalContext env; 91 v8::HandleScope scope(env->GetIsolate()); 92 v8::Local<v8::String> profile_name = v8::String::New("my_profile1"); 93 v8::CpuProfiler* cpu_profiler = env->GetIsolate()->GetCpuProfiler(); 94 95 cpu_profiler->StartCpuProfiling(profile_name); 96 (*test)(); 97 cpu_profiler->DeleteAllCpuProfiles(); 98 } 99 100 101 static void ExpectString(const char* code, const char* expected) { 102 Local<Value> result = CompileRun(code); 103 CHECK(result->IsString()); 104 String::Utf8Value utf8(result); 105 CHECK_EQ(expected, *utf8); 106 } 107 108 109 static void ExpectInt32(const char* code, int expected) { 110 Local<Value> result = CompileRun(code); 111 CHECK(result->IsInt32()); 112 CHECK_EQ(expected, result->Int32Value()); 113 } 114 115 116 static void ExpectBoolean(const char* code, bool expected) { 117 Local<Value> result = CompileRun(code); 118 CHECK(result->IsBoolean()); 119 CHECK_EQ(expected, result->BooleanValue()); 120 } 121 122 123 static void ExpectTrue(const char* code) { 124 ExpectBoolean(code, true); 125 } 126 127 128 static void ExpectFalse(const char* code) { 129 ExpectBoolean(code, false); 130 } 131 132 133 static void ExpectObject(const char* code, Local<Value> expected) { 134 Local<Value> result = CompileRun(code); 135 CHECK(result->Equals(expected)); 136 } 137 138 139 static void ExpectUndefined(const char* code) { 140 Local<Value> result = CompileRun(code); 141 CHECK(result->IsUndefined()); 142 } 143 144 145 static int signature_callback_count; 146 static void IncrementingSignatureCallback( 147 const v8::FunctionCallbackInfo<v8::Value>& args) { 148 ApiTestFuzzer::Fuzz(); 149 signature_callback_count++; 150 v8::Handle<v8::Array> result = v8::Array::New(args.Length()); 151 for (int i = 0; i < args.Length(); i++) 152 result->Set(v8::Integer::New(i), args[i]); 153 args.GetReturnValue().Set(result); 154 } 155 156 157 static void SignatureCallback( 158 const v8::FunctionCallbackInfo<v8::Value>& args) { 159 ApiTestFuzzer::Fuzz(); 160 v8::Handle<v8::Array> result = v8::Array::New(args.Length()); 161 for (int i = 0; i < args.Length(); i++) { 162 result->Set(v8::Integer::New(i), args[i]); 163 } 164 args.GetReturnValue().Set(result); 165 } 166 167 168 THREADED_TEST(Handles) { 169 v8::HandleScope scope(v8::Isolate::GetCurrent()); 170 Local<Context> local_env; 171 { 172 LocalContext env; 173 local_env = env.local(); 174 } 175 176 // Local context should still be live. 177 CHECK(!local_env.IsEmpty()); 178 local_env->Enter(); 179 180 v8::Handle<v8::Primitive> undef = v8::Undefined(); 181 CHECK(!undef.IsEmpty()); 182 CHECK(undef->IsUndefined()); 183 184 const char* c_source = "1 + 2 + 3"; 185 Local<String> source = String::New(c_source); 186 Local<Script> script = Script::Compile(source); 187 CHECK_EQ(6, script->Run()->Int32Value()); 188 189 local_env->Exit(); 190 } 191 192 193 THREADED_TEST(IsolateOfContext) { 194 v8::HandleScope scope(v8::Isolate::GetCurrent()); 195 v8::Handle<Context> env = Context::New(v8::Isolate::GetCurrent()); 196 197 CHECK(!env->InContext()); 198 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent()); 199 env->Enter(); 200 CHECK(env->InContext()); 201 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent()); 202 env->Exit(); 203 CHECK(!env->InContext()); 204 CHECK(env->GetIsolate() == v8::Isolate::GetCurrent()); 205 } 206 207 208 THREADED_TEST(ReceiverSignature) { 209 LocalContext env; 210 v8::HandleScope scope(env->GetIsolate()); 211 v8::Handle<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(); 212 v8::Handle<v8::Signature> sig = v8::Signature::New(fun); 213 fun->PrototypeTemplate()->Set( 214 v8_str("m"), 215 v8::FunctionTemplate::New(IncrementingSignatureCallback, 216 v8::Handle<Value>(), 217 sig)); 218 env->Global()->Set(v8_str("Fun"), fun->GetFunction()); 219 signature_callback_count = 0; 220 CompileRun( 221 "var o = new Fun();" 222 "o.m();"); 223 CHECK_EQ(1, signature_callback_count); 224 v8::Handle<v8::FunctionTemplate> sub_fun = v8::FunctionTemplate::New(); 225 sub_fun->Inherit(fun); 226 env->Global()->Set(v8_str("SubFun"), sub_fun->GetFunction()); 227 CompileRun( 228 "var o = new SubFun();" 229 "o.m();"); 230 CHECK_EQ(2, signature_callback_count); 231 232 v8::TryCatch try_catch; 233 CompileRun( 234 "var o = { };" 235 "o.m = Fun.prototype.m;" 236 "o.m();"); 237 CHECK_EQ(2, signature_callback_count); 238 CHECK(try_catch.HasCaught()); 239 try_catch.Reset(); 240 v8::Handle<v8::FunctionTemplate> unrel_fun = v8::FunctionTemplate::New(); 241 sub_fun->Inherit(fun); 242 env->Global()->Set(v8_str("UnrelFun"), unrel_fun->GetFunction()); 243 CompileRun( 244 "var o = new UnrelFun();" 245 "o.m = Fun.prototype.m;" 246 "o.m();"); 247 CHECK_EQ(2, signature_callback_count); 248 CHECK(try_catch.HasCaught()); 249 } 250 251 252 THREADED_TEST(ArgumentSignature) { 253 LocalContext env; 254 v8::HandleScope scope(env->GetIsolate()); 255 v8::Handle<v8::FunctionTemplate> cons = v8::FunctionTemplate::New(); 256 cons->SetClassName(v8_str("Cons")); 257 v8::Handle<v8::Signature> sig = 258 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 1, &cons); 259 v8::Handle<v8::FunctionTemplate> fun = 260 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), sig); 261 env->Global()->Set(v8_str("Cons"), cons->GetFunction()); 262 env->Global()->Set(v8_str("Fun1"), fun->GetFunction()); 263 264 v8::Handle<Value> value1 = CompileRun("Fun1(4) == '';"); 265 CHECK(value1->IsTrue()); 266 267 v8::Handle<Value> value2 = CompileRun("Fun1(new Cons()) == '[object Cons]';"); 268 CHECK(value2->IsTrue()); 269 270 v8::Handle<Value> value3 = CompileRun("Fun1() == '';"); 271 CHECK(value3->IsTrue()); 272 273 v8::Handle<v8::FunctionTemplate> cons1 = v8::FunctionTemplate::New(); 274 cons1->SetClassName(v8_str("Cons1")); 275 v8::Handle<v8::FunctionTemplate> cons2 = v8::FunctionTemplate::New(); 276 cons2->SetClassName(v8_str("Cons2")); 277 v8::Handle<v8::FunctionTemplate> cons3 = v8::FunctionTemplate::New(); 278 cons3->SetClassName(v8_str("Cons3")); 279 280 v8::Handle<v8::FunctionTemplate> args[3] = { cons1, cons2, cons3 }; 281 v8::Handle<v8::Signature> wsig = 282 v8::Signature::New(v8::Handle<v8::FunctionTemplate>(), 3, args); 283 v8::Handle<v8::FunctionTemplate> fun2 = 284 v8::FunctionTemplate::New(SignatureCallback, v8::Handle<Value>(), wsig); 285 286 env->Global()->Set(v8_str("Cons1"), cons1->GetFunction()); 287 env->Global()->Set(v8_str("Cons2"), cons2->GetFunction()); 288 env->Global()->Set(v8_str("Cons3"), cons3->GetFunction()); 289 env->Global()->Set(v8_str("Fun2"), fun2->GetFunction()); 290 v8::Handle<Value> value4 = CompileRun( 291 "Fun2(new Cons1(), new Cons2(), new Cons3()) ==" 292 "'[object Cons1],[object Cons2],[object Cons3]'"); 293 CHECK(value4->IsTrue()); 294 295 v8::Handle<Value> value5 = CompileRun( 296 "Fun2(new Cons1(), new Cons2(), 5) == '[object Cons1],[object Cons2],'"); 297 CHECK(value5->IsTrue()); 298 299 v8::Handle<Value> value6 = CompileRun( 300 "Fun2(new Cons3(), new Cons2(), new Cons1()) == ',[object Cons2],'"); 301 CHECK(value6->IsTrue()); 302 303 v8::Handle<Value> value7 = CompileRun( 304 "Fun2(new Cons1(), new Cons2(), new Cons3(), 'd') == " 305 "'[object Cons1],[object Cons2],[object Cons3],d';"); 306 CHECK(value7->IsTrue()); 307 308 v8::Handle<Value> value8 = CompileRun( 309 "Fun2(new Cons1(), new Cons2()) == '[object Cons1],[object Cons2]'"); 310 CHECK(value8->IsTrue()); 311 } 312 313 314 THREADED_TEST(HulIgennem) { 315 LocalContext env; 316 v8::HandleScope scope(env->GetIsolate()); 317 v8::Handle<v8::Primitive> undef = v8::Undefined(); 318 Local<String> undef_str = undef->ToString(); 319 char* value = i::NewArray<char>(undef_str->Utf8Length() + 1); 320 undef_str->WriteUtf8(value); 321 CHECK_EQ(0, strcmp(value, "undefined")); 322 i::DeleteArray(value); 323 } 324 325 326 THREADED_TEST(Access) { 327 LocalContext env; 328 v8::HandleScope scope(env->GetIsolate()); 329 Local<v8::Object> obj = v8::Object::New(); 330 Local<Value> foo_before = obj->Get(v8_str("foo")); 331 CHECK(foo_before->IsUndefined()); 332 Local<String> bar_str = v8_str("bar"); 333 obj->Set(v8_str("foo"), bar_str); 334 Local<Value> foo_after = obj->Get(v8_str("foo")); 335 CHECK(!foo_after->IsUndefined()); 336 CHECK(foo_after->IsString()); 337 CHECK_EQ(bar_str, foo_after); 338 } 339 340 341 THREADED_TEST(AccessElement) { 342 LocalContext env; 343 v8::HandleScope scope(env->GetIsolate()); 344 Local<v8::Object> obj = v8::Object::New(); 345 Local<Value> before = obj->Get(1); 346 CHECK(before->IsUndefined()); 347 Local<String> bar_str = v8_str("bar"); 348 obj->Set(1, bar_str); 349 Local<Value> after = obj->Get(1); 350 CHECK(!after->IsUndefined()); 351 CHECK(after->IsString()); 352 CHECK_EQ(bar_str, after); 353 354 Local<v8::Array> value = CompileRun("[\"a\", \"b\"]").As<v8::Array>(); 355 CHECK_EQ(v8_str("a"), value->Get(0)); 356 CHECK_EQ(v8_str("b"), value->Get(1)); 357 } 358 359 360 THREADED_TEST(Script) { 361 LocalContext env; 362 v8::HandleScope scope(env->GetIsolate()); 363 const char* c_source = "1 + 2 + 3"; 364 Local<String> source = String::New(c_source); 365 Local<Script> script = Script::Compile(source); 366 CHECK_EQ(6, script->Run()->Int32Value()); 367 } 368 369 370 static uint16_t* AsciiToTwoByteString(const char* source) { 371 int array_length = i::StrLength(source) + 1; 372 uint16_t* converted = i::NewArray<uint16_t>(array_length); 373 for (int i = 0; i < array_length; i++) converted[i] = source[i]; 374 return converted; 375 } 376 377 378 class TestResource: public String::ExternalStringResource { 379 public: 380 explicit TestResource(uint16_t* data, int* counter = NULL) 381 : data_(data), length_(0), counter_(counter) { 382 while (data[length_]) ++length_; 383 } 384 385 ~TestResource() { 386 i::DeleteArray(data_); 387 if (counter_ != NULL) ++*counter_; 388 } 389 390 const uint16_t* data() const { 391 return data_; 392 } 393 394 size_t length() const { 395 return length_; 396 } 397 private: 398 uint16_t* data_; 399 size_t length_; 400 int* counter_; 401 }; 402 403 404 class TestAsciiResource: public String::ExternalAsciiStringResource { 405 public: 406 explicit TestAsciiResource(const char* data, int* counter = NULL) 407 : data_(data), length_(strlen(data)), counter_(counter) { } 408 409 ~TestAsciiResource() { 410 i::DeleteArray(data_); 411 if (counter_ != NULL) ++*counter_; 412 } 413 414 const char* data() const { 415 return data_; 416 } 417 418 size_t length() const { 419 return length_; 420 } 421 private: 422 const char* data_; 423 size_t length_; 424 int* counter_; 425 }; 426 427 428 THREADED_TEST(ScriptUsingStringResource) { 429 int dispose_count = 0; 430 const char* c_source = "1 + 2 * 3"; 431 uint16_t* two_byte_source = AsciiToTwoByteString(c_source); 432 { 433 LocalContext env; 434 v8::HandleScope scope(env->GetIsolate()); 435 TestResource* resource = new TestResource(two_byte_source, &dispose_count); 436 Local<String> source = String::NewExternal(resource); 437 Local<Script> script = Script::Compile(source); 438 Local<Value> value = script->Run(); 439 CHECK(value->IsNumber()); 440 CHECK_EQ(7, value->Int32Value()); 441 CHECK(source->IsExternal()); 442 CHECK_EQ(resource, 443 static_cast<TestResource*>(source->GetExternalStringResource())); 444 String::Encoding encoding = String::UNKNOWN_ENCODING; 445 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 446 source->GetExternalStringResourceBase(&encoding)); 447 CHECK_EQ(String::TWO_BYTE_ENCODING, encoding); 448 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 449 CHECK_EQ(0, dispose_count); 450 } 451 v8::internal::Isolate::Current()->compilation_cache()->Clear(); 452 HEAP->CollectAllAvailableGarbage(); 453 CHECK_EQ(1, dispose_count); 454 } 455 456 457 THREADED_TEST(ScriptUsingAsciiStringResource) { 458 int dispose_count = 0; 459 const char* c_source = "1 + 2 * 3"; 460 { 461 LocalContext env; 462 v8::HandleScope scope(env->GetIsolate()); 463 TestAsciiResource* resource = new TestAsciiResource(i::StrDup(c_source), 464 &dispose_count); 465 Local<String> source = String::NewExternal(resource); 466 CHECK(source->IsExternalAscii()); 467 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 468 source->GetExternalAsciiStringResource()); 469 String::Encoding encoding = String::UNKNOWN_ENCODING; 470 CHECK_EQ(static_cast<const String::ExternalStringResourceBase*>(resource), 471 source->GetExternalStringResourceBase(&encoding)); 472 CHECK_EQ(String::ASCII_ENCODING, encoding); 473 Local<Script> script = Script::Compile(source); 474 Local<Value> value = script->Run(); 475 CHECK(value->IsNumber()); 476 CHECK_EQ(7, value->Int32Value()); 477 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 478 CHECK_EQ(0, dispose_count); 479 } 480 i::Isolate::Current()->compilation_cache()->Clear(); 481 HEAP->CollectAllAvailableGarbage(); 482 CHECK_EQ(1, dispose_count); 483 } 484 485 486 THREADED_TEST(ScriptMakingExternalString) { 487 int dispose_count = 0; 488 uint16_t* two_byte_source = AsciiToTwoByteString("1 + 2 * 3"); 489 { 490 LocalContext env; 491 v8::HandleScope scope(env->GetIsolate()); 492 Local<String> source = String::New(two_byte_source); 493 // Trigger GCs so that the newly allocated string moves to old gen. 494 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now 495 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now 496 CHECK_EQ(source->IsExternal(), false); 497 CHECK_EQ(source->IsExternalAscii(), false); 498 String::Encoding encoding = String::UNKNOWN_ENCODING; 499 CHECK_EQ(NULL, source->GetExternalStringResourceBase(&encoding)); 500 CHECK_EQ(String::ASCII_ENCODING, encoding); 501 bool success = source->MakeExternal(new TestResource(two_byte_source, 502 &dispose_count)); 503 CHECK(success); 504 Local<Script> script = Script::Compile(source); 505 Local<Value> value = script->Run(); 506 CHECK(value->IsNumber()); 507 CHECK_EQ(7, value->Int32Value()); 508 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 509 CHECK_EQ(0, dispose_count); 510 } 511 i::Isolate::Current()->compilation_cache()->Clear(); 512 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 513 CHECK_EQ(1, dispose_count); 514 } 515 516 517 THREADED_TEST(ScriptMakingExternalAsciiString) { 518 int dispose_count = 0; 519 const char* c_source = "1 + 2 * 3"; 520 { 521 LocalContext env; 522 v8::HandleScope scope(env->GetIsolate()); 523 Local<String> source = v8_str(c_source); 524 // Trigger GCs so that the newly allocated string moves to old gen. 525 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now 526 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now 527 bool success = source->MakeExternal( 528 new TestAsciiResource(i::StrDup(c_source), &dispose_count)); 529 CHECK(success); 530 Local<Script> script = Script::Compile(source); 531 Local<Value> value = script->Run(); 532 CHECK(value->IsNumber()); 533 CHECK_EQ(7, value->Int32Value()); 534 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 535 CHECK_EQ(0, dispose_count); 536 } 537 i::Isolate::Current()->compilation_cache()->Clear(); 538 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 539 CHECK_EQ(1, dispose_count); 540 } 541 542 543 TEST(MakingExternalStringConditions) { 544 LocalContext env; 545 v8::HandleScope scope(env->GetIsolate()); 546 547 // Free some space in the new space so that we can check freshness. 548 HEAP->CollectGarbage(i::NEW_SPACE); 549 HEAP->CollectGarbage(i::NEW_SPACE); 550 551 uint16_t* two_byte_string = AsciiToTwoByteString("s1"); 552 Local<String> small_string = String::New(two_byte_string); 553 i::DeleteArray(two_byte_string); 554 555 // We should refuse to externalize newly created small string. 556 CHECK(!small_string->CanMakeExternal()); 557 // Trigger GCs so that the newly allocated string moves to old gen. 558 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now 559 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now 560 // Old space strings should be accepted. 561 CHECK(small_string->CanMakeExternal()); 562 563 two_byte_string = AsciiToTwoByteString("small string 2"); 564 small_string = String::New(two_byte_string); 565 i::DeleteArray(two_byte_string); 566 567 // We should refuse externalizing newly created small string. 568 CHECK(!small_string->CanMakeExternal()); 569 for (int i = 0; i < 100; i++) { 570 String::Value value(small_string); 571 } 572 // Frequently used strings should be accepted. 573 CHECK(small_string->CanMakeExternal()); 574 575 const int buf_size = 10 * 1024; 576 char* buf = i::NewArray<char>(buf_size); 577 memset(buf, 'a', buf_size); 578 buf[buf_size - 1] = '\0'; 579 580 two_byte_string = AsciiToTwoByteString(buf); 581 Local<String> large_string = String::New(two_byte_string); 582 i::DeleteArray(buf); 583 i::DeleteArray(two_byte_string); 584 // Large strings should be immediately accepted. 585 CHECK(large_string->CanMakeExternal()); 586 } 587 588 589 TEST(MakingExternalAsciiStringConditions) { 590 LocalContext env; 591 v8::HandleScope scope(env->GetIsolate()); 592 593 // Free some space in the new space so that we can check freshness. 594 HEAP->CollectGarbage(i::NEW_SPACE); 595 HEAP->CollectGarbage(i::NEW_SPACE); 596 597 Local<String> small_string = String::New("s1"); 598 // We should refuse to externalize newly created small string. 599 CHECK(!small_string->CanMakeExternal()); 600 // Trigger GCs so that the newly allocated string moves to old gen. 601 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now 602 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now 603 // Old space strings should be accepted. 604 CHECK(small_string->CanMakeExternal()); 605 606 small_string = String::New("small string 2"); 607 // We should refuse externalizing newly created small string. 608 CHECK(!small_string->CanMakeExternal()); 609 for (int i = 0; i < 100; i++) { 610 String::Value value(small_string); 611 } 612 // Frequently used strings should be accepted. 613 CHECK(small_string->CanMakeExternal()); 614 615 const int buf_size = 10 * 1024; 616 char* buf = i::NewArray<char>(buf_size); 617 memset(buf, 'a', buf_size); 618 buf[buf_size - 1] = '\0'; 619 Local<String> large_string = String::New(buf); 620 i::DeleteArray(buf); 621 // Large strings should be immediately accepted. 622 CHECK(large_string->CanMakeExternal()); 623 } 624 625 626 TEST(MakingExternalUnalignedAsciiString) { 627 LocalContext env; 628 v8::HandleScope scope(env->GetIsolate()); 629 630 CompileRun("function cons(a, b) { return a + b; }" 631 "function slice(a) { return a.substring(1); }"); 632 // Create a cons string that will land in old pointer space. 633 Local<String> cons = Local<String>::Cast(CompileRun( 634 "cons('abcdefghijklm', 'nopqrstuvwxyz');")); 635 // Create a sliced string that will land in old pointer space. 636 Local<String> slice = Local<String>::Cast(CompileRun( 637 "slice('abcdefghijklmnopqrstuvwxyz');")); 638 639 // Trigger GCs so that the newly allocated string moves to old gen. 640 SimulateFullSpace(HEAP->old_pointer_space()); 641 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now 642 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now 643 644 // Turn into external string with unaligned resource data. 645 int dispose_count = 0; 646 const char* c_cons = "_abcdefghijklmnopqrstuvwxyz"; 647 bool success = cons->MakeExternal( 648 new TestAsciiResource(i::StrDup(c_cons) + 1, &dispose_count)); 649 CHECK(success); 650 const char* c_slice = "_bcdefghijklmnopqrstuvwxyz"; 651 success = slice->MakeExternal( 652 new TestAsciiResource(i::StrDup(c_slice) + 1, &dispose_count)); 653 CHECK(success); 654 655 // Trigger GCs and force evacuation. 656 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 657 HEAP->CollectAllGarbage(i::Heap::kReduceMemoryFootprintMask); 658 } 659 660 661 THREADED_TEST(UsingExternalString) { 662 i::Factory* factory = i::Isolate::Current()->factory(); 663 { 664 v8::HandleScope scope(v8::Isolate::GetCurrent()); 665 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 666 Local<String> string = 667 String::NewExternal(new TestResource(two_byte_string)); 668 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 669 // Trigger GCs so that the newly allocated string moves to old gen. 670 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now 671 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now 672 i::Handle<i::String> isymbol = 673 factory->InternalizedStringFromString(istring); 674 CHECK(isymbol->IsInternalizedString()); 675 } 676 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 677 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 678 } 679 680 681 THREADED_TEST(UsingExternalAsciiString) { 682 i::Factory* factory = i::Isolate::Current()->factory(); 683 { 684 v8::HandleScope scope(v8::Isolate::GetCurrent()); 685 const char* one_byte_string = "test string"; 686 Local<String> string = String::NewExternal( 687 new TestAsciiResource(i::StrDup(one_byte_string))); 688 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 689 // Trigger GCs so that the newly allocated string moves to old gen. 690 HEAP->CollectGarbage(i::NEW_SPACE); // in survivor space now 691 HEAP->CollectGarbage(i::NEW_SPACE); // in old gen now 692 i::Handle<i::String> isymbol = 693 factory->InternalizedStringFromString(istring); 694 CHECK(isymbol->IsInternalizedString()); 695 } 696 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 697 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 698 } 699 700 701 THREADED_TEST(ScavengeExternalString) { 702 i::FLAG_stress_compaction = false; 703 i::FLAG_gc_global = false; 704 int dispose_count = 0; 705 bool in_new_space = false; 706 { 707 v8::HandleScope scope(v8::Isolate::GetCurrent()); 708 uint16_t* two_byte_string = AsciiToTwoByteString("test string"); 709 Local<String> string = 710 String::NewExternal(new TestResource(two_byte_string, 711 &dispose_count)); 712 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 713 HEAP->CollectGarbage(i::NEW_SPACE); 714 in_new_space = HEAP->InNewSpace(*istring); 715 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring)); 716 CHECK_EQ(0, dispose_count); 717 } 718 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE); 719 CHECK_EQ(1, dispose_count); 720 } 721 722 723 THREADED_TEST(ScavengeExternalAsciiString) { 724 i::FLAG_stress_compaction = false; 725 i::FLAG_gc_global = false; 726 int dispose_count = 0; 727 bool in_new_space = false; 728 { 729 v8::HandleScope scope(v8::Isolate::GetCurrent()); 730 const char* one_byte_string = "test string"; 731 Local<String> string = String::NewExternal( 732 new TestAsciiResource(i::StrDup(one_byte_string), &dispose_count)); 733 i::Handle<i::String> istring = v8::Utils::OpenHandle(*string); 734 HEAP->CollectGarbage(i::NEW_SPACE); 735 in_new_space = HEAP->InNewSpace(*istring); 736 CHECK(in_new_space || HEAP->old_data_space()->Contains(*istring)); 737 CHECK_EQ(0, dispose_count); 738 } 739 HEAP->CollectGarbage(in_new_space ? i::NEW_SPACE : i::OLD_DATA_SPACE); 740 CHECK_EQ(1, dispose_count); 741 } 742 743 744 class TestAsciiResourceWithDisposeControl: public TestAsciiResource { 745 public: 746 // Only used by non-threaded tests, so it can use static fields. 747 static int dispose_calls; 748 static int dispose_count; 749 750 TestAsciiResourceWithDisposeControl(const char* data, bool dispose) 751 : TestAsciiResource(data, &dispose_count), 752 dispose_(dispose) { } 753 754 void Dispose() { 755 ++dispose_calls; 756 if (dispose_) delete this; 757 } 758 private: 759 bool dispose_; 760 }; 761 762 763 int TestAsciiResourceWithDisposeControl::dispose_count = 0; 764 int TestAsciiResourceWithDisposeControl::dispose_calls = 0; 765 766 767 TEST(ExternalStringWithDisposeHandling) { 768 const char* c_source = "1 + 2 * 3"; 769 770 // Use a stack allocated external string resource allocated object. 771 TestAsciiResourceWithDisposeControl::dispose_count = 0; 772 TestAsciiResourceWithDisposeControl::dispose_calls = 0; 773 TestAsciiResourceWithDisposeControl res_stack(i::StrDup(c_source), false); 774 { 775 LocalContext env; 776 v8::HandleScope scope(env->GetIsolate()); 777 Local<String> source = String::NewExternal(&res_stack); 778 Local<Script> script = Script::Compile(source); 779 Local<Value> value = script->Run(); 780 CHECK(value->IsNumber()); 781 CHECK_EQ(7, value->Int32Value()); 782 HEAP->CollectAllAvailableGarbage(); 783 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count); 784 } 785 i::Isolate::Current()->compilation_cache()->Clear(); 786 HEAP->CollectAllAvailableGarbage(); 787 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls); 788 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count); 789 790 // Use a heap allocated external string resource allocated object. 791 TestAsciiResourceWithDisposeControl::dispose_count = 0; 792 TestAsciiResourceWithDisposeControl::dispose_calls = 0; 793 TestAsciiResource* res_heap = 794 new TestAsciiResourceWithDisposeControl(i::StrDup(c_source), true); 795 { 796 LocalContext env; 797 v8::HandleScope scope(env->GetIsolate()); 798 Local<String> source = String::NewExternal(res_heap); 799 Local<Script> script = Script::Compile(source); 800 Local<Value> value = script->Run(); 801 CHECK(value->IsNumber()); 802 CHECK_EQ(7, value->Int32Value()); 803 HEAP->CollectAllAvailableGarbage(); 804 CHECK_EQ(0, TestAsciiResourceWithDisposeControl::dispose_count); 805 } 806 i::Isolate::Current()->compilation_cache()->Clear(); 807 HEAP->CollectAllAvailableGarbage(); 808 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_calls); 809 CHECK_EQ(1, TestAsciiResourceWithDisposeControl::dispose_count); 810 } 811 812 813 THREADED_TEST(StringConcat) { 814 { 815 LocalContext env; 816 v8::HandleScope scope(env->GetIsolate()); 817 const char* one_byte_string_1 = "function a_times_t"; 818 const char* two_byte_string_1 = "wo_plus_b(a, b) {return "; 819 const char* one_byte_extern_1 = "a * 2 + b;} a_times_two_plus_b(4, 8) + "; 820 const char* two_byte_extern_1 = "a_times_two_plus_b(4, 8) + "; 821 const char* one_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 822 const char* two_byte_string_2 = "a_times_two_plus_b(4, 8) + "; 823 const char* two_byte_extern_2 = "a_times_two_plus_b(1, 2);"; 824 Local<String> left = v8_str(one_byte_string_1); 825 826 uint16_t* two_byte_source = AsciiToTwoByteString(two_byte_string_1); 827 Local<String> right = String::New(two_byte_source); 828 i::DeleteArray(two_byte_source); 829 830 Local<String> source = String::Concat(left, right); 831 right = String::NewExternal( 832 new TestAsciiResource(i::StrDup(one_byte_extern_1))); 833 source = String::Concat(source, right); 834 right = String::NewExternal( 835 new TestResource(AsciiToTwoByteString(two_byte_extern_1))); 836 source = String::Concat(source, right); 837 right = v8_str(one_byte_string_2); 838 source = String::Concat(source, right); 839 840 two_byte_source = AsciiToTwoByteString(two_byte_string_2); 841 right = String::New(two_byte_source); 842 i::DeleteArray(two_byte_source); 843 844 source = String::Concat(source, right); 845 right = String::NewExternal( 846 new TestResource(AsciiToTwoByteString(two_byte_extern_2))); 847 source = String::Concat(source, right); 848 Local<Script> script = Script::Compile(source); 849 Local<Value> value = script->Run(); 850 CHECK(value->IsNumber()); 851 CHECK_EQ(68, value->Int32Value()); 852 } 853 i::Isolate::Current()->compilation_cache()->Clear(); 854 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 855 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 856 } 857 858 859 THREADED_TEST(GlobalProperties) { 860 LocalContext env; 861 v8::HandleScope scope(env->GetIsolate()); 862 v8::Handle<v8::Object> global = env->Global(); 863 global->Set(v8_str("pi"), v8_num(3.1415926)); 864 Local<Value> pi = global->Get(v8_str("pi")); 865 CHECK_EQ(3.1415926, pi->NumberValue()); 866 } 867 868 869 template<typename T> 870 static void CheckReturnValue(const T& t, i::Address callback) { 871 v8::ReturnValue<v8::Value> rv = t.GetReturnValue(); 872 i::Object** o = *reinterpret_cast<i::Object***>(&rv); 873 CHECK_EQ(v8::Isolate::GetCurrent(), t.GetIsolate()); 874 CHECK_EQ(t.GetIsolate(), rv.GetIsolate()); 875 CHECK((*o)->IsTheHole() || (*o)->IsUndefined()); 876 // Verify reset 877 bool is_runtime = (*o)->IsTheHole(); 878 rv.Set(true); 879 CHECK(!(*o)->IsTheHole() && !(*o)->IsUndefined()); 880 rv.Set(v8::Handle<v8::Object>()); 881 CHECK((*o)->IsTheHole() || (*o)->IsUndefined()); 882 CHECK_EQ(is_runtime, (*o)->IsTheHole()); 883 884 i::Isolate* isolate = reinterpret_cast<i::Isolate*>(t.GetIsolate()); 885 // If CPU profiler is active check that when API callback is invoked 886 // VMState is set to EXTERNAL. 887 if (isolate->cpu_profiler()->is_profiling()) { 888 CHECK_EQ(i::EXTERNAL, isolate->current_vm_state()); 889 CHECK(isolate->external_callback_scope()); 890 CHECK_EQ(callback, isolate->external_callback_scope()->callback()); 891 } 892 } 893 894 895 static void handle_callback_impl(const v8::FunctionCallbackInfo<Value>& info, 896 i::Address callback) { 897 ApiTestFuzzer::Fuzz(); 898 CheckReturnValue(info, callback); 899 info.GetReturnValue().Set(v8_str("bad value")); 900 info.GetReturnValue().Set(v8_num(102)); 901 } 902 903 904 static void handle_callback(const v8::FunctionCallbackInfo<Value>& info) { 905 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback)); 906 } 907 908 909 static void handle_callback_2(const v8::FunctionCallbackInfo<Value>& info) { 910 return handle_callback_impl(info, FUNCTION_ADDR(handle_callback_2)); 911 } 912 913 static void construct_callback( 914 const v8::FunctionCallbackInfo<Value>& info) { 915 ApiTestFuzzer::Fuzz(); 916 CheckReturnValue(info, FUNCTION_ADDR(construct_callback)); 917 info.This()->Set(v8_str("x"), v8_num(1)); 918 info.This()->Set(v8_str("y"), v8_num(2)); 919 info.GetReturnValue().Set(v8_str("bad value")); 920 info.GetReturnValue().Set(info.This()); 921 } 922 923 924 static void Return239Callback( 925 Local<String> name, const v8::PropertyCallbackInfo<Value>& info) { 926 ApiTestFuzzer::Fuzz(); 927 CheckReturnValue(info, FUNCTION_ADDR(Return239Callback)); 928 info.GetReturnValue().Set(v8_str("bad value")); 929 info.GetReturnValue().Set(v8_num(239)); 930 } 931 932 933 template<typename Handler> 934 static void TestFunctionTemplateInitializer(Handler handler, 935 Handler handler_2) { 936 // Test constructor calls. 937 { 938 LocalContext env; 939 v8::HandleScope scope(env->GetIsolate()); 940 941 Local<v8::FunctionTemplate> fun_templ = 942 v8::FunctionTemplate::New(handler); 943 Local<Function> fun = fun_templ->GetFunction(); 944 env->Global()->Set(v8_str("obj"), fun); 945 Local<Script> script = v8_compile("obj()"); 946 for (int i = 0; i < 30; i++) { 947 CHECK_EQ(102, script->Run()->Int32Value()); 948 } 949 } 950 // Use SetCallHandler to initialize a function template, should work like 951 // the previous one. 952 { 953 LocalContext env; 954 v8::HandleScope scope(env->GetIsolate()); 955 956 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 957 fun_templ->SetCallHandler(handler_2); 958 Local<Function> fun = fun_templ->GetFunction(); 959 env->Global()->Set(v8_str("obj"), fun); 960 Local<Script> script = v8_compile("obj()"); 961 for (int i = 0; i < 30; i++) { 962 CHECK_EQ(102, script->Run()->Int32Value()); 963 } 964 } 965 } 966 967 968 template<typename Constructor, typename Accessor> 969 static void TestFunctionTemplateAccessor(Constructor constructor, 970 Accessor accessor) { 971 LocalContext env; 972 v8::HandleScope scope(env->GetIsolate()); 973 974 Local<v8::FunctionTemplate> fun_templ = 975 v8::FunctionTemplate::New(constructor); 976 fun_templ->SetClassName(v8_str("funky")); 977 fun_templ->InstanceTemplate()->SetAccessor(v8_str("m"), accessor); 978 Local<Function> fun = fun_templ->GetFunction(); 979 env->Global()->Set(v8_str("obj"), fun); 980 Local<Value> result = v8_compile("(new obj()).toString()")->Run(); 981 CHECK_EQ(v8_str("[object funky]"), result); 982 CompileRun("var obj_instance = new obj();"); 983 Local<Script> script; 984 script = v8_compile("obj_instance.x"); 985 for (int i = 0; i < 30; i++) { 986 CHECK_EQ(1, script->Run()->Int32Value()); 987 } 988 script = v8_compile("obj_instance.m"); 989 for (int i = 0; i < 30; i++) { 990 CHECK_EQ(239, script->Run()->Int32Value()); 991 } 992 } 993 994 995 THREADED_PROFILED_TEST(FunctionTemplate) { 996 TestFunctionTemplateInitializer(handle_callback, handle_callback_2); 997 TestFunctionTemplateAccessor(construct_callback, Return239Callback); 998 } 999 1000 1001 static void SimpleCallback(const v8::FunctionCallbackInfo<v8::Value>& info) { 1002 ApiTestFuzzer::Fuzz(); 1003 CheckReturnValue(info, FUNCTION_ADDR(SimpleCallback)); 1004 info.GetReturnValue().Set(v8_num(51423 + info.Length())); 1005 } 1006 1007 1008 template<typename Callback> 1009 static void TestSimpleCallback(Callback callback) { 1010 LocalContext env; 1011 v8::HandleScope scope(env->GetIsolate()); 1012 1013 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(); 1014 object_template->Set("callback", v8::FunctionTemplate::New(callback)); 1015 v8::Local<v8::Object> object = object_template->NewInstance(); 1016 (*env)->Global()->Set(v8_str("callback_object"), object); 1017 v8::Handle<v8::Script> script; 1018 script = v8_compile("callback_object.callback(17)"); 1019 for (int i = 0; i < 30; i++) { 1020 CHECK_EQ(51424, script->Run()->Int32Value()); 1021 } 1022 script = v8_compile("callback_object.callback(17, 24)"); 1023 for (int i = 0; i < 30; i++) { 1024 CHECK_EQ(51425, script->Run()->Int32Value()); 1025 } 1026 } 1027 1028 1029 THREADED_PROFILED_TEST(SimpleCallback) { 1030 TestSimpleCallback(SimpleCallback); 1031 } 1032 1033 1034 template<typename T> 1035 void FastReturnValueCallback(const v8::FunctionCallbackInfo<v8::Value>& info); 1036 1037 // constant return values 1038 static int32_t fast_return_value_int32 = 471; 1039 static uint32_t fast_return_value_uint32 = 571; 1040 static const double kFastReturnValueDouble = 2.7; 1041 // variable return values 1042 static bool fast_return_value_bool = false; 1043 enum ReturnValueOddball { 1044 kNullReturnValue, 1045 kUndefinedReturnValue, 1046 kEmptyStringReturnValue 1047 }; 1048 static ReturnValueOddball fast_return_value_void; 1049 static bool fast_return_value_object_is_empty = false; 1050 1051 // Helper function to avoid compiler error: insufficient contextual information 1052 // to determine type when applying FUNCTION_ADDR to a template function. 1053 static i::Address address_of(v8::FunctionCallback callback) { 1054 return FUNCTION_ADDR(callback); 1055 } 1056 1057 template<> 1058 void FastReturnValueCallback<int32_t>( 1059 const v8::FunctionCallbackInfo<v8::Value>& info) { 1060 CheckReturnValue(info, address_of(FastReturnValueCallback<int32_t>)); 1061 info.GetReturnValue().Set(fast_return_value_int32); 1062 } 1063 1064 template<> 1065 void FastReturnValueCallback<uint32_t>( 1066 const v8::FunctionCallbackInfo<v8::Value>& info) { 1067 CheckReturnValue(info, address_of(FastReturnValueCallback<uint32_t>)); 1068 info.GetReturnValue().Set(fast_return_value_uint32); 1069 } 1070 1071 template<> 1072 void FastReturnValueCallback<double>( 1073 const v8::FunctionCallbackInfo<v8::Value>& info) { 1074 CheckReturnValue(info, address_of(FastReturnValueCallback<double>)); 1075 info.GetReturnValue().Set(kFastReturnValueDouble); 1076 } 1077 1078 template<> 1079 void FastReturnValueCallback<bool>( 1080 const v8::FunctionCallbackInfo<v8::Value>& info) { 1081 CheckReturnValue(info, address_of(FastReturnValueCallback<bool>)); 1082 info.GetReturnValue().Set(fast_return_value_bool); 1083 } 1084 1085 template<> 1086 void FastReturnValueCallback<void>( 1087 const v8::FunctionCallbackInfo<v8::Value>& info) { 1088 CheckReturnValue(info, address_of(FastReturnValueCallback<void>)); 1089 switch (fast_return_value_void) { 1090 case kNullReturnValue: 1091 info.GetReturnValue().SetNull(); 1092 break; 1093 case kUndefinedReturnValue: 1094 info.GetReturnValue().SetUndefined(); 1095 break; 1096 case kEmptyStringReturnValue: 1097 info.GetReturnValue().SetEmptyString(); 1098 break; 1099 } 1100 } 1101 1102 template<> 1103 void FastReturnValueCallback<Object>( 1104 const v8::FunctionCallbackInfo<v8::Value>& info) { 1105 v8::Handle<v8::Object> object; 1106 if (!fast_return_value_object_is_empty) object = Object::New(); 1107 info.GetReturnValue().Set(object); 1108 } 1109 1110 template<typename T> 1111 Handle<Value> TestFastReturnValues() { 1112 LocalContext env; 1113 v8::HandleScope scope(env->GetIsolate()); 1114 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(); 1115 v8::FunctionCallback callback = &FastReturnValueCallback<T>; 1116 object_template->Set("callback", v8::FunctionTemplate::New(callback)); 1117 v8::Local<v8::Object> object = object_template->NewInstance(); 1118 (*env)->Global()->Set(v8_str("callback_object"), object); 1119 return scope.Close(CompileRun("callback_object.callback()")); 1120 } 1121 1122 1123 THREADED_PROFILED_TEST(FastReturnValues) { 1124 LocalContext env; 1125 v8::HandleScope scope(v8::Isolate::GetCurrent()); 1126 v8::Handle<v8::Value> value; 1127 // check int32_t and uint32_t 1128 int32_t int_values[] = { 1129 0, 234, -723, 1130 i::Smi::kMinValue, i::Smi::kMaxValue 1131 }; 1132 for (size_t i = 0; i < ARRAY_SIZE(int_values); i++) { 1133 for (int modifier = -1; modifier <= 1; modifier++) { 1134 int int_value = int_values[i] + modifier; 1135 // check int32_t 1136 fast_return_value_int32 = int_value; 1137 value = TestFastReturnValues<int32_t>(); 1138 CHECK(value->IsInt32()); 1139 CHECK(fast_return_value_int32 == value->Int32Value()); 1140 // check uint32_t 1141 fast_return_value_uint32 = static_cast<uint32_t>(int_value); 1142 value = TestFastReturnValues<uint32_t>(); 1143 CHECK(value->IsUint32()); 1144 CHECK(fast_return_value_uint32 == value->Uint32Value()); 1145 } 1146 } 1147 // check double 1148 value = TestFastReturnValues<double>(); 1149 CHECK(value->IsNumber()); 1150 CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value()); 1151 // check bool values 1152 for (int i = 0; i < 2; i++) { 1153 fast_return_value_bool = i == 0; 1154 value = TestFastReturnValues<bool>(); 1155 CHECK(value->IsBoolean()); 1156 CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value()); 1157 } 1158 // check oddballs 1159 ReturnValueOddball oddballs[] = { 1160 kNullReturnValue, 1161 kUndefinedReturnValue, 1162 kEmptyStringReturnValue 1163 }; 1164 for (size_t i = 0; i < ARRAY_SIZE(oddballs); i++) { 1165 fast_return_value_void = oddballs[i]; 1166 value = TestFastReturnValues<void>(); 1167 switch (fast_return_value_void) { 1168 case kNullReturnValue: 1169 CHECK(value->IsNull()); 1170 break; 1171 case kUndefinedReturnValue: 1172 CHECK(value->IsUndefined()); 1173 break; 1174 case kEmptyStringReturnValue: 1175 CHECK(value->IsString()); 1176 CHECK_EQ(0, v8::String::Cast(*value)->Length()); 1177 break; 1178 } 1179 } 1180 // check handles 1181 fast_return_value_object_is_empty = false; 1182 value = TestFastReturnValues<Object>(); 1183 CHECK(value->IsObject()); 1184 fast_return_value_object_is_empty = true; 1185 value = TestFastReturnValues<Object>(); 1186 CHECK(value->IsUndefined()); 1187 } 1188 1189 1190 THREADED_TEST(FunctionTemplateSetLength) { 1191 LocalContext env; 1192 v8::HandleScope scope(env->GetIsolate()); 1193 { 1194 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New( 1195 handle_callback, Handle<v8::Value>(), Handle<v8::Signature>(), 23); 1196 Local<Function> fun = fun_templ->GetFunction(); 1197 env->Global()->Set(v8_str("obj"), fun); 1198 Local<Script> script = v8_compile("obj.length"); 1199 CHECK_EQ(23, script->Run()->Int32Value()); 1200 } 1201 { 1202 Local<v8::FunctionTemplate> fun_templ = 1203 v8::FunctionTemplate::New(handle_callback); 1204 fun_templ->SetLength(22); 1205 Local<Function> fun = fun_templ->GetFunction(); 1206 env->Global()->Set(v8_str("obj"), fun); 1207 Local<Script> script = v8_compile("obj.length"); 1208 CHECK_EQ(22, script->Run()->Int32Value()); 1209 } 1210 { 1211 // Without setting length it defaults to 0. 1212 Local<v8::FunctionTemplate> fun_templ = 1213 v8::FunctionTemplate::New(handle_callback); 1214 Local<Function> fun = fun_templ->GetFunction(); 1215 env->Global()->Set(v8_str("obj"), fun); 1216 Local<Script> script = v8_compile("obj.length"); 1217 CHECK_EQ(0, script->Run()->Int32Value()); 1218 } 1219 } 1220 1221 1222 static void* expected_ptr; 1223 static void callback(const v8::FunctionCallbackInfo<v8::Value>& args) { 1224 void* ptr = v8::External::Cast(*args.Data())->Value(); 1225 CHECK_EQ(expected_ptr, ptr); 1226 args.GetReturnValue().Set(true); 1227 } 1228 1229 1230 static void TestExternalPointerWrapping() { 1231 LocalContext env; 1232 v8::HandleScope scope(env->GetIsolate()); 1233 1234 v8::Handle<v8::Value> data = v8::External::New(expected_ptr); 1235 1236 v8::Handle<v8::Object> obj = v8::Object::New(); 1237 obj->Set(v8_str("func"), 1238 v8::FunctionTemplate::New(callback, data)->GetFunction()); 1239 env->Global()->Set(v8_str("obj"), obj); 1240 1241 CHECK(CompileRun( 1242 "function foo() {\n" 1243 " for (var i = 0; i < 13; i++) obj.func();\n" 1244 "}\n" 1245 "foo(), true")->BooleanValue()); 1246 } 1247 1248 1249 THREADED_TEST(ExternalWrap) { 1250 // Check heap allocated object. 1251 int* ptr = new int; 1252 expected_ptr = ptr; 1253 TestExternalPointerWrapping(); 1254 delete ptr; 1255 1256 // Check stack allocated object. 1257 int foo; 1258 expected_ptr = &foo; 1259 TestExternalPointerWrapping(); 1260 1261 // Check not aligned addresses. 1262 const int n = 100; 1263 char* s = new char[n]; 1264 for (int i = 0; i < n; i++) { 1265 expected_ptr = s + i; 1266 TestExternalPointerWrapping(); 1267 } 1268 1269 delete[] s; 1270 1271 // Check several invalid addresses. 1272 expected_ptr = reinterpret_cast<void*>(1); 1273 TestExternalPointerWrapping(); 1274 1275 expected_ptr = reinterpret_cast<void*>(0xdeadbeef); 1276 TestExternalPointerWrapping(); 1277 1278 expected_ptr = reinterpret_cast<void*>(0xdeadbeef + 1); 1279 TestExternalPointerWrapping(); 1280 1281 #if defined(V8_HOST_ARCH_X64) 1282 // Check a value with a leading 1 bit in x64 Smi encoding. 1283 expected_ptr = reinterpret_cast<void*>(0x400000000); 1284 TestExternalPointerWrapping(); 1285 1286 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef); 1287 TestExternalPointerWrapping(); 1288 1289 expected_ptr = reinterpret_cast<void*>(0xdeadbeefdeadbeef + 1); 1290 TestExternalPointerWrapping(); 1291 #endif 1292 } 1293 1294 1295 THREADED_TEST(FindInstanceInPrototypeChain) { 1296 LocalContext env; 1297 v8::HandleScope scope(env->GetIsolate()); 1298 1299 Local<v8::FunctionTemplate> base = v8::FunctionTemplate::New(); 1300 Local<v8::FunctionTemplate> derived = v8::FunctionTemplate::New(); 1301 Local<v8::FunctionTemplate> other = v8::FunctionTemplate::New(); 1302 derived->Inherit(base); 1303 1304 Local<v8::Function> base_function = base->GetFunction(); 1305 Local<v8::Function> derived_function = derived->GetFunction(); 1306 Local<v8::Function> other_function = other->GetFunction(); 1307 1308 Local<v8::Object> base_instance = base_function->NewInstance(); 1309 Local<v8::Object> derived_instance = derived_function->NewInstance(); 1310 Local<v8::Object> derived_instance2 = derived_function->NewInstance(); 1311 Local<v8::Object> other_instance = other_function->NewInstance(); 1312 derived_instance2->Set(v8_str("__proto__"), derived_instance); 1313 other_instance->Set(v8_str("__proto__"), derived_instance2); 1314 1315 // base_instance is only an instance of base. 1316 CHECK_EQ(base_instance, 1317 base_instance->FindInstanceInPrototypeChain(base)); 1318 CHECK(base_instance->FindInstanceInPrototypeChain(derived).IsEmpty()); 1319 CHECK(base_instance->FindInstanceInPrototypeChain(other).IsEmpty()); 1320 1321 // derived_instance is an instance of base and derived. 1322 CHECK_EQ(derived_instance, 1323 derived_instance->FindInstanceInPrototypeChain(base)); 1324 CHECK_EQ(derived_instance, 1325 derived_instance->FindInstanceInPrototypeChain(derived)); 1326 CHECK(derived_instance->FindInstanceInPrototypeChain(other).IsEmpty()); 1327 1328 // other_instance is an instance of other and its immediate 1329 // prototype derived_instance2 is an instance of base and derived. 1330 // Note, derived_instance is an instance of base and derived too, 1331 // but it comes after derived_instance2 in the prototype chain of 1332 // other_instance. 1333 CHECK_EQ(derived_instance2, 1334 other_instance->FindInstanceInPrototypeChain(base)); 1335 CHECK_EQ(derived_instance2, 1336 other_instance->FindInstanceInPrototypeChain(derived)); 1337 CHECK_EQ(other_instance, 1338 other_instance->FindInstanceInPrototypeChain(other)); 1339 } 1340 1341 1342 THREADED_TEST(TinyInteger) { 1343 LocalContext env; 1344 v8::HandleScope scope(env->GetIsolate()); 1345 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 1346 1347 int32_t value = 239; 1348 Local<v8::Integer> value_obj = v8::Integer::New(value); 1349 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1350 1351 value_obj = v8::Integer::New(value, isolate); 1352 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1353 } 1354 1355 1356 THREADED_TEST(BigSmiInteger) { 1357 LocalContext env; 1358 v8::HandleScope scope(env->GetIsolate()); 1359 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 1360 1361 int32_t value = i::Smi::kMaxValue; 1362 // We cannot add one to a Smi::kMaxValue without wrapping. 1363 if (i::kSmiValueSize < 32) { 1364 CHECK(i::Smi::IsValid(value)); 1365 CHECK(!i::Smi::IsValid(value + 1)); 1366 1367 Local<v8::Integer> value_obj = v8::Integer::New(value); 1368 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1369 1370 value_obj = v8::Integer::New(value, isolate); 1371 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1372 } 1373 } 1374 1375 1376 THREADED_TEST(BigInteger) { 1377 LocalContext env; 1378 v8::HandleScope scope(env->GetIsolate()); 1379 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 1380 1381 // We cannot add one to a Smi::kMaxValue without wrapping. 1382 if (i::kSmiValueSize < 32) { 1383 // The casts allow this to compile, even if Smi::kMaxValue is 2^31-1. 1384 // The code will not be run in that case, due to the "if" guard. 1385 int32_t value = 1386 static_cast<int32_t>(static_cast<uint32_t>(i::Smi::kMaxValue) + 1); 1387 CHECK(value > i::Smi::kMaxValue); 1388 CHECK(!i::Smi::IsValid(value)); 1389 1390 Local<v8::Integer> value_obj = v8::Integer::New(value); 1391 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1392 1393 value_obj = v8::Integer::New(value, isolate); 1394 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1395 } 1396 } 1397 1398 1399 THREADED_TEST(TinyUnsignedInteger) { 1400 LocalContext env; 1401 v8::HandleScope scope(env->GetIsolate()); 1402 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 1403 1404 uint32_t value = 239; 1405 1406 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); 1407 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1408 1409 value_obj = v8::Integer::NewFromUnsigned(value, isolate); 1410 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1411 } 1412 1413 1414 THREADED_TEST(BigUnsignedSmiInteger) { 1415 LocalContext env; 1416 v8::HandleScope scope(env->GetIsolate()); 1417 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 1418 1419 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue); 1420 CHECK(i::Smi::IsValid(value)); 1421 CHECK(!i::Smi::IsValid(value + 1)); 1422 1423 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); 1424 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1425 1426 value_obj = v8::Integer::NewFromUnsigned(value, isolate); 1427 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1428 } 1429 1430 1431 THREADED_TEST(BigUnsignedInteger) { 1432 LocalContext env; 1433 v8::HandleScope scope(env->GetIsolate()); 1434 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 1435 1436 uint32_t value = static_cast<uint32_t>(i::Smi::kMaxValue) + 1; 1437 CHECK(value > static_cast<uint32_t>(i::Smi::kMaxValue)); 1438 CHECK(!i::Smi::IsValid(value)); 1439 1440 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); 1441 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1442 1443 value_obj = v8::Integer::NewFromUnsigned(value, isolate); 1444 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1445 } 1446 1447 1448 THREADED_TEST(OutOfSignedRangeUnsignedInteger) { 1449 LocalContext env; 1450 v8::HandleScope scope(env->GetIsolate()); 1451 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 1452 1453 uint32_t INT32_MAX_AS_UINT = (1U << 31) - 1; 1454 uint32_t value = INT32_MAX_AS_UINT + 1; 1455 CHECK(value > INT32_MAX_AS_UINT); // No overflow. 1456 1457 Local<v8::Integer> value_obj = v8::Integer::NewFromUnsigned(value); 1458 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1459 1460 value_obj = v8::Integer::NewFromUnsigned(value, isolate); 1461 CHECK_EQ(static_cast<int64_t>(value), value_obj->Value()); 1462 } 1463 1464 1465 THREADED_TEST(IsNativeError) { 1466 LocalContext env; 1467 v8::HandleScope scope(env->GetIsolate()); 1468 v8::Handle<Value> syntax_error = CompileRun( 1469 "var out = 0; try { eval(\"#\"); } catch(x) { out = x; } out; "); 1470 CHECK(syntax_error->IsNativeError()); 1471 v8::Handle<Value> not_error = CompileRun("{a:42}"); 1472 CHECK(!not_error->IsNativeError()); 1473 v8::Handle<Value> not_object = CompileRun("42"); 1474 CHECK(!not_object->IsNativeError()); 1475 } 1476 1477 1478 THREADED_TEST(StringObject) { 1479 LocalContext env; 1480 v8::HandleScope scope(env->GetIsolate()); 1481 v8::Handle<Value> boxed_string = CompileRun("new String(\"test\")"); 1482 CHECK(boxed_string->IsStringObject()); 1483 v8::Handle<Value> unboxed_string = CompileRun("\"test\""); 1484 CHECK(!unboxed_string->IsStringObject()); 1485 v8::Handle<Value> boxed_not_string = CompileRun("new Number(42)"); 1486 CHECK(!boxed_not_string->IsStringObject()); 1487 v8::Handle<Value> not_object = CompileRun("0"); 1488 CHECK(!not_object->IsStringObject()); 1489 v8::Handle<v8::StringObject> as_boxed = boxed_string.As<v8::StringObject>(); 1490 CHECK(!as_boxed.IsEmpty()); 1491 Local<v8::String> the_string = as_boxed->ValueOf(); 1492 CHECK(!the_string.IsEmpty()); 1493 ExpectObject("\"test\"", the_string); 1494 v8::Handle<v8::Value> new_boxed_string = v8::StringObject::New(the_string); 1495 CHECK(new_boxed_string->IsStringObject()); 1496 as_boxed = new_boxed_string.As<v8::StringObject>(); 1497 the_string = as_boxed->ValueOf(); 1498 CHECK(!the_string.IsEmpty()); 1499 ExpectObject("\"test\"", the_string); 1500 } 1501 1502 1503 THREADED_TEST(NumberObject) { 1504 LocalContext env; 1505 v8::HandleScope scope(env->GetIsolate()); 1506 v8::Handle<Value> boxed_number = CompileRun("new Number(42)"); 1507 CHECK(boxed_number->IsNumberObject()); 1508 v8::Handle<Value> unboxed_number = CompileRun("42"); 1509 CHECK(!unboxed_number->IsNumberObject()); 1510 v8::Handle<Value> boxed_not_number = CompileRun("new Boolean(false)"); 1511 CHECK(!boxed_not_number->IsNumberObject()); 1512 v8::Handle<v8::NumberObject> as_boxed = boxed_number.As<v8::NumberObject>(); 1513 CHECK(!as_boxed.IsEmpty()); 1514 double the_number = as_boxed->ValueOf(); 1515 CHECK_EQ(42.0, the_number); 1516 v8::Handle<v8::Value> new_boxed_number = v8::NumberObject::New(43); 1517 CHECK(new_boxed_number->IsNumberObject()); 1518 as_boxed = new_boxed_number.As<v8::NumberObject>(); 1519 the_number = as_boxed->ValueOf(); 1520 CHECK_EQ(43.0, the_number); 1521 } 1522 1523 1524 THREADED_TEST(BooleanObject) { 1525 LocalContext env; 1526 v8::HandleScope scope(env->GetIsolate()); 1527 v8::Handle<Value> boxed_boolean = CompileRun("new Boolean(true)"); 1528 CHECK(boxed_boolean->IsBooleanObject()); 1529 v8::Handle<Value> unboxed_boolean = CompileRun("true"); 1530 CHECK(!unboxed_boolean->IsBooleanObject()); 1531 v8::Handle<Value> boxed_not_boolean = CompileRun("new Number(42)"); 1532 CHECK(!boxed_not_boolean->IsBooleanObject()); 1533 v8::Handle<v8::BooleanObject> as_boxed = 1534 boxed_boolean.As<v8::BooleanObject>(); 1535 CHECK(!as_boxed.IsEmpty()); 1536 bool the_boolean = as_boxed->ValueOf(); 1537 CHECK_EQ(true, the_boolean); 1538 v8::Handle<v8::Value> boxed_true = v8::BooleanObject::New(true); 1539 v8::Handle<v8::Value> boxed_false = v8::BooleanObject::New(false); 1540 CHECK(boxed_true->IsBooleanObject()); 1541 CHECK(boxed_false->IsBooleanObject()); 1542 as_boxed = boxed_true.As<v8::BooleanObject>(); 1543 CHECK_EQ(true, as_boxed->ValueOf()); 1544 as_boxed = boxed_false.As<v8::BooleanObject>(); 1545 CHECK_EQ(false, as_boxed->ValueOf()); 1546 } 1547 1548 1549 THREADED_TEST(PrimitiveAndWrappedBooleans) { 1550 LocalContext env; 1551 v8::HandleScope scope(env->GetIsolate()); 1552 1553 Local<Value> primitive_false = Boolean::New(false); 1554 CHECK(primitive_false->IsBoolean()); 1555 CHECK(!primitive_false->IsBooleanObject()); 1556 CHECK(!primitive_false->BooleanValue()); 1557 CHECK(!primitive_false->IsTrue()); 1558 CHECK(primitive_false->IsFalse()); 1559 1560 Local<Value> false_value = BooleanObject::New(false); 1561 CHECK(!false_value->IsBoolean()); 1562 CHECK(false_value->IsBooleanObject()); 1563 CHECK(false_value->BooleanValue()); 1564 CHECK(!false_value->IsTrue()); 1565 CHECK(!false_value->IsFalse()); 1566 1567 Local<BooleanObject> false_boolean_object = false_value.As<BooleanObject>(); 1568 CHECK(!false_boolean_object->IsBoolean()); 1569 CHECK(false_boolean_object->IsBooleanObject()); 1570 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted. 1571 // CHECK(false_boolean_object->BooleanValue()); 1572 CHECK(!false_boolean_object->ValueOf()); 1573 CHECK(!false_boolean_object->IsTrue()); 1574 CHECK(!false_boolean_object->IsFalse()); 1575 1576 Local<Value> primitive_true = Boolean::New(true); 1577 CHECK(primitive_true->IsBoolean()); 1578 CHECK(!primitive_true->IsBooleanObject()); 1579 CHECK(primitive_true->BooleanValue()); 1580 CHECK(primitive_true->IsTrue()); 1581 CHECK(!primitive_true->IsFalse()); 1582 1583 Local<Value> true_value = BooleanObject::New(true); 1584 CHECK(!true_value->IsBoolean()); 1585 CHECK(true_value->IsBooleanObject()); 1586 CHECK(true_value->BooleanValue()); 1587 CHECK(!true_value->IsTrue()); 1588 CHECK(!true_value->IsFalse()); 1589 1590 Local<BooleanObject> true_boolean_object = true_value.As<BooleanObject>(); 1591 CHECK(!true_boolean_object->IsBoolean()); 1592 CHECK(true_boolean_object->IsBooleanObject()); 1593 // TODO(svenpanne) Uncomment when BooleanObject::BooleanValue() is deleted. 1594 // CHECK(true_boolean_object->BooleanValue()); 1595 CHECK(true_boolean_object->ValueOf()); 1596 CHECK(!true_boolean_object->IsTrue()); 1597 CHECK(!true_boolean_object->IsFalse()); 1598 } 1599 1600 1601 THREADED_TEST(Number) { 1602 LocalContext env; 1603 v8::HandleScope scope(env->GetIsolate()); 1604 double PI = 3.1415926; 1605 Local<v8::Number> pi_obj = v8::Number::New(PI); 1606 CHECK_EQ(PI, pi_obj->NumberValue()); 1607 } 1608 1609 1610 THREADED_TEST(ToNumber) { 1611 LocalContext env; 1612 v8::HandleScope scope(env->GetIsolate()); 1613 Local<String> str = v8_str("3.1415926"); 1614 CHECK_EQ(3.1415926, str->NumberValue()); 1615 v8::Handle<v8::Boolean> t = v8::True(); 1616 CHECK_EQ(1.0, t->NumberValue()); 1617 v8::Handle<v8::Boolean> f = v8::False(); 1618 CHECK_EQ(0.0, f->NumberValue()); 1619 } 1620 1621 1622 THREADED_TEST(Date) { 1623 LocalContext env; 1624 v8::HandleScope scope(env->GetIsolate()); 1625 double PI = 3.1415926; 1626 Local<Value> date = v8::Date::New(PI); 1627 CHECK_EQ(3.0, date->NumberValue()); 1628 date.As<v8::Date>()->Set(v8_str("property"), v8::Integer::New(42)); 1629 CHECK_EQ(42, date.As<v8::Date>()->Get(v8_str("property"))->Int32Value()); 1630 } 1631 1632 1633 THREADED_TEST(Boolean) { 1634 LocalContext env; 1635 v8::HandleScope scope(env->GetIsolate()); 1636 v8::Handle<v8::Boolean> t = v8::True(); 1637 CHECK(t->Value()); 1638 v8::Handle<v8::Boolean> f = v8::False(); 1639 CHECK(!f->Value()); 1640 v8::Handle<v8::Primitive> u = v8::Undefined(); 1641 CHECK(!u->BooleanValue()); 1642 v8::Handle<v8::Primitive> n = v8::Null(); 1643 CHECK(!n->BooleanValue()); 1644 v8::Handle<String> str1 = v8_str(""); 1645 CHECK(!str1->BooleanValue()); 1646 v8::Handle<String> str2 = v8_str("x"); 1647 CHECK(str2->BooleanValue()); 1648 CHECK(!v8::Number::New(0)->BooleanValue()); 1649 CHECK(v8::Number::New(-1)->BooleanValue()); 1650 CHECK(v8::Number::New(1)->BooleanValue()); 1651 CHECK(v8::Number::New(42)->BooleanValue()); 1652 CHECK(!v8_compile("NaN")->Run()->BooleanValue()); 1653 } 1654 1655 1656 static void DummyCallHandler(const v8::FunctionCallbackInfo<v8::Value>& args) { 1657 ApiTestFuzzer::Fuzz(); 1658 args.GetReturnValue().Set(v8_num(13.4)); 1659 } 1660 1661 1662 static void GetM(Local<String> name, 1663 const v8::PropertyCallbackInfo<v8::Value>& info) { 1664 ApiTestFuzzer::Fuzz(); 1665 info.GetReturnValue().Set(v8_num(876)); 1666 } 1667 1668 1669 THREADED_TEST(GlobalPrototype) { 1670 v8::HandleScope scope(v8::Isolate::GetCurrent()); 1671 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New(); 1672 func_templ->PrototypeTemplate()->Set( 1673 "dummy", 1674 v8::FunctionTemplate::New(DummyCallHandler)); 1675 v8::Handle<ObjectTemplate> templ = func_templ->InstanceTemplate(); 1676 templ->Set("x", v8_num(200)); 1677 templ->SetAccessor(v8_str("m"), GetM); 1678 LocalContext env(0, templ); 1679 v8::Handle<Script> script(v8_compile("dummy()")); 1680 v8::Handle<Value> result(script->Run()); 1681 CHECK_EQ(13.4, result->NumberValue()); 1682 CHECK_EQ(200, v8_compile("x")->Run()->Int32Value()); 1683 CHECK_EQ(876, v8_compile("m")->Run()->Int32Value()); 1684 } 1685 1686 1687 THREADED_TEST(ObjectTemplate) { 1688 v8::HandleScope scope(v8::Isolate::GetCurrent()); 1689 Local<ObjectTemplate> templ1 = ObjectTemplate::New(); 1690 templ1->Set("x", v8_num(10)); 1691 templ1->Set("y", v8_num(13)); 1692 LocalContext env; 1693 Local<v8::Object> instance1 = templ1->NewInstance(); 1694 env->Global()->Set(v8_str("p"), instance1); 1695 CHECK(v8_compile("(p.x == 10)")->Run()->BooleanValue()); 1696 CHECK(v8_compile("(p.y == 13)")->Run()->BooleanValue()); 1697 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(); 1698 fun->PrototypeTemplate()->Set("nirk", v8_num(123)); 1699 Local<ObjectTemplate> templ2 = fun->InstanceTemplate(); 1700 templ2->Set("a", v8_num(12)); 1701 templ2->Set("b", templ1); 1702 Local<v8::Object> instance2 = templ2->NewInstance(); 1703 env->Global()->Set(v8_str("q"), instance2); 1704 CHECK(v8_compile("(q.nirk == 123)")->Run()->BooleanValue()); 1705 CHECK(v8_compile("(q.a == 12)")->Run()->BooleanValue()); 1706 CHECK(v8_compile("(q.b.x == 10)")->Run()->BooleanValue()); 1707 CHECK(v8_compile("(q.b.y == 13)")->Run()->BooleanValue()); 1708 } 1709 1710 1711 static void GetFlabby(const v8::FunctionCallbackInfo<v8::Value>& args) { 1712 ApiTestFuzzer::Fuzz(); 1713 args.GetReturnValue().Set(v8_num(17.2)); 1714 } 1715 1716 1717 static void GetKnurd(Local<String> property, 1718 const v8::PropertyCallbackInfo<v8::Value>& info) { 1719 ApiTestFuzzer::Fuzz(); 1720 info.GetReturnValue().Set(v8_num(15.2)); 1721 } 1722 1723 1724 THREADED_TEST(DescriptorInheritance) { 1725 v8::HandleScope scope(v8::Isolate::GetCurrent()); 1726 v8::Handle<v8::FunctionTemplate> super = v8::FunctionTemplate::New(); 1727 super->PrototypeTemplate()->Set("flabby", 1728 v8::FunctionTemplate::New(GetFlabby)); 1729 super->PrototypeTemplate()->Set("PI", v8_num(3.14)); 1730 1731 super->InstanceTemplate()->SetAccessor(v8_str("knurd"), GetKnurd); 1732 1733 v8::Handle<v8::FunctionTemplate> base1 = v8::FunctionTemplate::New(); 1734 base1->Inherit(super); 1735 base1->PrototypeTemplate()->Set("v1", v8_num(20.1)); 1736 1737 v8::Handle<v8::FunctionTemplate> base2 = v8::FunctionTemplate::New(); 1738 base2->Inherit(super); 1739 base2->PrototypeTemplate()->Set("v2", v8_num(10.1)); 1740 1741 LocalContext env; 1742 1743 env->Global()->Set(v8_str("s"), super->GetFunction()); 1744 env->Global()->Set(v8_str("base1"), base1->GetFunction()); 1745 env->Global()->Set(v8_str("base2"), base2->GetFunction()); 1746 1747 // Checks right __proto__ chain. 1748 CHECK(CompileRun("base1.prototype.__proto__ == s.prototype")->BooleanValue()); 1749 CHECK(CompileRun("base2.prototype.__proto__ == s.prototype")->BooleanValue()); 1750 1751 CHECK(v8_compile("s.prototype.PI == 3.14")->Run()->BooleanValue()); 1752 1753 // Instance accessor should not be visible on function object or its prototype 1754 CHECK(CompileRun("s.knurd == undefined")->BooleanValue()); 1755 CHECK(CompileRun("s.prototype.knurd == undefined")->BooleanValue()); 1756 CHECK(CompileRun("base1.prototype.knurd == undefined")->BooleanValue()); 1757 1758 env->Global()->Set(v8_str("obj"), 1759 base1->GetFunction()->NewInstance()); 1760 CHECK_EQ(17.2, v8_compile("obj.flabby()")->Run()->NumberValue()); 1761 CHECK(v8_compile("'flabby' in obj")->Run()->BooleanValue()); 1762 CHECK_EQ(15.2, v8_compile("obj.knurd")->Run()->NumberValue()); 1763 CHECK(v8_compile("'knurd' in obj")->Run()->BooleanValue()); 1764 CHECK_EQ(20.1, v8_compile("obj.v1")->Run()->NumberValue()); 1765 1766 env->Global()->Set(v8_str("obj2"), 1767 base2->GetFunction()->NewInstance()); 1768 CHECK_EQ(17.2, v8_compile("obj2.flabby()")->Run()->NumberValue()); 1769 CHECK(v8_compile("'flabby' in obj2")->Run()->BooleanValue()); 1770 CHECK_EQ(15.2, v8_compile("obj2.knurd")->Run()->NumberValue()); 1771 CHECK(v8_compile("'knurd' in obj2")->Run()->BooleanValue()); 1772 CHECK_EQ(10.1, v8_compile("obj2.v2")->Run()->NumberValue()); 1773 1774 // base1 and base2 cannot cross reference to each's prototype 1775 CHECK(v8_compile("obj.v2")->Run()->IsUndefined()); 1776 CHECK(v8_compile("obj2.v1")->Run()->IsUndefined()); 1777 } 1778 1779 1780 int echo_named_call_count; 1781 1782 1783 static void EchoNamedProperty(Local<String> name, 1784 const v8::PropertyCallbackInfo<v8::Value>& info) { 1785 ApiTestFuzzer::Fuzz(); 1786 CHECK_EQ(v8_str("data"), info.Data()); 1787 echo_named_call_count++; 1788 info.GetReturnValue().Set(name); 1789 } 1790 1791 1792 // Helper functions for Interceptor/Accessor interaction tests 1793 1794 void SimpleAccessorGetter(Local<String> name, 1795 const v8::PropertyCallbackInfo<v8::Value>& info) { 1796 Handle<Object> self = info.This(); 1797 info.GetReturnValue().Set( 1798 self->Get(String::Concat(v8_str("accessor_"), name))); 1799 } 1800 1801 void SimpleAccessorSetter(Local<String> name, Local<Value> value, 1802 const v8::PropertyCallbackInfo<void>& info) { 1803 Handle<Object> self = info.This(); 1804 self->Set(String::Concat(v8_str("accessor_"), name), value); 1805 } 1806 1807 void EmptyInterceptorGetter(Local<String> name, 1808 const v8::PropertyCallbackInfo<v8::Value>& info) { 1809 } 1810 1811 void EmptyInterceptorSetter(Local<String> name, 1812 Local<Value> value, 1813 const v8::PropertyCallbackInfo<v8::Value>& info) { 1814 } 1815 1816 void InterceptorGetter(Local<String> name, 1817 const v8::PropertyCallbackInfo<v8::Value>& info) { 1818 // Intercept names that start with 'interceptor_'. 1819 String::Utf8Value utf8(name); 1820 char* name_str = *utf8; 1821 char prefix[] = "interceptor_"; 1822 int i; 1823 for (i = 0; name_str[i] && prefix[i]; ++i) { 1824 if (name_str[i] != prefix[i]) return; 1825 } 1826 Handle<Object> self = info.This(); 1827 info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i))); 1828 } 1829 1830 void InterceptorSetter(Local<String> name, 1831 Local<Value> value, 1832 const v8::PropertyCallbackInfo<v8::Value>& info) { 1833 // Intercept accesses that set certain integer values. 1834 if (value->IsInt32() && value->Int32Value() < 10000) { 1835 Handle<Object> self = info.This(); 1836 self->SetHiddenValue(name, value); 1837 info.GetReturnValue().Set(value); 1838 } 1839 } 1840 1841 void AddAccessor(Handle<FunctionTemplate> templ, 1842 Handle<String> name, 1843 v8::AccessorGetterCallback getter, 1844 v8::AccessorSetterCallback setter) { 1845 templ->PrototypeTemplate()->SetAccessor(name, getter, setter); 1846 } 1847 1848 void AddInterceptor(Handle<FunctionTemplate> templ, 1849 v8::NamedPropertyGetterCallback getter, 1850 v8::NamedPropertySetterCallback setter) { 1851 templ->InstanceTemplate()->SetNamedPropertyHandler(getter, setter); 1852 } 1853 1854 1855 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) { 1856 v8::HandleScope scope(v8::Isolate::GetCurrent()); 1857 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 1858 Handle<FunctionTemplate> child = FunctionTemplate::New(); 1859 child->Inherit(parent); 1860 AddAccessor(parent, v8_str("age"), 1861 SimpleAccessorGetter, SimpleAccessorSetter); 1862 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); 1863 LocalContext env; 1864 env->Global()->Set(v8_str("Child"), child->GetFunction()); 1865 CompileRun("var child = new Child;" 1866 "child.age = 10;"); 1867 ExpectBoolean("child.hasOwnProperty('age')", false); 1868 ExpectInt32("child.age", 10); 1869 ExpectInt32("child.accessor_age", 10); 1870 } 1871 1872 1873 THREADED_TEST(EmptyInterceptorDoesNotShadowJSAccessors) { 1874 v8::HandleScope scope(v8::Isolate::GetCurrent()); 1875 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 1876 Handle<FunctionTemplate> child = FunctionTemplate::New(); 1877 child->Inherit(parent); 1878 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); 1879 LocalContext env; 1880 env->Global()->Set(v8_str("Child"), child->GetFunction()); 1881 CompileRun("var child = new Child;" 1882 "var parent = child.__proto__;" 1883 "Object.defineProperty(parent, 'age', " 1884 " {get: function(){ return this.accessor_age; }, " 1885 " set: function(v){ this.accessor_age = v; }, " 1886 " enumerable: true, configurable: true});" 1887 "child.age = 10;"); 1888 ExpectBoolean("child.hasOwnProperty('age')", false); 1889 ExpectInt32("child.age", 10); 1890 ExpectInt32("child.accessor_age", 10); 1891 } 1892 1893 1894 THREADED_TEST(EmptyInterceptorDoesNotAffectJSProperties) { 1895 v8::HandleScope scope(v8::Isolate::GetCurrent()); 1896 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 1897 Handle<FunctionTemplate> child = FunctionTemplate::New(); 1898 child->Inherit(parent); 1899 AddInterceptor(child, EmptyInterceptorGetter, EmptyInterceptorSetter); 1900 LocalContext env; 1901 env->Global()->Set(v8_str("Child"), child->GetFunction()); 1902 CompileRun("var child = new Child;" 1903 "var parent = child.__proto__;" 1904 "parent.name = 'Alice';"); 1905 ExpectBoolean("child.hasOwnProperty('name')", false); 1906 ExpectString("child.name", "Alice"); 1907 CompileRun("child.name = 'Bob';"); 1908 ExpectString("child.name", "Bob"); 1909 ExpectBoolean("child.hasOwnProperty('name')", true); 1910 ExpectString("parent.name", "Alice"); 1911 } 1912 1913 1914 THREADED_TEST(SwitchFromInterceptorToAccessor) { 1915 v8::HandleScope scope(v8::Isolate::GetCurrent()); 1916 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 1917 AddAccessor(templ, v8_str("age"), 1918 SimpleAccessorGetter, SimpleAccessorSetter); 1919 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 1920 LocalContext env; 1921 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 1922 CompileRun("var obj = new Obj;" 1923 "function setAge(i){ obj.age = i; };" 1924 "for(var i = 0; i <= 10000; i++) setAge(i);"); 1925 // All i < 10000 go to the interceptor. 1926 ExpectInt32("obj.interceptor_age", 9999); 1927 // The last i goes to the accessor. 1928 ExpectInt32("obj.accessor_age", 10000); 1929 } 1930 1931 1932 THREADED_TEST(SwitchFromAccessorToInterceptor) { 1933 v8::HandleScope scope(v8::Isolate::GetCurrent()); 1934 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 1935 AddAccessor(templ, v8_str("age"), 1936 SimpleAccessorGetter, SimpleAccessorSetter); 1937 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 1938 LocalContext env; 1939 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 1940 CompileRun("var obj = new Obj;" 1941 "function setAge(i){ obj.age = i; };" 1942 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 1943 // All i >= 10000 go to the accessor. 1944 ExpectInt32("obj.accessor_age", 10000); 1945 // The last i goes to the interceptor. 1946 ExpectInt32("obj.interceptor_age", 9999); 1947 } 1948 1949 1950 THREADED_TEST(SwitchFromInterceptorToAccessorWithInheritance) { 1951 v8::HandleScope scope(v8::Isolate::GetCurrent()); 1952 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 1953 Handle<FunctionTemplate> child = FunctionTemplate::New(); 1954 child->Inherit(parent); 1955 AddAccessor(parent, v8_str("age"), 1956 SimpleAccessorGetter, SimpleAccessorSetter); 1957 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 1958 LocalContext env; 1959 env->Global()->Set(v8_str("Child"), child->GetFunction()); 1960 CompileRun("var child = new Child;" 1961 "function setAge(i){ child.age = i; };" 1962 "for(var i = 0; i <= 10000; i++) setAge(i);"); 1963 // All i < 10000 go to the interceptor. 1964 ExpectInt32("child.interceptor_age", 9999); 1965 // The last i goes to the accessor. 1966 ExpectInt32("child.accessor_age", 10000); 1967 } 1968 1969 1970 THREADED_TEST(SwitchFromAccessorToInterceptorWithInheritance) { 1971 v8::HandleScope scope(v8::Isolate::GetCurrent()); 1972 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 1973 Handle<FunctionTemplate> child = FunctionTemplate::New(); 1974 child->Inherit(parent); 1975 AddAccessor(parent, v8_str("age"), 1976 SimpleAccessorGetter, SimpleAccessorSetter); 1977 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 1978 LocalContext env; 1979 env->Global()->Set(v8_str("Child"), child->GetFunction()); 1980 CompileRun("var child = new Child;" 1981 "function setAge(i){ child.age = i; };" 1982 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 1983 // All i >= 10000 go to the accessor. 1984 ExpectInt32("child.accessor_age", 10000); 1985 // The last i goes to the interceptor. 1986 ExpectInt32("child.interceptor_age", 9999); 1987 } 1988 1989 1990 THREADED_TEST(SwitchFromInterceptorToJSAccessor) { 1991 v8::HandleScope scope(v8::Isolate::GetCurrent()); 1992 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 1993 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 1994 LocalContext env; 1995 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 1996 CompileRun("var obj = new Obj;" 1997 "function setter(i) { this.accessor_age = i; };" 1998 "function getter() { return this.accessor_age; };" 1999 "function setAge(i) { obj.age = i; };" 2000 "Object.defineProperty(obj, 'age', { get:getter, set:setter });" 2001 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2002 // All i < 10000 go to the interceptor. 2003 ExpectInt32("obj.interceptor_age", 9999); 2004 // The last i goes to the JavaScript accessor. 2005 ExpectInt32("obj.accessor_age", 10000); 2006 // The installed JavaScript getter is still intact. 2007 // This last part is a regression test for issue 1651 and relies on the fact 2008 // that both interceptor and accessor are being installed on the same object. 2009 ExpectInt32("obj.age", 10000); 2010 ExpectBoolean("obj.hasOwnProperty('age')", true); 2011 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value"); 2012 } 2013 2014 2015 THREADED_TEST(SwitchFromJSAccessorToInterceptor) { 2016 v8::HandleScope scope(v8::Isolate::GetCurrent()); 2017 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 2018 AddInterceptor(templ, InterceptorGetter, InterceptorSetter); 2019 LocalContext env; 2020 env->Global()->Set(v8_str("Obj"), templ->GetFunction()); 2021 CompileRun("var obj = new Obj;" 2022 "function setter(i) { this.accessor_age = i; };" 2023 "function getter() { return this.accessor_age; };" 2024 "function setAge(i) { obj.age = i; };" 2025 "Object.defineProperty(obj, 'age', { get:getter, set:setter });" 2026 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 2027 // All i >= 10000 go to the accessor. 2028 ExpectInt32("obj.accessor_age", 10000); 2029 // The last i goes to the interceptor. 2030 ExpectInt32("obj.interceptor_age", 9999); 2031 // The installed JavaScript getter is still intact. 2032 // This last part is a regression test for issue 1651 and relies on the fact 2033 // that both interceptor and accessor are being installed on the same object. 2034 ExpectInt32("obj.age", 10000); 2035 ExpectBoolean("obj.hasOwnProperty('age')", true); 2036 ExpectUndefined("Object.getOwnPropertyDescriptor(obj, 'age').value"); 2037 } 2038 2039 2040 THREADED_TEST(SwitchFromInterceptorToProperty) { 2041 v8::HandleScope scope(v8::Isolate::GetCurrent()); 2042 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 2043 Handle<FunctionTemplate> child = FunctionTemplate::New(); 2044 child->Inherit(parent); 2045 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2046 LocalContext env; 2047 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2048 CompileRun("var child = new Child;" 2049 "function setAge(i){ child.age = i; };" 2050 "for(var i = 0; i <= 10000; i++) setAge(i);"); 2051 // All i < 10000 go to the interceptor. 2052 ExpectInt32("child.interceptor_age", 9999); 2053 // The last i goes to child's own property. 2054 ExpectInt32("child.age", 10000); 2055 } 2056 2057 2058 THREADED_TEST(SwitchFromPropertyToInterceptor) { 2059 v8::HandleScope scope(v8::Isolate::GetCurrent()); 2060 Handle<FunctionTemplate> parent = FunctionTemplate::New(); 2061 Handle<FunctionTemplate> child = FunctionTemplate::New(); 2062 child->Inherit(parent); 2063 AddInterceptor(child, InterceptorGetter, InterceptorSetter); 2064 LocalContext env; 2065 env->Global()->Set(v8_str("Child"), child->GetFunction()); 2066 CompileRun("var child = new Child;" 2067 "function setAge(i){ child.age = i; };" 2068 "for(var i = 20000; i >= 9999; i--) setAge(i);"); 2069 // All i >= 10000 go to child's own property. 2070 ExpectInt32("child.age", 10000); 2071 // The last i goes to the interceptor. 2072 ExpectInt32("child.interceptor_age", 9999); 2073 } 2074 2075 2076 THREADED_TEST(NamedPropertyHandlerGetter) { 2077 echo_named_call_count = 0; 2078 v8::HandleScope scope(v8::Isolate::GetCurrent()); 2079 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 2080 templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty, 2081 0, 0, 0, 0, 2082 v8_str("data")); 2083 LocalContext env; 2084 env->Global()->Set(v8_str("obj"), 2085 templ->GetFunction()->NewInstance()); 2086 CHECK_EQ(echo_named_call_count, 0); 2087 v8_compile("obj.x")->Run(); 2088 CHECK_EQ(echo_named_call_count, 1); 2089 const char* code = "var str = 'oddle'; obj[str] + obj.poddle;"; 2090 v8::Handle<Value> str = CompileRun(code); 2091 String::Utf8Value value(str); 2092 CHECK_EQ(*value, "oddlepoddle"); 2093 // Check default behavior 2094 CHECK_EQ(v8_compile("obj.flob = 10;")->Run()->Int32Value(), 10); 2095 CHECK(v8_compile("'myProperty' in obj")->Run()->BooleanValue()); 2096 CHECK(v8_compile("delete obj.myProperty")->Run()->BooleanValue()); 2097 } 2098 2099 2100 int echo_indexed_call_count = 0; 2101 2102 2103 static void EchoIndexedProperty( 2104 uint32_t index, 2105 const v8::PropertyCallbackInfo<v8::Value>& info) { 2106 ApiTestFuzzer::Fuzz(); 2107 CHECK_EQ(v8_num(637), info.Data()); 2108 echo_indexed_call_count++; 2109 info.GetReturnValue().Set(v8_num(index)); 2110 } 2111 2112 2113 THREADED_TEST(IndexedPropertyHandlerGetter) { 2114 v8::HandleScope scope(v8::Isolate::GetCurrent()); 2115 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 2116 templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty, 2117 0, 0, 0, 0, 2118 v8_num(637)); 2119 LocalContext env; 2120 env->Global()->Set(v8_str("obj"), 2121 templ->GetFunction()->NewInstance()); 2122 Local<Script> script = v8_compile("obj[900]"); 2123 CHECK_EQ(script->Run()->Int32Value(), 900); 2124 } 2125 2126 2127 v8::Handle<v8::Object> bottom; 2128 2129 static void CheckThisIndexedPropertyHandler( 2130 uint32_t index, 2131 const v8::PropertyCallbackInfo<v8::Value>& info) { 2132 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyHandler)); 2133 ApiTestFuzzer::Fuzz(); 2134 CHECK(info.This()->Equals(bottom)); 2135 } 2136 2137 static void CheckThisNamedPropertyHandler( 2138 Local<String> name, 2139 const v8::PropertyCallbackInfo<v8::Value>& info) { 2140 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler)); 2141 ApiTestFuzzer::Fuzz(); 2142 CHECK(info.This()->Equals(bottom)); 2143 } 2144 2145 void CheckThisIndexedPropertySetter( 2146 uint32_t index, 2147 Local<Value> value, 2148 const v8::PropertyCallbackInfo<v8::Value>& info) { 2149 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertySetter)); 2150 ApiTestFuzzer::Fuzz(); 2151 CHECK(info.This()->Equals(bottom)); 2152 } 2153 2154 2155 void CheckThisNamedPropertySetter( 2156 Local<String> property, 2157 Local<Value> value, 2158 const v8::PropertyCallbackInfo<v8::Value>& info) { 2159 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter)); 2160 ApiTestFuzzer::Fuzz(); 2161 CHECK(info.This()->Equals(bottom)); 2162 } 2163 2164 void CheckThisIndexedPropertyQuery( 2165 uint32_t index, 2166 const v8::PropertyCallbackInfo<v8::Integer>& info) { 2167 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyQuery)); 2168 ApiTestFuzzer::Fuzz(); 2169 CHECK(info.This()->Equals(bottom)); 2170 } 2171 2172 2173 void CheckThisNamedPropertyQuery( 2174 Local<String> property, 2175 const v8::PropertyCallbackInfo<v8::Integer>& info) { 2176 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery)); 2177 ApiTestFuzzer::Fuzz(); 2178 CHECK(info.This()->Equals(bottom)); 2179 } 2180 2181 2182 void CheckThisIndexedPropertyDeleter( 2183 uint32_t index, 2184 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 2185 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyDeleter)); 2186 ApiTestFuzzer::Fuzz(); 2187 CHECK(info.This()->Equals(bottom)); 2188 } 2189 2190 2191 void CheckThisNamedPropertyDeleter( 2192 Local<String> property, 2193 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 2194 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter)); 2195 ApiTestFuzzer::Fuzz(); 2196 CHECK(info.This()->Equals(bottom)); 2197 } 2198 2199 2200 void CheckThisIndexedPropertyEnumerator( 2201 const v8::PropertyCallbackInfo<v8::Array>& info) { 2202 CheckReturnValue(info, FUNCTION_ADDR(CheckThisIndexedPropertyEnumerator)); 2203 ApiTestFuzzer::Fuzz(); 2204 CHECK(info.This()->Equals(bottom)); 2205 } 2206 2207 2208 void CheckThisNamedPropertyEnumerator( 2209 const v8::PropertyCallbackInfo<v8::Array>& info) { 2210 CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyEnumerator)); 2211 ApiTestFuzzer::Fuzz(); 2212 CHECK(info.This()->Equals(bottom)); 2213 } 2214 2215 2216 THREADED_PROFILED_TEST(PropertyHandlerInPrototype) { 2217 LocalContext env; 2218 v8::HandleScope scope(env->GetIsolate()); 2219 2220 // Set up a prototype chain with three interceptors. 2221 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 2222 templ->InstanceTemplate()->SetIndexedPropertyHandler( 2223 CheckThisIndexedPropertyHandler, 2224 CheckThisIndexedPropertySetter, 2225 CheckThisIndexedPropertyQuery, 2226 CheckThisIndexedPropertyDeleter, 2227 CheckThisIndexedPropertyEnumerator); 2228 2229 templ->InstanceTemplate()->SetNamedPropertyHandler( 2230 CheckThisNamedPropertyHandler, 2231 CheckThisNamedPropertySetter, 2232 CheckThisNamedPropertyQuery, 2233 CheckThisNamedPropertyDeleter, 2234 CheckThisNamedPropertyEnumerator); 2235 2236 bottom = templ->GetFunction()->NewInstance(); 2237 Local<v8::Object> top = templ->GetFunction()->NewInstance(); 2238 Local<v8::Object> middle = templ->GetFunction()->NewInstance(); 2239 2240 bottom->SetPrototype(middle); 2241 middle->SetPrototype(top); 2242 env->Global()->Set(v8_str("obj"), bottom); 2243 2244 // Indexed and named get. 2245 Script::Compile(v8_str("obj[0]"))->Run(); 2246 Script::Compile(v8_str("obj.x"))->Run(); 2247 2248 // Indexed and named set. 2249 Script::Compile(v8_str("obj[1] = 42"))->Run(); 2250 Script::Compile(v8_str("obj.y = 42"))->Run(); 2251 2252 // Indexed and named query. 2253 Script::Compile(v8_str("0 in obj"))->Run(); 2254 Script::Compile(v8_str("'x' in obj"))->Run(); 2255 2256 // Indexed and named deleter. 2257 Script::Compile(v8_str("delete obj[0]"))->Run(); 2258 Script::Compile(v8_str("delete obj.x"))->Run(); 2259 2260 // Enumerators. 2261 Script::Compile(v8_str("for (var p in obj) ;"))->Run(); 2262 } 2263 2264 2265 static void PrePropertyHandlerGet( 2266 Local<String> key, 2267 const v8::PropertyCallbackInfo<v8::Value>& info) { 2268 ApiTestFuzzer::Fuzz(); 2269 if (v8_str("pre")->Equals(key)) { 2270 info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre")); 2271 } 2272 } 2273 2274 2275 static void PrePropertyHandlerQuery( 2276 Local<String> key, 2277 const v8::PropertyCallbackInfo<v8::Integer>& info) { 2278 if (v8_str("pre")->Equals(key)) { 2279 info.GetReturnValue().Set(static_cast<int32_t>(v8::None)); 2280 } 2281 } 2282 2283 2284 THREADED_TEST(PrePropertyHandler) { 2285 v8::HandleScope scope(v8::Isolate::GetCurrent()); 2286 v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(); 2287 desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet, 2288 0, 2289 PrePropertyHandlerQuery); 2290 LocalContext env(NULL, desc->InstanceTemplate()); 2291 Script::Compile(v8_str( 2292 "var pre = 'Object: pre'; var on = 'Object: on';"))->Run(); 2293 v8::Handle<Value> result_pre = Script::Compile(v8_str("pre"))->Run(); 2294 CHECK_EQ(v8_str("PrePropertyHandler: pre"), result_pre); 2295 v8::Handle<Value> result_on = Script::Compile(v8_str("on"))->Run(); 2296 CHECK_EQ(v8_str("Object: on"), result_on); 2297 v8::Handle<Value> result_post = Script::Compile(v8_str("post"))->Run(); 2298 CHECK(result_post.IsEmpty()); 2299 } 2300 2301 2302 THREADED_TEST(UndefinedIsNotEnumerable) { 2303 LocalContext env; 2304 v8::HandleScope scope(env->GetIsolate()); 2305 v8::Handle<Value> result = Script::Compile(v8_str( 2306 "this.propertyIsEnumerable(undefined)"))->Run(); 2307 CHECK(result->IsFalse()); 2308 } 2309 2310 2311 v8::Handle<Script> call_recursively_script; 2312 static const int kTargetRecursionDepth = 200; // near maximum 2313 2314 2315 static void CallScriptRecursivelyCall( 2316 const v8::FunctionCallbackInfo<v8::Value>& args) { 2317 ApiTestFuzzer::Fuzz(); 2318 int depth = args.This()->Get(v8_str("depth"))->Int32Value(); 2319 if (depth == kTargetRecursionDepth) return; 2320 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1)); 2321 args.GetReturnValue().Set(call_recursively_script->Run()); 2322 } 2323 2324 2325 static void CallFunctionRecursivelyCall( 2326 const v8::FunctionCallbackInfo<v8::Value>& args) { 2327 ApiTestFuzzer::Fuzz(); 2328 int depth = args.This()->Get(v8_str("depth"))->Int32Value(); 2329 if (depth == kTargetRecursionDepth) { 2330 printf("[depth = %d]\n", depth); 2331 return; 2332 } 2333 args.This()->Set(v8_str("depth"), v8::Integer::New(depth + 1)); 2334 v8::Handle<Value> function = 2335 args.This()->Get(v8_str("callFunctionRecursively")); 2336 args.GetReturnValue().Set( 2337 function.As<Function>()->Call(args.This(), 0, NULL)); 2338 } 2339 2340 2341 THREADED_TEST(DeepCrossLanguageRecursion) { 2342 v8::HandleScope scope(v8::Isolate::GetCurrent()); 2343 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(); 2344 global->Set(v8_str("callScriptRecursively"), 2345 v8::FunctionTemplate::New(CallScriptRecursivelyCall)); 2346 global->Set(v8_str("callFunctionRecursively"), 2347 v8::FunctionTemplate::New(CallFunctionRecursivelyCall)); 2348 LocalContext env(NULL, global); 2349 2350 env->Global()->Set(v8_str("depth"), v8::Integer::New(0)); 2351 call_recursively_script = v8_compile("callScriptRecursively()"); 2352 call_recursively_script->Run(); 2353 call_recursively_script = v8::Handle<Script>(); 2354 2355 env->Global()->Set(v8_str("depth"), v8::Integer::New(0)); 2356 Script::Compile(v8_str("callFunctionRecursively()"))->Run(); 2357 } 2358 2359 2360 static void ThrowingPropertyHandlerGet( 2361 Local<String> key, 2362 const v8::PropertyCallbackInfo<v8::Value>& info) { 2363 ApiTestFuzzer::Fuzz(); 2364 info.GetReturnValue().Set(v8::ThrowException(key)); 2365 } 2366 2367 2368 static void ThrowingPropertyHandlerSet( 2369 Local<String> key, 2370 Local<Value>, 2371 const v8::PropertyCallbackInfo<v8::Value>& info) { 2372 v8::ThrowException(key); 2373 info.GetReturnValue().SetUndefined(); // not the same as empty handle 2374 } 2375 2376 2377 THREADED_TEST(CallbackExceptionRegression) { 2378 v8::HandleScope scope(v8::Isolate::GetCurrent()); 2379 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 2380 obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet, 2381 ThrowingPropertyHandlerSet); 2382 LocalContext env; 2383 env->Global()->Set(v8_str("obj"), obj->NewInstance()); 2384 v8::Handle<Value> otto = Script::Compile(v8_str( 2385 "try { with (obj) { otto; } } catch (e) { e; }"))->Run(); 2386 CHECK_EQ(v8_str("otto"), otto); 2387 v8::Handle<Value> netto = Script::Compile(v8_str( 2388 "try { with (obj) { netto = 4; } } catch (e) { e; }"))->Run(); 2389 CHECK_EQ(v8_str("netto"), netto); 2390 } 2391 2392 2393 THREADED_TEST(FunctionPrototype) { 2394 v8::HandleScope scope(v8::Isolate::GetCurrent()); 2395 Local<v8::FunctionTemplate> Foo = v8::FunctionTemplate::New(); 2396 Foo->PrototypeTemplate()->Set(v8_str("plak"), v8_num(321)); 2397 LocalContext env; 2398 env->Global()->Set(v8_str("Foo"), Foo->GetFunction()); 2399 Local<Script> script = Script::Compile(v8_str("Foo.prototype.plak")); 2400 CHECK_EQ(script->Run()->Int32Value(), 321); 2401 } 2402 2403 2404 THREADED_TEST(InternalFields) { 2405 LocalContext env; 2406 v8::HandleScope scope(env->GetIsolate()); 2407 2408 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 2409 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 2410 instance_templ->SetInternalFieldCount(1); 2411 Local<v8::Object> obj = templ->GetFunction()->NewInstance(); 2412 CHECK_EQ(1, obj->InternalFieldCount()); 2413 CHECK(obj->GetInternalField(0)->IsUndefined()); 2414 obj->SetInternalField(0, v8_num(17)); 2415 CHECK_EQ(17, obj->GetInternalField(0)->Int32Value()); 2416 } 2417 2418 2419 THREADED_TEST(GlobalObjectInternalFields) { 2420 v8::HandleScope scope(v8::Isolate::GetCurrent()); 2421 Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 2422 global_template->SetInternalFieldCount(1); 2423 LocalContext env(NULL, global_template); 2424 v8::Handle<v8::Object> global_proxy = env->Global(); 2425 v8::Handle<v8::Object> global = global_proxy->GetPrototype().As<v8::Object>(); 2426 CHECK_EQ(1, global->InternalFieldCount()); 2427 CHECK(global->GetInternalField(0)->IsUndefined()); 2428 global->SetInternalField(0, v8_num(17)); 2429 CHECK_EQ(17, global->GetInternalField(0)->Int32Value()); 2430 } 2431 2432 2433 THREADED_TEST(GlobalObjectHasRealIndexedProperty) { 2434 LocalContext env; 2435 v8::HandleScope scope(v8::Isolate::GetCurrent()); 2436 2437 v8::Local<v8::Object> global = env->Global(); 2438 global->Set(0, v8::String::New("value")); 2439 CHECK(global->HasRealIndexedProperty(0)); 2440 } 2441 2442 2443 static void CheckAlignedPointerInInternalField(Handle<v8::Object> obj, 2444 void* value) { 2445 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); 2446 obj->SetAlignedPointerInInternalField(0, value); 2447 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 2448 CHECK_EQ(value, obj->GetAlignedPointerFromInternalField(0)); 2449 } 2450 2451 2452 THREADED_TEST(InternalFieldsAlignedPointers) { 2453 LocalContext env; 2454 v8::HandleScope scope(env->GetIsolate()); 2455 2456 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 2457 Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate(); 2458 instance_templ->SetInternalFieldCount(1); 2459 Local<v8::Object> obj = templ->GetFunction()->NewInstance(); 2460 CHECK_EQ(1, obj->InternalFieldCount()); 2461 2462 CheckAlignedPointerInInternalField(obj, NULL); 2463 2464 int* heap_allocated = new int[100]; 2465 CheckAlignedPointerInInternalField(obj, heap_allocated); 2466 delete[] heap_allocated; 2467 2468 int stack_allocated[100]; 2469 CheckAlignedPointerInInternalField(obj, stack_allocated); 2470 2471 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); 2472 CheckAlignedPointerInInternalField(obj, huge); 2473 } 2474 2475 2476 static void CheckAlignedPointerInEmbedderData(LocalContext* env, 2477 int index, 2478 void* value) { 2479 CHECK_EQ(0, static_cast<int>(reinterpret_cast<uintptr_t>(value) & 0x1)); 2480 (*env)->SetAlignedPointerInEmbedderData(index, value); 2481 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 2482 CHECK_EQ(value, (*env)->GetAlignedPointerFromEmbedderData(index)); 2483 } 2484 2485 2486 static void* AlignedTestPointer(int i) { 2487 return reinterpret_cast<void*>(i * 1234); 2488 } 2489 2490 2491 THREADED_TEST(EmbedderDataAlignedPointers) { 2492 LocalContext env; 2493 v8::HandleScope scope(env->GetIsolate()); 2494 2495 CheckAlignedPointerInEmbedderData(&env, 0, NULL); 2496 2497 int* heap_allocated = new int[100]; 2498 CheckAlignedPointerInEmbedderData(&env, 1, heap_allocated); 2499 delete[] heap_allocated; 2500 2501 int stack_allocated[100]; 2502 CheckAlignedPointerInEmbedderData(&env, 2, stack_allocated); 2503 2504 void* huge = reinterpret_cast<void*>(~static_cast<uintptr_t>(1)); 2505 CheckAlignedPointerInEmbedderData(&env, 3, huge); 2506 2507 // Test growing of the embedder data's backing store. 2508 for (int i = 0; i < 100; i++) { 2509 env->SetAlignedPointerInEmbedderData(i, AlignedTestPointer(i)); 2510 } 2511 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 2512 for (int i = 0; i < 100; i++) { 2513 CHECK_EQ(AlignedTestPointer(i), env->GetAlignedPointerFromEmbedderData(i)); 2514 } 2515 } 2516 2517 2518 static void CheckEmbedderData(LocalContext* env, 2519 int index, 2520 v8::Handle<Value> data) { 2521 (*env)->SetEmbedderData(index, data); 2522 CHECK((*env)->GetEmbedderData(index)->StrictEquals(data)); 2523 } 2524 2525 2526 THREADED_TEST(EmbedderData) { 2527 LocalContext env; 2528 v8::HandleScope scope(env->GetIsolate()); 2529 2530 CheckEmbedderData(&env, 3, v8::String::New("The quick brown fox jumps")); 2531 CheckEmbedderData(&env, 2, v8::String::New("over the lazy dog.")); 2532 CheckEmbedderData(&env, 1, v8::Number::New(1.2345)); 2533 CheckEmbedderData(&env, 0, v8::Boolean::New(true)); 2534 } 2535 2536 2537 THREADED_TEST(IdentityHash) { 2538 LocalContext env; 2539 v8::HandleScope scope(env->GetIsolate()); 2540 2541 // Ensure that the test starts with an fresh heap to test whether the hash 2542 // code is based on the address. 2543 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 2544 Local<v8::Object> obj = v8::Object::New(); 2545 int hash = obj->GetIdentityHash(); 2546 int hash1 = obj->GetIdentityHash(); 2547 CHECK_EQ(hash, hash1); 2548 int hash2 = v8::Object::New()->GetIdentityHash(); 2549 // Since the identity hash is essentially a random number two consecutive 2550 // objects should not be assigned the same hash code. If the test below fails 2551 // the random number generator should be evaluated. 2552 CHECK_NE(hash, hash2); 2553 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 2554 int hash3 = v8::Object::New()->GetIdentityHash(); 2555 // Make sure that the identity hash is not based on the initial address of 2556 // the object alone. If the test below fails the random number generator 2557 // should be evaluated. 2558 CHECK_NE(hash, hash3); 2559 int hash4 = obj->GetIdentityHash(); 2560 CHECK_EQ(hash, hash4); 2561 2562 // Check identity hashes behaviour in the presence of JS accessors. 2563 // Put a getter for 'v8::IdentityHash' on the Object's prototype: 2564 { 2565 CompileRun("Object.prototype['v8::IdentityHash'] = 42;\n"); 2566 Local<v8::Object> o1 = v8::Object::New(); 2567 Local<v8::Object> o2 = v8::Object::New(); 2568 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 2569 } 2570 { 2571 CompileRun( 2572 "function cnst() { return 42; };\n" 2573 "Object.prototype.__defineGetter__('v8::IdentityHash', cnst);\n"); 2574 Local<v8::Object> o1 = v8::Object::New(); 2575 Local<v8::Object> o2 = v8::Object::New(); 2576 CHECK_NE(o1->GetIdentityHash(), o2->GetIdentityHash()); 2577 } 2578 } 2579 2580 2581 THREADED_TEST(SymbolProperties) { 2582 i::FLAG_harmony_symbols = true; 2583 2584 LocalContext env; 2585 v8::Isolate* isolate = env->GetIsolate(); 2586 v8::HandleScope scope(isolate); 2587 2588 v8::Local<v8::Object> obj = v8::Object::New(); 2589 v8::Local<v8::Symbol> sym1 = v8::Symbol::New(isolate); 2590 v8::Local<v8::Symbol> sym2 = v8::Symbol::New(isolate, "my-symbol"); 2591 2592 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 2593 2594 // Check basic symbol functionality. 2595 CHECK(sym1->IsSymbol()); 2596 CHECK(sym2->IsSymbol()); 2597 CHECK(!obj->IsSymbol()); 2598 2599 CHECK(sym1->Equals(sym1)); 2600 CHECK(sym2->Equals(sym2)); 2601 CHECK(!sym1->Equals(sym2)); 2602 CHECK(!sym2->Equals(sym1)); 2603 CHECK(sym1->StrictEquals(sym1)); 2604 CHECK(sym2->StrictEquals(sym2)); 2605 CHECK(!sym1->StrictEquals(sym2)); 2606 CHECK(!sym2->StrictEquals(sym1)); 2607 2608 CHECK(sym2->Name()->Equals(v8::String::New("my-symbol"))); 2609 2610 v8::Local<v8::Value> sym_val = sym2; 2611 CHECK(sym_val->IsSymbol()); 2612 CHECK(sym_val->Equals(sym2)); 2613 CHECK(sym_val->StrictEquals(sym2)); 2614 CHECK(v8::Symbol::Cast(*sym_val)->Equals(sym2)); 2615 2616 v8::Local<v8::Value> sym_obj = v8::SymbolObject::New(isolate, sym2); 2617 CHECK(sym_obj->IsSymbolObject()); 2618 CHECK(!sym2->IsSymbolObject()); 2619 CHECK(!obj->IsSymbolObject()); 2620 CHECK(sym_obj->Equals(sym2)); 2621 CHECK(!sym_obj->StrictEquals(sym2)); 2622 CHECK(v8::SymbolObject::Cast(*sym_obj)->Equals(sym_obj)); 2623 CHECK(v8::SymbolObject::Cast(*sym_obj)->ValueOf()->Equals(sym2)); 2624 2625 // Make sure delete of a non-existent symbol property works. 2626 CHECK(obj->Delete(sym1)); 2627 CHECK(!obj->Has(sym1)); 2628 2629 CHECK(obj->Set(sym1, v8::Integer::New(1503))); 2630 CHECK(obj->Has(sym1)); 2631 CHECK_EQ(1503, obj->Get(sym1)->Int32Value()); 2632 CHECK(obj->Set(sym1, v8::Integer::New(2002))); 2633 CHECK(obj->Has(sym1)); 2634 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2635 CHECK_EQ(v8::None, obj->GetPropertyAttributes(sym1)); 2636 2637 CHECK_EQ(0, obj->GetOwnPropertyNames()->Length()); 2638 int num_props = obj->GetPropertyNames()->Length(); 2639 CHECK(obj->Set(v8::String::New("bla"), v8::Integer::New(20))); 2640 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2641 CHECK_EQ(num_props + 1, obj->GetPropertyNames()->Length()); 2642 2643 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 2644 2645 // Add another property and delete it afterwards to force the object in 2646 // slow case. 2647 CHECK(obj->Set(sym2, v8::Integer::New(2008))); 2648 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2649 CHECK_EQ(2008, obj->Get(sym2)->Int32Value()); 2650 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2651 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2652 2653 CHECK(obj->Has(sym1)); 2654 CHECK(obj->Has(sym2)); 2655 CHECK(obj->Delete(sym2)); 2656 CHECK(obj->Has(sym1)); 2657 CHECK(!obj->Has(sym2)); 2658 CHECK_EQ(2002, obj->Get(sym1)->Int32Value()); 2659 CHECK_EQ(1, obj->GetOwnPropertyNames()->Length()); 2660 } 2661 2662 2663 class ScopedArrayBufferContents { 2664 public: 2665 explicit ScopedArrayBufferContents( 2666 const v8::ArrayBuffer::Contents& contents) 2667 : contents_(contents) {} 2668 ~ScopedArrayBufferContents() { free(contents_.Data()); } 2669 void* Data() const { return contents_.Data(); } 2670 size_t ByteLength() const { return contents_.ByteLength(); } 2671 private: 2672 const v8::ArrayBuffer::Contents contents_; 2673 }; 2674 2675 template <typename T> 2676 static void CheckInternalFieldsAreZero(v8::Handle<T> value) { 2677 CHECK_EQ(T::kInternalFieldCount, value->InternalFieldCount()); 2678 for (int i = 0; i < value->InternalFieldCount(); i++) { 2679 CHECK_EQ(0, value->GetInternalField(i)->Int32Value()); 2680 } 2681 } 2682 2683 2684 THREADED_TEST(ArrayBuffer_ApiInternalToExternal) { 2685 i::FLAG_harmony_array_buffer = true; 2686 i::FLAG_harmony_typed_arrays = true; 2687 2688 LocalContext env; 2689 v8::Isolate* isolate = env->GetIsolate(); 2690 v8::HandleScope handle_scope(isolate); 2691 2692 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New(1024); 2693 CheckInternalFieldsAreZero(ab); 2694 CHECK_EQ(1024, static_cast<int>(ab->ByteLength())); 2695 CHECK(!ab->IsExternal()); 2696 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 2697 2698 ScopedArrayBufferContents ab_contents(ab->Externalize()); 2699 CHECK(ab->IsExternal()); 2700 2701 CHECK_EQ(1024, static_cast<int>(ab_contents.ByteLength())); 2702 uint8_t* data = static_cast<uint8_t*>(ab_contents.Data()); 2703 ASSERT(data != NULL); 2704 env->Global()->Set(v8_str("ab"), ab); 2705 2706 v8::Handle<v8::Value> result = CompileRun("ab.byteLength"); 2707 CHECK_EQ(1024, result->Int32Value()); 2708 2709 result = CompileRun("var u8 = new Uint8Array(ab);" 2710 "u8[0] = 0xFF;" 2711 "u8[1] = 0xAA;" 2712 "u8.length"); 2713 CHECK_EQ(1024, result->Int32Value()); 2714 CHECK_EQ(0xFF, data[0]); 2715 CHECK_EQ(0xAA, data[1]); 2716 data[0] = 0xCC; 2717 data[1] = 0x11; 2718 result = CompileRun("u8[0] + u8[1]"); 2719 CHECK_EQ(0xDD, result->Int32Value()); 2720 } 2721 2722 2723 THREADED_TEST(ArrayBuffer_JSInternalToExternal) { 2724 i::FLAG_harmony_array_buffer = true; 2725 i::FLAG_harmony_typed_arrays = true; 2726 2727 LocalContext env; 2728 v8::Isolate* isolate = env->GetIsolate(); 2729 v8::HandleScope handle_scope(isolate); 2730 2731 2732 v8::Local<v8::Value> result = 2733 CompileRun("var ab1 = new ArrayBuffer(2);" 2734 "var u8_a = new Uint8Array(ab1);" 2735 "u8_a[0] = 0xAA;" 2736 "u8_a[1] = 0xFF; u8_a.buffer"); 2737 Local<v8::ArrayBuffer> ab1 = Local<v8::ArrayBuffer>::Cast(result); 2738 CheckInternalFieldsAreZero(ab1); 2739 CHECK_EQ(2, static_cast<int>(ab1->ByteLength())); 2740 CHECK(!ab1->IsExternal()); 2741 ScopedArrayBufferContents ab1_contents(ab1->Externalize()); 2742 CHECK(ab1->IsExternal()); 2743 2744 result = CompileRun("ab1.byteLength"); 2745 CHECK_EQ(2, result->Int32Value()); 2746 result = CompileRun("u8_a[0]"); 2747 CHECK_EQ(0xAA, result->Int32Value()); 2748 result = CompileRun("u8_a[1]"); 2749 CHECK_EQ(0xFF, result->Int32Value()); 2750 result = CompileRun("var u8_b = new Uint8Array(ab1);" 2751 "u8_b[0] = 0xBB;" 2752 "u8_a[0]"); 2753 CHECK_EQ(0xBB, result->Int32Value()); 2754 result = CompileRun("u8_b[1]"); 2755 CHECK_EQ(0xFF, result->Int32Value()); 2756 2757 CHECK_EQ(2, static_cast<int>(ab1_contents.ByteLength())); 2758 uint8_t* ab1_data = static_cast<uint8_t*>(ab1_contents.Data()); 2759 CHECK_EQ(0xBB, ab1_data[0]); 2760 CHECK_EQ(0xFF, ab1_data[1]); 2761 ab1_data[0] = 0xCC; 2762 ab1_data[1] = 0x11; 2763 result = CompileRun("u8_a[0] + u8_a[1]"); 2764 CHECK_EQ(0xDD, result->Int32Value()); 2765 } 2766 2767 2768 THREADED_TEST(ArrayBuffer_External) { 2769 i::FLAG_harmony_array_buffer = true; 2770 i::FLAG_harmony_typed_arrays = true; 2771 2772 LocalContext env; 2773 v8::Isolate* isolate = env->GetIsolate(); 2774 v8::HandleScope handle_scope(isolate); 2775 2776 i::ScopedVector<uint8_t> my_data(100); 2777 memset(my_data.start(), 0, 100); 2778 Local<v8::ArrayBuffer> ab3 = v8::ArrayBuffer::New(my_data.start(), 100); 2779 CheckInternalFieldsAreZero(ab3); 2780 CHECK_EQ(100, static_cast<int>(ab3->ByteLength())); 2781 CHECK(ab3->IsExternal()); 2782 2783 env->Global()->Set(v8_str("ab3"), ab3); 2784 2785 v8::Handle<v8::Value> result = CompileRun("ab3.byteLength"); 2786 CHECK_EQ(100, result->Int32Value()); 2787 2788 result = CompileRun("var u8_b = new Uint8Array(ab3);" 2789 "u8_b[0] = 0xBB;" 2790 "u8_b[1] = 0xCC;" 2791 "u8_b.length"); 2792 CHECK_EQ(100, result->Int32Value()); 2793 CHECK_EQ(0xBB, my_data[0]); 2794 CHECK_EQ(0xCC, my_data[1]); 2795 my_data[0] = 0xCC; 2796 my_data[1] = 0x11; 2797 result = CompileRun("u8_b[0] + u8_b[1]"); 2798 CHECK_EQ(0xDD, result->Int32Value()); 2799 } 2800 2801 2802 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) { 2803 CHECK_EQ(0, static_cast<int>(dv->ByteLength())); 2804 CHECK_EQ(0, static_cast<int>(dv->ByteOffset())); 2805 } 2806 2807 2808 static void CheckIsNeutered(v8::Handle<v8::TypedArray> ta) { 2809 CHECK_EQ(0, static_cast<int>(ta->ByteLength())); 2810 CHECK_EQ(0, static_cast<int>(ta->Length())); 2811 CHECK_EQ(0, static_cast<int>(ta->ByteOffset())); 2812 } 2813 2814 2815 static void CheckIsTypedArrayVarNeutered(const char* name) { 2816 i::ScopedVector<char> source(1024); 2817 i::OS::SNPrintF(source, 2818 "%s.byteLength == 0 && %s.byteOffset == 0 && %s.length == 0", 2819 name, name, name); 2820 CHECK(CompileRun(source.start())->IsTrue()); 2821 v8::Handle<v8::TypedArray> ta = 2822 v8::Handle<v8::TypedArray>::Cast(CompileRun(name)); 2823 CheckIsNeutered(ta); 2824 } 2825 2826 2827 template <typename TypedArray, int kElementSize> 2828 static Handle<TypedArray> CreateAndCheck(Handle<v8::ArrayBuffer> ab, 2829 int byteOffset, 2830 int length) { 2831 v8::Handle<TypedArray> ta = TypedArray::New(ab, byteOffset, length); 2832 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta); 2833 CHECK_EQ(byteOffset, static_cast<int>(ta->ByteOffset())); 2834 CHECK_EQ(length, static_cast<int>(ta->Length())); 2835 CHECK_EQ(length * kElementSize, static_cast<int>(ta->ByteLength())); 2836 return ta; 2837 } 2838 2839 2840 THREADED_TEST(ArrayBuffer_NeuteringApi) { 2841 LocalContext env; 2842 v8::Isolate* isolate = env->GetIsolate(); 2843 v8::HandleScope handle_scope(isolate); 2844 2845 v8::Handle<v8::ArrayBuffer> buffer = v8::ArrayBuffer::New(1024); 2846 2847 v8::Handle<v8::Uint8Array> u8a = 2848 CreateAndCheck<v8::Uint8Array, 1>(buffer, 1, 1023); 2849 v8::Handle<v8::Uint8ClampedArray> u8c = 2850 CreateAndCheck<v8::Uint8ClampedArray, 1>(buffer, 1, 1023); 2851 v8::Handle<v8::Int8Array> i8a = 2852 CreateAndCheck<v8::Int8Array, 1>(buffer, 1, 1023); 2853 2854 v8::Handle<v8::Uint16Array> u16a = 2855 CreateAndCheck<v8::Uint16Array, 2>(buffer, 2, 511); 2856 v8::Handle<v8::Int16Array> i16a = 2857 CreateAndCheck<v8::Int16Array, 2>(buffer, 2, 511); 2858 2859 v8::Handle<v8::Uint32Array> u32a = 2860 CreateAndCheck<v8::Uint32Array, 4>(buffer, 4, 255); 2861 v8::Handle<v8::Int32Array> i32a = 2862 CreateAndCheck<v8::Int32Array, 4>(buffer, 4, 255); 2863 2864 v8::Handle<v8::Float32Array> f32a = 2865 CreateAndCheck<v8::Float32Array, 4>(buffer, 4, 255); 2866 v8::Handle<v8::Float64Array> f64a = 2867 CreateAndCheck<v8::Float64Array, 8>(buffer, 8, 127); 2868 2869 v8::Handle<v8::DataView> dv = v8::DataView::New(buffer, 1, 1023); 2870 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 2871 CHECK_EQ(1, static_cast<int>(dv->ByteOffset())); 2872 CHECK_EQ(1023, static_cast<int>(dv->ByteLength())); 2873 2874 ScopedArrayBufferContents contents(buffer->Externalize()); 2875 buffer->Neuter(); 2876 CHECK_EQ(0, static_cast<int>(buffer->ByteLength())); 2877 CheckIsNeutered(u8a); 2878 CheckIsNeutered(u8c); 2879 CheckIsNeutered(i8a); 2880 CheckIsNeutered(u16a); 2881 CheckIsNeutered(i16a); 2882 CheckIsNeutered(u32a); 2883 CheckIsNeutered(i32a); 2884 CheckIsNeutered(f32a); 2885 CheckIsNeutered(f64a); 2886 CheckDataViewIsNeutered(dv); 2887 } 2888 2889 2890 THREADED_TEST(ArrayBuffer_NeuteringScript) { 2891 LocalContext env; 2892 v8::Isolate* isolate = env->GetIsolate(); 2893 v8::HandleScope handle_scope(isolate); 2894 2895 CompileRun( 2896 "var ab = new ArrayBuffer(1024);" 2897 "var u8a = new Uint8Array(ab, 1, 1023);" 2898 "var u8c = new Uint8ClampedArray(ab, 1, 1023);" 2899 "var i8a = new Int8Array(ab, 1, 1023);" 2900 "var u16a = new Uint16Array(ab, 2, 511);" 2901 "var i16a = new Int16Array(ab, 2, 511);" 2902 "var u32a = new Uint32Array(ab, 4, 255);" 2903 "var i32a = new Int32Array(ab, 4, 255);" 2904 "var f32a = new Float32Array(ab, 4, 255);" 2905 "var f64a = new Float64Array(ab, 8, 127);" 2906 "var dv = new DataView(ab, 1, 1023);"); 2907 2908 v8::Handle<v8::ArrayBuffer> ab = 2909 Local<v8::ArrayBuffer>::Cast(CompileRun("ab")); 2910 2911 v8::Handle<v8::DataView> dv = 2912 v8::Handle<v8::DataView>::Cast(CompileRun("dv")); 2913 2914 ScopedArrayBufferContents contents(ab->Externalize()); 2915 ab->Neuter(); 2916 CHECK_EQ(0, static_cast<int>(ab->ByteLength())); 2917 CHECK_EQ(0, CompileRun("ab.byteLength")->Int32Value()); 2918 2919 CheckIsTypedArrayVarNeutered("u8a"); 2920 CheckIsTypedArrayVarNeutered("u8c"); 2921 CheckIsTypedArrayVarNeutered("i8a"); 2922 CheckIsTypedArrayVarNeutered("u16a"); 2923 CheckIsTypedArrayVarNeutered("i16a"); 2924 CheckIsTypedArrayVarNeutered("u32a"); 2925 CheckIsTypedArrayVarNeutered("i32a"); 2926 CheckIsTypedArrayVarNeutered("f32a"); 2927 CheckIsTypedArrayVarNeutered("f64a"); 2928 2929 CHECK(CompileRun("dv.byteLength == 0 && dv.byteOffset == 0")->IsTrue()); 2930 CheckDataViewIsNeutered(dv); 2931 } 2932 2933 2934 2935 THREADED_TEST(HiddenProperties) { 2936 LocalContext env; 2937 v8::HandleScope scope(env->GetIsolate()); 2938 2939 v8::Local<v8::Object> obj = v8::Object::New(); 2940 v8::Local<v8::String> key = v8_str("api-test::hidden-key"); 2941 v8::Local<v8::String> empty = v8_str(""); 2942 v8::Local<v8::String> prop_name = v8_str("prop_name"); 2943 2944 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 2945 2946 // Make sure delete of a non-existent hidden value works 2947 CHECK(obj->DeleteHiddenValue(key)); 2948 2949 CHECK(obj->SetHiddenValue(key, v8::Integer::New(1503))); 2950 CHECK_EQ(1503, obj->GetHiddenValue(key)->Int32Value()); 2951 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002))); 2952 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 2953 2954 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 2955 2956 // Make sure we do not find the hidden property. 2957 CHECK(!obj->Has(empty)); 2958 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 2959 CHECK(obj->Get(empty)->IsUndefined()); 2960 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 2961 CHECK(obj->Set(empty, v8::Integer::New(2003))); 2962 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 2963 CHECK_EQ(2003, obj->Get(empty)->Int32Value()); 2964 2965 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 2966 2967 // Add another property and delete it afterwards to force the object in 2968 // slow case. 2969 CHECK(obj->Set(prop_name, v8::Integer::New(2008))); 2970 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 2971 CHECK_EQ(2008, obj->Get(prop_name)->Int32Value()); 2972 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 2973 CHECK(obj->Delete(prop_name)); 2974 CHECK_EQ(2002, obj->GetHiddenValue(key)->Int32Value()); 2975 2976 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 2977 2978 CHECK(obj->SetHiddenValue(key, Handle<Value>())); 2979 CHECK(obj->GetHiddenValue(key).IsEmpty()); 2980 2981 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2002))); 2982 CHECK(obj->DeleteHiddenValue(key)); 2983 CHECK(obj->GetHiddenValue(key).IsEmpty()); 2984 } 2985 2986 2987 THREADED_TEST(Regress97784) { 2988 // Regression test for crbug.com/97784 2989 // Messing with the Object.prototype should not have effect on 2990 // hidden properties. 2991 LocalContext env; 2992 v8::HandleScope scope(env->GetIsolate()); 2993 2994 v8::Local<v8::Object> obj = v8::Object::New(); 2995 v8::Local<v8::String> key = v8_str("hidden"); 2996 2997 CompileRun( 2998 "set_called = false;" 2999 "Object.defineProperty(" 3000 " Object.prototype," 3001 " 'hidden'," 3002 " {get: function() { return 45; }," 3003 " set: function() { set_called = true; }})"); 3004 3005 CHECK(obj->GetHiddenValue(key).IsEmpty()); 3006 // Make sure that the getter and setter from Object.prototype is not invoked. 3007 // If it did we would have full access to the hidden properties in 3008 // the accessor. 3009 CHECK(obj->SetHiddenValue(key, v8::Integer::New(42))); 3010 ExpectFalse("set_called"); 3011 CHECK_EQ(42, obj->GetHiddenValue(key)->Int32Value()); 3012 } 3013 3014 3015 static bool interceptor_for_hidden_properties_called; 3016 static void InterceptorForHiddenProperties( 3017 Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) { 3018 interceptor_for_hidden_properties_called = true; 3019 } 3020 3021 3022 THREADED_TEST(HiddenPropertiesWithInterceptors) { 3023 LocalContext context; 3024 v8::HandleScope scope(context->GetIsolate()); 3025 3026 interceptor_for_hidden_properties_called = false; 3027 3028 v8::Local<v8::String> key = v8_str("api-test::hidden-key"); 3029 3030 // Associate an interceptor with an object and start setting hidden values. 3031 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 3032 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 3033 instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties); 3034 Local<v8::Function> function = fun_templ->GetFunction(); 3035 Local<v8::Object> obj = function->NewInstance(); 3036 CHECK(obj->SetHiddenValue(key, v8::Integer::New(2302))); 3037 CHECK_EQ(2302, obj->GetHiddenValue(key)->Int32Value()); 3038 CHECK(!interceptor_for_hidden_properties_called); 3039 } 3040 3041 3042 THREADED_TEST(External) { 3043 v8::HandleScope scope(v8::Isolate::GetCurrent()); 3044 int x = 3; 3045 Local<v8::External> ext = v8::External::New(&x); 3046 LocalContext env; 3047 env->Global()->Set(v8_str("ext"), ext); 3048 Local<Value> reext_obj = Script::Compile(v8_str("this.ext"))->Run(); 3049 v8::Handle<v8::External> reext = reext_obj.As<v8::External>(); 3050 int* ptr = static_cast<int*>(reext->Value()); 3051 CHECK_EQ(x, 3); 3052 *ptr = 10; 3053 CHECK_EQ(x, 10); 3054 3055 // Make sure unaligned pointers are wrapped properly. 3056 char* data = i::StrDup("0123456789"); 3057 Local<v8::Value> zero = v8::External::New(&data[0]); 3058 Local<v8::Value> one = v8::External::New(&data[1]); 3059 Local<v8::Value> two = v8::External::New(&data[2]); 3060 Local<v8::Value> three = v8::External::New(&data[3]); 3061 3062 char* char_ptr = reinterpret_cast<char*>(v8::External::Cast(*zero)->Value()); 3063 CHECK_EQ('0', *char_ptr); 3064 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*one)->Value()); 3065 CHECK_EQ('1', *char_ptr); 3066 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*two)->Value()); 3067 CHECK_EQ('2', *char_ptr); 3068 char_ptr = reinterpret_cast<char*>(v8::External::Cast(*three)->Value()); 3069 CHECK_EQ('3', *char_ptr); 3070 i::DeleteArray(data); 3071 } 3072 3073 3074 THREADED_TEST(GlobalHandle) { 3075 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 3076 v8::Persistent<String> global; 3077 { 3078 v8::HandleScope scope(isolate); 3079 global.Reset(isolate, v8_str("str")); 3080 } 3081 { 3082 v8::HandleScope scope(isolate); 3083 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3084 } 3085 global.Dispose(); 3086 global.Clear(); 3087 { 3088 v8::HandleScope scope(isolate); 3089 global.Reset(isolate, v8_str("str")); 3090 } 3091 { 3092 v8::HandleScope scope(isolate); 3093 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3094 } 3095 global.Dispose(); 3096 } 3097 3098 3099 THREADED_TEST(ResettingGlobalHandle) { 3100 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 3101 v8::Persistent<String> global; 3102 { 3103 v8::HandleScope scope(isolate); 3104 global.Reset(isolate, v8_str("str")); 3105 } 3106 v8::internal::GlobalHandles* global_handles = 3107 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3108 int initial_handle_count = global_handles->global_handles_count(); 3109 { 3110 v8::HandleScope scope(isolate); 3111 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3112 } 3113 { 3114 v8::HandleScope scope(isolate); 3115 global.Reset(isolate, v8_str("longer")); 3116 } 3117 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count); 3118 { 3119 v8::HandleScope scope(isolate); 3120 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 6); 3121 } 3122 global.Dispose(isolate); 3123 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1); 3124 } 3125 3126 3127 THREADED_TEST(ResettingGlobalHandleToEmpty) { 3128 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 3129 v8::Persistent<String> global; 3130 { 3131 v8::HandleScope scope(isolate); 3132 global.Reset(isolate, v8_str("str")); 3133 } 3134 v8::internal::GlobalHandles* global_handles = 3135 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3136 int initial_handle_count = global_handles->global_handles_count(); 3137 { 3138 v8::HandleScope scope(isolate); 3139 CHECK_EQ(v8::Local<String>::New(isolate, global)->Length(), 3); 3140 } 3141 { 3142 v8::HandleScope scope(isolate); 3143 Local<String> empty; 3144 global.Reset(isolate, empty); 3145 } 3146 CHECK(global.IsEmpty()); 3147 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count - 1); 3148 } 3149 3150 3151 THREADED_TEST(ClearAndLeakGlobal) { 3152 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 3153 v8::internal::GlobalHandles* global_handles = NULL; 3154 int initial_handle_count = 0; 3155 v8::Persistent<String> global; 3156 { 3157 v8::HandleScope scope(isolate); 3158 Local<String> str = v8_str("str"); 3159 global_handles = 3160 reinterpret_cast<v8::internal::Isolate*>(isolate)->global_handles(); 3161 initial_handle_count = global_handles->global_handles_count(); 3162 global.Reset(isolate, str); 3163 } 3164 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count + 1); 3165 String* str = global.ClearAndLeak(); 3166 CHECK(global.IsEmpty()); 3167 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count + 1); 3168 global_handles->Destroy(reinterpret_cast<i::Object**>(str)); 3169 CHECK_EQ(global_handles->global_handles_count(), initial_handle_count); 3170 } 3171 3172 3173 THREADED_TEST(GlobalHandleUpcast) { 3174 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 3175 v8::HandleScope scope(isolate); 3176 v8::Local<String> local = v8::Local<String>::New(v8_str("str")); 3177 v8::Persistent<String> global_string(isolate, local); 3178 #ifdef V8_USE_UNSAFE_HANDLES 3179 v8::Persistent<Value> global_value = 3180 v8::Persistent<Value>::Cast(global_string); 3181 #else 3182 v8::Persistent<Value>& global_value = 3183 v8::Persistent<Value>::Cast(global_string); 3184 #endif 3185 CHECK(v8::Local<v8::Value>::New(isolate, global_value)->IsString()); 3186 CHECK(global_string == v8::Persistent<String>::Cast(global_value)); 3187 global_string.Dispose(); 3188 } 3189 3190 3191 THREADED_TEST(LocalHandle) { 3192 v8::HandleScope scope(v8::Isolate::GetCurrent()); 3193 v8::Local<String> local = v8::Local<String>::New(v8_str("str")); 3194 CHECK_EQ(local->Length(), 3); 3195 3196 local = v8::Local<String>::New(v8::Isolate::GetCurrent(), v8_str("str")); 3197 CHECK_EQ(local->Length(), 3); 3198 } 3199 3200 3201 class WeakCallCounter { 3202 public: 3203 explicit WeakCallCounter(int id) : id_(id), number_of_weak_calls_(0) { } 3204 int id() { return id_; } 3205 void increment() { number_of_weak_calls_++; } 3206 int NumberOfWeakCalls() { return number_of_weak_calls_; } 3207 private: 3208 int id_; 3209 int number_of_weak_calls_; 3210 }; 3211 3212 3213 static void WeakPointerCallback(v8::Isolate* isolate, 3214 Persistent<Value>* handle, 3215 WeakCallCounter* counter) { 3216 CHECK_EQ(1234, counter->id()); 3217 counter->increment(); 3218 handle->Dispose(isolate); 3219 } 3220 3221 3222 static UniqueId MakeUniqueId(const Persistent<Value>& p) { 3223 return UniqueId(reinterpret_cast<uintptr_t>(*v8::Utils::OpenPersistent(p))); 3224 } 3225 3226 3227 THREADED_TEST(ApiObjectGroups) { 3228 LocalContext env; 3229 v8::Isolate* iso = env->GetIsolate(); 3230 HandleScope scope(iso); 3231 3232 Persistent<Value> g1s1; 3233 Persistent<Value> g1s2; 3234 Persistent<Value> g1c1; 3235 Persistent<Value> g2s1; 3236 Persistent<Value> g2s2; 3237 Persistent<Value> g2c1; 3238 3239 WeakCallCounter counter(1234); 3240 3241 { 3242 HandleScope scope(iso); 3243 g1s1.Reset(iso, Object::New()); 3244 g1s2.Reset(iso, Object::New()); 3245 g1c1.Reset(iso, Object::New()); 3246 g1s1.MakeWeak(&counter, &WeakPointerCallback); 3247 g1s2.MakeWeak(&counter, &WeakPointerCallback); 3248 g1c1.MakeWeak(&counter, &WeakPointerCallback); 3249 3250 g2s1.Reset(iso, Object::New()); 3251 g2s2.Reset(iso, Object::New()); 3252 g2c1.Reset(iso, Object::New()); 3253 g2s1.MakeWeak(&counter, &WeakPointerCallback); 3254 g2s2.MakeWeak(&counter, &WeakPointerCallback); 3255 g2c1.MakeWeak(&counter, &WeakPointerCallback); 3256 } 3257 3258 Persistent<Value> root(iso, g1s1); // make a root. 3259 3260 // Connect group 1 and 2, make a cycle. 3261 { 3262 HandleScope scope(iso); 3263 CHECK(Local<Object>::New(iso, g1s2.As<Object>())-> 3264 Set(0, Local<Value>::New(iso, g2s2))); 3265 CHECK(Local<Object>::New(iso, g2s1.As<Object>())-> 3266 Set(0, Local<Value>::New(iso, g1s1))); 3267 } 3268 3269 { 3270 UniqueId id1 = MakeUniqueId(g1s1); 3271 UniqueId id2 = MakeUniqueId(g2s2); 3272 iso->SetObjectGroupId(g1s1, id1); 3273 iso->SetObjectGroupId(g1s2, id1); 3274 iso->SetReferenceFromGroup(id1, g1c1); 3275 iso->SetObjectGroupId(g2s1, id2); 3276 iso->SetObjectGroupId(g2s2, id2); 3277 iso->SetReferenceFromGroup(id2, g2c1); 3278 } 3279 // Do a single full GC, ensure incremental marking is stopped. 3280 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 3281 iso)->heap(); 3282 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3283 3284 // All object should be alive. 3285 CHECK_EQ(0, counter.NumberOfWeakCalls()); 3286 3287 // Weaken the root. 3288 root.MakeWeak(&counter, &WeakPointerCallback); 3289 // But make children strong roots---all the objects (except for children) 3290 // should be collectable now. 3291 g1c1.ClearWeak(iso); 3292 g2c1.ClearWeak(iso); 3293 3294 // Groups are deleted, rebuild groups. 3295 { 3296 UniqueId id1 = MakeUniqueId(g1s1); 3297 UniqueId id2 = MakeUniqueId(g2s2); 3298 iso->SetObjectGroupId(g1s1, id1); 3299 iso->SetObjectGroupId(g1s2, id1); 3300 iso->SetReferenceFromGroup(id1, g1c1); 3301 iso->SetObjectGroupId(g2s1, id2); 3302 iso->SetObjectGroupId(g2s2, id2); 3303 iso->SetReferenceFromGroup(id2, g2c1); 3304 } 3305 3306 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3307 3308 // All objects should be gone. 5 global handles in total. 3309 CHECK_EQ(5, counter.NumberOfWeakCalls()); 3310 3311 // And now make children weak again and collect them. 3312 g1c1.MakeWeak(&counter, &WeakPointerCallback); 3313 g2c1.MakeWeak(&counter, &WeakPointerCallback); 3314 3315 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3316 CHECK_EQ(7, counter.NumberOfWeakCalls()); 3317 } 3318 3319 3320 THREADED_TEST(ApiObjectGroupsCycle) { 3321 LocalContext env; 3322 v8::Isolate* iso = env->GetIsolate(); 3323 HandleScope scope(iso); 3324 3325 WeakCallCounter counter(1234); 3326 3327 Persistent<Value> g1s1; 3328 Persistent<Value> g1s2; 3329 Persistent<Value> g2s1; 3330 Persistent<Value> g2s2; 3331 Persistent<Value> g3s1; 3332 Persistent<Value> g3s2; 3333 Persistent<Value> g4s1; 3334 Persistent<Value> g4s2; 3335 3336 { 3337 HandleScope scope(iso); 3338 g1s1.Reset(iso, Object::New()); 3339 g1s2.Reset(iso, Object::New()); 3340 g1s1.MakeWeak(&counter, &WeakPointerCallback); 3341 g1s2.MakeWeak(&counter, &WeakPointerCallback); 3342 CHECK(g1s1.IsWeak(iso)); 3343 CHECK(g1s2.IsWeak(iso)); 3344 3345 g2s1.Reset(iso, Object::New()); 3346 g2s2.Reset(iso, Object::New()); 3347 g2s1.MakeWeak(&counter, &WeakPointerCallback); 3348 g2s2.MakeWeak(&counter, &WeakPointerCallback); 3349 CHECK(g2s1.IsWeak(iso)); 3350 CHECK(g2s2.IsWeak(iso)); 3351 3352 g3s1.Reset(iso, Object::New()); 3353 g3s2.Reset(iso, Object::New()); 3354 g3s1.MakeWeak(&counter, &WeakPointerCallback); 3355 g3s2.MakeWeak(&counter, &WeakPointerCallback); 3356 CHECK(g3s1.IsWeak(iso)); 3357 CHECK(g3s2.IsWeak(iso)); 3358 3359 g4s1.Reset(iso, Object::New()); 3360 g4s2.Reset(iso, Object::New()); 3361 g4s1.MakeWeak(&counter, &WeakPointerCallback); 3362 g4s2.MakeWeak(&counter, &WeakPointerCallback); 3363 CHECK(g4s1.IsWeak(iso)); 3364 CHECK(g4s2.IsWeak(iso)); 3365 } 3366 3367 Persistent<Value> root(iso, g1s1); // make a root. 3368 3369 // Connect groups. We're building the following cycle: 3370 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other 3371 // groups. 3372 { 3373 UniqueId id1 = MakeUniqueId(g1s1); 3374 UniqueId id2 = MakeUniqueId(g2s1); 3375 UniqueId id3 = MakeUniqueId(g3s1); 3376 UniqueId id4 = MakeUniqueId(g4s1); 3377 iso->SetObjectGroupId(g1s1, id1); 3378 iso->SetObjectGroupId(g1s2, id1); 3379 iso->SetReferenceFromGroup(id1, g2s1); 3380 iso->SetObjectGroupId(g2s1, id2); 3381 iso->SetObjectGroupId(g2s2, id2); 3382 iso->SetReferenceFromGroup(id2, g3s1); 3383 iso->SetObjectGroupId(g3s1, id3); 3384 iso->SetObjectGroupId(g3s2, id3); 3385 iso->SetReferenceFromGroup(id3, g4s1); 3386 iso->SetObjectGroupId(g4s1, id4); 3387 iso->SetObjectGroupId(g4s2, id4); 3388 iso->SetReferenceFromGroup(id4, g1s1); 3389 } 3390 // Do a single full GC 3391 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 3392 iso)->heap(); 3393 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3394 3395 // All object should be alive. 3396 CHECK_EQ(0, counter.NumberOfWeakCalls()); 3397 3398 // Weaken the root. 3399 root.MakeWeak(&counter, &WeakPointerCallback); 3400 3401 // Groups are deleted, rebuild groups. 3402 { 3403 UniqueId id1 = MakeUniqueId(g1s1); 3404 UniqueId id2 = MakeUniqueId(g2s1); 3405 UniqueId id3 = MakeUniqueId(g3s1); 3406 UniqueId id4 = MakeUniqueId(g4s1); 3407 iso->SetObjectGroupId(g1s1, id1); 3408 iso->SetObjectGroupId(g1s2, id1); 3409 iso->SetReferenceFromGroup(id1, g2s1); 3410 iso->SetObjectGroupId(g2s1, id2); 3411 iso->SetObjectGroupId(g2s2, id2); 3412 iso->SetReferenceFromGroup(id2, g3s1); 3413 iso->SetObjectGroupId(g3s1, id3); 3414 iso->SetObjectGroupId(g3s2, id3); 3415 iso->SetReferenceFromGroup(id3, g4s1); 3416 iso->SetObjectGroupId(g4s1, id4); 3417 iso->SetObjectGroupId(g4s2, id4); 3418 iso->SetReferenceFromGroup(id4, g1s1); 3419 } 3420 3421 heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 3422 3423 // All objects should be gone. 9 global handles in total. 3424 CHECK_EQ(9, counter.NumberOfWeakCalls()); 3425 } 3426 3427 3428 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures 3429 // on the buildbots, so was made non-threaded for the time being. 3430 TEST(ApiObjectGroupsCycleForScavenger) { 3431 i::FLAG_stress_compaction = false; 3432 i::FLAG_gc_global = false; 3433 LocalContext env; 3434 v8::Isolate* iso = env->GetIsolate(); 3435 HandleScope scope(iso); 3436 3437 WeakCallCounter counter(1234); 3438 3439 Persistent<Value> g1s1; 3440 Persistent<Value> g1s2; 3441 Persistent<Value> g2s1; 3442 Persistent<Value> g2s2; 3443 Persistent<Value> g3s1; 3444 Persistent<Value> g3s2; 3445 3446 { 3447 HandleScope scope(iso); 3448 g1s1.Reset(iso, Object::New()); 3449 g1s2.Reset(iso, Object::New()); 3450 g1s1.MakeWeak(&counter, &WeakPointerCallback); 3451 g1s2.MakeWeak(&counter, &WeakPointerCallback); 3452 3453 g2s1.Reset(iso, Object::New()); 3454 g2s2.Reset(iso, Object::New()); 3455 g2s1.MakeWeak(&counter, &WeakPointerCallback); 3456 g2s2.MakeWeak(&counter, &WeakPointerCallback); 3457 3458 g3s1.Reset(iso, Object::New()); 3459 g3s2.Reset(iso, Object::New()); 3460 g3s1.MakeWeak(&counter, &WeakPointerCallback); 3461 g3s2.MakeWeak(&counter, &WeakPointerCallback); 3462 } 3463 3464 // Make a root. 3465 Persistent<Value> root(iso, g1s1); 3466 root.MarkPartiallyDependent(iso); 3467 3468 // Connect groups. We're building the following cycle: 3469 // G1: { g1s1, g2s1 }, g1s1 implicitly references g2s1, ditto for other 3470 // groups. 3471 { 3472 HandleScope handle_scope(iso); 3473 g1s1.MarkPartiallyDependent(iso); 3474 g1s2.MarkPartiallyDependent(iso); 3475 g2s1.MarkPartiallyDependent(iso); 3476 g2s2.MarkPartiallyDependent(iso); 3477 g3s1.MarkPartiallyDependent(iso); 3478 g3s2.MarkPartiallyDependent(iso); 3479 iso->SetObjectGroupId(g1s1, UniqueId(1)); 3480 iso->SetObjectGroupId(g1s2, UniqueId(1)); 3481 Local<Object>::New(iso, g1s1.As<Object>())->Set( 3482 v8_str("x"), Local<Value>::New(iso, g2s1)); 3483 iso->SetObjectGroupId(g2s1, UniqueId(2)); 3484 iso->SetObjectGroupId(g2s2, UniqueId(2)); 3485 Local<Object>::New(iso, g2s1.As<Object>())->Set( 3486 v8_str("x"), Local<Value>::New(iso, g3s1)); 3487 iso->SetObjectGroupId(g3s1, UniqueId(3)); 3488 iso->SetObjectGroupId(g3s2, UniqueId(3)); 3489 Local<Object>::New(iso, g3s1.As<Object>())->Set( 3490 v8_str("x"), Local<Value>::New(iso, g1s1)); 3491 } 3492 3493 v8::internal::Heap* heap = reinterpret_cast<v8::internal::Isolate*>( 3494 iso)->heap(); 3495 heap->CollectGarbage(i::NEW_SPACE); 3496 3497 // All objects should be alive. 3498 CHECK_EQ(0, counter.NumberOfWeakCalls()); 3499 3500 // Weaken the root. 3501 root.MakeWeak(&counter, &WeakPointerCallback); 3502 root.MarkPartiallyDependent(iso); 3503 3504 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 3505 // Groups are deleted, rebuild groups. 3506 { 3507 HandleScope handle_scope(iso); 3508 g1s1.MarkPartiallyDependent(isolate); 3509 g1s2.MarkPartiallyDependent(isolate); 3510 g2s1.MarkPartiallyDependent(isolate); 3511 g2s2.MarkPartiallyDependent(isolate); 3512 g3s1.MarkPartiallyDependent(isolate); 3513 g3s2.MarkPartiallyDependent(isolate); 3514 iso->SetObjectGroupId(g1s1, UniqueId(1)); 3515 iso->SetObjectGroupId(g1s2, UniqueId(1)); 3516 Local<Object>::New(iso, g1s1.As<Object>())->Set( 3517 v8_str("x"), Local<Value>::New(iso, g2s1)); 3518 iso->SetObjectGroupId(g2s1, UniqueId(2)); 3519 iso->SetObjectGroupId(g2s2, UniqueId(2)); 3520 Local<Object>::New(iso, g2s1.As<Object>())->Set( 3521 v8_str("x"), Local<Value>::New(iso, g3s1)); 3522 iso->SetObjectGroupId(g3s1, UniqueId(3)); 3523 iso->SetObjectGroupId(g3s2, UniqueId(3)); 3524 Local<Object>::New(iso, g3s1.As<Object>())->Set( 3525 v8_str("x"), Local<Value>::New(iso, g1s1)); 3526 } 3527 3528 heap->CollectGarbage(i::NEW_SPACE); 3529 3530 // All objects should be gone. 7 global handles in total. 3531 CHECK_EQ(7, counter.NumberOfWeakCalls()); 3532 } 3533 3534 3535 THREADED_TEST(ScriptException) { 3536 LocalContext env; 3537 v8::HandleScope scope(env->GetIsolate()); 3538 Local<Script> script = Script::Compile(v8_str("throw 'panama!';")); 3539 v8::TryCatch try_catch; 3540 Local<Value> result = script->Run(); 3541 CHECK(result.IsEmpty()); 3542 CHECK(try_catch.HasCaught()); 3543 String::Utf8Value exception_value(try_catch.Exception()); 3544 CHECK_EQ(*exception_value, "panama!"); 3545 } 3546 3547 3548 TEST(TryCatchCustomException) { 3549 LocalContext env; 3550 v8::HandleScope scope(env->GetIsolate()); 3551 v8::TryCatch try_catch; 3552 CompileRun("function CustomError() { this.a = 'b'; }" 3553 "(function f() { throw new CustomError(); })();"); 3554 CHECK(try_catch.HasCaught()); 3555 CHECK(try_catch.Exception()->ToObject()-> 3556 Get(v8_str("a"))->Equals(v8_str("b"))); 3557 } 3558 3559 3560 bool message_received; 3561 3562 3563 static void check_message_0(v8::Handle<v8::Message> message, 3564 v8::Handle<Value> data) { 3565 CHECK_EQ(5.76, data->NumberValue()); 3566 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 3567 CHECK_EQ(7.56, message->GetScriptData()->NumberValue()); 3568 CHECK(!message->IsSharedCrossOrigin()); 3569 message_received = true; 3570 } 3571 3572 3573 THREADED_TEST(MessageHandler0) { 3574 message_received = false; 3575 v8::HandleScope scope(v8::Isolate::GetCurrent()); 3576 CHECK(!message_received); 3577 v8::V8::AddMessageListener(check_message_0, v8_num(5.76)); 3578 LocalContext context; 3579 v8::ScriptOrigin origin = 3580 v8::ScriptOrigin(v8_str("6.75")); 3581 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 3582 &origin); 3583 script->SetData(v8_str("7.56")); 3584 script->Run(); 3585 CHECK(message_received); 3586 // clear out the message listener 3587 v8::V8::RemoveMessageListeners(check_message_0); 3588 } 3589 3590 3591 static void check_message_1(v8::Handle<v8::Message> message, 3592 v8::Handle<Value> data) { 3593 CHECK(data->IsNumber()); 3594 CHECK_EQ(1337, data->Int32Value()); 3595 CHECK(!message->IsSharedCrossOrigin()); 3596 message_received = true; 3597 } 3598 3599 3600 TEST(MessageHandler1) { 3601 message_received = false; 3602 v8::HandleScope scope(v8::Isolate::GetCurrent()); 3603 CHECK(!message_received); 3604 v8::V8::AddMessageListener(check_message_1); 3605 LocalContext context; 3606 CompileRun("throw 1337;"); 3607 CHECK(message_received); 3608 // clear out the message listener 3609 v8::V8::RemoveMessageListeners(check_message_1); 3610 } 3611 3612 3613 static void check_message_2(v8::Handle<v8::Message> message, 3614 v8::Handle<Value> data) { 3615 LocalContext context; 3616 CHECK(data->IsObject()); 3617 v8::Local<v8::Value> hidden_property = 3618 v8::Object::Cast(*data)->GetHiddenValue(v8_str("hidden key")); 3619 CHECK(v8_str("hidden value")->Equals(hidden_property)); 3620 CHECK(!message->IsSharedCrossOrigin()); 3621 message_received = true; 3622 } 3623 3624 3625 TEST(MessageHandler2) { 3626 message_received = false; 3627 v8::HandleScope scope(v8::Isolate::GetCurrent()); 3628 CHECK(!message_received); 3629 v8::V8::AddMessageListener(check_message_2); 3630 LocalContext context; 3631 v8::Local<v8::Value> error = v8::Exception::Error(v8_str("custom error")); 3632 v8::Object::Cast(*error)->SetHiddenValue(v8_str("hidden key"), 3633 v8_str("hidden value")); 3634 context->Global()->Set(v8_str("error"), error); 3635 CompileRun("throw error;"); 3636 CHECK(message_received); 3637 // clear out the message listener 3638 v8::V8::RemoveMessageListeners(check_message_2); 3639 } 3640 3641 3642 static void check_message_3(v8::Handle<v8::Message> message, 3643 v8::Handle<Value> data) { 3644 CHECK(message->IsSharedCrossOrigin()); 3645 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 3646 message_received = true; 3647 } 3648 3649 3650 TEST(MessageHandler3) { 3651 message_received = false; 3652 v8::HandleScope scope(v8::Isolate::GetCurrent()); 3653 CHECK(!message_received); 3654 v8::V8::AddMessageListener(check_message_3); 3655 LocalContext context; 3656 v8::ScriptOrigin origin = 3657 v8::ScriptOrigin(v8_str("6.75"), 3658 v8::Integer::New(1), 3659 v8::Integer::New(2), 3660 v8::True()); 3661 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 3662 &origin); 3663 script->Run(); 3664 CHECK(message_received); 3665 // clear out the message listener 3666 v8::V8::RemoveMessageListeners(check_message_3); 3667 } 3668 3669 3670 static void check_message_4(v8::Handle<v8::Message> message, 3671 v8::Handle<Value> data) { 3672 CHECK(!message->IsSharedCrossOrigin()); 3673 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 3674 message_received = true; 3675 } 3676 3677 3678 TEST(MessageHandler4) { 3679 message_received = false; 3680 v8::HandleScope scope(v8::Isolate::GetCurrent()); 3681 CHECK(!message_received); 3682 v8::V8::AddMessageListener(check_message_4); 3683 LocalContext context; 3684 v8::ScriptOrigin origin = 3685 v8::ScriptOrigin(v8_str("6.75"), 3686 v8::Integer::New(1), 3687 v8::Integer::New(2), 3688 v8::False()); 3689 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 3690 &origin); 3691 script->Run(); 3692 CHECK(message_received); 3693 // clear out the message listener 3694 v8::V8::RemoveMessageListeners(check_message_4); 3695 } 3696 3697 3698 static void check_message_5a(v8::Handle<v8::Message> message, 3699 v8::Handle<Value> data) { 3700 CHECK(message->IsSharedCrossOrigin()); 3701 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 3702 message_received = true; 3703 } 3704 3705 3706 static void check_message_5b(v8::Handle<v8::Message> message, 3707 v8::Handle<Value> data) { 3708 CHECK(!message->IsSharedCrossOrigin()); 3709 CHECK_EQ(6.75, message->GetScriptResourceName()->NumberValue()); 3710 message_received = true; 3711 } 3712 3713 3714 TEST(MessageHandler5) { 3715 message_received = false; 3716 v8::HandleScope scope(v8::Isolate::GetCurrent()); 3717 CHECK(!message_received); 3718 v8::V8::AddMessageListener(check_message_5a); 3719 LocalContext context; 3720 v8::ScriptOrigin origin = 3721 v8::ScriptOrigin(v8_str("6.75"), 3722 v8::Integer::New(1), 3723 v8::Integer::New(2), 3724 v8::True()); 3725 v8::Handle<v8::Script> script = Script::Compile(v8_str("throw 'error'"), 3726 &origin); 3727 script->Run(); 3728 CHECK(message_received); 3729 // clear out the message listener 3730 v8::V8::RemoveMessageListeners(check_message_5a); 3731 3732 message_received = false; 3733 v8::V8::AddMessageListener(check_message_5b); 3734 origin = 3735 v8::ScriptOrigin(v8_str("6.75"), 3736 v8::Integer::New(1), 3737 v8::Integer::New(2), 3738 v8::False()); 3739 script = Script::Compile(v8_str("throw 'error'"), 3740 &origin); 3741 script->Run(); 3742 CHECK(message_received); 3743 // clear out the message listener 3744 v8::V8::RemoveMessageListeners(check_message_5b); 3745 } 3746 3747 3748 THREADED_TEST(GetSetProperty) { 3749 LocalContext context; 3750 v8::HandleScope scope(context->GetIsolate()); 3751 context->Global()->Set(v8_str("foo"), v8_num(14)); 3752 context->Global()->Set(v8_str("12"), v8_num(92)); 3753 context->Global()->Set(v8::Integer::New(16), v8_num(32)); 3754 context->Global()->Set(v8_num(13), v8_num(56)); 3755 Local<Value> foo = Script::Compile(v8_str("this.foo"))->Run(); 3756 CHECK_EQ(14, foo->Int32Value()); 3757 Local<Value> twelve = Script::Compile(v8_str("this[12]"))->Run(); 3758 CHECK_EQ(92, twelve->Int32Value()); 3759 Local<Value> sixteen = Script::Compile(v8_str("this[16]"))->Run(); 3760 CHECK_EQ(32, sixteen->Int32Value()); 3761 Local<Value> thirteen = Script::Compile(v8_str("this[13]"))->Run(); 3762 CHECK_EQ(56, thirteen->Int32Value()); 3763 CHECK_EQ(92, context->Global()->Get(v8::Integer::New(12))->Int32Value()); 3764 CHECK_EQ(92, context->Global()->Get(v8_str("12"))->Int32Value()); 3765 CHECK_EQ(92, context->Global()->Get(v8_num(12))->Int32Value()); 3766 CHECK_EQ(32, context->Global()->Get(v8::Integer::New(16))->Int32Value()); 3767 CHECK_EQ(32, context->Global()->Get(v8_str("16"))->Int32Value()); 3768 CHECK_EQ(32, context->Global()->Get(v8_num(16))->Int32Value()); 3769 CHECK_EQ(56, context->Global()->Get(v8::Integer::New(13))->Int32Value()); 3770 CHECK_EQ(56, context->Global()->Get(v8_str("13"))->Int32Value()); 3771 CHECK_EQ(56, context->Global()->Get(v8_num(13))->Int32Value()); 3772 } 3773 3774 3775 THREADED_TEST(PropertyAttributes) { 3776 LocalContext context; 3777 v8::HandleScope scope(context->GetIsolate()); 3778 // none 3779 Local<String> prop = v8_str("none"); 3780 context->Global()->Set(prop, v8_num(7)); 3781 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop)); 3782 // read-only 3783 prop = v8_str("read_only"); 3784 context->Global()->Set(prop, v8_num(7), v8::ReadOnly); 3785 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 3786 CHECK_EQ(v8::ReadOnly, context->Global()->GetPropertyAttributes(prop)); 3787 Script::Compile(v8_str("read_only = 9"))->Run(); 3788 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 3789 context->Global()->Set(prop, v8_num(10)); 3790 CHECK_EQ(7, context->Global()->Get(prop)->Int32Value()); 3791 // dont-delete 3792 prop = v8_str("dont_delete"); 3793 context->Global()->Set(prop, v8_num(13), v8::DontDelete); 3794 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); 3795 Script::Compile(v8_str("delete dont_delete"))->Run(); 3796 CHECK_EQ(13, context->Global()->Get(prop)->Int32Value()); 3797 CHECK_EQ(v8::DontDelete, context->Global()->GetPropertyAttributes(prop)); 3798 // dont-enum 3799 prop = v8_str("dont_enum"); 3800 context->Global()->Set(prop, v8_num(28), v8::DontEnum); 3801 CHECK_EQ(v8::DontEnum, context->Global()->GetPropertyAttributes(prop)); 3802 // absent 3803 prop = v8_str("absent"); 3804 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(prop)); 3805 Local<Value> fake_prop = v8_num(1); 3806 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(fake_prop)); 3807 // exception 3808 TryCatch try_catch; 3809 Local<Value> exception = 3810 CompileRun("({ toString: function() { throw 'exception';} })"); 3811 CHECK_EQ(v8::None, context->Global()->GetPropertyAttributes(exception)); 3812 CHECK(try_catch.HasCaught()); 3813 String::Utf8Value exception_value(try_catch.Exception()); 3814 CHECK_EQ("exception", *exception_value); 3815 try_catch.Reset(); 3816 } 3817 3818 3819 THREADED_TEST(Array) { 3820 LocalContext context; 3821 v8::HandleScope scope(context->GetIsolate()); 3822 Local<v8::Array> array = v8::Array::New(); 3823 CHECK_EQ(0, array->Length()); 3824 CHECK(array->Get(0)->IsUndefined()); 3825 CHECK(!array->Has(0)); 3826 CHECK(array->Get(100)->IsUndefined()); 3827 CHECK(!array->Has(100)); 3828 array->Set(2, v8_num(7)); 3829 CHECK_EQ(3, array->Length()); 3830 CHECK(!array->Has(0)); 3831 CHECK(!array->Has(1)); 3832 CHECK(array->Has(2)); 3833 CHECK_EQ(7, array->Get(2)->Int32Value()); 3834 Local<Value> obj = Script::Compile(v8_str("[1, 2, 3]"))->Run(); 3835 Local<v8::Array> arr = obj.As<v8::Array>(); 3836 CHECK_EQ(3, arr->Length()); 3837 CHECK_EQ(1, arr->Get(0)->Int32Value()); 3838 CHECK_EQ(2, arr->Get(1)->Int32Value()); 3839 CHECK_EQ(3, arr->Get(2)->Int32Value()); 3840 array = v8::Array::New(27); 3841 CHECK_EQ(27, array->Length()); 3842 array = v8::Array::New(-27); 3843 CHECK_EQ(0, array->Length()); 3844 } 3845 3846 3847 void HandleF(const v8::FunctionCallbackInfo<v8::Value>& args) { 3848 v8::HandleScope scope(args.GetIsolate()); 3849 ApiTestFuzzer::Fuzz(); 3850 Local<v8::Array> result = v8::Array::New(args.Length()); 3851 for (int i = 0; i < args.Length(); i++) 3852 result->Set(i, args[i]); 3853 args.GetReturnValue().Set(scope.Close(result)); 3854 } 3855 3856 3857 THREADED_TEST(Vector) { 3858 v8::HandleScope scope(v8::Isolate::GetCurrent()); 3859 Local<ObjectTemplate> global = ObjectTemplate::New(); 3860 global->Set(v8_str("f"), v8::FunctionTemplate::New(HandleF)); 3861 LocalContext context(0, global); 3862 3863 const char* fun = "f()"; 3864 Local<v8::Array> a0 = CompileRun(fun).As<v8::Array>(); 3865 CHECK_EQ(0, a0->Length()); 3866 3867 const char* fun2 = "f(11)"; 3868 Local<v8::Array> a1 = CompileRun(fun2).As<v8::Array>(); 3869 CHECK_EQ(1, a1->Length()); 3870 CHECK_EQ(11, a1->Get(0)->Int32Value()); 3871 3872 const char* fun3 = "f(12, 13)"; 3873 Local<v8::Array> a2 = CompileRun(fun3).As<v8::Array>(); 3874 CHECK_EQ(2, a2->Length()); 3875 CHECK_EQ(12, a2->Get(0)->Int32Value()); 3876 CHECK_EQ(13, a2->Get(1)->Int32Value()); 3877 3878 const char* fun4 = "f(14, 15, 16)"; 3879 Local<v8::Array> a3 = CompileRun(fun4).As<v8::Array>(); 3880 CHECK_EQ(3, a3->Length()); 3881 CHECK_EQ(14, a3->Get(0)->Int32Value()); 3882 CHECK_EQ(15, a3->Get(1)->Int32Value()); 3883 CHECK_EQ(16, a3->Get(2)->Int32Value()); 3884 3885 const char* fun5 = "f(17, 18, 19, 20)"; 3886 Local<v8::Array> a4 = CompileRun(fun5).As<v8::Array>(); 3887 CHECK_EQ(4, a4->Length()); 3888 CHECK_EQ(17, a4->Get(0)->Int32Value()); 3889 CHECK_EQ(18, a4->Get(1)->Int32Value()); 3890 CHECK_EQ(19, a4->Get(2)->Int32Value()); 3891 CHECK_EQ(20, a4->Get(3)->Int32Value()); 3892 } 3893 3894 3895 THREADED_TEST(FunctionCall) { 3896 LocalContext context; 3897 v8::HandleScope scope(context->GetIsolate()); 3898 CompileRun( 3899 "function Foo() {" 3900 " var result = [];" 3901 " for (var i = 0; i < arguments.length; i++) {" 3902 " result.push(arguments[i]);" 3903 " }" 3904 " return result;" 3905 "}"); 3906 Local<Function> Foo = 3907 Local<Function>::Cast(context->Global()->Get(v8_str("Foo"))); 3908 3909 v8::Handle<Value>* args0 = NULL; 3910 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->Call(Foo, 0, args0)); 3911 CHECK_EQ(0, a0->Length()); 3912 3913 v8::Handle<Value> args1[] = { v8_num(1.1) }; 3914 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->Call(Foo, 1, args1)); 3915 CHECK_EQ(1, a1->Length()); 3916 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue()); 3917 3918 v8::Handle<Value> args2[] = { v8_num(2.2), 3919 v8_num(3.3) }; 3920 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->Call(Foo, 2, args2)); 3921 CHECK_EQ(2, a2->Length()); 3922 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue()); 3923 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue()); 3924 3925 v8::Handle<Value> args3[] = { v8_num(4.4), 3926 v8_num(5.5), 3927 v8_num(6.6) }; 3928 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->Call(Foo, 3, args3)); 3929 CHECK_EQ(3, a3->Length()); 3930 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue()); 3931 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue()); 3932 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue()); 3933 3934 v8::Handle<Value> args4[] = { v8_num(7.7), 3935 v8_num(8.8), 3936 v8_num(9.9), 3937 v8_num(10.11) }; 3938 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->Call(Foo, 4, args4)); 3939 CHECK_EQ(4, a4->Length()); 3940 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue()); 3941 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue()); 3942 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue()); 3943 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue()); 3944 } 3945 3946 3947 static const char* js_code_causing_out_of_memory = 3948 "var a = new Array(); while(true) a.push(a);"; 3949 3950 3951 // These tests run for a long time and prevent us from running tests 3952 // that come after them so they cannot run in parallel. 3953 TEST(OutOfMemory) { 3954 // It's not possible to read a snapshot into a heap with different dimensions. 3955 if (i::Snapshot::IsEnabled()) return; 3956 // Set heap limits. 3957 static const int K = 1024; 3958 v8::ResourceConstraints constraints; 3959 constraints.set_max_young_space_size(256 * K); 3960 constraints.set_max_old_space_size(5 * K * K); 3961 v8::SetResourceConstraints(&constraints); 3962 3963 // Execute a script that causes out of memory. 3964 LocalContext context; 3965 v8::HandleScope scope(context->GetIsolate()); 3966 v8::V8::IgnoreOutOfMemoryException(); 3967 Local<Script> script = 3968 Script::Compile(String::New(js_code_causing_out_of_memory)); 3969 Local<Value> result = script->Run(); 3970 3971 // Check for out of memory state. 3972 CHECK(result.IsEmpty()); 3973 CHECK(context->HasOutOfMemoryException()); 3974 } 3975 3976 3977 void ProvokeOutOfMemory(const v8::FunctionCallbackInfo<v8::Value>& args) { 3978 ApiTestFuzzer::Fuzz(); 3979 3980 LocalContext context; 3981 v8::HandleScope scope(context->GetIsolate()); 3982 Local<Script> script = 3983 Script::Compile(String::New(js_code_causing_out_of_memory)); 3984 Local<Value> result = script->Run(); 3985 3986 // Check for out of memory state. 3987 CHECK(result.IsEmpty()); 3988 CHECK(context->HasOutOfMemoryException()); 3989 3990 args.GetReturnValue().Set(result); 3991 } 3992 3993 3994 TEST(OutOfMemoryNested) { 3995 // It's not possible to read a snapshot into a heap with different dimensions. 3996 if (i::Snapshot::IsEnabled()) return; 3997 // Set heap limits. 3998 static const int K = 1024; 3999 v8::ResourceConstraints constraints; 4000 constraints.set_max_young_space_size(256 * K); 4001 constraints.set_max_old_space_size(5 * K * K); 4002 v8::SetResourceConstraints(&constraints); 4003 4004 v8::HandleScope scope(v8::Isolate::GetCurrent()); 4005 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4006 templ->Set(v8_str("ProvokeOutOfMemory"), 4007 v8::FunctionTemplate::New(ProvokeOutOfMemory)); 4008 LocalContext context(0, templ); 4009 v8::V8::IgnoreOutOfMemoryException(); 4010 Local<Value> result = CompileRun( 4011 "var thrown = false;" 4012 "try {" 4013 " ProvokeOutOfMemory();" 4014 "} catch (e) {" 4015 " thrown = true;" 4016 "}"); 4017 // Check for out of memory state. 4018 CHECK(result.IsEmpty()); 4019 CHECK(context->HasOutOfMemoryException()); 4020 } 4021 4022 4023 TEST(HugeConsStringOutOfMemory) { 4024 // It's not possible to read a snapshot into a heap with different dimensions. 4025 if (i::Snapshot::IsEnabled()) return; 4026 // Set heap limits. 4027 static const int K = 1024; 4028 v8::ResourceConstraints constraints; 4029 constraints.set_max_young_space_size(256 * K); 4030 constraints.set_max_old_space_size(4 * K * K); 4031 v8::SetResourceConstraints(&constraints); 4032 4033 // Execute a script that causes out of memory. 4034 v8::V8::IgnoreOutOfMemoryException(); 4035 4036 LocalContext context; 4037 v8::HandleScope scope(context->GetIsolate()); 4038 4039 // Build huge string. This should fail with out of memory exception. 4040 Local<Value> result = CompileRun( 4041 "var str = Array.prototype.join.call({length: 513}, \"A\").toUpperCase();" 4042 "for (var i = 0; i < 22; i++) { str = str + str; }"); 4043 4044 // Check for out of memory state. 4045 CHECK(result.IsEmpty()); 4046 CHECK(context->HasOutOfMemoryException()); 4047 } 4048 4049 4050 THREADED_TEST(ConstructCall) { 4051 LocalContext context; 4052 v8::HandleScope scope(context->GetIsolate()); 4053 CompileRun( 4054 "function Foo() {" 4055 " var result = [];" 4056 " for (var i = 0; i < arguments.length; i++) {" 4057 " result.push(arguments[i]);" 4058 " }" 4059 " return result;" 4060 "}"); 4061 Local<Function> Foo = 4062 Local<Function>::Cast(context->Global()->Get(v8_str("Foo"))); 4063 4064 v8::Handle<Value>* args0 = NULL; 4065 Local<v8::Array> a0 = Local<v8::Array>::Cast(Foo->NewInstance(0, args0)); 4066 CHECK_EQ(0, a0->Length()); 4067 4068 v8::Handle<Value> args1[] = { v8_num(1.1) }; 4069 Local<v8::Array> a1 = Local<v8::Array>::Cast(Foo->NewInstance(1, args1)); 4070 CHECK_EQ(1, a1->Length()); 4071 CHECK_EQ(1.1, a1->Get(v8::Integer::New(0))->NumberValue()); 4072 4073 v8::Handle<Value> args2[] = { v8_num(2.2), 4074 v8_num(3.3) }; 4075 Local<v8::Array> a2 = Local<v8::Array>::Cast(Foo->NewInstance(2, args2)); 4076 CHECK_EQ(2, a2->Length()); 4077 CHECK_EQ(2.2, a2->Get(v8::Integer::New(0))->NumberValue()); 4078 CHECK_EQ(3.3, a2->Get(v8::Integer::New(1))->NumberValue()); 4079 4080 v8::Handle<Value> args3[] = { v8_num(4.4), 4081 v8_num(5.5), 4082 v8_num(6.6) }; 4083 Local<v8::Array> a3 = Local<v8::Array>::Cast(Foo->NewInstance(3, args3)); 4084 CHECK_EQ(3, a3->Length()); 4085 CHECK_EQ(4.4, a3->Get(v8::Integer::New(0))->NumberValue()); 4086 CHECK_EQ(5.5, a3->Get(v8::Integer::New(1))->NumberValue()); 4087 CHECK_EQ(6.6, a3->Get(v8::Integer::New(2))->NumberValue()); 4088 4089 v8::Handle<Value> args4[] = { v8_num(7.7), 4090 v8_num(8.8), 4091 v8_num(9.9), 4092 v8_num(10.11) }; 4093 Local<v8::Array> a4 = Local<v8::Array>::Cast(Foo->NewInstance(4, args4)); 4094 CHECK_EQ(4, a4->Length()); 4095 CHECK_EQ(7.7, a4->Get(v8::Integer::New(0))->NumberValue()); 4096 CHECK_EQ(8.8, a4->Get(v8::Integer::New(1))->NumberValue()); 4097 CHECK_EQ(9.9, a4->Get(v8::Integer::New(2))->NumberValue()); 4098 CHECK_EQ(10.11, a4->Get(v8::Integer::New(3))->NumberValue()); 4099 } 4100 4101 4102 static void CheckUncle(v8::TryCatch* try_catch) { 4103 CHECK(try_catch->HasCaught()); 4104 String::Utf8Value str_value(try_catch->Exception()); 4105 CHECK_EQ(*str_value, "uncle?"); 4106 try_catch->Reset(); 4107 } 4108 4109 4110 THREADED_TEST(ConversionNumber) { 4111 LocalContext env; 4112 v8::HandleScope scope(env->GetIsolate()); 4113 // Very large number. 4114 CompileRun("var obj = Math.pow(2,32) * 1237;"); 4115 Local<Value> obj = env->Global()->Get(v8_str("obj")); 4116 CHECK_EQ(5312874545152.0, obj->ToNumber()->Value()); 4117 CHECK_EQ(0, obj->ToInt32()->Value()); 4118 CHECK(0u == obj->ToUint32()->Value()); // NOLINT - no CHECK_EQ for unsigned. 4119 // Large number. 4120 CompileRun("var obj = -1234567890123;"); 4121 obj = env->Global()->Get(v8_str("obj")); 4122 CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value()); 4123 CHECK_EQ(-1912276171, obj->ToInt32()->Value()); 4124 CHECK(2382691125u == obj->ToUint32()->Value()); // NOLINT 4125 // Small positive integer. 4126 CompileRun("var obj = 42;"); 4127 obj = env->Global()->Get(v8_str("obj")); 4128 CHECK_EQ(42.0, obj->ToNumber()->Value()); 4129 CHECK_EQ(42, obj->ToInt32()->Value()); 4130 CHECK(42u == obj->ToUint32()->Value()); // NOLINT 4131 // Negative integer. 4132 CompileRun("var obj = -37;"); 4133 obj = env->Global()->Get(v8_str("obj")); 4134 CHECK_EQ(-37.0, obj->ToNumber()->Value()); 4135 CHECK_EQ(-37, obj->ToInt32()->Value()); 4136 CHECK(4294967259u == obj->ToUint32()->Value()); // NOLINT 4137 // Positive non-int32 integer. 4138 CompileRun("var obj = 0x81234567;"); 4139 obj = env->Global()->Get(v8_str("obj")); 4140 CHECK_EQ(2166572391.0, obj->ToNumber()->Value()); 4141 CHECK_EQ(-2128394905, obj->ToInt32()->Value()); 4142 CHECK(2166572391u == obj->ToUint32()->Value()); // NOLINT 4143 // Fraction. 4144 CompileRun("var obj = 42.3;"); 4145 obj = env->Global()->Get(v8_str("obj")); 4146 CHECK_EQ(42.3, obj->ToNumber()->Value()); 4147 CHECK_EQ(42, obj->ToInt32()->Value()); 4148 CHECK(42u == obj->ToUint32()->Value()); // NOLINT 4149 // Large negative fraction. 4150 CompileRun("var obj = -5726623061.75;"); 4151 obj = env->Global()->Get(v8_str("obj")); 4152 CHECK_EQ(-5726623061.75, obj->ToNumber()->Value()); 4153 CHECK_EQ(-1431655765, obj->ToInt32()->Value()); 4154 CHECK(2863311531u == obj->ToUint32()->Value()); // NOLINT 4155 } 4156 4157 4158 THREADED_TEST(isNumberType) { 4159 LocalContext env; 4160 v8::HandleScope scope(env->GetIsolate()); 4161 // Very large number. 4162 CompileRun("var obj = Math.pow(2,32) * 1237;"); 4163 Local<Value> obj = env->Global()->Get(v8_str("obj")); 4164 CHECK(!obj->IsInt32()); 4165 CHECK(!obj->IsUint32()); 4166 // Large negative number. 4167 CompileRun("var obj = -1234567890123;"); 4168 obj = env->Global()->Get(v8_str("obj")); 4169 CHECK(!obj->IsInt32()); 4170 CHECK(!obj->IsUint32()); 4171 // Small positive integer. 4172 CompileRun("var obj = 42;"); 4173 obj = env->Global()->Get(v8_str("obj")); 4174 CHECK(obj->IsInt32()); 4175 CHECK(obj->IsUint32()); 4176 // Negative integer. 4177 CompileRun("var obj = -37;"); 4178 obj = env->Global()->Get(v8_str("obj")); 4179 CHECK(obj->IsInt32()); 4180 CHECK(!obj->IsUint32()); 4181 // Positive non-int32 integer. 4182 CompileRun("var obj = 0x81234567;"); 4183 obj = env->Global()->Get(v8_str("obj")); 4184 CHECK(!obj->IsInt32()); 4185 CHECK(obj->IsUint32()); 4186 // Fraction. 4187 CompileRun("var obj = 42.3;"); 4188 obj = env->Global()->Get(v8_str("obj")); 4189 CHECK(!obj->IsInt32()); 4190 CHECK(!obj->IsUint32()); 4191 // Large negative fraction. 4192 CompileRun("var obj = -5726623061.75;"); 4193 obj = env->Global()->Get(v8_str("obj")); 4194 CHECK(!obj->IsInt32()); 4195 CHECK(!obj->IsUint32()); 4196 // Positive zero 4197 CompileRun("var obj = 0.0;"); 4198 obj = env->Global()->Get(v8_str("obj")); 4199 CHECK(obj->IsInt32()); 4200 CHECK(obj->IsUint32()); 4201 // Positive zero 4202 CompileRun("var obj = -0.0;"); 4203 obj = env->Global()->Get(v8_str("obj")); 4204 CHECK(!obj->IsInt32()); 4205 CHECK(!obj->IsUint32()); 4206 } 4207 4208 4209 THREADED_TEST(ConversionException) { 4210 LocalContext env; 4211 v8::HandleScope scope(env->GetIsolate()); 4212 CompileRun( 4213 "function TestClass() { };" 4214 "TestClass.prototype.toString = function () { throw 'uncle?'; };" 4215 "var obj = new TestClass();"); 4216 Local<Value> obj = env->Global()->Get(v8_str("obj")); 4217 4218 v8::TryCatch try_catch; 4219 4220 Local<Value> to_string_result = obj->ToString(); 4221 CHECK(to_string_result.IsEmpty()); 4222 CheckUncle(&try_catch); 4223 4224 Local<Value> to_number_result = obj->ToNumber(); 4225 CHECK(to_number_result.IsEmpty()); 4226 CheckUncle(&try_catch); 4227 4228 Local<Value> to_integer_result = obj->ToInteger(); 4229 CHECK(to_integer_result.IsEmpty()); 4230 CheckUncle(&try_catch); 4231 4232 Local<Value> to_uint32_result = obj->ToUint32(); 4233 CHECK(to_uint32_result.IsEmpty()); 4234 CheckUncle(&try_catch); 4235 4236 Local<Value> to_int32_result = obj->ToInt32(); 4237 CHECK(to_int32_result.IsEmpty()); 4238 CheckUncle(&try_catch); 4239 4240 Local<Value> to_object_result = v8::Undefined()->ToObject(); 4241 CHECK(to_object_result.IsEmpty()); 4242 CHECK(try_catch.HasCaught()); 4243 try_catch.Reset(); 4244 4245 int32_t int32_value = obj->Int32Value(); 4246 CHECK_EQ(0, int32_value); 4247 CheckUncle(&try_catch); 4248 4249 uint32_t uint32_value = obj->Uint32Value(); 4250 CHECK_EQ(0, uint32_value); 4251 CheckUncle(&try_catch); 4252 4253 double number_value = obj->NumberValue(); 4254 CHECK_NE(0, std::isnan(number_value)); 4255 CheckUncle(&try_catch); 4256 4257 int64_t integer_value = obj->IntegerValue(); 4258 CHECK_EQ(0.0, static_cast<double>(integer_value)); 4259 CheckUncle(&try_catch); 4260 } 4261 4262 4263 void ThrowFromC(const v8::FunctionCallbackInfo<v8::Value>& args) { 4264 ApiTestFuzzer::Fuzz(); 4265 v8::ThrowException(v8_str("konto")); 4266 } 4267 4268 4269 void CCatcher(const v8::FunctionCallbackInfo<v8::Value>& args) { 4270 if (args.Length() < 1) { 4271 args.GetReturnValue().Set(false); 4272 return; 4273 } 4274 v8::HandleScope scope(args.GetIsolate()); 4275 v8::TryCatch try_catch; 4276 Local<Value> result = v8::Script::Compile(args[0]->ToString())->Run(); 4277 CHECK(!try_catch.HasCaught() || result.IsEmpty()); 4278 args.GetReturnValue().Set(try_catch.HasCaught()); 4279 } 4280 4281 4282 THREADED_TEST(APICatch) { 4283 v8::HandleScope scope(v8::Isolate::GetCurrent()); 4284 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4285 templ->Set(v8_str("ThrowFromC"), 4286 v8::FunctionTemplate::New(ThrowFromC)); 4287 LocalContext context(0, templ); 4288 CompileRun( 4289 "var thrown = false;" 4290 "try {" 4291 " ThrowFromC();" 4292 "} catch (e) {" 4293 " thrown = true;" 4294 "}"); 4295 Local<Value> thrown = context->Global()->Get(v8_str("thrown")); 4296 CHECK(thrown->BooleanValue()); 4297 } 4298 4299 4300 THREADED_TEST(APIThrowTryCatch) { 4301 v8::HandleScope scope(v8::Isolate::GetCurrent()); 4302 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4303 templ->Set(v8_str("ThrowFromC"), 4304 v8::FunctionTemplate::New(ThrowFromC)); 4305 LocalContext context(0, templ); 4306 v8::TryCatch try_catch; 4307 CompileRun("ThrowFromC();"); 4308 CHECK(try_catch.HasCaught()); 4309 } 4310 4311 4312 // Test that a try-finally block doesn't shadow a try-catch block 4313 // when setting up an external handler. 4314 // 4315 // BUG(271): Some of the exception propagation does not work on the 4316 // ARM simulator because the simulator separates the C++ stack and the 4317 // JS stack. This test therefore fails on the simulator. The test is 4318 // not threaded to allow the threading tests to run on the simulator. 4319 TEST(TryCatchInTryFinally) { 4320 v8::HandleScope scope(v8::Isolate::GetCurrent()); 4321 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4322 templ->Set(v8_str("CCatcher"), 4323 v8::FunctionTemplate::New(CCatcher)); 4324 LocalContext context(0, templ); 4325 Local<Value> result = CompileRun("try {" 4326 " try {" 4327 " CCatcher('throw 7;');" 4328 " } finally {" 4329 " }" 4330 "} catch (e) {" 4331 "}"); 4332 CHECK(result->IsTrue()); 4333 } 4334 4335 4336 static void check_reference_error_message( 4337 v8::Handle<v8::Message> message, 4338 v8::Handle<v8::Value> data) { 4339 const char* reference_error = "Uncaught ReferenceError: asdf is not defined"; 4340 CHECK(message->Get()->Equals(v8_str(reference_error))); 4341 } 4342 4343 4344 static void Fail(const v8::FunctionCallbackInfo<v8::Value>& args) { 4345 ApiTestFuzzer::Fuzz(); 4346 CHECK(false); 4347 } 4348 4349 4350 // Test that overwritten methods are not invoked on uncaught exception 4351 // formatting. However, they are invoked when performing normal error 4352 // string conversions. 4353 TEST(APIThrowMessageOverwrittenToString) { 4354 v8::HandleScope scope(v8::Isolate::GetCurrent()); 4355 v8::V8::AddMessageListener(check_reference_error_message); 4356 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4357 templ->Set(v8_str("fail"), v8::FunctionTemplate::New(Fail)); 4358 LocalContext context(NULL, templ); 4359 CompileRun("asdf;"); 4360 CompileRun("var limit = {};" 4361 "limit.valueOf = fail;" 4362 "Error.stackTraceLimit = limit;"); 4363 CompileRun("asdf"); 4364 CompileRun("Array.prototype.pop = fail;"); 4365 CompileRun("Object.prototype.hasOwnProperty = fail;"); 4366 CompileRun("Object.prototype.toString = function f() { return 'Yikes'; }"); 4367 CompileRun("Number.prototype.toString = function f() { return 'Yikes'; }"); 4368 CompileRun("String.prototype.toString = function f() { return 'Yikes'; }"); 4369 CompileRun("ReferenceError.prototype.toString =" 4370 " function() { return 'Whoops' }"); 4371 CompileRun("asdf;"); 4372 CompileRun("ReferenceError.prototype.constructor.name = void 0;"); 4373 CompileRun("asdf;"); 4374 CompileRun("ReferenceError.prototype.constructor = void 0;"); 4375 CompileRun("asdf;"); 4376 CompileRun("ReferenceError.prototype.__proto__ = new Object();"); 4377 CompileRun("asdf;"); 4378 CompileRun("ReferenceError.prototype = new Object();"); 4379 CompileRun("asdf;"); 4380 v8::Handle<Value> string = CompileRun("try { asdf; } catch(e) { e + ''; }"); 4381 CHECK(string->Equals(v8_str("Whoops"))); 4382 CompileRun("ReferenceError.prototype.constructor = new Object();" 4383 "ReferenceError.prototype.constructor.name = 1;" 4384 "Number.prototype.toString = function() { return 'Whoops'; };" 4385 "ReferenceError.prototype.toString = Object.prototype.toString;"); 4386 CompileRun("asdf;"); 4387 v8::V8::RemoveMessageListeners(check_reference_error_message); 4388 } 4389 4390 4391 static void check_custom_error_tostring( 4392 v8::Handle<v8::Message> message, 4393 v8::Handle<v8::Value> data) { 4394 const char* uncaught_error = "Uncaught MyError toString"; 4395 CHECK(message->Get()->Equals(v8_str(uncaught_error))); 4396 } 4397 4398 4399 TEST(CustomErrorToString) { 4400 LocalContext context; 4401 v8::HandleScope scope(context->GetIsolate()); 4402 v8::V8::AddMessageListener(check_custom_error_tostring); 4403 CompileRun( 4404 "function MyError(name, message) { " 4405 " this.name = name; " 4406 " this.message = message; " 4407 "} " 4408 "MyError.prototype = Object.create(Error.prototype); " 4409 "MyError.prototype.toString = function() { " 4410 " return 'MyError toString'; " 4411 "}; " 4412 "throw new MyError('my name', 'my message'); "); 4413 v8::V8::RemoveMessageListeners(check_custom_error_tostring); 4414 } 4415 4416 4417 static void check_custom_error_message( 4418 v8::Handle<v8::Message> message, 4419 v8::Handle<v8::Value> data) { 4420 const char* uncaught_error = "Uncaught MyError: my message"; 4421 printf("%s\n", *v8::String::Utf8Value(message->Get())); 4422 CHECK(message->Get()->Equals(v8_str(uncaught_error))); 4423 } 4424 4425 4426 TEST(CustomErrorMessage) { 4427 LocalContext context; 4428 v8::HandleScope scope(context->GetIsolate()); 4429 v8::V8::AddMessageListener(check_custom_error_message); 4430 4431 // Handlebars. 4432 CompileRun( 4433 "function MyError(msg) { " 4434 " this.name = 'MyError'; " 4435 " this.message = msg; " 4436 "} " 4437 "MyError.prototype = new Error(); " 4438 "throw new MyError('my message'); "); 4439 4440 // Closure. 4441 CompileRun( 4442 "function MyError(msg) { " 4443 " this.name = 'MyError'; " 4444 " this.message = msg; " 4445 "} " 4446 "inherits = function(childCtor, parentCtor) { " 4447 " function tempCtor() {}; " 4448 " tempCtor.prototype = parentCtor.prototype; " 4449 " childCtor.superClass_ = parentCtor.prototype; " 4450 " childCtor.prototype = new tempCtor(); " 4451 " childCtor.prototype.constructor = childCtor; " 4452 "}; " 4453 "inherits(MyError, Error); " 4454 "throw new MyError('my message'); "); 4455 4456 // Object.create. 4457 CompileRun( 4458 "function MyError(msg) { " 4459 " this.name = 'MyError'; " 4460 " this.message = msg; " 4461 "} " 4462 "MyError.prototype = Object.create(Error.prototype); " 4463 "throw new MyError('my message'); "); 4464 4465 v8::V8::RemoveMessageListeners(check_custom_error_message); 4466 } 4467 4468 4469 static void receive_message(v8::Handle<v8::Message> message, 4470 v8::Handle<v8::Value> data) { 4471 message->Get(); 4472 message_received = true; 4473 } 4474 4475 4476 TEST(APIThrowMessage) { 4477 message_received = false; 4478 v8::HandleScope scope(v8::Isolate::GetCurrent()); 4479 v8::V8::AddMessageListener(receive_message); 4480 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4481 templ->Set(v8_str("ThrowFromC"), 4482 v8::FunctionTemplate::New(ThrowFromC)); 4483 LocalContext context(0, templ); 4484 CompileRun("ThrowFromC();"); 4485 CHECK(message_received); 4486 v8::V8::RemoveMessageListeners(receive_message); 4487 } 4488 4489 4490 TEST(APIThrowMessageAndVerboseTryCatch) { 4491 message_received = false; 4492 v8::HandleScope scope(v8::Isolate::GetCurrent()); 4493 v8::V8::AddMessageListener(receive_message); 4494 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4495 templ->Set(v8_str("ThrowFromC"), 4496 v8::FunctionTemplate::New(ThrowFromC)); 4497 LocalContext context(0, templ); 4498 v8::TryCatch try_catch; 4499 try_catch.SetVerbose(true); 4500 Local<Value> result = CompileRun("ThrowFromC();"); 4501 CHECK(try_catch.HasCaught()); 4502 CHECK(result.IsEmpty()); 4503 CHECK(message_received); 4504 v8::V8::RemoveMessageListeners(receive_message); 4505 } 4506 4507 4508 TEST(APIStackOverflowAndVerboseTryCatch) { 4509 message_received = false; 4510 LocalContext context; 4511 v8::HandleScope scope(context->GetIsolate()); 4512 v8::V8::AddMessageListener(receive_message); 4513 v8::TryCatch try_catch; 4514 try_catch.SetVerbose(true); 4515 Local<Value> result = CompileRun("function foo() { foo(); } foo();"); 4516 CHECK(try_catch.HasCaught()); 4517 CHECK(result.IsEmpty()); 4518 CHECK(message_received); 4519 v8::V8::RemoveMessageListeners(receive_message); 4520 } 4521 4522 4523 THREADED_TEST(ExternalScriptException) { 4524 v8::HandleScope scope(v8::Isolate::GetCurrent()); 4525 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4526 templ->Set(v8_str("ThrowFromC"), 4527 v8::FunctionTemplate::New(ThrowFromC)); 4528 LocalContext context(0, templ); 4529 4530 v8::TryCatch try_catch; 4531 Local<Script> script 4532 = Script::Compile(v8_str("ThrowFromC(); throw 'panama';")); 4533 Local<Value> result = script->Run(); 4534 CHECK(result.IsEmpty()); 4535 CHECK(try_catch.HasCaught()); 4536 String::Utf8Value exception_value(try_catch.Exception()); 4537 CHECK_EQ("konto", *exception_value); 4538 } 4539 4540 4541 4542 void CThrowCountDown(const v8::FunctionCallbackInfo<v8::Value>& args) { 4543 ApiTestFuzzer::Fuzz(); 4544 CHECK_EQ(4, args.Length()); 4545 int count = args[0]->Int32Value(); 4546 int cInterval = args[2]->Int32Value(); 4547 if (count == 0) { 4548 v8::ThrowException(v8_str("FromC")); 4549 return; 4550 } else { 4551 Local<v8::Object> global = Context::GetCurrent()->Global(); 4552 Local<Value> fun = global->Get(v8_str("JSThrowCountDown")); 4553 v8::Handle<Value> argv[] = { v8_num(count - 1), 4554 args[1], 4555 args[2], 4556 args[3] }; 4557 if (count % cInterval == 0) { 4558 v8::TryCatch try_catch; 4559 Local<Value> result = fun.As<Function>()->Call(global, 4, argv); 4560 int expected = args[3]->Int32Value(); 4561 if (try_catch.HasCaught()) { 4562 CHECK_EQ(expected, count); 4563 CHECK(result.IsEmpty()); 4564 CHECK(!i::Isolate::Current()->has_scheduled_exception()); 4565 } else { 4566 CHECK_NE(expected, count); 4567 } 4568 args.GetReturnValue().Set(result); 4569 return; 4570 } else { 4571 args.GetReturnValue().Set(fun.As<Function>()->Call(global, 4, argv)); 4572 return; 4573 } 4574 } 4575 } 4576 4577 4578 void JSCheck(const v8::FunctionCallbackInfo<v8::Value>& args) { 4579 ApiTestFuzzer::Fuzz(); 4580 CHECK_EQ(3, args.Length()); 4581 bool equality = args[0]->BooleanValue(); 4582 int count = args[1]->Int32Value(); 4583 int expected = args[2]->Int32Value(); 4584 if (equality) { 4585 CHECK_EQ(count, expected); 4586 } else { 4587 CHECK_NE(count, expected); 4588 } 4589 } 4590 4591 4592 THREADED_TEST(EvalInTryFinally) { 4593 LocalContext context; 4594 v8::HandleScope scope(context->GetIsolate()); 4595 v8::TryCatch try_catch; 4596 CompileRun("(function() {" 4597 " try {" 4598 " eval('asldkf (*&^&*^');" 4599 " } finally {" 4600 " return;" 4601 " }" 4602 "})()"); 4603 CHECK(!try_catch.HasCaught()); 4604 } 4605 4606 4607 // This test works by making a stack of alternating JavaScript and C 4608 // activations. These activations set up exception handlers with regular 4609 // intervals, one interval for C activations and another for JavaScript 4610 // activations. When enough activations have been created an exception is 4611 // thrown and we check that the right activation catches the exception and that 4612 // no other activations do. The right activation is always the topmost one with 4613 // a handler, regardless of whether it is in JavaScript or C. 4614 // 4615 // The notation used to describe a test case looks like this: 4616 // 4617 // *JS[4] *C[3] @JS[2] C[1] JS[0] 4618 // 4619 // Each entry is an activation, either JS or C. The index is the count at that 4620 // level. Stars identify activations with exception handlers, the @ identifies 4621 // the exception handler that should catch the exception. 4622 // 4623 // BUG(271): Some of the exception propagation does not work on the 4624 // ARM simulator because the simulator separates the C++ stack and the 4625 // JS stack. This test therefore fails on the simulator. The test is 4626 // not threaded to allow the threading tests to run on the simulator. 4627 TEST(ExceptionOrder) { 4628 v8::HandleScope scope(v8::Isolate::GetCurrent()); 4629 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4630 templ->Set(v8_str("check"), v8::FunctionTemplate::New(JSCheck)); 4631 templ->Set(v8_str("CThrowCountDown"), 4632 v8::FunctionTemplate::New(CThrowCountDown)); 4633 LocalContext context(0, templ); 4634 CompileRun( 4635 "function JSThrowCountDown(count, jsInterval, cInterval, expected) {" 4636 " if (count == 0) throw 'FromJS';" 4637 " if (count % jsInterval == 0) {" 4638 " try {" 4639 " var value = CThrowCountDown(count - 1," 4640 " jsInterval," 4641 " cInterval," 4642 " expected);" 4643 " check(false, count, expected);" 4644 " return value;" 4645 " } catch (e) {" 4646 " check(true, count, expected);" 4647 " }" 4648 " } else {" 4649 " return CThrowCountDown(count - 1, jsInterval, cInterval, expected);" 4650 " }" 4651 "}"); 4652 Local<Function> fun = 4653 Local<Function>::Cast(context->Global()->Get(v8_str("JSThrowCountDown"))); 4654 4655 const int argc = 4; 4656 // count jsInterval cInterval expected 4657 4658 // *JS[4] *C[3] @JS[2] C[1] JS[0] 4659 v8::Handle<Value> a0[argc] = { v8_num(4), v8_num(2), v8_num(3), v8_num(2) }; 4660 fun->Call(fun, argc, a0); 4661 4662 // JS[5] *C[4] JS[3] @C[2] JS[1] C[0] 4663 v8::Handle<Value> a1[argc] = { v8_num(5), v8_num(6), v8_num(1), v8_num(2) }; 4664 fun->Call(fun, argc, a1); 4665 4666 // JS[6] @C[5] JS[4] C[3] JS[2] C[1] JS[0] 4667 v8::Handle<Value> a2[argc] = { v8_num(6), v8_num(7), v8_num(5), v8_num(5) }; 4668 fun->Call(fun, argc, a2); 4669 4670 // @JS[6] C[5] JS[4] C[3] JS[2] C[1] JS[0] 4671 v8::Handle<Value> a3[argc] = { v8_num(6), v8_num(6), v8_num(7), v8_num(6) }; 4672 fun->Call(fun, argc, a3); 4673 4674 // JS[6] *C[5] @JS[4] C[3] JS[2] C[1] JS[0] 4675 v8::Handle<Value> a4[argc] = { v8_num(6), v8_num(4), v8_num(5), v8_num(4) }; 4676 fun->Call(fun, argc, a4); 4677 4678 // JS[6] C[5] *JS[4] @C[3] JS[2] C[1] JS[0] 4679 v8::Handle<Value> a5[argc] = { v8_num(6), v8_num(4), v8_num(3), v8_num(3) }; 4680 fun->Call(fun, argc, a5); 4681 } 4682 4683 4684 void ThrowValue(const v8::FunctionCallbackInfo<v8::Value>& args) { 4685 ApiTestFuzzer::Fuzz(); 4686 CHECK_EQ(1, args.Length()); 4687 v8::ThrowException(args[0]); 4688 } 4689 4690 4691 THREADED_TEST(ThrowValues) { 4692 v8::HandleScope scope(v8::Isolate::GetCurrent()); 4693 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4694 templ->Set(v8_str("Throw"), v8::FunctionTemplate::New(ThrowValue)); 4695 LocalContext context(0, templ); 4696 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 4697 "function Run(obj) {" 4698 " try {" 4699 " Throw(obj);" 4700 " } catch (e) {" 4701 " return e;" 4702 " }" 4703 " return 'no exception';" 4704 "}" 4705 "[Run('str'), Run(1), Run(0), Run(null), Run(void 0)];")); 4706 CHECK_EQ(5, result->Length()); 4707 CHECK(result->Get(v8::Integer::New(0))->IsString()); 4708 CHECK(result->Get(v8::Integer::New(1))->IsNumber()); 4709 CHECK_EQ(1, result->Get(v8::Integer::New(1))->Int32Value()); 4710 CHECK(result->Get(v8::Integer::New(2))->IsNumber()); 4711 CHECK_EQ(0, result->Get(v8::Integer::New(2))->Int32Value()); 4712 CHECK(result->Get(v8::Integer::New(3))->IsNull()); 4713 CHECK(result->Get(v8::Integer::New(4))->IsUndefined()); 4714 } 4715 4716 4717 THREADED_TEST(CatchZero) { 4718 LocalContext context; 4719 v8::HandleScope scope(context->GetIsolate()); 4720 v8::TryCatch try_catch; 4721 CHECK(!try_catch.HasCaught()); 4722 Script::Compile(v8_str("throw 10"))->Run(); 4723 CHECK(try_catch.HasCaught()); 4724 CHECK_EQ(10, try_catch.Exception()->Int32Value()); 4725 try_catch.Reset(); 4726 CHECK(!try_catch.HasCaught()); 4727 Script::Compile(v8_str("throw 0"))->Run(); 4728 CHECK(try_catch.HasCaught()); 4729 CHECK_EQ(0, try_catch.Exception()->Int32Value()); 4730 } 4731 4732 4733 THREADED_TEST(CatchExceptionFromWith) { 4734 LocalContext context; 4735 v8::HandleScope scope(context->GetIsolate()); 4736 v8::TryCatch try_catch; 4737 CHECK(!try_catch.HasCaught()); 4738 Script::Compile(v8_str("var o = {}; with (o) { throw 42; }"))->Run(); 4739 CHECK(try_catch.HasCaught()); 4740 } 4741 4742 4743 THREADED_TEST(TryCatchAndFinallyHidingException) { 4744 LocalContext context; 4745 v8::HandleScope scope(context->GetIsolate()); 4746 v8::TryCatch try_catch; 4747 CHECK(!try_catch.HasCaught()); 4748 CompileRun("function f(k) { try { this[k]; } finally { return 0; } };"); 4749 CompileRun("f({toString: function() { throw 42; }});"); 4750 CHECK(!try_catch.HasCaught()); 4751 } 4752 4753 4754 void WithTryCatch(const v8::FunctionCallbackInfo<v8::Value>& args) { 4755 v8::TryCatch try_catch; 4756 } 4757 4758 4759 THREADED_TEST(TryCatchAndFinally) { 4760 LocalContext context; 4761 v8::HandleScope scope(context->GetIsolate()); 4762 context->Global()->Set( 4763 v8_str("native_with_try_catch"), 4764 v8::FunctionTemplate::New(WithTryCatch)->GetFunction()); 4765 v8::TryCatch try_catch; 4766 CHECK(!try_catch.HasCaught()); 4767 CompileRun( 4768 "try {\n" 4769 " throw new Error('a');\n" 4770 "} finally {\n" 4771 " native_with_try_catch();\n" 4772 "}\n"); 4773 CHECK(try_catch.HasCaught()); 4774 } 4775 4776 4777 static void TryCatchNestedHelper(int depth) { 4778 if (depth > 0) { 4779 v8::TryCatch try_catch; 4780 try_catch.SetVerbose(true); 4781 TryCatchNestedHelper(depth - 1); 4782 CHECK(try_catch.HasCaught()); 4783 try_catch.ReThrow(); 4784 } else { 4785 v8::ThrowException(v8_str("back")); 4786 } 4787 } 4788 4789 4790 TEST(TryCatchNested) { 4791 v8::V8::Initialize(); 4792 LocalContext context; 4793 v8::HandleScope scope(context->GetIsolate()); 4794 v8::TryCatch try_catch; 4795 TryCatchNestedHelper(5); 4796 CHECK(try_catch.HasCaught()); 4797 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(try_catch.Exception()), "back")); 4798 } 4799 4800 4801 void TryCatchMixedNestingCheck(v8::TryCatch* try_catch) { 4802 CHECK(try_catch->HasCaught()); 4803 Handle<Message> message = try_catch->Message(); 4804 Handle<Value> resource = message->GetScriptResourceName(); 4805 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(resource), "inner")); 4806 CHECK_EQ(0, strcmp(*v8::String::Utf8Value(message->Get()), 4807 "Uncaught Error: a")); 4808 CHECK_EQ(1, message->GetLineNumber()); 4809 CHECK_EQ(6, message->GetStartColumn()); 4810 } 4811 4812 4813 void TryCatchMixedNestingHelper( 4814 const v8::FunctionCallbackInfo<v8::Value>& args) { 4815 ApiTestFuzzer::Fuzz(); 4816 v8::TryCatch try_catch; 4817 CompileRunWithOrigin("throw new Error('a');\n", "inner", 0, 0); 4818 CHECK(try_catch.HasCaught()); 4819 TryCatchMixedNestingCheck(&try_catch); 4820 try_catch.ReThrow(); 4821 } 4822 4823 4824 // This test ensures that an outer TryCatch in the following situation: 4825 // C++/TryCatch -> JS -> C++/TryCatch -> JS w/ SyntaxError 4826 // does not clobber the Message object generated for the inner TryCatch. 4827 // This exercises the ability of TryCatch.ReThrow() to restore the 4828 // inner pending Message before throwing the exception again. 4829 TEST(TryCatchMixedNesting) { 4830 v8::HandleScope scope(v8::Isolate::GetCurrent()); 4831 v8::V8::Initialize(); 4832 v8::TryCatch try_catch; 4833 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4834 templ->Set(v8_str("TryCatchMixedNestingHelper"), 4835 v8::FunctionTemplate::New(TryCatchMixedNestingHelper)); 4836 LocalContext context(0, templ); 4837 CompileRunWithOrigin("TryCatchMixedNestingHelper();\n", "outer", 1, 1); 4838 TryCatchMixedNestingCheck(&try_catch); 4839 } 4840 4841 4842 THREADED_TEST(Equality) { 4843 LocalContext context; 4844 v8::Isolate* isolate = context->GetIsolate(); 4845 v8::HandleScope scope(context->GetIsolate()); 4846 // Check that equality works at all before relying on CHECK_EQ 4847 CHECK(v8_str("a")->Equals(v8_str("a"))); 4848 CHECK(!v8_str("a")->Equals(v8_str("b"))); 4849 4850 CHECK_EQ(v8_str("a"), v8_str("a")); 4851 CHECK_NE(v8_str("a"), v8_str("b")); 4852 CHECK_EQ(v8_num(1), v8_num(1)); 4853 CHECK_EQ(v8_num(1.00), v8_num(1)); 4854 CHECK_NE(v8_num(1), v8_num(2)); 4855 4856 // Assume String is not internalized. 4857 CHECK(v8_str("a")->StrictEquals(v8_str("a"))); 4858 CHECK(!v8_str("a")->StrictEquals(v8_str("b"))); 4859 CHECK(!v8_str("5")->StrictEquals(v8_num(5))); 4860 CHECK(v8_num(1)->StrictEquals(v8_num(1))); 4861 CHECK(!v8_num(1)->StrictEquals(v8_num(2))); 4862 CHECK(v8_num(0)->StrictEquals(v8_num(-0))); 4863 Local<Value> not_a_number = v8_num(i::OS::nan_value()); 4864 CHECK(!not_a_number->StrictEquals(not_a_number)); 4865 CHECK(v8::False()->StrictEquals(v8::False())); 4866 CHECK(!v8::False()->StrictEquals(v8::Undefined())); 4867 4868 v8::Handle<v8::Object> obj = v8::Object::New(); 4869 v8::Persistent<v8::Object> alias(isolate, obj); 4870 CHECK(v8::Local<v8::Object>::New(isolate, alias)->StrictEquals(obj)); 4871 alias.Dispose(isolate); 4872 } 4873 4874 4875 THREADED_TEST(MultiRun) { 4876 LocalContext context; 4877 v8::HandleScope scope(context->GetIsolate()); 4878 Local<Script> script = Script::Compile(v8_str("x")); 4879 for (int i = 0; i < 10; i++) 4880 script->Run(); 4881 } 4882 4883 4884 static void GetXValue(Local<String> name, 4885 const v8::PropertyCallbackInfo<v8::Value>& info) { 4886 ApiTestFuzzer::Fuzz(); 4887 CHECK_EQ(info.Data(), v8_str("donut")); 4888 CHECK_EQ(name, v8_str("x")); 4889 info.GetReturnValue().Set(name); 4890 } 4891 4892 4893 THREADED_TEST(SimplePropertyRead) { 4894 LocalContext context; 4895 v8::HandleScope scope(context->GetIsolate()); 4896 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4897 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 4898 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 4899 Local<Script> script = Script::Compile(v8_str("obj.x")); 4900 for (int i = 0; i < 10; i++) { 4901 Local<Value> result = script->Run(); 4902 CHECK_EQ(result, v8_str("x")); 4903 } 4904 } 4905 4906 4907 THREADED_TEST(DefinePropertyOnAPIAccessor) { 4908 LocalContext context; 4909 v8::HandleScope scope(context->GetIsolate()); 4910 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4911 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 4912 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 4913 4914 // Uses getOwnPropertyDescriptor to check the configurable status 4915 Local<Script> script_desc 4916 = Script::Compile(v8_str("var prop = Object.getOwnPropertyDescriptor( " 4917 "obj, 'x');" 4918 "prop.configurable;")); 4919 Local<Value> result = script_desc->Run(); 4920 CHECK_EQ(result->BooleanValue(), true); 4921 4922 // Redefine get - but still configurable 4923 Local<Script> script_define 4924 = Script::Compile(v8_str("var desc = { get: function(){return 42; }," 4925 " configurable: true };" 4926 "Object.defineProperty(obj, 'x', desc);" 4927 "obj.x")); 4928 result = script_define->Run(); 4929 CHECK_EQ(result, v8_num(42)); 4930 4931 // Check that the accessor is still configurable 4932 result = script_desc->Run(); 4933 CHECK_EQ(result->BooleanValue(), true); 4934 4935 // Redefine to a non-configurable 4936 script_define 4937 = Script::Compile(v8_str("var desc = { get: function(){return 43; }," 4938 " configurable: false };" 4939 "Object.defineProperty(obj, 'x', desc);" 4940 "obj.x")); 4941 result = script_define->Run(); 4942 CHECK_EQ(result, v8_num(43)); 4943 result = script_desc->Run(); 4944 CHECK_EQ(result->BooleanValue(), false); 4945 4946 // Make sure that it is not possible to redefine again 4947 v8::TryCatch try_catch; 4948 result = script_define->Run(); 4949 CHECK(try_catch.HasCaught()); 4950 String::Utf8Value exception_value(try_catch.Exception()); 4951 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 4952 } 4953 4954 4955 THREADED_TEST(DefinePropertyOnDefineGetterSetter) { 4956 v8::HandleScope scope(v8::Isolate::GetCurrent()); 4957 Local<ObjectTemplate> templ = ObjectTemplate::New(); 4958 templ->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut")); 4959 LocalContext context; 4960 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 4961 4962 Local<Script> script_desc = Script::Compile(v8_str("var prop =" 4963 "Object.getOwnPropertyDescriptor( " 4964 "obj, 'x');" 4965 "prop.configurable;")); 4966 Local<Value> result = script_desc->Run(); 4967 CHECK_EQ(result->BooleanValue(), true); 4968 4969 Local<Script> script_define = 4970 Script::Compile(v8_str("var desc = {get: function(){return 42; }," 4971 " configurable: true };" 4972 "Object.defineProperty(obj, 'x', desc);" 4973 "obj.x")); 4974 result = script_define->Run(); 4975 CHECK_EQ(result, v8_num(42)); 4976 4977 4978 result = script_desc->Run(); 4979 CHECK_EQ(result->BooleanValue(), true); 4980 4981 4982 script_define = 4983 Script::Compile(v8_str("var desc = {get: function(){return 43; }," 4984 " configurable: false };" 4985 "Object.defineProperty(obj, 'x', desc);" 4986 "obj.x")); 4987 result = script_define->Run(); 4988 CHECK_EQ(result, v8_num(43)); 4989 result = script_desc->Run(); 4990 4991 CHECK_EQ(result->BooleanValue(), false); 4992 4993 v8::TryCatch try_catch; 4994 result = script_define->Run(); 4995 CHECK(try_catch.HasCaught()); 4996 String::Utf8Value exception_value(try_catch.Exception()); 4997 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 4998 } 4999 5000 5001 static v8::Handle<v8::Object> GetGlobalProperty(LocalContext* context, 5002 char const* name) { 5003 return v8::Handle<v8::Object>::Cast((*context)->Global()->Get(v8_str(name))); 5004 } 5005 5006 5007 THREADED_TEST(DefineAPIAccessorOnObject) { 5008 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5009 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5010 LocalContext context; 5011 5012 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 5013 CompileRun("var obj2 = {};"); 5014 5015 CHECK(CompileRun("obj1.x")->IsUndefined()); 5016 CHECK(CompileRun("obj2.x")->IsUndefined()); 5017 5018 CHECK(GetGlobalProperty(&context, "obj1")-> 5019 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5020 5021 ExpectString("obj1.x", "x"); 5022 CHECK(CompileRun("obj2.x")->IsUndefined()); 5023 5024 CHECK(GetGlobalProperty(&context, "obj2")-> 5025 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5026 5027 ExpectString("obj1.x", "x"); 5028 ExpectString("obj2.x", "x"); 5029 5030 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5031 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5032 5033 CompileRun("Object.defineProperty(obj1, 'x'," 5034 "{ get: function() { return 'y'; }, configurable: true })"); 5035 5036 ExpectString("obj1.x", "y"); 5037 ExpectString("obj2.x", "x"); 5038 5039 CompileRun("Object.defineProperty(obj2, 'x'," 5040 "{ get: function() { return 'y'; }, configurable: true })"); 5041 5042 ExpectString("obj1.x", "y"); 5043 ExpectString("obj2.x", "y"); 5044 5045 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5046 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5047 5048 CHECK(GetGlobalProperty(&context, "obj1")-> 5049 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5050 CHECK(GetGlobalProperty(&context, "obj2")-> 5051 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5052 5053 ExpectString("obj1.x", "x"); 5054 ExpectString("obj2.x", "x"); 5055 5056 ExpectTrue("Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5057 ExpectTrue("Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5058 5059 // Define getters/setters, but now make them not configurable. 5060 CompileRun("Object.defineProperty(obj1, 'x'," 5061 "{ get: function() { return 'z'; }, configurable: false })"); 5062 CompileRun("Object.defineProperty(obj2, 'x'," 5063 "{ get: function() { return 'z'; }, configurable: false })"); 5064 5065 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5066 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5067 5068 ExpectString("obj1.x", "z"); 5069 ExpectString("obj2.x", "z"); 5070 5071 CHECK(!GetGlobalProperty(&context, "obj1")-> 5072 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5073 CHECK(!GetGlobalProperty(&context, "obj2")-> 5074 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5075 5076 ExpectString("obj1.x", "z"); 5077 ExpectString("obj2.x", "z"); 5078 } 5079 5080 5081 THREADED_TEST(DontDeleteAPIAccessorsCannotBeOverriden) { 5082 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5083 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5084 LocalContext context; 5085 5086 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 5087 CompileRun("var obj2 = {};"); 5088 5089 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor( 5090 v8_str("x"), 5091 GetXValue, NULL, 5092 v8_str("donut"), v8::DEFAULT, v8::DontDelete)); 5093 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor( 5094 v8_str("x"), 5095 GetXValue, NULL, 5096 v8_str("donut"), v8::DEFAULT, v8::DontDelete)); 5097 5098 ExpectString("obj1.x", "x"); 5099 ExpectString("obj2.x", "x"); 5100 5101 ExpectTrue("!Object.getOwnPropertyDescriptor(obj1, 'x').configurable"); 5102 ExpectTrue("!Object.getOwnPropertyDescriptor(obj2, 'x').configurable"); 5103 5104 CHECK(!GetGlobalProperty(&context, "obj1")-> 5105 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5106 CHECK(!GetGlobalProperty(&context, "obj2")-> 5107 SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("donut"))); 5108 5109 { 5110 v8::TryCatch try_catch; 5111 CompileRun("Object.defineProperty(obj1, 'x'," 5112 "{get: function() { return 'func'; }})"); 5113 CHECK(try_catch.HasCaught()); 5114 String::Utf8Value exception_value(try_catch.Exception()); 5115 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5116 } 5117 { 5118 v8::TryCatch try_catch; 5119 CompileRun("Object.defineProperty(obj2, 'x'," 5120 "{get: function() { return 'func'; }})"); 5121 CHECK(try_catch.HasCaught()); 5122 String::Utf8Value exception_value(try_catch.Exception()); 5123 CHECK_EQ(*exception_value, "TypeError: Cannot redefine property: x"); 5124 } 5125 } 5126 5127 5128 static void Get239Value(Local<String> name, 5129 const v8::PropertyCallbackInfo<v8::Value>& info) { 5130 ApiTestFuzzer::Fuzz(); 5131 CHECK_EQ(info.Data(), v8_str("donut")); 5132 CHECK_EQ(name, v8_str("239")); 5133 info.GetReturnValue().Set(name); 5134 } 5135 5136 5137 THREADED_TEST(ElementAPIAccessor) { 5138 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5139 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5140 LocalContext context; 5141 5142 context->Global()->Set(v8_str("obj1"), templ->NewInstance()); 5143 CompileRun("var obj2 = {};"); 5144 5145 CHECK(GetGlobalProperty(&context, "obj1")->SetAccessor( 5146 v8_str("239"), 5147 Get239Value, NULL, 5148 v8_str("donut"))); 5149 CHECK(GetGlobalProperty(&context, "obj2")->SetAccessor( 5150 v8_str("239"), 5151 Get239Value, NULL, 5152 v8_str("donut"))); 5153 5154 ExpectString("obj1[239]", "239"); 5155 ExpectString("obj2[239]", "239"); 5156 ExpectString("obj1['239']", "239"); 5157 ExpectString("obj2['239']", "239"); 5158 } 5159 5160 5161 v8::Persistent<Value> xValue; 5162 5163 5164 static void SetXValue(Local<String> name, 5165 Local<Value> value, 5166 const v8::PropertyCallbackInfo<void>& info) { 5167 CHECK_EQ(value, v8_num(4)); 5168 CHECK_EQ(info.Data(), v8_str("donut")); 5169 CHECK_EQ(name, v8_str("x")); 5170 CHECK(xValue.IsEmpty()); 5171 xValue.Reset(info.GetIsolate(), value); 5172 } 5173 5174 5175 THREADED_TEST(SimplePropertyWrite) { 5176 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5177 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5178 templ->SetAccessor(v8_str("x"), GetXValue, SetXValue, v8_str("donut")); 5179 LocalContext context; 5180 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5181 Local<Script> script = Script::Compile(v8_str("obj.x = 4")); 5182 for (int i = 0; i < 10; i++) { 5183 CHECK(xValue.IsEmpty()); 5184 script->Run(); 5185 CHECK_EQ(v8_num(4), Local<Value>::New(v8::Isolate::GetCurrent(), xValue)); 5186 xValue.Dispose(context->GetIsolate()); 5187 xValue.Clear(); 5188 } 5189 } 5190 5191 5192 THREADED_TEST(SetterOnly) { 5193 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5194 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5195 templ->SetAccessor(v8_str("x"), NULL, SetXValue, v8_str("donut")); 5196 LocalContext context; 5197 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5198 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x")); 5199 for (int i = 0; i < 10; i++) { 5200 CHECK(xValue.IsEmpty()); 5201 script->Run(); 5202 CHECK_EQ(v8_num(4), Local<Value>::New(v8::Isolate::GetCurrent(), xValue)); 5203 xValue.Dispose(context->GetIsolate()); 5204 xValue.Clear(); 5205 } 5206 } 5207 5208 5209 THREADED_TEST(NoAccessors) { 5210 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5211 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5212 templ->SetAccessor(v8_str("x"), 5213 static_cast<v8::AccessorGetterCallback>(NULL), 5214 NULL, 5215 v8_str("donut")); 5216 LocalContext context; 5217 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5218 Local<Script> script = Script::Compile(v8_str("obj.x = 4; obj.x")); 5219 for (int i = 0; i < 10; i++) { 5220 script->Run(); 5221 } 5222 } 5223 5224 5225 static void XPropertyGetter(Local<String> property, 5226 const v8::PropertyCallbackInfo<v8::Value>& info) { 5227 ApiTestFuzzer::Fuzz(); 5228 CHECK(info.Data()->IsUndefined()); 5229 info.GetReturnValue().Set(property); 5230 } 5231 5232 5233 THREADED_TEST(NamedInterceptorPropertyRead) { 5234 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5235 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5236 templ->SetNamedPropertyHandler(XPropertyGetter); 5237 LocalContext context; 5238 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5239 Local<Script> script = Script::Compile(v8_str("obj.x")); 5240 for (int i = 0; i < 10; i++) { 5241 Local<Value> result = script->Run(); 5242 CHECK_EQ(result, v8_str("x")); 5243 } 5244 } 5245 5246 5247 THREADED_TEST(NamedInterceptorDictionaryIC) { 5248 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5249 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5250 templ->SetNamedPropertyHandler(XPropertyGetter); 5251 LocalContext context; 5252 // Create an object with a named interceptor. 5253 context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance()); 5254 Local<Script> script = Script::Compile(v8_str("interceptor_obj.x")); 5255 for (int i = 0; i < 10; i++) { 5256 Local<Value> result = script->Run(); 5257 CHECK_EQ(result, v8_str("x")); 5258 } 5259 // Create a slow case object and a function accessing a property in 5260 // that slow case object (with dictionary probing in generated 5261 // code). Then force object with a named interceptor into slow-case, 5262 // pass it to the function, and check that the interceptor is called 5263 // instead of accessing the local property. 5264 Local<Value> result = 5265 CompileRun("function get_x(o) { return o.x; };" 5266 "var obj = { x : 42, y : 0 };" 5267 "delete obj.y;" 5268 "for (var i = 0; i < 10; i++) get_x(obj);" 5269 "interceptor_obj.x = 42;" 5270 "interceptor_obj.y = 10;" 5271 "delete interceptor_obj.y;" 5272 "get_x(interceptor_obj)"); 5273 CHECK_EQ(result, v8_str("x")); 5274 } 5275 5276 5277 THREADED_TEST(NamedInterceptorDictionaryICMultipleContext) { 5278 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 5279 v8::HandleScope scope(isolate); 5280 v8::Local<Context> context1 = Context::New(isolate); 5281 5282 context1->Enter(); 5283 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5284 templ->SetNamedPropertyHandler(XPropertyGetter); 5285 // Create an object with a named interceptor. 5286 v8::Local<v8::Object> object = templ->NewInstance(); 5287 context1->Global()->Set(v8_str("interceptor_obj"), object); 5288 5289 // Force the object into the slow case. 5290 CompileRun("interceptor_obj.y = 0;" 5291 "delete interceptor_obj.y;"); 5292 context1->Exit(); 5293 5294 { 5295 // Introduce the object into a different context. 5296 // Repeat named loads to exercise ICs. 5297 LocalContext context2; 5298 context2->Global()->Set(v8_str("interceptor_obj"), object); 5299 Local<Value> result = 5300 CompileRun("function get_x(o) { return o.x; }" 5301 "interceptor_obj.x = 42;" 5302 "for (var i=0; i != 10; i++) {" 5303 " get_x(interceptor_obj);" 5304 "}" 5305 "get_x(interceptor_obj)"); 5306 // Check that the interceptor was actually invoked. 5307 CHECK_EQ(result, v8_str("x")); 5308 } 5309 5310 // Return to the original context and force some object to the slow case 5311 // to cause the NormalizedMapCache to verify. 5312 context1->Enter(); 5313 CompileRun("var obj = { x : 0 }; delete obj.x;"); 5314 context1->Exit(); 5315 } 5316 5317 5318 static void SetXOnPrototypeGetter( 5319 Local<String> property, 5320 const v8::PropertyCallbackInfo<v8::Value>& info) { 5321 // Set x on the prototype object and do not handle the get request. 5322 v8::Handle<v8::Value> proto = info.Holder()->GetPrototype(); 5323 proto.As<v8::Object>()->Set(v8_str("x"), v8::Integer::New(23)); 5324 } 5325 5326 5327 // This is a regression test for http://crbug.com/20104. Map 5328 // transitions should not interfere with post interceptor lookup. 5329 THREADED_TEST(NamedInterceptorMapTransitionRead) { 5330 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5331 Local<v8::FunctionTemplate> function_template = v8::FunctionTemplate::New(); 5332 Local<v8::ObjectTemplate> instance_template 5333 = function_template->InstanceTemplate(); 5334 instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter); 5335 LocalContext context; 5336 context->Global()->Set(v8_str("F"), function_template->GetFunction()); 5337 // Create an instance of F and introduce a map transition for x. 5338 CompileRun("var o = new F(); o.x = 23;"); 5339 // Create an instance of F and invoke the getter. The result should be 23. 5340 Local<Value> result = CompileRun("o = new F(); o.x"); 5341 CHECK_EQ(result->Int32Value(), 23); 5342 } 5343 5344 5345 static void IndexedPropertyGetter( 5346 uint32_t index, 5347 const v8::PropertyCallbackInfo<v8::Value>& info) { 5348 ApiTestFuzzer::Fuzz(); 5349 if (index == 37) { 5350 info.GetReturnValue().Set(v8_num(625)); 5351 } 5352 } 5353 5354 5355 static void IndexedPropertySetter( 5356 uint32_t index, 5357 Local<Value> value, 5358 const v8::PropertyCallbackInfo<v8::Value>& info) { 5359 ApiTestFuzzer::Fuzz(); 5360 if (index == 39) { 5361 info.GetReturnValue().Set(value); 5362 } 5363 } 5364 5365 5366 THREADED_TEST(IndexedInterceptorWithIndexedAccessor) { 5367 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5368 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5369 templ->SetIndexedPropertyHandler(IndexedPropertyGetter, 5370 IndexedPropertySetter); 5371 LocalContext context; 5372 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5373 Local<Script> getter_script = Script::Compile(v8_str( 5374 "obj.__defineGetter__(\"3\", function(){return 5;});obj[3];")); 5375 Local<Script> setter_script = Script::Compile(v8_str( 5376 "obj.__defineSetter__(\"17\", function(val){this.foo = val;});" 5377 "obj[17] = 23;" 5378 "obj.foo;")); 5379 Local<Script> interceptor_setter_script = Script::Compile(v8_str( 5380 "obj.__defineSetter__(\"39\", function(val){this.foo = \"hit\";});" 5381 "obj[39] = 47;" 5382 "obj.foo;")); // This setter should not run, due to the interceptor. 5383 Local<Script> interceptor_getter_script = Script::Compile(v8_str( 5384 "obj[37];")); 5385 Local<Value> result = getter_script->Run(); 5386 CHECK_EQ(v8_num(5), result); 5387 result = setter_script->Run(); 5388 CHECK_EQ(v8_num(23), result); 5389 result = interceptor_setter_script->Run(); 5390 CHECK_EQ(v8_num(23), result); 5391 result = interceptor_getter_script->Run(); 5392 CHECK_EQ(v8_num(625), result); 5393 } 5394 5395 5396 static void UnboxedDoubleIndexedPropertyGetter( 5397 uint32_t index, 5398 const v8::PropertyCallbackInfo<v8::Value>& info) { 5399 ApiTestFuzzer::Fuzz(); 5400 if (index < 25) { 5401 info.GetReturnValue().Set(v8_num(index)); 5402 } 5403 } 5404 5405 5406 static void UnboxedDoubleIndexedPropertySetter( 5407 uint32_t index, 5408 Local<Value> value, 5409 const v8::PropertyCallbackInfo<v8::Value>& info) { 5410 ApiTestFuzzer::Fuzz(); 5411 if (index < 25) { 5412 info.GetReturnValue().Set(v8_num(index)); 5413 } 5414 } 5415 5416 5417 void UnboxedDoubleIndexedPropertyEnumerator( 5418 const v8::PropertyCallbackInfo<v8::Array>& info) { 5419 // Force the list of returned keys to be stored in a FastDoubleArray. 5420 Local<Script> indexed_property_names_script = Script::Compile(v8_str( 5421 "keys = new Array(); keys[125000] = 1;" 5422 "for(i = 0; i < 80000; i++) { keys[i] = i; };" 5423 "keys.length = 25; keys;")); 5424 Local<Value> result = indexed_property_names_script->Run(); 5425 info.GetReturnValue().Set(Local<v8::Array>::Cast(result)); 5426 } 5427 5428 5429 // Make sure that the the interceptor code in the runtime properly handles 5430 // merging property name lists for double-array-backed arrays. 5431 THREADED_TEST(IndexedInterceptorUnboxedDoubleWithIndexedAccessor) { 5432 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5433 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5434 templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter, 5435 UnboxedDoubleIndexedPropertySetter, 5436 0, 5437 0, 5438 UnboxedDoubleIndexedPropertyEnumerator); 5439 LocalContext context; 5440 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5441 // When obj is created, force it to be Stored in a FastDoubleArray. 5442 Local<Script> create_unboxed_double_script = Script::Compile(v8_str( 5443 "obj[125000] = 1; for(i = 0; i < 80000; i+=2) { obj[i] = i; } " 5444 "key_count = 0; " 5445 "for (x in obj) {key_count++;};" 5446 "obj;")); 5447 Local<Value> result = create_unboxed_double_script->Run(); 5448 CHECK(result->ToObject()->HasRealIndexedProperty(2000)); 5449 Local<Script> key_count_check = Script::Compile(v8_str( 5450 "key_count;")); 5451 result = key_count_check->Run(); 5452 CHECK_EQ(v8_num(40013), result); 5453 } 5454 5455 5456 void NonStrictArgsIndexedPropertyEnumerator( 5457 const v8::PropertyCallbackInfo<v8::Array>& info) { 5458 // Force the list of returned keys to be stored in a Arguments object. 5459 Local<Script> indexed_property_names_script = Script::Compile(v8_str( 5460 "function f(w,x) {" 5461 " return arguments;" 5462 "}" 5463 "keys = f(0, 1, 2, 3);" 5464 "keys;")); 5465 Local<Object> result = 5466 Local<Object>::Cast(indexed_property_names_script->Run()); 5467 // Have to populate the handle manually, as it's not Cast-able. 5468 i::Handle<i::JSObject> o = 5469 v8::Utils::OpenHandle<Object, i::JSObject>(result); 5470 i::Handle<i::JSArray> array(reinterpret_cast<i::JSArray*>(*o)); 5471 info.GetReturnValue().Set(v8::Utils::ToLocal(array)); 5472 } 5473 5474 5475 static void NonStrictIndexedPropertyGetter( 5476 uint32_t index, 5477 const v8::PropertyCallbackInfo<v8::Value>& info) { 5478 ApiTestFuzzer::Fuzz(); 5479 if (index < 4) { 5480 info.GetReturnValue().Set(v8_num(index)); 5481 } 5482 } 5483 5484 5485 // Make sure that the the interceptor code in the runtime properly handles 5486 // merging property name lists for non-string arguments arrays. 5487 THREADED_TEST(IndexedInterceptorNonStrictArgsWithIndexedAccessor) { 5488 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5489 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5490 templ->SetIndexedPropertyHandler(NonStrictIndexedPropertyGetter, 5491 0, 5492 0, 5493 0, 5494 NonStrictArgsIndexedPropertyEnumerator); 5495 LocalContext context; 5496 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5497 Local<Script> create_args_script = 5498 Script::Compile(v8_str( 5499 "var key_count = 0;" 5500 "for (x in obj) {key_count++;} key_count;")); 5501 Local<Value> result = create_args_script->Run(); 5502 CHECK_EQ(v8_num(4), result); 5503 } 5504 5505 5506 static void IdentityIndexedPropertyGetter( 5507 uint32_t index, 5508 const v8::PropertyCallbackInfo<v8::Value>& info) { 5509 info.GetReturnValue().Set(index); 5510 } 5511 5512 5513 THREADED_TEST(IndexedInterceptorWithGetOwnPropertyDescriptor) { 5514 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5515 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5516 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5517 5518 LocalContext context; 5519 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5520 5521 // Check fast object case. 5522 const char* fast_case_code = 5523 "Object.getOwnPropertyDescriptor(obj, 0).value.toString()"; 5524 ExpectString(fast_case_code, "0"); 5525 5526 // Check slow case. 5527 const char* slow_case_code = 5528 "obj.x = 1; delete obj.x;" 5529 "Object.getOwnPropertyDescriptor(obj, 1).value.toString()"; 5530 ExpectString(slow_case_code, "1"); 5531 } 5532 5533 5534 THREADED_TEST(IndexedInterceptorWithNoSetter) { 5535 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5536 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5537 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5538 5539 LocalContext context; 5540 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 5541 5542 const char* code = 5543 "try {" 5544 " obj[0] = 239;" 5545 " for (var i = 0; i < 100; i++) {" 5546 " var v = obj[0];" 5547 " if (v != 0) throw 'Wrong value ' + v + ' at iteration ' + i;" 5548 " }" 5549 " 'PASSED'" 5550 "} catch(e) {" 5551 " e" 5552 "}"; 5553 ExpectString(code, "PASSED"); 5554 } 5555 5556 5557 THREADED_TEST(IndexedInterceptorWithAccessorCheck) { 5558 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5559 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5560 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5561 5562 LocalContext context; 5563 Local<v8::Object> obj = templ->NewInstance(); 5564 obj->TurnOnAccessCheck(); 5565 context->Global()->Set(v8_str("obj"), obj); 5566 5567 const char* code = 5568 "try {" 5569 " for (var i = 0; i < 100; i++) {" 5570 " var v = obj[0];" 5571 " if (v != undefined) throw 'Wrong value ' + v + ' at iteration ' + i;" 5572 " }" 5573 " 'PASSED'" 5574 "} catch(e) {" 5575 " e" 5576 "}"; 5577 ExpectString(code, "PASSED"); 5578 } 5579 5580 5581 THREADED_TEST(IndexedInterceptorWithAccessorCheckSwitchedOn) { 5582 i::FLAG_allow_natives_syntax = true; 5583 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5584 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5585 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5586 5587 LocalContext context; 5588 Local<v8::Object> obj = templ->NewInstance(); 5589 context->Global()->Set(v8_str("obj"), obj); 5590 5591 const char* code = 5592 "try {" 5593 " for (var i = 0; i < 100; i++) {" 5594 " var expected = i;" 5595 " if (i == 5) {" 5596 " %EnableAccessChecks(obj);" 5597 " expected = undefined;" 5598 " }" 5599 " var v = obj[i];" 5600 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 5601 " if (i == 5) %DisableAccessChecks(obj);" 5602 " }" 5603 " 'PASSED'" 5604 "} catch(e) {" 5605 " e" 5606 "}"; 5607 ExpectString(code, "PASSED"); 5608 } 5609 5610 5611 THREADED_TEST(IndexedInterceptorWithDifferentIndices) { 5612 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5613 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5614 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5615 5616 LocalContext context; 5617 Local<v8::Object> obj = templ->NewInstance(); 5618 context->Global()->Set(v8_str("obj"), obj); 5619 5620 const char* code = 5621 "try {" 5622 " for (var i = 0; i < 100; i++) {" 5623 " var v = obj[i];" 5624 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;" 5625 " }" 5626 " 'PASSED'" 5627 "} catch(e) {" 5628 " e" 5629 "}"; 5630 ExpectString(code, "PASSED"); 5631 } 5632 5633 5634 THREADED_TEST(IndexedInterceptorWithNegativeIndices) { 5635 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5636 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5637 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5638 5639 LocalContext context; 5640 Local<v8::Object> obj = templ->NewInstance(); 5641 context->Global()->Set(v8_str("obj"), obj); 5642 5643 const char* code = 5644 "try {" 5645 " for (var i = 0; i < 100; i++) {" 5646 " var expected = i;" 5647 " var key = i;" 5648 " if (i == 25) {" 5649 " key = -1;" 5650 " expected = undefined;" 5651 " }" 5652 " if (i == 50) {" 5653 " /* probe minimal Smi number on 32-bit platforms */" 5654 " key = -(1 << 30);" 5655 " expected = undefined;" 5656 " }" 5657 " if (i == 75) {" 5658 " /* probe minimal Smi number on 64-bit platforms */" 5659 " key = 1 << 31;" 5660 " expected = undefined;" 5661 " }" 5662 " var v = obj[key];" 5663 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 5664 " }" 5665 " 'PASSED'" 5666 "} catch(e) {" 5667 " e" 5668 "}"; 5669 ExpectString(code, "PASSED"); 5670 } 5671 5672 5673 THREADED_TEST(IndexedInterceptorWithNotSmiLookup) { 5674 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5675 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5676 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5677 5678 LocalContext context; 5679 Local<v8::Object> obj = templ->NewInstance(); 5680 context->Global()->Set(v8_str("obj"), obj); 5681 5682 const char* code = 5683 "try {" 5684 " for (var i = 0; i < 100; i++) {" 5685 " var expected = i;" 5686 " var key = i;" 5687 " if (i == 50) {" 5688 " key = 'foobar';" 5689 " expected = undefined;" 5690 " }" 5691 " var v = obj[key];" 5692 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 5693 " }" 5694 " 'PASSED'" 5695 "} catch(e) {" 5696 " e" 5697 "}"; 5698 ExpectString(code, "PASSED"); 5699 } 5700 5701 5702 THREADED_TEST(IndexedInterceptorGoingMegamorphic) { 5703 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5704 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5705 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5706 5707 LocalContext context; 5708 Local<v8::Object> obj = templ->NewInstance(); 5709 context->Global()->Set(v8_str("obj"), obj); 5710 5711 const char* code = 5712 "var original = obj;" 5713 "try {" 5714 " for (var i = 0; i < 100; i++) {" 5715 " var expected = i;" 5716 " if (i == 50) {" 5717 " obj = {50: 'foobar'};" 5718 " expected = 'foobar';" 5719 " }" 5720 " var v = obj[i];" 5721 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 5722 " if (i == 50) obj = original;" 5723 " }" 5724 " 'PASSED'" 5725 "} catch(e) {" 5726 " e" 5727 "}"; 5728 ExpectString(code, "PASSED"); 5729 } 5730 5731 5732 THREADED_TEST(IndexedInterceptorReceiverTurningSmi) { 5733 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5734 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5735 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5736 5737 LocalContext context; 5738 Local<v8::Object> obj = templ->NewInstance(); 5739 context->Global()->Set(v8_str("obj"), obj); 5740 5741 const char* code = 5742 "var original = obj;" 5743 "try {" 5744 " for (var i = 0; i < 100; i++) {" 5745 " var expected = i;" 5746 " if (i == 5) {" 5747 " obj = 239;" 5748 " expected = undefined;" 5749 " }" 5750 " var v = obj[i];" 5751 " if (v != expected) throw 'Wrong value ' + v + ' at iteration ' + i;" 5752 " if (i == 5) obj = original;" 5753 " }" 5754 " 'PASSED'" 5755 "} catch(e) {" 5756 " e" 5757 "}"; 5758 ExpectString(code, "PASSED"); 5759 } 5760 5761 5762 THREADED_TEST(IndexedInterceptorOnProto) { 5763 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5764 Local<ObjectTemplate> templ = ObjectTemplate::New(); 5765 templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter); 5766 5767 LocalContext context; 5768 Local<v8::Object> obj = templ->NewInstance(); 5769 context->Global()->Set(v8_str("obj"), obj); 5770 5771 const char* code = 5772 "var o = {__proto__: obj};" 5773 "try {" 5774 " for (var i = 0; i < 100; i++) {" 5775 " var v = o[i];" 5776 " if (v != i) throw 'Wrong value ' + v + ' at iteration ' + i;" 5777 " }" 5778 " 'PASSED'" 5779 "} catch(e) {" 5780 " e" 5781 "}"; 5782 ExpectString(code, "PASSED"); 5783 } 5784 5785 5786 THREADED_TEST(MultiContexts) { 5787 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5788 v8::Handle<ObjectTemplate> templ = ObjectTemplate::New(); 5789 templ->Set(v8_str("dummy"), v8::FunctionTemplate::New(DummyCallHandler)); 5790 5791 Local<String> password = v8_str("Password"); 5792 5793 // Create an environment 5794 LocalContext context0(0, templ); 5795 context0->SetSecurityToken(password); 5796 v8::Handle<v8::Object> global0 = context0->Global(); 5797 global0->Set(v8_str("custom"), v8_num(1234)); 5798 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value()); 5799 5800 // Create an independent environment 5801 LocalContext context1(0, templ); 5802 context1->SetSecurityToken(password); 5803 v8::Handle<v8::Object> global1 = context1->Global(); 5804 global1->Set(v8_str("custom"), v8_num(1234)); 5805 CHECK_NE(global0, global1); 5806 CHECK_EQ(1234, global0->Get(v8_str("custom"))->Int32Value()); 5807 CHECK_EQ(1234, global1->Get(v8_str("custom"))->Int32Value()); 5808 5809 // Now create a new context with the old global 5810 LocalContext context2(0, templ, global1); 5811 context2->SetSecurityToken(password); 5812 v8::Handle<v8::Object> global2 = context2->Global(); 5813 CHECK_EQ(global1, global2); 5814 CHECK_EQ(0, global1->Get(v8_str("custom"))->Int32Value()); 5815 CHECK_EQ(0, global2->Get(v8_str("custom"))->Int32Value()); 5816 } 5817 5818 5819 THREADED_TEST(FunctionPrototypeAcrossContexts) { 5820 // Make sure that functions created by cloning boilerplates cannot 5821 // communicate through their __proto__ field. 5822 5823 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5824 5825 LocalContext env0; 5826 v8::Handle<v8::Object> global0 = 5827 env0->Global(); 5828 v8::Handle<v8::Object> object0 = 5829 global0->Get(v8_str("Object")).As<v8::Object>(); 5830 v8::Handle<v8::Object> tostring0 = 5831 object0->Get(v8_str("toString")).As<v8::Object>(); 5832 v8::Handle<v8::Object> proto0 = 5833 tostring0->Get(v8_str("__proto__")).As<v8::Object>(); 5834 proto0->Set(v8_str("custom"), v8_num(1234)); 5835 5836 LocalContext env1; 5837 v8::Handle<v8::Object> global1 = 5838 env1->Global(); 5839 v8::Handle<v8::Object> object1 = 5840 global1->Get(v8_str("Object")).As<v8::Object>(); 5841 v8::Handle<v8::Object> tostring1 = 5842 object1->Get(v8_str("toString")).As<v8::Object>(); 5843 v8::Handle<v8::Object> proto1 = 5844 tostring1->Get(v8_str("__proto__")).As<v8::Object>(); 5845 CHECK(!proto1->Has(v8_str("custom"))); 5846 } 5847 5848 5849 THREADED_TEST(Regress892105) { 5850 // Make sure that object and array literals created by cloning 5851 // boilerplates cannot communicate through their __proto__ 5852 // field. This is rather difficult to check, but we try to add stuff 5853 // to Object.prototype and Array.prototype and create a new 5854 // environment. This should succeed. 5855 5856 v8::HandleScope scope(v8::Isolate::GetCurrent()); 5857 5858 Local<String> source = v8_str("Object.prototype.obj = 1234;" 5859 "Array.prototype.arr = 4567;" 5860 "8901"); 5861 5862 LocalContext env0; 5863 Local<Script> script0 = Script::Compile(source); 5864 CHECK_EQ(8901.0, script0->Run()->NumberValue()); 5865 5866 LocalContext env1; 5867 Local<Script> script1 = Script::Compile(source); 5868 CHECK_EQ(8901.0, script1->Run()->NumberValue()); 5869 } 5870 5871 5872 THREADED_TEST(UndetectableObject) { 5873 LocalContext env; 5874 v8::HandleScope scope(env->GetIsolate()); 5875 5876 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(); 5877 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 5878 5879 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 5880 env->Global()->Set(v8_str("undetectable"), obj); 5881 5882 ExpectString("undetectable.toString()", "[object Object]"); 5883 ExpectString("typeof undetectable", "undefined"); 5884 ExpectString("typeof(undetectable)", "undefined"); 5885 ExpectBoolean("typeof undetectable == 'undefined'", true); 5886 ExpectBoolean("typeof undetectable == 'object'", false); 5887 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 5888 ExpectBoolean("!undetectable", true); 5889 5890 ExpectObject("true&&undetectable", obj); 5891 ExpectBoolean("false&&undetectable", false); 5892 ExpectBoolean("true||undetectable", true); 5893 ExpectObject("false||undetectable", obj); 5894 5895 ExpectObject("undetectable&&true", obj); 5896 ExpectObject("undetectable&&false", obj); 5897 ExpectBoolean("undetectable||true", true); 5898 ExpectBoolean("undetectable||false", false); 5899 5900 ExpectBoolean("undetectable==null", true); 5901 ExpectBoolean("null==undetectable", true); 5902 ExpectBoolean("undetectable==undefined", true); 5903 ExpectBoolean("undefined==undetectable", true); 5904 ExpectBoolean("undetectable==undetectable", true); 5905 5906 5907 ExpectBoolean("undetectable===null", false); 5908 ExpectBoolean("null===undetectable", false); 5909 ExpectBoolean("undetectable===undefined", false); 5910 ExpectBoolean("undefined===undetectable", false); 5911 ExpectBoolean("undetectable===undetectable", true); 5912 } 5913 5914 5915 THREADED_TEST(VoidLiteral) { 5916 LocalContext env; 5917 v8::HandleScope scope(env->GetIsolate()); 5918 5919 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(); 5920 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 5921 5922 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 5923 env->Global()->Set(v8_str("undetectable"), obj); 5924 5925 ExpectBoolean("undefined == void 0", true); 5926 ExpectBoolean("undetectable == void 0", true); 5927 ExpectBoolean("null == void 0", true); 5928 ExpectBoolean("undefined === void 0", true); 5929 ExpectBoolean("undetectable === void 0", false); 5930 ExpectBoolean("null === void 0", false); 5931 5932 ExpectBoolean("void 0 == undefined", true); 5933 ExpectBoolean("void 0 == undetectable", true); 5934 ExpectBoolean("void 0 == null", true); 5935 ExpectBoolean("void 0 === undefined", true); 5936 ExpectBoolean("void 0 === undetectable", false); 5937 ExpectBoolean("void 0 === null", false); 5938 5939 ExpectString("(function() {" 5940 " try {" 5941 " return x === void 0;" 5942 " } catch(e) {" 5943 " return e.toString();" 5944 " }" 5945 "})()", 5946 "ReferenceError: x is not defined"); 5947 ExpectString("(function() {" 5948 " try {" 5949 " return void 0 === x;" 5950 " } catch(e) {" 5951 " return e.toString();" 5952 " }" 5953 "})()", 5954 "ReferenceError: x is not defined"); 5955 } 5956 5957 5958 THREADED_TEST(ExtensibleOnUndetectable) { 5959 LocalContext env; 5960 v8::HandleScope scope(env->GetIsolate()); 5961 5962 Local<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(); 5963 desc->InstanceTemplate()->MarkAsUndetectable(); // undetectable 5964 5965 Local<v8::Object> obj = desc->GetFunction()->NewInstance(); 5966 env->Global()->Set(v8_str("undetectable"), obj); 5967 5968 Local<String> source = v8_str("undetectable.x = 42;" 5969 "undetectable.x"); 5970 5971 Local<Script> script = Script::Compile(source); 5972 5973 CHECK_EQ(v8::Integer::New(42), script->Run()); 5974 5975 ExpectBoolean("Object.isExtensible(undetectable)", true); 5976 5977 source = v8_str("Object.preventExtensions(undetectable);"); 5978 script = Script::Compile(source); 5979 script->Run(); 5980 ExpectBoolean("Object.isExtensible(undetectable)", false); 5981 5982 source = v8_str("undetectable.y = 2000;"); 5983 script = Script::Compile(source); 5984 script->Run(); 5985 ExpectBoolean("undetectable.y == undefined", true); 5986 } 5987 5988 5989 5990 THREADED_TEST(UndetectableString) { 5991 LocalContext env; 5992 v8::HandleScope scope(env->GetIsolate()); 5993 5994 Local<String> obj = String::NewUndetectable("foo"); 5995 env->Global()->Set(v8_str("undetectable"), obj); 5996 5997 ExpectString("undetectable", "foo"); 5998 ExpectString("typeof undetectable", "undefined"); 5999 ExpectString("typeof(undetectable)", "undefined"); 6000 ExpectBoolean("typeof undetectable == 'undefined'", true); 6001 ExpectBoolean("typeof undetectable == 'string'", false); 6002 ExpectBoolean("if (undetectable) { true; } else { false; }", false); 6003 ExpectBoolean("!undetectable", true); 6004 6005 ExpectObject("true&&undetectable", obj); 6006 ExpectBoolean("false&&undetectable", false); 6007 ExpectBoolean("true||undetectable", true); 6008 ExpectObject("false||undetectable", obj); 6009 6010 ExpectObject("undetectable&&true", obj); 6011 ExpectObject("undetectable&&false", obj); 6012 ExpectBoolean("undetectable||true", true); 6013 ExpectBoolean("undetectable||false", false); 6014 6015 ExpectBoolean("undetectable==null", true); 6016 ExpectBoolean("null==undetectable", true); 6017 ExpectBoolean("undetectable==undefined", true); 6018 ExpectBoolean("undefined==undetectable", true); 6019 ExpectBoolean("undetectable==undetectable", true); 6020 6021 6022 ExpectBoolean("undetectable===null", false); 6023 ExpectBoolean("null===undetectable", false); 6024 ExpectBoolean("undetectable===undefined", false); 6025 ExpectBoolean("undefined===undetectable", false); 6026 ExpectBoolean("undetectable===undetectable", true); 6027 } 6028 6029 6030 TEST(UndetectableOptimized) { 6031 i::FLAG_allow_natives_syntax = true; 6032 LocalContext env; 6033 v8::HandleScope scope(env->GetIsolate()); 6034 6035 Local<String> obj = String::NewUndetectable("foo"); 6036 env->Global()->Set(v8_str("undetectable"), obj); 6037 env->Global()->Set(v8_str("detectable"), v8_str("bar")); 6038 6039 ExpectString( 6040 "function testBranch() {" 6041 " if (!%_IsUndetectableObject(undetectable)) throw 1;" 6042 " if (%_IsUndetectableObject(detectable)) throw 2;" 6043 "}\n" 6044 "function testBool() {" 6045 " var b1 = !%_IsUndetectableObject(undetectable);" 6046 " var b2 = %_IsUndetectableObject(detectable);" 6047 " if (b1) throw 3;" 6048 " if (b2) throw 4;" 6049 " return b1 == b2;" 6050 "}\n" 6051 "%OptimizeFunctionOnNextCall(testBranch);" 6052 "%OptimizeFunctionOnNextCall(testBool);" 6053 "for (var i = 0; i < 10; i++) {" 6054 " testBranch();" 6055 " testBool();" 6056 "}\n" 6057 "\"PASS\"", 6058 "PASS"); 6059 } 6060 6061 6062 template <typename T> static void USE(T) { } 6063 6064 6065 // This test is not intended to be run, just type checked. 6066 static inline void PersistentHandles(v8::Isolate* isolate) { 6067 USE(PersistentHandles); 6068 Local<String> str = v8_str("foo"); 6069 v8::Persistent<String> p_str(isolate, str); 6070 p_str.Dispose(); 6071 Local<Script> scr = Script::Compile(v8_str("")); 6072 v8::Persistent<Script> p_scr(isolate, scr); 6073 p_scr.Dispose(); 6074 Local<ObjectTemplate> templ = ObjectTemplate::New(); 6075 v8::Persistent<ObjectTemplate> p_templ(isolate, templ); 6076 p_templ.Dispose(); 6077 } 6078 6079 6080 static void HandleLogDelegator( 6081 const v8::FunctionCallbackInfo<v8::Value>& args) { 6082 ApiTestFuzzer::Fuzz(); 6083 } 6084 6085 6086 THREADED_TEST(GlobalObjectTemplate) { 6087 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 6088 v8::HandleScope handle_scope(isolate); 6089 Local<ObjectTemplate> global_template = ObjectTemplate::New(); 6090 global_template->Set(v8_str("JSNI_Log"), 6091 v8::FunctionTemplate::New(HandleLogDelegator)); 6092 v8::Local<Context> context = Context::New(isolate, 0, global_template); 6093 Context::Scope context_scope(context); 6094 Script::Compile(v8_str("JSNI_Log('LOG')"))->Run(); 6095 } 6096 6097 6098 static const char* kSimpleExtensionSource = 6099 "function Foo() {" 6100 " return 4;" 6101 "}"; 6102 6103 6104 THREADED_TEST(SimpleExtensions) { 6105 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6106 v8::RegisterExtension(new Extension("simpletest", kSimpleExtensionSource)); 6107 const char* extension_names[] = { "simpletest" }; 6108 v8::ExtensionConfiguration extensions(1, extension_names); 6109 v8::Handle<Context> context = 6110 Context::New(v8::Isolate::GetCurrent(), &extensions); 6111 Context::Scope lock(context); 6112 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run(); 6113 CHECK_EQ(result, v8::Integer::New(4)); 6114 } 6115 6116 6117 THREADED_TEST(NullExtensions) { 6118 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6119 v8::RegisterExtension(new Extension("nulltest", NULL)); 6120 const char* extension_names[] = { "nulltest" }; 6121 v8::ExtensionConfiguration extensions(1, extension_names); 6122 v8::Handle<Context> context = 6123 Context::New(v8::Isolate::GetCurrent(), &extensions); 6124 Context::Scope lock(context); 6125 v8::Handle<Value> result = Script::Compile(v8_str("1+3"))->Run(); 6126 CHECK_EQ(result, v8::Integer::New(4)); 6127 } 6128 6129 6130 static const char* kEmbeddedExtensionSource = 6131 "function Ret54321(){return 54321;}~~@@$" 6132 "$%% THIS IS A SERIES OF NON-NULL-TERMINATED STRINGS."; 6133 static const int kEmbeddedExtensionSourceValidLen = 34; 6134 6135 6136 THREADED_TEST(ExtensionMissingSourceLength) { 6137 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6138 v8::RegisterExtension(new Extension("srclentest_fail", 6139 kEmbeddedExtensionSource)); 6140 const char* extension_names[] = { "srclentest_fail" }; 6141 v8::ExtensionConfiguration extensions(1, extension_names); 6142 v8::Handle<Context> context = 6143 Context::New(v8::Isolate::GetCurrent(), &extensions); 6144 CHECK_EQ(0, *context); 6145 } 6146 6147 6148 THREADED_TEST(ExtensionWithSourceLength) { 6149 for (int source_len = kEmbeddedExtensionSourceValidLen - 1; 6150 source_len <= kEmbeddedExtensionSourceValidLen + 1; ++source_len) { 6151 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6152 i::ScopedVector<char> extension_name(32); 6153 i::OS::SNPrintF(extension_name, "ext #%d", source_len); 6154 v8::RegisterExtension(new Extension(extension_name.start(), 6155 kEmbeddedExtensionSource, 0, 0, 6156 source_len)); 6157 const char* extension_names[1] = { extension_name.start() }; 6158 v8::ExtensionConfiguration extensions(1, extension_names); 6159 v8::Handle<Context> context = 6160 Context::New(v8::Isolate::GetCurrent(), &extensions); 6161 if (source_len == kEmbeddedExtensionSourceValidLen) { 6162 Context::Scope lock(context); 6163 v8::Handle<Value> result = Script::Compile(v8_str("Ret54321()"))->Run(); 6164 CHECK_EQ(v8::Integer::New(54321), result); 6165 } else { 6166 // Anything but exactly the right length should fail to compile. 6167 CHECK_EQ(0, *context); 6168 } 6169 } 6170 } 6171 6172 6173 static const char* kEvalExtensionSource1 = 6174 "function UseEval1() {" 6175 " var x = 42;" 6176 " return eval('x');" 6177 "}"; 6178 6179 6180 static const char* kEvalExtensionSource2 = 6181 "(function() {" 6182 " var x = 42;" 6183 " function e() {" 6184 " return eval('x');" 6185 " }" 6186 " this.UseEval2 = e;" 6187 "})()"; 6188 6189 6190 THREADED_TEST(UseEvalFromExtension) { 6191 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6192 v8::RegisterExtension(new Extension("evaltest1", kEvalExtensionSource1)); 6193 v8::RegisterExtension(new Extension("evaltest2", kEvalExtensionSource2)); 6194 const char* extension_names[] = { "evaltest1", "evaltest2" }; 6195 v8::ExtensionConfiguration extensions(2, extension_names); 6196 v8::Handle<Context> context = 6197 Context::New(v8::Isolate::GetCurrent(), &extensions); 6198 Context::Scope lock(context); 6199 v8::Handle<Value> result = Script::Compile(v8_str("UseEval1()"))->Run(); 6200 CHECK_EQ(result, v8::Integer::New(42)); 6201 result = Script::Compile(v8_str("UseEval2()"))->Run(); 6202 CHECK_EQ(result, v8::Integer::New(42)); 6203 } 6204 6205 6206 static const char* kWithExtensionSource1 = 6207 "function UseWith1() {" 6208 " var x = 42;" 6209 " with({x:87}) { return x; }" 6210 "}"; 6211 6212 6213 6214 static const char* kWithExtensionSource2 = 6215 "(function() {" 6216 " var x = 42;" 6217 " function e() {" 6218 " with ({x:87}) { return x; }" 6219 " }" 6220 " this.UseWith2 = e;" 6221 "})()"; 6222 6223 6224 THREADED_TEST(UseWithFromExtension) { 6225 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6226 v8::RegisterExtension(new Extension("withtest1", kWithExtensionSource1)); 6227 v8::RegisterExtension(new Extension("withtest2", kWithExtensionSource2)); 6228 const char* extension_names[] = { "withtest1", "withtest2" }; 6229 v8::ExtensionConfiguration extensions(2, extension_names); 6230 v8::Handle<Context> context = 6231 Context::New(v8::Isolate::GetCurrent(), &extensions); 6232 Context::Scope lock(context); 6233 v8::Handle<Value> result = Script::Compile(v8_str("UseWith1()"))->Run(); 6234 CHECK_EQ(result, v8::Integer::New(87)); 6235 result = Script::Compile(v8_str("UseWith2()"))->Run(); 6236 CHECK_EQ(result, v8::Integer::New(87)); 6237 } 6238 6239 6240 THREADED_TEST(AutoExtensions) { 6241 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6242 Extension* extension = new Extension("autotest", kSimpleExtensionSource); 6243 extension->set_auto_enable(true); 6244 v8::RegisterExtension(extension); 6245 v8::Handle<Context> context = 6246 Context::New(v8::Isolate::GetCurrent()); 6247 Context::Scope lock(context); 6248 v8::Handle<Value> result = Script::Compile(v8_str("Foo()"))->Run(); 6249 CHECK_EQ(result, v8::Integer::New(4)); 6250 } 6251 6252 6253 static const char* kSyntaxErrorInExtensionSource = 6254 "["; 6255 6256 6257 // Test that a syntax error in an extension does not cause a fatal 6258 // error but results in an empty context. 6259 THREADED_TEST(SyntaxErrorExtensions) { 6260 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6261 v8::RegisterExtension(new Extension("syntaxerror", 6262 kSyntaxErrorInExtensionSource)); 6263 const char* extension_names[] = { "syntaxerror" }; 6264 v8::ExtensionConfiguration extensions(1, extension_names); 6265 v8::Handle<Context> context = 6266 Context::New(v8::Isolate::GetCurrent(), &extensions); 6267 CHECK(context.IsEmpty()); 6268 } 6269 6270 6271 static const char* kExceptionInExtensionSource = 6272 "throw 42"; 6273 6274 6275 // Test that an exception when installing an extension does not cause 6276 // a fatal error but results in an empty context. 6277 THREADED_TEST(ExceptionExtensions) { 6278 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6279 v8::RegisterExtension(new Extension("exception", 6280 kExceptionInExtensionSource)); 6281 const char* extension_names[] = { "exception" }; 6282 v8::ExtensionConfiguration extensions(1, extension_names); 6283 v8::Handle<Context> context = 6284 Context::New(v8::Isolate::GetCurrent(), &extensions); 6285 CHECK(context.IsEmpty()); 6286 } 6287 6288 6289 static const char* kNativeCallInExtensionSource = 6290 "function call_runtime_last_index_of(x) {" 6291 " return %StringLastIndexOf(x, 'bob', 10);" 6292 "}"; 6293 6294 6295 static const char* kNativeCallTest = 6296 "call_runtime_last_index_of('bobbobboellebobboellebobbob');"; 6297 6298 // Test that a native runtime calls are supported in extensions. 6299 THREADED_TEST(NativeCallInExtensions) { 6300 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6301 v8::RegisterExtension(new Extension("nativecall", 6302 kNativeCallInExtensionSource)); 6303 const char* extension_names[] = { "nativecall" }; 6304 v8::ExtensionConfiguration extensions(1, extension_names); 6305 v8::Handle<Context> context = 6306 Context::New(v8::Isolate::GetCurrent(), &extensions); 6307 Context::Scope lock(context); 6308 v8::Handle<Value> result = Script::Compile(v8_str(kNativeCallTest))->Run(); 6309 CHECK_EQ(result, v8::Integer::New(3)); 6310 } 6311 6312 6313 class NativeFunctionExtension : public Extension { 6314 public: 6315 NativeFunctionExtension(const char* name, 6316 const char* source, 6317 v8::FunctionCallback fun = &Echo) 6318 : Extension(name, source), 6319 function_(fun) { } 6320 6321 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( 6322 v8::Handle<v8::String> name) { 6323 return v8::FunctionTemplate::New(function_); 6324 } 6325 6326 static void Echo(const v8::FunctionCallbackInfo<v8::Value>& args) { 6327 if (args.Length() >= 1) args.GetReturnValue().Set(args[0]); 6328 } 6329 private: 6330 v8::FunctionCallback function_; 6331 }; 6332 6333 6334 THREADED_TEST(NativeFunctionDeclaration) { 6335 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6336 const char* name = "nativedecl"; 6337 v8::RegisterExtension(new NativeFunctionExtension(name, 6338 "native function foo();")); 6339 const char* extension_names[] = { name }; 6340 v8::ExtensionConfiguration extensions(1, extension_names); 6341 v8::Handle<Context> context = 6342 Context::New(v8::Isolate::GetCurrent(), &extensions); 6343 Context::Scope lock(context); 6344 v8::Handle<Value> result = Script::Compile(v8_str("foo(42);"))->Run(); 6345 CHECK_EQ(result, v8::Integer::New(42)); 6346 } 6347 6348 6349 THREADED_TEST(NativeFunctionDeclarationError) { 6350 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6351 const char* name = "nativedeclerr"; 6352 // Syntax error in extension code. 6353 v8::RegisterExtension(new NativeFunctionExtension(name, 6354 "native\nfunction foo();")); 6355 const char* extension_names[] = { name }; 6356 v8::ExtensionConfiguration extensions(1, extension_names); 6357 v8::Handle<Context> context = 6358 Context::New(v8::Isolate::GetCurrent(), &extensions); 6359 CHECK(context.IsEmpty()); 6360 } 6361 6362 6363 THREADED_TEST(NativeFunctionDeclarationErrorEscape) { 6364 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6365 const char* name = "nativedeclerresc"; 6366 // Syntax error in extension code - escape code in "native" means that 6367 // it's not treated as a keyword. 6368 v8::RegisterExtension(new NativeFunctionExtension( 6369 name, 6370 "nativ\\u0065 function foo();")); 6371 const char* extension_names[] = { name }; 6372 v8::ExtensionConfiguration extensions(1, extension_names); 6373 v8::Handle<Context> context = 6374 Context::New(v8::Isolate::GetCurrent(), &extensions); 6375 CHECK(context.IsEmpty()); 6376 } 6377 6378 6379 static void CheckDependencies(const char* name, const char* expected) { 6380 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6381 v8::ExtensionConfiguration config(1, &name); 6382 LocalContext context(&config); 6383 CHECK_EQ(String::New(expected), context->Global()->Get(v8_str("loaded"))); 6384 } 6385 6386 6387 /* 6388 * Configuration: 6389 * 6390 * /-- B <--\ 6391 * A <- -- D <-- E 6392 * \-- C <--/ 6393 */ 6394 THREADED_TEST(ExtensionDependency) { 6395 static const char* kEDeps[] = { "D" }; 6396 v8::RegisterExtension(new Extension("E", "this.loaded += 'E';", 1, kEDeps)); 6397 static const char* kDDeps[] = { "B", "C" }; 6398 v8::RegisterExtension(new Extension("D", "this.loaded += 'D';", 2, kDDeps)); 6399 static const char* kBCDeps[] = { "A" }; 6400 v8::RegisterExtension(new Extension("B", "this.loaded += 'B';", 1, kBCDeps)); 6401 v8::RegisterExtension(new Extension("C", "this.loaded += 'C';", 1, kBCDeps)); 6402 v8::RegisterExtension(new Extension("A", "this.loaded += 'A';")); 6403 CheckDependencies("A", "undefinedA"); 6404 CheckDependencies("B", "undefinedAB"); 6405 CheckDependencies("C", "undefinedAC"); 6406 CheckDependencies("D", "undefinedABCD"); 6407 CheckDependencies("E", "undefinedABCDE"); 6408 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6409 static const char* exts[2] = { "C", "E" }; 6410 v8::ExtensionConfiguration config(2, exts); 6411 LocalContext context(&config); 6412 CHECK_EQ(v8_str("undefinedACBDE"), context->Global()->Get(v8_str("loaded"))); 6413 } 6414 6415 6416 static const char* kExtensionTestScript = 6417 "native function A();" 6418 "native function B();" 6419 "native function C();" 6420 "function Foo(i) {" 6421 " if (i == 0) return A();" 6422 " if (i == 1) return B();" 6423 " if (i == 2) return C();" 6424 "}"; 6425 6426 6427 static void CallFun(const v8::FunctionCallbackInfo<v8::Value>& args) { 6428 ApiTestFuzzer::Fuzz(); 6429 if (args.IsConstructCall()) { 6430 args.This()->Set(v8_str("data"), args.Data()); 6431 args.GetReturnValue().SetNull(); 6432 return; 6433 } 6434 args.GetReturnValue().Set(args.Data()); 6435 } 6436 6437 6438 class FunctionExtension : public Extension { 6439 public: 6440 FunctionExtension() : Extension("functiontest", kExtensionTestScript) { } 6441 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( 6442 v8::Handle<String> name); 6443 }; 6444 6445 6446 static int lookup_count = 0; 6447 v8::Handle<v8::FunctionTemplate> FunctionExtension::GetNativeFunction( 6448 v8::Handle<String> name) { 6449 lookup_count++; 6450 if (name->Equals(v8_str("A"))) { 6451 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(8)); 6452 } else if (name->Equals(v8_str("B"))) { 6453 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(7)); 6454 } else if (name->Equals(v8_str("C"))) { 6455 return v8::FunctionTemplate::New(CallFun, v8::Integer::New(6)); 6456 } else { 6457 return v8::Handle<v8::FunctionTemplate>(); 6458 } 6459 } 6460 6461 6462 THREADED_TEST(FunctionLookup) { 6463 v8::RegisterExtension(new FunctionExtension()); 6464 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6465 static const char* exts[1] = { "functiontest" }; 6466 v8::ExtensionConfiguration config(1, exts); 6467 LocalContext context(&config); 6468 CHECK_EQ(3, lookup_count); 6469 CHECK_EQ(v8::Integer::New(8), Script::Compile(v8_str("Foo(0)"))->Run()); 6470 CHECK_EQ(v8::Integer::New(7), Script::Compile(v8_str("Foo(1)"))->Run()); 6471 CHECK_EQ(v8::Integer::New(6), Script::Compile(v8_str("Foo(2)"))->Run()); 6472 } 6473 6474 6475 THREADED_TEST(NativeFunctionConstructCall) { 6476 v8::RegisterExtension(new FunctionExtension()); 6477 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6478 static const char* exts[1] = { "functiontest" }; 6479 v8::ExtensionConfiguration config(1, exts); 6480 LocalContext context(&config); 6481 for (int i = 0; i < 10; i++) { 6482 // Run a few times to ensure that allocation of objects doesn't 6483 // change behavior of a constructor function. 6484 CHECK_EQ(v8::Integer::New(8), 6485 Script::Compile(v8_str("(new A()).data"))->Run()); 6486 CHECK_EQ(v8::Integer::New(7), 6487 Script::Compile(v8_str("(new B()).data"))->Run()); 6488 CHECK_EQ(v8::Integer::New(6), 6489 Script::Compile(v8_str("(new C()).data"))->Run()); 6490 } 6491 } 6492 6493 6494 static const char* last_location; 6495 static const char* last_message; 6496 void StoringErrorCallback(const char* location, const char* message) { 6497 if (last_location == NULL) { 6498 last_location = location; 6499 last_message = message; 6500 } 6501 } 6502 6503 6504 // ErrorReporting creates a circular extensions configuration and 6505 // tests that the fatal error handler gets called. This renders V8 6506 // unusable and therefore this test cannot be run in parallel. 6507 TEST(ErrorReporting) { 6508 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 6509 static const char* aDeps[] = { "B" }; 6510 v8::RegisterExtension(new Extension("A", "", 1, aDeps)); 6511 static const char* bDeps[] = { "A" }; 6512 v8::RegisterExtension(new Extension("B", "", 1, bDeps)); 6513 last_location = NULL; 6514 v8::ExtensionConfiguration config(1, bDeps); 6515 v8::Handle<Context> context = 6516 Context::New(v8::Isolate::GetCurrent(), &config); 6517 CHECK(context.IsEmpty()); 6518 CHECK_NE(last_location, NULL); 6519 } 6520 6521 6522 static const char* js_code_causing_huge_string_flattening = 6523 "var str = 'X';" 6524 "for (var i = 0; i < 30; i++) {" 6525 " str = str + str;" 6526 "}" 6527 "str.match(/X/);"; 6528 6529 6530 void OOMCallback(const char* location, const char* message) { 6531 exit(0); 6532 } 6533 6534 6535 TEST(RegexpOutOfMemory) { 6536 // Execute a script that causes out of memory when flattening a string. 6537 v8::HandleScope scope(v8::Isolate::GetCurrent()); 6538 v8::V8::SetFatalErrorHandler(OOMCallback); 6539 LocalContext context; 6540 Local<Script> script = 6541 Script::Compile(String::New(js_code_causing_huge_string_flattening)); 6542 last_location = NULL; 6543 script->Run(); 6544 6545 CHECK(false); // Should not return. 6546 } 6547 6548 6549 static void MissingScriptInfoMessageListener(v8::Handle<v8::Message> message, 6550 v8::Handle<Value> data) { 6551 CHECK(message->GetScriptResourceName()->IsUndefined()); 6552 CHECK_EQ(v8::Undefined(), message->GetScriptResourceName()); 6553 message->GetLineNumber(); 6554 message->GetSourceLine(); 6555 } 6556 6557 6558 THREADED_TEST(ErrorWithMissingScriptInfo) { 6559 LocalContext context; 6560 v8::HandleScope scope(context->GetIsolate()); 6561 v8::V8::AddMessageListener(MissingScriptInfoMessageListener); 6562 Script::Compile(v8_str("throw Error()"))->Run(); 6563 v8::V8::RemoveMessageListeners(MissingScriptInfoMessageListener); 6564 } 6565 6566 6567 int global_index = 0; 6568 6569 class Snorkel { 6570 public: 6571 Snorkel() { index_ = global_index++; } 6572 int index_; 6573 }; 6574 6575 class Whammy { 6576 public: 6577 explicit Whammy(v8::Isolate* isolate) : cursor_(0), isolate_(isolate) { } 6578 ~Whammy() { script_.Dispose(isolate_); } 6579 v8::Handle<Script> getScript() { 6580 if (script_.IsEmpty()) script_.Reset(isolate_, v8_compile("({}).blammo")); 6581 return Local<Script>::New(isolate_, script_); 6582 } 6583 6584 public: 6585 static const int kObjectCount = 256; 6586 int cursor_; 6587 v8::Isolate* isolate_; 6588 v8::Persistent<v8::Object> objects_[kObjectCount]; 6589 v8::Persistent<Script> script_; 6590 }; 6591 6592 static void HandleWeakReference(v8::Isolate* isolate, 6593 v8::Persistent<v8::Value>* obj, 6594 Snorkel* snorkel) { 6595 delete snorkel; 6596 obj->ClearWeak(isolate); 6597 } 6598 6599 void WhammyPropertyGetter(Local<String> name, 6600 const v8::PropertyCallbackInfo<v8::Value>& info) { 6601 Whammy* whammy = 6602 static_cast<Whammy*>(v8::Handle<v8::External>::Cast(info.Data())->Value()); 6603 6604 v8::Persistent<v8::Object>& prev = whammy->objects_[whammy->cursor_]; 6605 6606 v8::Handle<v8::Object> obj = v8::Object::New(); 6607 if (!prev.IsEmpty()) { 6608 v8::Local<v8::Object>::New(info.GetIsolate(), prev) 6609 ->Set(v8_str("next"), obj); 6610 prev.MakeWeak<Value, Snorkel>(new Snorkel(), &HandleWeakReference); 6611 whammy->objects_[whammy->cursor_].Clear(); 6612 } 6613 whammy->objects_[whammy->cursor_].Reset(info.GetIsolate(), obj); 6614 whammy->cursor_ = (whammy->cursor_ + 1) % Whammy::kObjectCount; 6615 info.GetReturnValue().Set(whammy->getScript()->Run()); 6616 } 6617 6618 6619 THREADED_TEST(WeakReference) { 6620 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 6621 v8::Handle<v8::ObjectTemplate> templ= v8::ObjectTemplate::New(); 6622 Whammy* whammy = new Whammy(v8::Isolate::GetCurrent()); 6623 templ->SetNamedPropertyHandler(WhammyPropertyGetter, 6624 0, 0, 0, 0, 6625 v8::External::New(whammy)); 6626 const char* extension_list[] = { "v8/gc" }; 6627 v8::ExtensionConfiguration extensions(1, extension_list); 6628 v8::Handle<Context> context = 6629 Context::New(v8::Isolate::GetCurrent(), &extensions); 6630 Context::Scope context_scope(context); 6631 6632 v8::Handle<v8::Object> interceptor = templ->NewInstance(); 6633 context->Global()->Set(v8_str("whammy"), interceptor); 6634 const char* code = 6635 "var last;" 6636 "for (var i = 0; i < 10000; i++) {" 6637 " var obj = whammy.length;" 6638 " if (last) last.next = obj;" 6639 " last = obj;" 6640 "}" 6641 "gc();" 6642 "4"; 6643 v8::Handle<Value> result = CompileRun(code); 6644 CHECK_EQ(4.0, result->NumberValue()); 6645 delete whammy; 6646 } 6647 6648 6649 static void DisposeAndSetFlag(v8::Isolate* isolate, 6650 v8::Persistent<v8::Object>* obj, 6651 bool* data) { 6652 obj->Dispose(isolate); 6653 *(data) = true; 6654 } 6655 6656 6657 THREADED_TEST(IndependentWeakHandle) { 6658 v8::Isolate* iso = v8::Isolate::GetCurrent(); 6659 v8::HandleScope scope(iso); 6660 v8::Handle<Context> context = Context::New(iso); 6661 Context::Scope context_scope(context); 6662 6663 v8::Persistent<v8::Object> object_a, object_b; 6664 6665 { 6666 v8::HandleScope handle_scope(iso); 6667 object_a.Reset(iso, v8::Object::New()); 6668 object_b.Reset(iso, v8::Object::New()); 6669 } 6670 6671 bool object_a_disposed = false; 6672 bool object_b_disposed = false; 6673 object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag); 6674 object_b.MakeWeak(&object_b_disposed, &DisposeAndSetFlag); 6675 CHECK(!object_b.IsIndependent(iso)); 6676 object_a.MarkIndependent(iso); 6677 object_b.MarkIndependent(iso); 6678 CHECK(object_b.IsIndependent(iso)); 6679 HEAP->PerformScavenge(); 6680 CHECK(object_a_disposed); 6681 CHECK(object_b_disposed); 6682 } 6683 6684 6685 static void InvokeScavenge() { 6686 HEAP->PerformScavenge(); 6687 } 6688 6689 6690 static void InvokeMarkSweep() { 6691 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 6692 } 6693 6694 6695 static void ForceScavenge(v8::Isolate* isolate, 6696 v8::Persistent<v8::Object>* obj, 6697 bool* data) { 6698 obj->Dispose(isolate); 6699 *(data) = true; 6700 InvokeScavenge(); 6701 } 6702 6703 6704 static void ForceMarkSweep(v8::Isolate* isolate, 6705 v8::Persistent<v8::Object>* obj, 6706 bool* data) { 6707 obj->Dispose(isolate); 6708 *(data) = true; 6709 InvokeMarkSweep(); 6710 } 6711 6712 6713 THREADED_TEST(GCFromWeakCallbacks) { 6714 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 6715 v8::HandleScope scope(isolate); 6716 v8::Handle<Context> context = Context::New(isolate); 6717 Context::Scope context_scope(context); 6718 6719 static const int kNumberOfGCTypes = 2; 6720 typedef v8::WeakReferenceCallbacks<v8::Object, bool>::Revivable Callback; 6721 Callback gc_forcing_callback[kNumberOfGCTypes] = 6722 {&ForceScavenge, &ForceMarkSweep}; 6723 6724 typedef void (*GCInvoker)(); 6725 GCInvoker invoke_gc[kNumberOfGCTypes] = {&InvokeScavenge, &InvokeMarkSweep}; 6726 6727 for (int outer_gc = 0; outer_gc < kNumberOfGCTypes; outer_gc++) { 6728 for (int inner_gc = 0; inner_gc < kNumberOfGCTypes; inner_gc++) { 6729 v8::Persistent<v8::Object> object; 6730 { 6731 v8::HandleScope handle_scope(isolate); 6732 object.Reset(isolate, v8::Object::New()); 6733 } 6734 bool disposed = false; 6735 object.MakeWeak(&disposed, gc_forcing_callback[inner_gc]); 6736 object.MarkIndependent(isolate); 6737 invoke_gc[outer_gc](); 6738 CHECK(disposed); 6739 } 6740 } 6741 } 6742 6743 6744 static void RevivingCallback(v8::Isolate* isolate, 6745 v8::Persistent<v8::Object>* obj, 6746 bool* data) { 6747 obj->ClearWeak(isolate); 6748 *(data) = true; 6749 } 6750 6751 6752 THREADED_TEST(IndependentHandleRevival) { 6753 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 6754 v8::HandleScope scope(isolate); 6755 v8::Handle<Context> context = Context::New(isolate); 6756 Context::Scope context_scope(context); 6757 6758 v8::Persistent<v8::Object> object; 6759 { 6760 v8::HandleScope handle_scope(isolate); 6761 v8::Local<v8::Object> o = v8::Object::New(); 6762 object.Reset(isolate, o); 6763 o->Set(v8_str("x"), v8::Integer::New(1)); 6764 v8::Local<String> y_str = v8_str("y"); 6765 o->Set(y_str, y_str); 6766 } 6767 bool revived = false; 6768 object.MakeWeak(&revived, &RevivingCallback); 6769 object.MarkIndependent(isolate); 6770 HEAP->PerformScavenge(); 6771 CHECK(revived); 6772 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 6773 { 6774 v8::HandleScope handle_scope(isolate); 6775 v8::Local<v8::Object> o = v8::Local<v8::Object>::New(isolate, object); 6776 v8::Local<String> y_str = v8_str("y"); 6777 CHECK_EQ(v8::Integer::New(1), o->Get(v8_str("x"))); 6778 CHECK(o->Get(y_str)->Equals(y_str)); 6779 } 6780 } 6781 6782 6783 v8::Handle<Function> args_fun; 6784 6785 6786 static void ArgumentsTestCallback( 6787 const v8::FunctionCallbackInfo<v8::Value>& args) { 6788 ApiTestFuzzer::Fuzz(); 6789 CHECK_EQ(args_fun, args.Callee()); 6790 CHECK_EQ(3, args.Length()); 6791 CHECK_EQ(v8::Integer::New(1), args[0]); 6792 CHECK_EQ(v8::Integer::New(2), args[1]); 6793 CHECK_EQ(v8::Integer::New(3), args[2]); 6794 CHECK_EQ(v8::Undefined(), args[3]); 6795 v8::HandleScope scope(args.GetIsolate()); 6796 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 6797 } 6798 6799 6800 THREADED_TEST(Arguments) { 6801 v8::HandleScope scope(v8::Isolate::GetCurrent()); 6802 v8::Handle<v8::ObjectTemplate> global = ObjectTemplate::New(); 6803 global->Set(v8_str("f"), v8::FunctionTemplate::New(ArgumentsTestCallback)); 6804 LocalContext context(NULL, global); 6805 args_fun = context->Global()->Get(v8_str("f")).As<Function>(); 6806 v8_compile("f(1, 2, 3)")->Run(); 6807 } 6808 6809 6810 static void NoBlockGetterX(Local<String> name, 6811 const v8::PropertyCallbackInfo<v8::Value>&) { 6812 } 6813 6814 6815 static void NoBlockGetterI(uint32_t index, 6816 const v8::PropertyCallbackInfo<v8::Value>&) { 6817 } 6818 6819 6820 static void PDeleter(Local<String> name, 6821 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 6822 if (!name->Equals(v8_str("foo"))) { 6823 return; // not intercepted 6824 } 6825 6826 info.GetReturnValue().Set(false); // intercepted, don't delete the property 6827 } 6828 6829 6830 static void IDeleter(uint32_t index, 6831 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 6832 if (index != 2) { 6833 return; // not intercepted 6834 } 6835 6836 info.GetReturnValue().Set(false); // intercepted, don't delete the property 6837 } 6838 6839 6840 THREADED_TEST(Deleter) { 6841 v8::HandleScope scope(v8::Isolate::GetCurrent()); 6842 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 6843 obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL); 6844 obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL); 6845 LocalContext context; 6846 context->Global()->Set(v8_str("k"), obj->NewInstance()); 6847 CompileRun( 6848 "k.foo = 'foo';" 6849 "k.bar = 'bar';" 6850 "k[2] = 2;" 6851 "k[4] = 4;"); 6852 CHECK(v8_compile("delete k.foo")->Run()->IsFalse()); 6853 CHECK(v8_compile("delete k.bar")->Run()->IsTrue()); 6854 6855 CHECK_EQ(v8_compile("k.foo")->Run(), v8_str("foo")); 6856 CHECK(v8_compile("k.bar")->Run()->IsUndefined()); 6857 6858 CHECK(v8_compile("delete k[2]")->Run()->IsFalse()); 6859 CHECK(v8_compile("delete k[4]")->Run()->IsTrue()); 6860 6861 CHECK_EQ(v8_compile("k[2]")->Run(), v8_num(2)); 6862 CHECK(v8_compile("k[4]")->Run()->IsUndefined()); 6863 } 6864 6865 6866 static void GetK(Local<String> name, 6867 const v8::PropertyCallbackInfo<v8::Value>& info) { 6868 ApiTestFuzzer::Fuzz(); 6869 if (name->Equals(v8_str("foo")) || 6870 name->Equals(v8_str("bar")) || 6871 name->Equals(v8_str("baz"))) { 6872 info.GetReturnValue().SetUndefined(); 6873 } 6874 } 6875 6876 6877 static void IndexedGetK(uint32_t index, 6878 const v8::PropertyCallbackInfo<v8::Value>& info) { 6879 ApiTestFuzzer::Fuzz(); 6880 if (index == 0 || index == 1) info.GetReturnValue().SetUndefined(); 6881 } 6882 6883 6884 static void NamedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) { 6885 ApiTestFuzzer::Fuzz(); 6886 v8::Handle<v8::Array> result = v8::Array::New(3); 6887 result->Set(v8::Integer::New(0), v8_str("foo")); 6888 result->Set(v8::Integer::New(1), v8_str("bar")); 6889 result->Set(v8::Integer::New(2), v8_str("baz")); 6890 info.GetReturnValue().Set(result); 6891 } 6892 6893 6894 static void IndexedEnum(const v8::PropertyCallbackInfo<v8::Array>& info) { 6895 ApiTestFuzzer::Fuzz(); 6896 v8::Handle<v8::Array> result = v8::Array::New(2); 6897 result->Set(v8::Integer::New(0), v8_str("0")); 6898 result->Set(v8::Integer::New(1), v8_str("1")); 6899 info.GetReturnValue().Set(result); 6900 } 6901 6902 6903 THREADED_TEST(Enumerators) { 6904 v8::HandleScope scope(v8::Isolate::GetCurrent()); 6905 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 6906 obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum); 6907 obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum); 6908 LocalContext context; 6909 context->Global()->Set(v8_str("k"), obj->NewInstance()); 6910 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 6911 "k[10] = 0;" 6912 "k.a = 0;" 6913 "k[5] = 0;" 6914 "k.b = 0;" 6915 "k[4294967295] = 0;" 6916 "k.c = 0;" 6917 "k[4294967296] = 0;" 6918 "k.d = 0;" 6919 "k[140000] = 0;" 6920 "k.e = 0;" 6921 "k[30000000000] = 0;" 6922 "k.f = 0;" 6923 "var result = [];" 6924 "for (var prop in k) {" 6925 " result.push(prop);" 6926 "}" 6927 "result")); 6928 // Check that we get all the property names returned including the 6929 // ones from the enumerators in the right order: indexed properties 6930 // in numerical order, indexed interceptor properties, named 6931 // properties in insertion order, named interceptor properties. 6932 // This order is not mandated by the spec, so this test is just 6933 // documenting our behavior. 6934 CHECK_EQ(17, result->Length()); 6935 // Indexed properties in numerical order. 6936 CHECK_EQ(v8_str("5"), result->Get(v8::Integer::New(0))); 6937 CHECK_EQ(v8_str("10"), result->Get(v8::Integer::New(1))); 6938 CHECK_EQ(v8_str("140000"), result->Get(v8::Integer::New(2))); 6939 CHECK_EQ(v8_str("4294967295"), result->Get(v8::Integer::New(3))); 6940 // Indexed interceptor properties in the order they are returned 6941 // from the enumerator interceptor. 6942 CHECK_EQ(v8_str("0"), result->Get(v8::Integer::New(4))); 6943 CHECK_EQ(v8_str("1"), result->Get(v8::Integer::New(5))); 6944 // Named properties in insertion order. 6945 CHECK_EQ(v8_str("a"), result->Get(v8::Integer::New(6))); 6946 CHECK_EQ(v8_str("b"), result->Get(v8::Integer::New(7))); 6947 CHECK_EQ(v8_str("c"), result->Get(v8::Integer::New(8))); 6948 CHECK_EQ(v8_str("4294967296"), result->Get(v8::Integer::New(9))); 6949 CHECK_EQ(v8_str("d"), result->Get(v8::Integer::New(10))); 6950 CHECK_EQ(v8_str("e"), result->Get(v8::Integer::New(11))); 6951 CHECK_EQ(v8_str("30000000000"), result->Get(v8::Integer::New(12))); 6952 CHECK_EQ(v8_str("f"), result->Get(v8::Integer::New(13))); 6953 // Named interceptor properties. 6954 CHECK_EQ(v8_str("foo"), result->Get(v8::Integer::New(14))); 6955 CHECK_EQ(v8_str("bar"), result->Get(v8::Integer::New(15))); 6956 CHECK_EQ(v8_str("baz"), result->Get(v8::Integer::New(16))); 6957 } 6958 6959 6960 int p_getter_count; 6961 int p_getter_count2; 6962 6963 6964 static void PGetter(Local<String> name, 6965 const v8::PropertyCallbackInfo<v8::Value>& info) { 6966 ApiTestFuzzer::Fuzz(); 6967 p_getter_count++; 6968 v8::Handle<v8::Object> global = Context::GetCurrent()->Global(); 6969 CHECK_EQ(info.Holder(), global->Get(v8_str("o1"))); 6970 if (name->Equals(v8_str("p1"))) { 6971 CHECK_EQ(info.This(), global->Get(v8_str("o1"))); 6972 } else if (name->Equals(v8_str("p2"))) { 6973 CHECK_EQ(info.This(), global->Get(v8_str("o2"))); 6974 } else if (name->Equals(v8_str("p3"))) { 6975 CHECK_EQ(info.This(), global->Get(v8_str("o3"))); 6976 } else if (name->Equals(v8_str("p4"))) { 6977 CHECK_EQ(info.This(), global->Get(v8_str("o4"))); 6978 } 6979 } 6980 6981 6982 static void RunHolderTest(v8::Handle<v8::ObjectTemplate> obj) { 6983 ApiTestFuzzer::Fuzz(); 6984 LocalContext context; 6985 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 6986 CompileRun( 6987 "o1.__proto__ = { };" 6988 "var o2 = { __proto__: o1 };" 6989 "var o3 = { __proto__: o2 };" 6990 "var o4 = { __proto__: o3 };" 6991 "for (var i = 0; i < 10; i++) o4.p4;" 6992 "for (var i = 0; i < 10; i++) o3.p3;" 6993 "for (var i = 0; i < 10; i++) o2.p2;" 6994 "for (var i = 0; i < 10; i++) o1.p1;"); 6995 } 6996 6997 6998 static void PGetter2(Local<String> name, 6999 const v8::PropertyCallbackInfo<v8::Value>& info) { 7000 ApiTestFuzzer::Fuzz(); 7001 p_getter_count2++; 7002 v8::Handle<v8::Object> global = Context::GetCurrent()->Global(); 7003 CHECK_EQ(info.Holder(), global->Get(v8_str("o1"))); 7004 if (name->Equals(v8_str("p1"))) { 7005 CHECK_EQ(info.This(), global->Get(v8_str("o1"))); 7006 } else if (name->Equals(v8_str("p2"))) { 7007 CHECK_EQ(info.This(), global->Get(v8_str("o2"))); 7008 } else if (name->Equals(v8_str("p3"))) { 7009 CHECK_EQ(info.This(), global->Get(v8_str("o3"))); 7010 } else if (name->Equals(v8_str("p4"))) { 7011 CHECK_EQ(info.This(), global->Get(v8_str("o4"))); 7012 } 7013 } 7014 7015 7016 THREADED_TEST(GetterHolders) { 7017 v8::HandleScope scope(v8::Isolate::GetCurrent()); 7018 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 7019 obj->SetAccessor(v8_str("p1"), PGetter); 7020 obj->SetAccessor(v8_str("p2"), PGetter); 7021 obj->SetAccessor(v8_str("p3"), PGetter); 7022 obj->SetAccessor(v8_str("p4"), PGetter); 7023 p_getter_count = 0; 7024 RunHolderTest(obj); 7025 CHECK_EQ(40, p_getter_count); 7026 } 7027 7028 7029 THREADED_TEST(PreInterceptorHolders) { 7030 v8::HandleScope scope(v8::Isolate::GetCurrent()); 7031 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 7032 obj->SetNamedPropertyHandler(PGetter2); 7033 p_getter_count2 = 0; 7034 RunHolderTest(obj); 7035 CHECK_EQ(40, p_getter_count2); 7036 } 7037 7038 7039 THREADED_TEST(ObjectInstantiation) { 7040 v8::HandleScope scope(v8::Isolate::GetCurrent()); 7041 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 7042 templ->SetAccessor(v8_str("t"), PGetter2); 7043 LocalContext context; 7044 context->Global()->Set(v8_str("o"), templ->NewInstance()); 7045 for (int i = 0; i < 100; i++) { 7046 v8::HandleScope inner_scope(v8::Isolate::GetCurrent()); 7047 v8::Handle<v8::Object> obj = templ->NewInstance(); 7048 CHECK_NE(obj, context->Global()->Get(v8_str("o"))); 7049 context->Global()->Set(v8_str("o2"), obj); 7050 v8::Handle<Value> value = 7051 Script::Compile(v8_str("o.__proto__ === o2.__proto__"))->Run(); 7052 CHECK_EQ(v8::True(), value); 7053 context->Global()->Set(v8_str("o"), obj); 7054 } 7055 } 7056 7057 7058 static int StrCmp16(uint16_t* a, uint16_t* b) { 7059 while (true) { 7060 if (*a == 0 && *b == 0) return 0; 7061 if (*a != *b) return 0 + *a - *b; 7062 a++; 7063 b++; 7064 } 7065 } 7066 7067 7068 static int StrNCmp16(uint16_t* a, uint16_t* b, int n) { 7069 while (true) { 7070 if (n-- == 0) return 0; 7071 if (*a == 0 && *b == 0) return 0; 7072 if (*a != *b) return 0 + *a - *b; 7073 a++; 7074 b++; 7075 } 7076 } 7077 7078 7079 int GetUtf8Length(Handle<String> str) { 7080 int len = str->Utf8Length(); 7081 if (len < 0) { 7082 i::Handle<i::String> istr(v8::Utils::OpenHandle(*str)); 7083 i::FlattenString(istr); 7084 len = str->Utf8Length(); 7085 } 7086 return len; 7087 } 7088 7089 7090 THREADED_TEST(StringWrite) { 7091 LocalContext context; 7092 v8::HandleScope scope(context->GetIsolate()); 7093 v8::Handle<String> str = v8_str("abcde"); 7094 // abc<Icelandic eth><Unicode snowman>. 7095 v8::Handle<String> str2 = v8_str("abc\303\260\342\230\203"); 7096 v8::Handle<String> str3 = v8::String::New("abc\0def", 7); 7097 const int kStride = 4; // Must match stride in for loops in JS below. 7098 CompileRun( 7099 "var left = '';" 7100 "for (var i = 0; i < 0xd800; i += 4) {" 7101 " left = left + String.fromCharCode(i);" 7102 "}"); 7103 CompileRun( 7104 "var right = '';" 7105 "for (var i = 0; i < 0xd800; i += 4) {" 7106 " right = String.fromCharCode(i) + right;" 7107 "}"); 7108 v8::Handle<v8::Object> global = Context::GetCurrent()->Global(); 7109 Handle<String> left_tree = global->Get(v8_str("left")).As<String>(); 7110 Handle<String> right_tree = global->Get(v8_str("right")).As<String>(); 7111 7112 CHECK_EQ(5, str2->Length()); 7113 CHECK_EQ(0xd800 / kStride, left_tree->Length()); 7114 CHECK_EQ(0xd800 / kStride, right_tree->Length()); 7115 7116 char buf[100]; 7117 char utf8buf[0xd800 * 3]; 7118 uint16_t wbuf[100]; 7119 int len; 7120 int charlen; 7121 7122 memset(utf8buf, 0x1, 1000); 7123 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen); 7124 CHECK_EQ(9, len); 7125 CHECK_EQ(5, charlen); 7126 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 7127 7128 memset(utf8buf, 0x1, 1000); 7129 len = str2->WriteUtf8(utf8buf, 8, &charlen); 7130 CHECK_EQ(8, len); 7131 CHECK_EQ(5, charlen); 7132 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203\1", 9)); 7133 7134 memset(utf8buf, 0x1, 1000); 7135 len = str2->WriteUtf8(utf8buf, 7, &charlen); 7136 CHECK_EQ(5, len); 7137 CHECK_EQ(4, charlen); 7138 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 7139 7140 memset(utf8buf, 0x1, 1000); 7141 len = str2->WriteUtf8(utf8buf, 6, &charlen); 7142 CHECK_EQ(5, len); 7143 CHECK_EQ(4, charlen); 7144 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 7145 7146 memset(utf8buf, 0x1, 1000); 7147 len = str2->WriteUtf8(utf8buf, 5, &charlen); 7148 CHECK_EQ(5, len); 7149 CHECK_EQ(4, charlen); 7150 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\1", 5)); 7151 7152 memset(utf8buf, 0x1, 1000); 7153 len = str2->WriteUtf8(utf8buf, 4, &charlen); 7154 CHECK_EQ(3, len); 7155 CHECK_EQ(3, charlen); 7156 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 7157 7158 memset(utf8buf, 0x1, 1000); 7159 len = str2->WriteUtf8(utf8buf, 3, &charlen); 7160 CHECK_EQ(3, len); 7161 CHECK_EQ(3, charlen); 7162 CHECK_EQ(0, strncmp(utf8buf, "abc\1", 4)); 7163 7164 memset(utf8buf, 0x1, 1000); 7165 len = str2->WriteUtf8(utf8buf, 2, &charlen); 7166 CHECK_EQ(2, len); 7167 CHECK_EQ(2, charlen); 7168 CHECK_EQ(0, strncmp(utf8buf, "ab\1", 3)); 7169 7170 memset(utf8buf, 0x1, sizeof(utf8buf)); 7171 len = GetUtf8Length(left_tree); 7172 int utf8_expected = 7173 (0x80 + (0x800 - 0x80) * 2 + (0xd800 - 0x800) * 3) / kStride; 7174 CHECK_EQ(utf8_expected, len); 7175 len = left_tree->WriteUtf8(utf8buf, utf8_expected, &charlen); 7176 CHECK_EQ(utf8_expected, len); 7177 CHECK_EQ(0xd800 / kStride, charlen); 7178 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[utf8_expected - 3])); 7179 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[utf8_expected - 2])); 7180 CHECK_EQ(0xc0 - kStride, 7181 static_cast<unsigned char>(utf8buf[utf8_expected - 1])); 7182 CHECK_EQ(1, utf8buf[utf8_expected]); 7183 7184 memset(utf8buf, 0x1, sizeof(utf8buf)); 7185 len = GetUtf8Length(right_tree); 7186 CHECK_EQ(utf8_expected, len); 7187 len = right_tree->WriteUtf8(utf8buf, utf8_expected, &charlen); 7188 CHECK_EQ(utf8_expected, len); 7189 CHECK_EQ(0xd800 / kStride, charlen); 7190 CHECK_EQ(0xed, static_cast<unsigned char>(utf8buf[0])); 7191 CHECK_EQ(0x9f, static_cast<unsigned char>(utf8buf[1])); 7192 CHECK_EQ(0xc0 - kStride, static_cast<unsigned char>(utf8buf[2])); 7193 CHECK_EQ(1, utf8buf[utf8_expected]); 7194 7195 memset(buf, 0x1, sizeof(buf)); 7196 memset(wbuf, 0x1, sizeof(wbuf)); 7197 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 7198 CHECK_EQ(5, len); 7199 len = str->Write(wbuf); 7200 CHECK_EQ(5, len); 7201 CHECK_EQ(0, strcmp("abcde", buf)); 7202 uint16_t answer1[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 7203 CHECK_EQ(0, StrCmp16(answer1, wbuf)); 7204 7205 memset(buf, 0x1, sizeof(buf)); 7206 memset(wbuf, 0x1, sizeof(wbuf)); 7207 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 4); 7208 CHECK_EQ(4, len); 7209 len = str->Write(wbuf, 0, 4); 7210 CHECK_EQ(4, len); 7211 CHECK_EQ(0, strncmp("abcd\1", buf, 5)); 7212 uint16_t answer2[] = {'a', 'b', 'c', 'd', 0x101}; 7213 CHECK_EQ(0, StrNCmp16(answer2, wbuf, 5)); 7214 7215 memset(buf, 0x1, sizeof(buf)); 7216 memset(wbuf, 0x1, sizeof(wbuf)); 7217 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 5); 7218 CHECK_EQ(5, len); 7219 len = str->Write(wbuf, 0, 5); 7220 CHECK_EQ(5, len); 7221 CHECK_EQ(0, strncmp("abcde\1", buf, 6)); 7222 uint16_t answer3[] = {'a', 'b', 'c', 'd', 'e', 0x101}; 7223 CHECK_EQ(0, StrNCmp16(answer3, wbuf, 6)); 7224 7225 memset(buf, 0x1, sizeof(buf)); 7226 memset(wbuf, 0x1, sizeof(wbuf)); 7227 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 0, 6); 7228 CHECK_EQ(5, len); 7229 len = str->Write(wbuf, 0, 6); 7230 CHECK_EQ(5, len); 7231 CHECK_EQ(0, strcmp("abcde", buf)); 7232 uint16_t answer4[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 7233 CHECK_EQ(0, StrCmp16(answer4, wbuf)); 7234 7235 memset(buf, 0x1, sizeof(buf)); 7236 memset(wbuf, 0x1, sizeof(wbuf)); 7237 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, -1); 7238 CHECK_EQ(1, len); 7239 len = str->Write(wbuf, 4, -1); 7240 CHECK_EQ(1, len); 7241 CHECK_EQ(0, strcmp("e", buf)); 7242 uint16_t answer5[] = {'e', '\0'}; 7243 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 7244 7245 memset(buf, 0x1, sizeof(buf)); 7246 memset(wbuf, 0x1, sizeof(wbuf)); 7247 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 6); 7248 CHECK_EQ(1, len); 7249 len = str->Write(wbuf, 4, 6); 7250 CHECK_EQ(1, len); 7251 CHECK_EQ(0, strcmp("e", buf)); 7252 CHECK_EQ(0, StrCmp16(answer5, wbuf)); 7253 7254 memset(buf, 0x1, sizeof(buf)); 7255 memset(wbuf, 0x1, sizeof(wbuf)); 7256 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 4, 1); 7257 CHECK_EQ(1, len); 7258 len = str->Write(wbuf, 4, 1); 7259 CHECK_EQ(1, len); 7260 CHECK_EQ(0, strncmp("e\1", buf, 2)); 7261 uint16_t answer6[] = {'e', 0x101}; 7262 CHECK_EQ(0, StrNCmp16(answer6, wbuf, 2)); 7263 7264 memset(buf, 0x1, sizeof(buf)); 7265 memset(wbuf, 0x1, sizeof(wbuf)); 7266 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 3, 1); 7267 CHECK_EQ(1, len); 7268 len = str->Write(wbuf, 3, 1); 7269 CHECK_EQ(1, len); 7270 CHECK_EQ(0, strncmp("d\1", buf, 2)); 7271 uint16_t answer7[] = {'d', 0x101}; 7272 CHECK_EQ(0, StrNCmp16(answer7, wbuf, 2)); 7273 7274 memset(wbuf, 0x1, sizeof(wbuf)); 7275 wbuf[5] = 'X'; 7276 len = str->Write(wbuf, 0, 6, String::NO_NULL_TERMINATION); 7277 CHECK_EQ(5, len); 7278 CHECK_EQ('X', wbuf[5]); 7279 uint16_t answer8a[] = {'a', 'b', 'c', 'd', 'e'}; 7280 uint16_t answer8b[] = {'a', 'b', 'c', 'd', 'e', '\0'}; 7281 CHECK_EQ(0, StrNCmp16(answer8a, wbuf, 5)); 7282 CHECK_NE(0, StrCmp16(answer8b, wbuf)); 7283 wbuf[5] = '\0'; 7284 CHECK_EQ(0, StrCmp16(answer8b, wbuf)); 7285 7286 memset(buf, 0x1, sizeof(buf)); 7287 buf[5] = 'X'; 7288 len = str->WriteOneByte(reinterpret_cast<uint8_t*>(buf), 7289 0, 7290 6, 7291 String::NO_NULL_TERMINATION); 7292 CHECK_EQ(5, len); 7293 CHECK_EQ('X', buf[5]); 7294 CHECK_EQ(0, strncmp("abcde", buf, 5)); 7295 CHECK_NE(0, strcmp("abcde", buf)); 7296 buf[5] = '\0'; 7297 CHECK_EQ(0, strcmp("abcde", buf)); 7298 7299 memset(utf8buf, 0x1, sizeof(utf8buf)); 7300 utf8buf[8] = 'X'; 7301 len = str2->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen, 7302 String::NO_NULL_TERMINATION); 7303 CHECK_EQ(8, len); 7304 CHECK_EQ('X', utf8buf[8]); 7305 CHECK_EQ(5, charlen); 7306 CHECK_EQ(0, strncmp(utf8buf, "abc\303\260\342\230\203", 8)); 7307 CHECK_NE(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 7308 utf8buf[8] = '\0'; 7309 CHECK_EQ(0, strcmp(utf8buf, "abc\303\260\342\230\203")); 7310 7311 memset(utf8buf, 0x1, sizeof(utf8buf)); 7312 utf8buf[5] = 'X'; 7313 len = str->WriteUtf8(utf8buf, sizeof(utf8buf), &charlen, 7314 String::NO_NULL_TERMINATION); 7315 CHECK_EQ(5, len); 7316 CHECK_EQ('X', utf8buf[5]); // Test that the sixth character is untouched. 7317 CHECK_EQ(5, charlen); 7318 utf8buf[5] = '\0'; 7319 CHECK_EQ(0, strcmp(utf8buf, "abcde")); 7320 7321 memset(buf, 0x1, sizeof(buf)); 7322 len = str3->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 7323 CHECK_EQ(7, len); 7324 CHECK_EQ(0, strcmp("abc", buf)); 7325 CHECK_EQ(0, buf[3]); 7326 CHECK_EQ(0, strcmp("def", buf + 4)); 7327 7328 CHECK_EQ(0, str->WriteOneByte(NULL, 0, 0, String::NO_NULL_TERMINATION)); 7329 CHECK_EQ(0, str->WriteUtf8(NULL, 0, 0, String::NO_NULL_TERMINATION)); 7330 CHECK_EQ(0, str->Write(NULL, 0, 0, String::NO_NULL_TERMINATION)); 7331 } 7332 7333 7334 static void Utf16Helper( 7335 LocalContext& context, 7336 const char* name, 7337 const char* lengths_name, 7338 int len) { 7339 Local<v8::Array> a = 7340 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name))); 7341 Local<v8::Array> alens = 7342 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name))); 7343 for (int i = 0; i < len; i++) { 7344 Local<v8::String> string = 7345 Local<v8::String>::Cast(a->Get(i)); 7346 Local<v8::Number> expected_len = 7347 Local<v8::Number>::Cast(alens->Get(i)); 7348 int length = GetUtf8Length(string); 7349 CHECK_EQ(static_cast<int>(expected_len->Value()), length); 7350 } 7351 } 7352 7353 7354 static uint16_t StringGet(Handle<String> str, int index) { 7355 i::Handle<i::String> istring = 7356 v8::Utils::OpenHandle(String::Cast(*str)); 7357 return istring->Get(index); 7358 } 7359 7360 7361 static void WriteUtf8Helper( 7362 LocalContext& context, 7363 const char* name, 7364 const char* lengths_name, 7365 int len) { 7366 Local<v8::Array> b = 7367 Local<v8::Array>::Cast(context->Global()->Get(v8_str(name))); 7368 Local<v8::Array> alens = 7369 Local<v8::Array>::Cast(context->Global()->Get(v8_str(lengths_name))); 7370 char buffer[1000]; 7371 char buffer2[1000]; 7372 for (int i = 0; i < len; i++) { 7373 Local<v8::String> string = 7374 Local<v8::String>::Cast(b->Get(i)); 7375 Local<v8::Number> expected_len = 7376 Local<v8::Number>::Cast(alens->Get(i)); 7377 int utf8_length = static_cast<int>(expected_len->Value()); 7378 for (int j = utf8_length + 1; j >= 0; j--) { 7379 memset(reinterpret_cast<void*>(&buffer), 42, sizeof(buffer)); 7380 memset(reinterpret_cast<void*>(&buffer2), 42, sizeof(buffer2)); 7381 int nchars; 7382 int utf8_written = 7383 string->WriteUtf8(buffer, j, &nchars, String::NO_OPTIONS); 7384 int utf8_written2 = 7385 string->WriteUtf8(buffer2, j, &nchars, String::NO_NULL_TERMINATION); 7386 CHECK_GE(utf8_length + 1, utf8_written); 7387 CHECK_GE(utf8_length, utf8_written2); 7388 for (int k = 0; k < utf8_written2; k++) { 7389 CHECK_EQ(buffer[k], buffer2[k]); 7390 } 7391 CHECK(nchars * 3 >= utf8_written - 1); 7392 CHECK(nchars <= utf8_written); 7393 if (j == utf8_length + 1) { 7394 CHECK_EQ(utf8_written2, utf8_length); 7395 CHECK_EQ(utf8_written2 + 1, utf8_written); 7396 } 7397 CHECK_EQ(buffer[utf8_written], 42); 7398 if (j > utf8_length) { 7399 if (utf8_written != 0) CHECK_EQ(buffer[utf8_written - 1], 0); 7400 if (utf8_written > 1) CHECK_NE(buffer[utf8_written - 2], 42); 7401 Handle<String> roundtrip = v8_str(buffer); 7402 CHECK(roundtrip->Equals(string)); 7403 } else { 7404 if (utf8_written != 0) CHECK_NE(buffer[utf8_written - 1], 42); 7405 } 7406 if (utf8_written2 != 0) CHECK_NE(buffer[utf8_written - 1], 42); 7407 if (nchars >= 2) { 7408 uint16_t trail = StringGet(string, nchars - 1); 7409 uint16_t lead = StringGet(string, nchars - 2); 7410 if (((lead & 0xfc00) == 0xd800) && 7411 ((trail & 0xfc00) == 0xdc00)) { 7412 unsigned char u1 = buffer2[utf8_written2 - 4]; 7413 unsigned char u2 = buffer2[utf8_written2 - 3]; 7414 unsigned char u3 = buffer2[utf8_written2 - 2]; 7415 unsigned char u4 = buffer2[utf8_written2 - 1]; 7416 CHECK_EQ((u1 & 0xf8), 0xf0); 7417 CHECK_EQ((u2 & 0xc0), 0x80); 7418 CHECK_EQ((u3 & 0xc0), 0x80); 7419 CHECK_EQ((u4 & 0xc0), 0x80); 7420 uint32_t c = 0x10000 + ((lead & 0x3ff) << 10) + (trail & 0x3ff); 7421 CHECK_EQ((u4 & 0x3f), (c & 0x3f)); 7422 CHECK_EQ((u3 & 0x3f), ((c >> 6) & 0x3f)); 7423 CHECK_EQ((u2 & 0x3f), ((c >> 12) & 0x3f)); 7424 CHECK_EQ((u1 & 0x3), c >> 18); 7425 } 7426 } 7427 } 7428 } 7429 } 7430 7431 7432 THREADED_TEST(Utf16) { 7433 LocalContext context; 7434 v8::HandleScope scope(context->GetIsolate()); 7435 CompileRun( 7436 "var pad = '01234567890123456789';" 7437 "var p = [];" 7438 "var plens = [20, 3, 3];" 7439 "p.push('01234567890123456789');" 7440 "var lead = 0xd800;" 7441 "var trail = 0xdc00;" 7442 "p.push(String.fromCharCode(0xd800));" 7443 "p.push(String.fromCharCode(0xdc00));" 7444 "var a = [];" 7445 "var b = [];" 7446 "var c = [];" 7447 "var alens = [];" 7448 "for (var i = 0; i < 3; i++) {" 7449 " p[1] = String.fromCharCode(lead++);" 7450 " for (var j = 0; j < 3; j++) {" 7451 " p[2] = String.fromCharCode(trail++);" 7452 " a.push(p[i] + p[j]);" 7453 " b.push(p[i] + p[j]);" 7454 " c.push(p[i] + p[j]);" 7455 " alens.push(plens[i] + plens[j]);" 7456 " }" 7457 "}" 7458 "alens[5] -= 2;" // Here the surrogate pairs match up. 7459 "var a2 = [];" 7460 "var b2 = [];" 7461 "var c2 = [];" 7462 "var a2lens = [];" 7463 "for (var m = 0; m < 9; m++) {" 7464 " for (var n = 0; n < 9; n++) {" 7465 " a2.push(a[m] + a[n]);" 7466 " b2.push(b[m] + b[n]);" 7467 " var newc = 'x' + c[m] + c[n] + 'y';" 7468 " c2.push(newc.substring(1, newc.length - 1));" 7469 " var utf = alens[m] + alens[n];" // And here. 7470 // The 'n's that start with 0xdc.. are 6-8 7471 // The 'm's that end with 0xd8.. are 1, 4 and 7 7472 " if ((m % 3) == 1 && n >= 6) utf -= 2;" 7473 " a2lens.push(utf);" 7474 " }" 7475 "}"); 7476 Utf16Helper(context, "a", "alens", 9); 7477 Utf16Helper(context, "a2", "a2lens", 81); 7478 WriteUtf8Helper(context, "b", "alens", 9); 7479 WriteUtf8Helper(context, "b2", "a2lens", 81); 7480 WriteUtf8Helper(context, "c2", "a2lens", 81); 7481 } 7482 7483 7484 static bool SameSymbol(Handle<String> s1, Handle<String> s2) { 7485 i::Handle<i::String> is1(v8::Utils::OpenHandle(*s1)); 7486 i::Handle<i::String> is2(v8::Utils::OpenHandle(*s2)); 7487 return *is1 == *is2; 7488 } 7489 7490 7491 static void SameSymbolHelper(const char* a, const char* b) { 7492 Handle<String> symbol1 = v8::String::NewSymbol(a); 7493 Handle<String> symbol2 = v8::String::NewSymbol(b); 7494 CHECK(SameSymbol(symbol1, symbol2)); 7495 } 7496 7497 7498 THREADED_TEST(Utf16Symbol) { 7499 LocalContext context; 7500 v8::HandleScope scope(context->GetIsolate()); 7501 7502 Handle<String> symbol1 = v8::String::NewSymbol("abc"); 7503 Handle<String> symbol2 = v8::String::NewSymbol("abc"); 7504 CHECK(SameSymbol(symbol1, symbol2)); 7505 7506 SameSymbolHelper("\360\220\220\205", // 4 byte encoding. 7507 "\355\240\201\355\260\205"); // 2 3-byte surrogates. 7508 SameSymbolHelper("\355\240\201\355\260\206", // 2 3-byte surrogates. 7509 "\360\220\220\206"); // 4 byte encoding. 7510 SameSymbolHelper("x\360\220\220\205", // 4 byte encoding. 7511 "x\355\240\201\355\260\205"); // 2 3-byte surrogates. 7512 SameSymbolHelper("x\355\240\201\355\260\206", // 2 3-byte surrogates. 7513 "x\360\220\220\206"); // 4 byte encoding. 7514 CompileRun( 7515 "var sym0 = 'benedictus';" 7516 "var sym0b = 'S\303\270ren';" 7517 "var sym1 = '\355\240\201\355\260\207';" 7518 "var sym2 = '\360\220\220\210';" 7519 "var sym3 = 'x\355\240\201\355\260\207';" 7520 "var sym4 = 'x\360\220\220\210';" 7521 "if (sym1.length != 2) throw sym1;" 7522 "if (sym1.charCodeAt(1) != 0xdc07) throw sym1.charCodeAt(1);" 7523 "if (sym2.length != 2) throw sym2;" 7524 "if (sym2.charCodeAt(1) != 0xdc08) throw sym2.charCodeAt(2);" 7525 "if (sym3.length != 3) throw sym3;" 7526 "if (sym3.charCodeAt(2) != 0xdc07) throw sym1.charCodeAt(2);" 7527 "if (sym4.length != 3) throw sym4;" 7528 "if (sym4.charCodeAt(2) != 0xdc08) throw sym2.charCodeAt(2);"); 7529 Handle<String> sym0 = v8::String::NewSymbol("benedictus"); 7530 Handle<String> sym0b = v8::String::NewSymbol("S\303\270ren"); 7531 Handle<String> sym1 = v8::String::NewSymbol("\355\240\201\355\260\207"); 7532 Handle<String> sym2 = v8::String::NewSymbol("\360\220\220\210"); 7533 Handle<String> sym3 = v8::String::NewSymbol("x\355\240\201\355\260\207"); 7534 Handle<String> sym4 = v8::String::NewSymbol("x\360\220\220\210"); 7535 v8::Local<v8::Object> global = context->Global(); 7536 Local<Value> s0 = global->Get(v8_str("sym0")); 7537 Local<Value> s0b = global->Get(v8_str("sym0b")); 7538 Local<Value> s1 = global->Get(v8_str("sym1")); 7539 Local<Value> s2 = global->Get(v8_str("sym2")); 7540 Local<Value> s3 = global->Get(v8_str("sym3")); 7541 Local<Value> s4 = global->Get(v8_str("sym4")); 7542 CHECK(SameSymbol(sym0, Handle<String>::Cast(s0))); 7543 CHECK(SameSymbol(sym0b, Handle<String>::Cast(s0b))); 7544 CHECK(SameSymbol(sym1, Handle<String>::Cast(s1))); 7545 CHECK(SameSymbol(sym2, Handle<String>::Cast(s2))); 7546 CHECK(SameSymbol(sym3, Handle<String>::Cast(s3))); 7547 CHECK(SameSymbol(sym4, Handle<String>::Cast(s4))); 7548 } 7549 7550 7551 THREADED_TEST(ToArrayIndex) { 7552 LocalContext context; 7553 v8::HandleScope scope(context->GetIsolate()); 7554 7555 v8::Handle<String> str = v8_str("42"); 7556 v8::Handle<v8::Uint32> index = str->ToArrayIndex(); 7557 CHECK(!index.IsEmpty()); 7558 CHECK_EQ(42.0, index->Uint32Value()); 7559 str = v8_str("42asdf"); 7560 index = str->ToArrayIndex(); 7561 CHECK(index.IsEmpty()); 7562 str = v8_str("-42"); 7563 index = str->ToArrayIndex(); 7564 CHECK(index.IsEmpty()); 7565 str = v8_str("4294967295"); 7566 index = str->ToArrayIndex(); 7567 CHECK(!index.IsEmpty()); 7568 CHECK_EQ(4294967295.0, index->Uint32Value()); 7569 v8::Handle<v8::Number> num = v8::Number::New(1); 7570 index = num->ToArrayIndex(); 7571 CHECK(!index.IsEmpty()); 7572 CHECK_EQ(1.0, index->Uint32Value()); 7573 num = v8::Number::New(-1); 7574 index = num->ToArrayIndex(); 7575 CHECK(index.IsEmpty()); 7576 v8::Handle<v8::Object> obj = v8::Object::New(); 7577 index = obj->ToArrayIndex(); 7578 CHECK(index.IsEmpty()); 7579 } 7580 7581 7582 THREADED_TEST(ErrorConstruction) { 7583 LocalContext context; 7584 v8::HandleScope scope(context->GetIsolate()); 7585 7586 v8::Handle<String> foo = v8_str("foo"); 7587 v8::Handle<String> message = v8_str("message"); 7588 v8::Handle<Value> range_error = v8::Exception::RangeError(foo); 7589 CHECK(range_error->IsObject()); 7590 CHECK(range_error.As<v8::Object>()->Get(message)->Equals(foo)); 7591 v8::Handle<Value> reference_error = v8::Exception::ReferenceError(foo); 7592 CHECK(reference_error->IsObject()); 7593 CHECK(reference_error.As<v8::Object>()->Get(message)->Equals(foo)); 7594 v8::Handle<Value> syntax_error = v8::Exception::SyntaxError(foo); 7595 CHECK(syntax_error->IsObject()); 7596 CHECK(syntax_error.As<v8::Object>()->Get(message)->Equals(foo)); 7597 v8::Handle<Value> type_error = v8::Exception::TypeError(foo); 7598 CHECK(type_error->IsObject()); 7599 CHECK(type_error.As<v8::Object>()->Get(message)->Equals(foo)); 7600 v8::Handle<Value> error = v8::Exception::Error(foo); 7601 CHECK(error->IsObject()); 7602 CHECK(error.As<v8::Object>()->Get(message)->Equals(foo)); 7603 } 7604 7605 7606 static void YGetter(Local<String> name, 7607 const v8::PropertyCallbackInfo<v8::Value>& info) { 7608 ApiTestFuzzer::Fuzz(); 7609 info.GetReturnValue().Set(v8_num(10)); 7610 } 7611 7612 7613 static void YSetter(Local<String> name, 7614 Local<Value> value, 7615 const v8::PropertyCallbackInfo<void>& info) { 7616 if (info.This()->Has(name)) { 7617 info.This()->Delete(name); 7618 } 7619 info.This()->Set(name, value); 7620 } 7621 7622 7623 THREADED_TEST(DeleteAccessor) { 7624 v8::HandleScope scope(v8::Isolate::GetCurrent()); 7625 v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(); 7626 obj->SetAccessor(v8_str("y"), YGetter, YSetter); 7627 LocalContext context; 7628 v8::Handle<v8::Object> holder = obj->NewInstance(); 7629 context->Global()->Set(v8_str("holder"), holder); 7630 v8::Handle<Value> result = CompileRun( 7631 "holder.y = 11; holder.y = 12; holder.y"); 7632 CHECK_EQ(12, result->Uint32Value()); 7633 } 7634 7635 7636 THREADED_TEST(TypeSwitch) { 7637 v8::HandleScope scope(v8::Isolate::GetCurrent()); 7638 v8::Handle<v8::FunctionTemplate> templ1 = v8::FunctionTemplate::New(); 7639 v8::Handle<v8::FunctionTemplate> templ2 = v8::FunctionTemplate::New(); 7640 v8::Handle<v8::FunctionTemplate> templ3 = v8::FunctionTemplate::New(); 7641 v8::Handle<v8::FunctionTemplate> templs[3] = { templ1, templ2, templ3 }; 7642 v8::Handle<v8::TypeSwitch> type_switch = v8::TypeSwitch::New(3, templs); 7643 LocalContext context; 7644 v8::Handle<v8::Object> obj0 = v8::Object::New(); 7645 v8::Handle<v8::Object> obj1 = templ1->GetFunction()->NewInstance(); 7646 v8::Handle<v8::Object> obj2 = templ2->GetFunction()->NewInstance(); 7647 v8::Handle<v8::Object> obj3 = templ3->GetFunction()->NewInstance(); 7648 for (int i = 0; i < 10; i++) { 7649 CHECK_EQ(0, type_switch->match(obj0)); 7650 CHECK_EQ(1, type_switch->match(obj1)); 7651 CHECK_EQ(2, type_switch->match(obj2)); 7652 CHECK_EQ(3, type_switch->match(obj3)); 7653 CHECK_EQ(3, type_switch->match(obj3)); 7654 CHECK_EQ(2, type_switch->match(obj2)); 7655 CHECK_EQ(1, type_switch->match(obj1)); 7656 CHECK_EQ(0, type_switch->match(obj0)); 7657 } 7658 } 7659 7660 7661 // For use within the TestSecurityHandler() test. 7662 static bool g_security_callback_result = false; 7663 static bool NamedSecurityTestCallback(Local<v8::Object> global, 7664 Local<Value> name, 7665 v8::AccessType type, 7666 Local<Value> data) { 7667 // Always allow read access. 7668 if (type == v8::ACCESS_GET) 7669 return true; 7670 7671 // Sometimes allow other access. 7672 return g_security_callback_result; 7673 } 7674 7675 7676 static bool IndexedSecurityTestCallback(Local<v8::Object> global, 7677 uint32_t key, 7678 v8::AccessType type, 7679 Local<Value> data) { 7680 // Always allow read access. 7681 if (type == v8::ACCESS_GET) 7682 return true; 7683 7684 // Sometimes allow other access. 7685 return g_security_callback_result; 7686 } 7687 7688 7689 static int trouble_nesting = 0; 7690 static void TroubleCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 7691 ApiTestFuzzer::Fuzz(); 7692 trouble_nesting++; 7693 7694 // Call a JS function that throws an uncaught exception. 7695 Local<v8::Object> arg_this = Context::GetCurrent()->Global(); 7696 Local<Value> trouble_callee = (trouble_nesting == 3) ? 7697 arg_this->Get(v8_str("trouble_callee")) : 7698 arg_this->Get(v8_str("trouble_caller")); 7699 CHECK(trouble_callee->IsFunction()); 7700 args.GetReturnValue().Set( 7701 Function::Cast(*trouble_callee)->Call(arg_this, 0, NULL)); 7702 } 7703 7704 7705 static int report_count = 0; 7706 static void ApiUncaughtExceptionTestListener(v8::Handle<v8::Message>, 7707 v8::Handle<Value>) { 7708 report_count++; 7709 } 7710 7711 7712 // Counts uncaught exceptions, but other tests running in parallel 7713 // also have uncaught exceptions. 7714 TEST(ApiUncaughtException) { 7715 report_count = 0; 7716 LocalContext env; 7717 v8::HandleScope scope(env->GetIsolate()); 7718 v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener); 7719 7720 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback); 7721 v8::Local<v8::Object> global = env->Global(); 7722 global->Set(v8_str("trouble"), fun->GetFunction()); 7723 7724 Script::Compile(v8_str("function trouble_callee() {" 7725 " var x = null;" 7726 " return x.foo;" 7727 "};" 7728 "function trouble_caller() {" 7729 " trouble();" 7730 "};"))->Run(); 7731 Local<Value> trouble = global->Get(v8_str("trouble")); 7732 CHECK(trouble->IsFunction()); 7733 Local<Value> trouble_callee = global->Get(v8_str("trouble_callee")); 7734 CHECK(trouble_callee->IsFunction()); 7735 Local<Value> trouble_caller = global->Get(v8_str("trouble_caller")); 7736 CHECK(trouble_caller->IsFunction()); 7737 Function::Cast(*trouble_caller)->Call(global, 0, NULL); 7738 CHECK_EQ(1, report_count); 7739 v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener); 7740 } 7741 7742 static const char* script_resource_name = "ExceptionInNativeScript.js"; 7743 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message, 7744 v8::Handle<Value>) { 7745 v8::Handle<v8::Value> name_val = message->GetScriptResourceName(); 7746 CHECK(!name_val.IsEmpty() && name_val->IsString()); 7747 v8::String::Utf8Value name(message->GetScriptResourceName()); 7748 CHECK_EQ(script_resource_name, *name); 7749 CHECK_EQ(3, message->GetLineNumber()); 7750 v8::String::Utf8Value source_line(message->GetSourceLine()); 7751 CHECK_EQ(" new o.foo();", *source_line); 7752 } 7753 7754 7755 TEST(ExceptionInNativeScript) { 7756 LocalContext env; 7757 v8::HandleScope scope(env->GetIsolate()); 7758 v8::V8::AddMessageListener(ExceptionInNativeScriptTestListener); 7759 7760 Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(TroubleCallback); 7761 v8::Local<v8::Object> global = env->Global(); 7762 global->Set(v8_str("trouble"), fun->GetFunction()); 7763 7764 Script::Compile(v8_str("function trouble() {\n" 7765 " var o = {};\n" 7766 " new o.foo();\n" 7767 "};"), v8::String::New(script_resource_name))->Run(); 7768 Local<Value> trouble = global->Get(v8_str("trouble")); 7769 CHECK(trouble->IsFunction()); 7770 Function::Cast(*trouble)->Call(global, 0, NULL); 7771 v8::V8::RemoveMessageListeners(ExceptionInNativeScriptTestListener); 7772 } 7773 7774 7775 TEST(CompilationErrorUsingTryCatchHandler) { 7776 LocalContext env; 7777 v8::HandleScope scope(env->GetIsolate()); 7778 v8::TryCatch try_catch; 7779 Script::Compile(v8_str("This doesn't &*&@#$&*^ compile.")); 7780 CHECK_NE(NULL, *try_catch.Exception()); 7781 CHECK(try_catch.HasCaught()); 7782 } 7783 7784 7785 TEST(TryCatchFinallyUsingTryCatchHandler) { 7786 LocalContext env; 7787 v8::HandleScope scope(env->GetIsolate()); 7788 v8::TryCatch try_catch; 7789 Script::Compile(v8_str("try { throw ''; } catch (e) {}"))->Run(); 7790 CHECK(!try_catch.HasCaught()); 7791 Script::Compile(v8_str("try { throw ''; } finally {}"))->Run(); 7792 CHECK(try_catch.HasCaught()); 7793 try_catch.Reset(); 7794 Script::Compile(v8_str("(function() {" 7795 "try { throw ''; } finally { return; }" 7796 "})()"))->Run(); 7797 CHECK(!try_catch.HasCaught()); 7798 Script::Compile(v8_str("(function()" 7799 " { try { throw ''; } finally { throw 0; }" 7800 "})()"))->Run(); 7801 CHECK(try_catch.HasCaught()); 7802 } 7803 7804 7805 // SecurityHandler can't be run twice 7806 TEST(SecurityHandler) { 7807 v8::HandleScope scope0(v8::Isolate::GetCurrent()); 7808 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 7809 global_template->SetAccessCheckCallbacks(NamedSecurityTestCallback, 7810 IndexedSecurityTestCallback); 7811 // Create an environment 7812 v8::Handle<Context> context0 = 7813 Context::New(v8::Isolate::GetCurrent(), NULL, global_template); 7814 context0->Enter(); 7815 7816 v8::Handle<v8::Object> global0 = context0->Global(); 7817 v8::Handle<Script> script0 = v8_compile("foo = 111"); 7818 script0->Run(); 7819 global0->Set(v8_str("0"), v8_num(999)); 7820 v8::Handle<Value> foo0 = global0->Get(v8_str("foo")); 7821 CHECK_EQ(111, foo0->Int32Value()); 7822 v8::Handle<Value> z0 = global0->Get(v8_str("0")); 7823 CHECK_EQ(999, z0->Int32Value()); 7824 7825 // Create another environment, should fail security checks. 7826 v8::HandleScope scope1(v8::Isolate::GetCurrent()); 7827 7828 v8::Handle<Context> context1 = 7829 Context::New(v8::Isolate::GetCurrent(), NULL, global_template); 7830 context1->Enter(); 7831 7832 v8::Handle<v8::Object> global1 = context1->Global(); 7833 global1->Set(v8_str("othercontext"), global0); 7834 // This set will fail the security check. 7835 v8::Handle<Script> script1 = 7836 v8_compile("othercontext.foo = 222; othercontext[0] = 888;"); 7837 script1->Run(); 7838 // This read will pass the security check. 7839 v8::Handle<Value> foo1 = global0->Get(v8_str("foo")); 7840 CHECK_EQ(111, foo1->Int32Value()); 7841 // This read will pass the security check. 7842 v8::Handle<Value> z1 = global0->Get(v8_str("0")); 7843 CHECK_EQ(999, z1->Int32Value()); 7844 7845 // Create another environment, should pass security checks. 7846 { g_security_callback_result = true; // allow security handler to pass. 7847 v8::HandleScope scope2(v8::Isolate::GetCurrent()); 7848 LocalContext context2; 7849 v8::Handle<v8::Object> global2 = context2->Global(); 7850 global2->Set(v8_str("othercontext"), global0); 7851 v8::Handle<Script> script2 = 7852 v8_compile("othercontext.foo = 333; othercontext[0] = 888;"); 7853 script2->Run(); 7854 v8::Handle<Value> foo2 = global0->Get(v8_str("foo")); 7855 CHECK_EQ(333, foo2->Int32Value()); 7856 v8::Handle<Value> z2 = global0->Get(v8_str("0")); 7857 CHECK_EQ(888, z2->Int32Value()); 7858 } 7859 7860 context1->Exit(); 7861 context0->Exit(); 7862 } 7863 7864 7865 THREADED_TEST(SecurityChecks) { 7866 LocalContext env1; 7867 v8::HandleScope handle_scope(env1->GetIsolate()); 7868 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 7869 7870 Local<Value> foo = v8_str("foo"); 7871 Local<Value> bar = v8_str("bar"); 7872 7873 // Set to the same domain. 7874 env1->SetSecurityToken(foo); 7875 7876 // Create a function in env1. 7877 Script::Compile(v8_str("spy=function(){return spy;}"))->Run(); 7878 Local<Value> spy = env1->Global()->Get(v8_str("spy")); 7879 CHECK(spy->IsFunction()); 7880 7881 // Create another function accessing global objects. 7882 Script::Compile(v8_str("spy2=function(){return new this.Array();}"))->Run(); 7883 Local<Value> spy2 = env1->Global()->Get(v8_str("spy2")); 7884 CHECK(spy2->IsFunction()); 7885 7886 // Switch to env2 in the same domain and invoke spy on env2. 7887 { 7888 env2->SetSecurityToken(foo); 7889 // Enter env2 7890 Context::Scope scope_env2(env2); 7891 Local<Value> result = Function::Cast(*spy)->Call(env2->Global(), 0, NULL); 7892 CHECK(result->IsFunction()); 7893 } 7894 7895 { 7896 env2->SetSecurityToken(bar); 7897 Context::Scope scope_env2(env2); 7898 7899 // Call cross_domain_call, it should throw an exception 7900 v8::TryCatch try_catch; 7901 Function::Cast(*spy2)->Call(env2->Global(), 0, NULL); 7902 CHECK(try_catch.HasCaught()); 7903 } 7904 } 7905 7906 7907 // Regression test case for issue 1183439. 7908 THREADED_TEST(SecurityChecksForPrototypeChain) { 7909 LocalContext current; 7910 v8::HandleScope scope(current->GetIsolate()); 7911 v8::Handle<Context> other = Context::New(current->GetIsolate()); 7912 7913 // Change context to be able to get to the Object function in the 7914 // other context without hitting the security checks. 7915 v8::Local<Value> other_object; 7916 { Context::Scope scope(other); 7917 other_object = other->Global()->Get(v8_str("Object")); 7918 other->Global()->Set(v8_num(42), v8_num(87)); 7919 } 7920 7921 current->Global()->Set(v8_str("other"), other->Global()); 7922 CHECK(v8_compile("other")->Run()->Equals(other->Global())); 7923 7924 // Make sure the security check fails here and we get an undefined 7925 // result instead of getting the Object function. Repeat in a loop 7926 // to make sure to exercise the IC code. 7927 v8::Local<Script> access_other0 = v8_compile("other.Object"); 7928 v8::Local<Script> access_other1 = v8_compile("other[42]"); 7929 for (int i = 0; i < 5; i++) { 7930 CHECK(!access_other0->Run()->Equals(other_object)); 7931 CHECK(access_other0->Run()->IsUndefined()); 7932 CHECK(!access_other1->Run()->Equals(v8_num(87))); 7933 CHECK(access_other1->Run()->IsUndefined()); 7934 } 7935 7936 // Create an object that has 'other' in its prototype chain and make 7937 // sure we cannot access the Object function indirectly through 7938 // that. Repeat in a loop to make sure to exercise the IC code. 7939 v8_compile("function F() { };" 7940 "F.prototype = other;" 7941 "var f = new F();")->Run(); 7942 v8::Local<Script> access_f0 = v8_compile("f.Object"); 7943 v8::Local<Script> access_f1 = v8_compile("f[42]"); 7944 for (int j = 0; j < 5; j++) { 7945 CHECK(!access_f0->Run()->Equals(other_object)); 7946 CHECK(access_f0->Run()->IsUndefined()); 7947 CHECK(!access_f1->Run()->Equals(v8_num(87))); 7948 CHECK(access_f1->Run()->IsUndefined()); 7949 } 7950 7951 // Now it gets hairy: Set the prototype for the other global object 7952 // to be the current global object. The prototype chain for 'f' now 7953 // goes through 'other' but ends up in the current global object. 7954 { Context::Scope scope(other); 7955 other->Global()->Set(v8_str("__proto__"), current->Global()); 7956 } 7957 // Set a named and an index property on the current global 7958 // object. To force the lookup to go through the other global object, 7959 // the properties must not exist in the other global object. 7960 current->Global()->Set(v8_str("foo"), v8_num(100)); 7961 current->Global()->Set(v8_num(99), v8_num(101)); 7962 // Try to read the properties from f and make sure that the access 7963 // gets stopped by the security checks on the other global object. 7964 Local<Script> access_f2 = v8_compile("f.foo"); 7965 Local<Script> access_f3 = v8_compile("f[99]"); 7966 for (int k = 0; k < 5; k++) { 7967 CHECK(!access_f2->Run()->Equals(v8_num(100))); 7968 CHECK(access_f2->Run()->IsUndefined()); 7969 CHECK(!access_f3->Run()->Equals(v8_num(101))); 7970 CHECK(access_f3->Run()->IsUndefined()); 7971 } 7972 } 7973 7974 7975 THREADED_TEST(CrossDomainDelete) { 7976 LocalContext env1; 7977 v8::HandleScope handle_scope(env1->GetIsolate()); 7978 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 7979 7980 Local<Value> foo = v8_str("foo"); 7981 Local<Value> bar = v8_str("bar"); 7982 7983 // Set to the same domain. 7984 env1->SetSecurityToken(foo); 7985 env2->SetSecurityToken(foo); 7986 7987 env1->Global()->Set(v8_str("prop"), v8_num(3)); 7988 env2->Global()->Set(v8_str("env1"), env1->Global()); 7989 7990 // Change env2 to a different domain and delete env1.prop. 7991 env2->SetSecurityToken(bar); 7992 { 7993 Context::Scope scope_env2(env2); 7994 Local<Value> result = 7995 Script::Compile(v8_str("delete env1.prop"))->Run(); 7996 CHECK(result->IsFalse()); 7997 } 7998 7999 // Check that env1.prop still exists. 8000 Local<Value> v = env1->Global()->Get(v8_str("prop")); 8001 CHECK(v->IsNumber()); 8002 CHECK_EQ(3, v->Int32Value()); 8003 } 8004 8005 8006 THREADED_TEST(CrossDomainIsPropertyEnumerable) { 8007 LocalContext env1; 8008 v8::HandleScope handle_scope(env1->GetIsolate()); 8009 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8010 8011 Local<Value> foo = v8_str("foo"); 8012 Local<Value> bar = v8_str("bar"); 8013 8014 // Set to the same domain. 8015 env1->SetSecurityToken(foo); 8016 env2->SetSecurityToken(foo); 8017 8018 env1->Global()->Set(v8_str("prop"), v8_num(3)); 8019 env2->Global()->Set(v8_str("env1"), env1->Global()); 8020 8021 // env1.prop is enumerable in env2. 8022 Local<String> test = v8_str("propertyIsEnumerable.call(env1, 'prop')"); 8023 { 8024 Context::Scope scope_env2(env2); 8025 Local<Value> result = Script::Compile(test)->Run(); 8026 CHECK(result->IsTrue()); 8027 } 8028 8029 // Change env2 to a different domain and test again. 8030 env2->SetSecurityToken(bar); 8031 { 8032 Context::Scope scope_env2(env2); 8033 Local<Value> result = Script::Compile(test)->Run(); 8034 CHECK(result->IsFalse()); 8035 } 8036 } 8037 8038 8039 THREADED_TEST(CrossDomainForIn) { 8040 LocalContext env1; 8041 v8::HandleScope handle_scope(env1->GetIsolate()); 8042 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8043 8044 Local<Value> foo = v8_str("foo"); 8045 Local<Value> bar = v8_str("bar"); 8046 8047 // Set to the same domain. 8048 env1->SetSecurityToken(foo); 8049 env2->SetSecurityToken(foo); 8050 8051 env1->Global()->Set(v8_str("prop"), v8_num(3)); 8052 env2->Global()->Set(v8_str("env1"), env1->Global()); 8053 8054 // Change env2 to a different domain and set env1's global object 8055 // as the __proto__ of an object in env2 and enumerate properties 8056 // in for-in. It shouldn't enumerate properties on env1's global 8057 // object. 8058 env2->SetSecurityToken(bar); 8059 { 8060 Context::Scope scope_env2(env2); 8061 Local<Value> result = 8062 CompileRun("(function(){var obj = {'__proto__':env1};" 8063 "for (var p in obj)" 8064 " if (p == 'prop') return false;" 8065 "return true;})()"); 8066 CHECK(result->IsTrue()); 8067 } 8068 } 8069 8070 8071 TEST(ContextDetachGlobal) { 8072 LocalContext env1; 8073 v8::HandleScope handle_scope(env1->GetIsolate()); 8074 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8075 8076 Local<v8::Object> global1 = env1->Global(); 8077 8078 Local<Value> foo = v8_str("foo"); 8079 8080 // Set to the same domain. 8081 env1->SetSecurityToken(foo); 8082 env2->SetSecurityToken(foo); 8083 8084 // Enter env2 8085 env2->Enter(); 8086 8087 // Create a function in env2 and add a reference to it in env1. 8088 Local<v8::Object> global2 = env2->Global(); 8089 global2->Set(v8_str("prop"), v8::Integer::New(1)); 8090 CompileRun("function getProp() {return prop;}"); 8091 8092 env1->Global()->Set(v8_str("getProp"), 8093 global2->Get(v8_str("getProp"))); 8094 8095 // Detach env2's global, and reuse the global object of env2 8096 env2->Exit(); 8097 env2->DetachGlobal(); 8098 // env2 has a new global object. 8099 CHECK(!env2->Global()->Equals(global2)); 8100 8101 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(), 8102 0, 8103 v8::Handle<v8::ObjectTemplate>(), 8104 global2); 8105 env3->SetSecurityToken(v8_str("bar")); 8106 env3->Enter(); 8107 8108 Local<v8::Object> global3 = env3->Global(); 8109 CHECK_EQ(global2, global3); 8110 CHECK(global3->Get(v8_str("prop"))->IsUndefined()); 8111 CHECK(global3->Get(v8_str("getProp"))->IsUndefined()); 8112 global3->Set(v8_str("prop"), v8::Integer::New(-1)); 8113 global3->Set(v8_str("prop2"), v8::Integer::New(2)); 8114 env3->Exit(); 8115 8116 // Call getProp in env1, and it should return the value 1 8117 { 8118 Local<Value> get_prop = global1->Get(v8_str("getProp")); 8119 CHECK(get_prop->IsFunction()); 8120 v8::TryCatch try_catch; 8121 Local<Value> r = Function::Cast(*get_prop)->Call(global1, 0, NULL); 8122 CHECK(!try_catch.HasCaught()); 8123 CHECK_EQ(1, r->Int32Value()); 8124 } 8125 8126 // Check that env3 is not accessible from env1 8127 { 8128 Local<Value> r = global3->Get(v8_str("prop2")); 8129 CHECK(r->IsUndefined()); 8130 } 8131 } 8132 8133 8134 TEST(DetachAndReattachGlobal) { 8135 LocalContext env1; 8136 v8::HandleScope scope(env1->GetIsolate()); 8137 8138 // Create second environment. 8139 v8::Handle<Context> env2 = Context::New(env1->GetIsolate()); 8140 8141 Local<Value> foo = v8_str("foo"); 8142 8143 // Set same security token for env1 and env2. 8144 env1->SetSecurityToken(foo); 8145 env2->SetSecurityToken(foo); 8146 8147 // Create a property on the global object in env2. 8148 { 8149 v8::Context::Scope scope(env2); 8150 env2->Global()->Set(v8_str("p"), v8::Integer::New(42)); 8151 } 8152 8153 // Create a reference to env2 global from env1 global. 8154 env1->Global()->Set(v8_str("other"), env2->Global()); 8155 8156 // Check that we have access to other.p in env2 from env1. 8157 Local<Value> result = CompileRun("other.p"); 8158 CHECK(result->IsInt32()); 8159 CHECK_EQ(42, result->Int32Value()); 8160 8161 // Hold on to global from env2 and detach global from env2. 8162 Local<v8::Object> global2 = env2->Global(); 8163 env2->DetachGlobal(); 8164 8165 // Check that the global has been detached. No other.p property can 8166 // be found. 8167 result = CompileRun("other.p"); 8168 CHECK(result->IsUndefined()); 8169 8170 // Reuse global2 for env3. 8171 v8::Handle<Context> env3 = Context::New(env1->GetIsolate(), 8172 0, 8173 v8::Handle<v8::ObjectTemplate>(), 8174 global2); 8175 CHECK_EQ(global2, env3->Global()); 8176 8177 // Start by using the same security token for env3 as for env1 and env2. 8178 env3->SetSecurityToken(foo); 8179 8180 // Create a property on the global object in env3. 8181 { 8182 v8::Context::Scope scope(env3); 8183 env3->Global()->Set(v8_str("p"), v8::Integer::New(24)); 8184 } 8185 8186 // Check that other.p is now the property in env3 and that we have access. 8187 result = CompileRun("other.p"); 8188 CHECK(result->IsInt32()); 8189 CHECK_EQ(24, result->Int32Value()); 8190 8191 // Change security token for env3 to something different from env1 and env2. 8192 env3->SetSecurityToken(v8_str("bar")); 8193 8194 // Check that we do not have access to other.p in env1. |other| is now 8195 // the global object for env3 which has a different security token, 8196 // so access should be blocked. 8197 result = CompileRun("other.p"); 8198 CHECK(result->IsUndefined()); 8199 8200 // Detach the global for env3 and reattach it to env2. 8201 env3->DetachGlobal(); 8202 env2->ReattachGlobal(global2); 8203 8204 // Check that we have access to other.p again in env1. |other| is now 8205 // the global object for env2 which has the same security token as env1. 8206 result = CompileRun("other.p"); 8207 CHECK(result->IsInt32()); 8208 CHECK_EQ(42, result->Int32Value()); 8209 } 8210 8211 8212 static bool allowed_access_type[v8::ACCESS_KEYS + 1] = { false }; 8213 static bool NamedAccessBlocker(Local<v8::Object> global, 8214 Local<Value> name, 8215 v8::AccessType type, 8216 Local<Value> data) { 8217 return Context::GetCurrent()->Global()->Equals(global) || 8218 allowed_access_type[type]; 8219 } 8220 8221 8222 static bool IndexedAccessBlocker(Local<v8::Object> global, 8223 uint32_t key, 8224 v8::AccessType type, 8225 Local<Value> data) { 8226 return Context::GetCurrent()->Global()->Equals(global) || 8227 allowed_access_type[type]; 8228 } 8229 8230 8231 static int g_echo_value = -1; 8232 static void EchoGetter( 8233 Local<String> name, 8234 const v8::PropertyCallbackInfo<v8::Value>& info) { 8235 info.GetReturnValue().Set(v8_num(g_echo_value)); 8236 } 8237 8238 8239 static void EchoSetter(Local<String> name, 8240 Local<Value> value, 8241 const v8::PropertyCallbackInfo<void>&) { 8242 if (value->IsNumber()) 8243 g_echo_value = value->Int32Value(); 8244 } 8245 8246 8247 static void UnreachableGetter( 8248 Local<String> name, 8249 const v8::PropertyCallbackInfo<v8::Value>& info) { 8250 CHECK(false); // This function should not be called.. 8251 } 8252 8253 8254 static void UnreachableSetter(Local<String>, 8255 Local<Value>, 8256 const v8::PropertyCallbackInfo<void>&) { 8257 CHECK(false); // This function should nto be called. 8258 } 8259 8260 8261 TEST(AccessControl) { 8262 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 8263 v8::HandleScope handle_scope(isolate); 8264 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 8265 8266 global_template->SetAccessCheckCallbacks(NamedAccessBlocker, 8267 IndexedAccessBlocker); 8268 8269 // Add an accessor accessible by cross-domain JS code. 8270 global_template->SetAccessor( 8271 v8_str("accessible_prop"), 8272 EchoGetter, EchoSetter, 8273 v8::Handle<Value>(), 8274 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 8275 8276 // Add an accessor that is not accessible by cross-domain JS code. 8277 global_template->SetAccessor(v8_str("blocked_prop"), 8278 UnreachableGetter, UnreachableSetter, 8279 v8::Handle<Value>(), 8280 v8::DEFAULT); 8281 8282 // Create an environment 8283 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 8284 context0->Enter(); 8285 8286 v8::Handle<v8::Object> global0 = context0->Global(); 8287 8288 // Define a property with JS getter and setter. 8289 CompileRun( 8290 "function getter() { return 'getter'; };\n" 8291 "function setter() { return 'setter'; }\n" 8292 "Object.defineProperty(this, 'js_accessor_p', {get:getter, set:setter})"); 8293 8294 Local<Value> getter = global0->Get(v8_str("getter")); 8295 Local<Value> setter = global0->Get(v8_str("setter")); 8296 8297 // And define normal element. 8298 global0->Set(239, v8_str("239")); 8299 8300 // Define an element with JS getter and setter. 8301 CompileRun( 8302 "function el_getter() { return 'el_getter'; };\n" 8303 "function el_setter() { return 'el_setter'; };\n" 8304 "Object.defineProperty(this, '42', {get: el_getter, set: el_setter});"); 8305 8306 Local<Value> el_getter = global0->Get(v8_str("el_getter")); 8307 Local<Value> el_setter = global0->Get(v8_str("el_setter")); 8308 8309 v8::HandleScope scope1(isolate); 8310 8311 v8::Local<Context> context1 = Context::New(isolate); 8312 context1->Enter(); 8313 8314 v8::Handle<v8::Object> global1 = context1->Global(); 8315 global1->Set(v8_str("other"), global0); 8316 8317 // Access blocked property. 8318 CompileRun("other.blocked_prop = 1"); 8319 8320 ExpectUndefined("other.blocked_prop"); 8321 ExpectUndefined( 8322 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')"); 8323 ExpectFalse("propertyIsEnumerable.call(other, 'blocked_prop')"); 8324 8325 // Enable ACCESS_HAS 8326 allowed_access_type[v8::ACCESS_HAS] = true; 8327 ExpectUndefined("other.blocked_prop"); 8328 // ... and now we can get the descriptor... 8329 ExpectUndefined( 8330 "Object.getOwnPropertyDescriptor(other, 'blocked_prop').value"); 8331 // ... and enumerate the property. 8332 ExpectTrue("propertyIsEnumerable.call(other, 'blocked_prop')"); 8333 allowed_access_type[v8::ACCESS_HAS] = false; 8334 8335 // Access blocked element. 8336 CompileRun("other[239] = 1"); 8337 8338 ExpectUndefined("other[239]"); 8339 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239')"); 8340 ExpectFalse("propertyIsEnumerable.call(other, '239')"); 8341 8342 // Enable ACCESS_HAS 8343 allowed_access_type[v8::ACCESS_HAS] = true; 8344 ExpectUndefined("other[239]"); 8345 // ... and now we can get the descriptor... 8346 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '239').value"); 8347 // ... and enumerate the property. 8348 ExpectTrue("propertyIsEnumerable.call(other, '239')"); 8349 allowed_access_type[v8::ACCESS_HAS] = false; 8350 8351 // Access a property with JS accessor. 8352 CompileRun("other.js_accessor_p = 2"); 8353 8354 ExpectUndefined("other.js_accessor_p"); 8355 ExpectUndefined( 8356 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p')"); 8357 8358 // Enable ACCESS_HAS. 8359 allowed_access_type[v8::ACCESS_HAS] = true; 8360 ExpectUndefined("other.js_accessor_p"); 8361 ExpectUndefined( 8362 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get"); 8363 ExpectUndefined( 8364 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set"); 8365 ExpectUndefined( 8366 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 8367 allowed_access_type[v8::ACCESS_HAS] = false; 8368 8369 // Enable both ACCESS_HAS and ACCESS_GET. 8370 allowed_access_type[v8::ACCESS_HAS] = true; 8371 allowed_access_type[v8::ACCESS_GET] = true; 8372 8373 ExpectString("other.js_accessor_p", "getter"); 8374 ExpectObject( 8375 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter); 8376 ExpectUndefined( 8377 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set"); 8378 ExpectUndefined( 8379 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 8380 8381 allowed_access_type[v8::ACCESS_GET] = false; 8382 allowed_access_type[v8::ACCESS_HAS] = false; 8383 8384 // Enable both ACCESS_HAS and ACCESS_SET. 8385 allowed_access_type[v8::ACCESS_HAS] = true; 8386 allowed_access_type[v8::ACCESS_SET] = true; 8387 8388 ExpectUndefined("other.js_accessor_p"); 8389 ExpectUndefined( 8390 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get"); 8391 ExpectObject( 8392 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter); 8393 ExpectUndefined( 8394 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 8395 8396 allowed_access_type[v8::ACCESS_SET] = false; 8397 allowed_access_type[v8::ACCESS_HAS] = false; 8398 8399 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET. 8400 allowed_access_type[v8::ACCESS_HAS] = true; 8401 allowed_access_type[v8::ACCESS_GET] = true; 8402 allowed_access_type[v8::ACCESS_SET] = true; 8403 8404 ExpectString("other.js_accessor_p", "getter"); 8405 ExpectObject( 8406 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').get", getter); 8407 ExpectObject( 8408 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').set", setter); 8409 ExpectUndefined( 8410 "Object.getOwnPropertyDescriptor(other, 'js_accessor_p').value"); 8411 8412 allowed_access_type[v8::ACCESS_SET] = false; 8413 allowed_access_type[v8::ACCESS_GET] = false; 8414 allowed_access_type[v8::ACCESS_HAS] = false; 8415 8416 // Access an element with JS accessor. 8417 CompileRun("other[42] = 2"); 8418 8419 ExpectUndefined("other[42]"); 8420 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42')"); 8421 8422 // Enable ACCESS_HAS. 8423 allowed_access_type[v8::ACCESS_HAS] = true; 8424 ExpectUndefined("other[42]"); 8425 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get"); 8426 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set"); 8427 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 8428 allowed_access_type[v8::ACCESS_HAS] = false; 8429 8430 // Enable both ACCESS_HAS and ACCESS_GET. 8431 allowed_access_type[v8::ACCESS_HAS] = true; 8432 allowed_access_type[v8::ACCESS_GET] = true; 8433 8434 ExpectString("other[42]", "el_getter"); 8435 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); 8436 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').set"); 8437 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 8438 8439 allowed_access_type[v8::ACCESS_GET] = false; 8440 allowed_access_type[v8::ACCESS_HAS] = false; 8441 8442 // Enable both ACCESS_HAS and ACCESS_SET. 8443 allowed_access_type[v8::ACCESS_HAS] = true; 8444 allowed_access_type[v8::ACCESS_SET] = true; 8445 8446 ExpectUndefined("other[42]"); 8447 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').get"); 8448 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); 8449 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 8450 8451 allowed_access_type[v8::ACCESS_SET] = false; 8452 allowed_access_type[v8::ACCESS_HAS] = false; 8453 8454 // Enable both ACCESS_HAS, ACCESS_GET and ACCESS_SET. 8455 allowed_access_type[v8::ACCESS_HAS] = true; 8456 allowed_access_type[v8::ACCESS_GET] = true; 8457 allowed_access_type[v8::ACCESS_SET] = true; 8458 8459 ExpectString("other[42]", "el_getter"); 8460 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').get", el_getter); 8461 ExpectObject("Object.getOwnPropertyDescriptor(other, '42').set", el_setter); 8462 ExpectUndefined("Object.getOwnPropertyDescriptor(other, '42').value"); 8463 8464 allowed_access_type[v8::ACCESS_SET] = false; 8465 allowed_access_type[v8::ACCESS_GET] = false; 8466 allowed_access_type[v8::ACCESS_HAS] = false; 8467 8468 v8::Handle<Value> value; 8469 8470 // Access accessible property 8471 value = CompileRun("other.accessible_prop = 3"); 8472 CHECK(value->IsNumber()); 8473 CHECK_EQ(3, value->Int32Value()); 8474 CHECK_EQ(3, g_echo_value); 8475 8476 value = CompileRun("other.accessible_prop"); 8477 CHECK(value->IsNumber()); 8478 CHECK_EQ(3, value->Int32Value()); 8479 8480 value = CompileRun( 8481 "Object.getOwnPropertyDescriptor(other, 'accessible_prop').value"); 8482 CHECK(value->IsNumber()); 8483 CHECK_EQ(3, value->Int32Value()); 8484 8485 value = CompileRun("propertyIsEnumerable.call(other, 'accessible_prop')"); 8486 CHECK(value->IsTrue()); 8487 8488 // Enumeration doesn't enumerate accessors from inaccessible objects in 8489 // the prototype chain even if the accessors are in themselves accessible. 8490 value = 8491 CompileRun("(function(){var obj = {'__proto__':other};" 8492 "for (var p in obj)" 8493 " if (p == 'accessible_prop' || p == 'blocked_prop') {" 8494 " return false;" 8495 " }" 8496 "return true;})()"); 8497 CHECK(value->IsTrue()); 8498 8499 context1->Exit(); 8500 context0->Exit(); 8501 } 8502 8503 8504 TEST(AccessControlES5) { 8505 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 8506 v8::HandleScope handle_scope(isolate); 8507 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 8508 8509 global_template->SetAccessCheckCallbacks(NamedAccessBlocker, 8510 IndexedAccessBlocker); 8511 8512 // Add accessible accessor. 8513 global_template->SetAccessor( 8514 v8_str("accessible_prop"), 8515 EchoGetter, EchoSetter, 8516 v8::Handle<Value>(), 8517 v8::AccessControl(v8::ALL_CAN_READ | v8::ALL_CAN_WRITE)); 8518 8519 8520 // Add an accessor that is not accessible by cross-domain JS code. 8521 global_template->SetAccessor(v8_str("blocked_prop"), 8522 UnreachableGetter, UnreachableSetter, 8523 v8::Handle<Value>(), 8524 v8::DEFAULT); 8525 8526 // Create an environment 8527 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 8528 context0->Enter(); 8529 8530 v8::Handle<v8::Object> global0 = context0->Global(); 8531 8532 v8::Local<Context> context1 = Context::New(isolate); 8533 context1->Enter(); 8534 v8::Handle<v8::Object> global1 = context1->Global(); 8535 global1->Set(v8_str("other"), global0); 8536 8537 // Regression test for issue 1154. 8538 ExpectTrue("Object.keys(other).indexOf('blocked_prop') == -1"); 8539 8540 ExpectUndefined("other.blocked_prop"); 8541 8542 // Regression test for issue 1027. 8543 CompileRun("Object.defineProperty(\n" 8544 " other, 'blocked_prop', {configurable: false})"); 8545 ExpectUndefined("other.blocked_prop"); 8546 ExpectUndefined( 8547 "Object.getOwnPropertyDescriptor(other, 'blocked_prop')"); 8548 8549 // Regression test for issue 1171. 8550 ExpectTrue("Object.isExtensible(other)"); 8551 CompileRun("Object.preventExtensions(other)"); 8552 ExpectTrue("Object.isExtensible(other)"); 8553 8554 // Object.seal and Object.freeze. 8555 CompileRun("Object.freeze(other)"); 8556 ExpectTrue("Object.isExtensible(other)"); 8557 8558 CompileRun("Object.seal(other)"); 8559 ExpectTrue("Object.isExtensible(other)"); 8560 8561 // Regression test for issue 1250. 8562 // Make sure that we can set the accessible accessors value using normal 8563 // assignment. 8564 CompileRun("other.accessible_prop = 42"); 8565 CHECK_EQ(42, g_echo_value); 8566 8567 v8::Handle<Value> value; 8568 // We follow Safari in ignoring assignments to host object accessors. 8569 CompileRun("Object.defineProperty(other, 'accessible_prop', {value: -1})"); 8570 value = CompileRun("other.accessible_prop == 42"); 8571 CHECK(value->IsTrue()); 8572 } 8573 8574 8575 static bool GetOwnPropertyNamesNamedBlocker(Local<v8::Object> global, 8576 Local<Value> name, 8577 v8::AccessType type, 8578 Local<Value> data) { 8579 return false; 8580 } 8581 8582 8583 static bool GetOwnPropertyNamesIndexedBlocker(Local<v8::Object> global, 8584 uint32_t key, 8585 v8::AccessType type, 8586 Local<Value> data) { 8587 return false; 8588 } 8589 8590 8591 THREADED_TEST(AccessControlGetOwnPropertyNames) { 8592 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 8593 v8::HandleScope handle_scope(isolate); 8594 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(); 8595 8596 obj_template->Set(v8_str("x"), v8::Integer::New(42)); 8597 obj_template->SetAccessCheckCallbacks(GetOwnPropertyNamesNamedBlocker, 8598 GetOwnPropertyNamesIndexedBlocker); 8599 8600 // Create an environment 8601 v8::Local<Context> context0 = Context::New(isolate, NULL, obj_template); 8602 context0->Enter(); 8603 8604 v8::Handle<v8::Object> global0 = context0->Global(); 8605 8606 v8::HandleScope scope1(v8::Isolate::GetCurrent()); 8607 8608 v8::Local<Context> context1 = Context::New(isolate); 8609 context1->Enter(); 8610 8611 v8::Handle<v8::Object> global1 = context1->Global(); 8612 global1->Set(v8_str("other"), global0); 8613 global1->Set(v8_str("object"), obj_template->NewInstance()); 8614 8615 v8::Handle<Value> value; 8616 8617 // Attempt to get the property names of the other global object and 8618 // of an object that requires access checks. Accessing the other 8619 // global object should be blocked by access checks on the global 8620 // proxy object. Accessing the object that requires access checks 8621 // is blocked by the access checks on the object itself. 8622 value = CompileRun("Object.getOwnPropertyNames(other).length == 0"); 8623 CHECK(value->IsTrue()); 8624 8625 value = CompileRun("Object.getOwnPropertyNames(object).length == 0"); 8626 CHECK(value->IsTrue()); 8627 8628 context1->Exit(); 8629 context0->Exit(); 8630 } 8631 8632 8633 static void IndexedPropertyEnumerator( 8634 const v8::PropertyCallbackInfo<v8::Array>& info) { 8635 v8::Handle<v8::Array> result = v8::Array::New(2); 8636 result->Set(0, v8::Integer::New(7)); 8637 result->Set(1, v8::Object::New()); 8638 info.GetReturnValue().Set(result); 8639 } 8640 8641 8642 static void NamedPropertyEnumerator( 8643 const v8::PropertyCallbackInfo<v8::Array>& info) { 8644 v8::Handle<v8::Array> result = v8::Array::New(2); 8645 result->Set(0, v8_str("x")); 8646 result->Set(1, v8::Object::New()); 8647 info.GetReturnValue().Set(result); 8648 } 8649 8650 8651 THREADED_TEST(GetOwnPropertyNamesWithInterceptor) { 8652 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 8653 v8::Handle<v8::ObjectTemplate> obj_template = v8::ObjectTemplate::New(); 8654 8655 obj_template->Set(v8_str("7"), v8::Integer::New(7)); 8656 obj_template->Set(v8_str("x"), v8::Integer::New(42)); 8657 obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL, 8658 IndexedPropertyEnumerator); 8659 obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL, 8660 NamedPropertyEnumerator); 8661 8662 LocalContext context; 8663 v8::Handle<v8::Object> global = context->Global(); 8664 global->Set(v8_str("object"), obj_template->NewInstance()); 8665 8666 v8::Handle<v8::Value> result = 8667 CompileRun("Object.getOwnPropertyNames(object)"); 8668 CHECK(result->IsArray()); 8669 v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result); 8670 CHECK_EQ(3, result_array->Length()); 8671 CHECK(result_array->Get(0)->IsString()); 8672 CHECK(result_array->Get(1)->IsString()); 8673 CHECK(result_array->Get(2)->IsString()); 8674 CHECK_EQ(v8_str("7"), result_array->Get(0)); 8675 CHECK_EQ(v8_str("[object Object]"), result_array->Get(1)); 8676 CHECK_EQ(v8_str("x"), result_array->Get(2)); 8677 } 8678 8679 8680 static void ConstTenGetter(Local<String> name, 8681 const v8::PropertyCallbackInfo<v8::Value>& info) { 8682 info.GetReturnValue().Set(v8_num(10)); 8683 } 8684 8685 8686 THREADED_TEST(CrossDomainAccessors) { 8687 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 8688 v8::HandleScope handle_scope(isolate); 8689 8690 v8::Handle<v8::FunctionTemplate> func_template = v8::FunctionTemplate::New(); 8691 8692 v8::Handle<v8::ObjectTemplate> global_template = 8693 func_template->InstanceTemplate(); 8694 8695 v8::Handle<v8::ObjectTemplate> proto_template = 8696 func_template->PrototypeTemplate(); 8697 8698 // Add an accessor to proto that's accessible by cross-domain JS code. 8699 proto_template->SetAccessor(v8_str("accessible"), 8700 ConstTenGetter, 0, 8701 v8::Handle<Value>(), 8702 v8::ALL_CAN_READ); 8703 8704 // Add an accessor that is not accessible by cross-domain JS code. 8705 global_template->SetAccessor(v8_str("unreachable"), 8706 UnreachableGetter, 0, 8707 v8::Handle<Value>(), 8708 v8::DEFAULT); 8709 8710 v8::Local<Context> context0 = Context::New(isolate, NULL, global_template); 8711 context0->Enter(); 8712 8713 Local<v8::Object> global = context0->Global(); 8714 // Add a normal property that shadows 'accessible' 8715 global->Set(v8_str("accessible"), v8_num(11)); 8716 8717 // Enter a new context. 8718 v8::HandleScope scope1(v8::Isolate::GetCurrent()); 8719 v8::Local<Context> context1 = Context::New(isolate); 8720 context1->Enter(); 8721 8722 v8::Handle<v8::Object> global1 = context1->Global(); 8723 global1->Set(v8_str("other"), global); 8724 8725 // Should return 10, instead of 11 8726 v8::Handle<Value> value = v8_compile("other.accessible")->Run(); 8727 CHECK(value->IsNumber()); 8728 CHECK_EQ(10, value->Int32Value()); 8729 8730 value = v8_compile("other.unreachable")->Run(); 8731 CHECK(value->IsUndefined()); 8732 8733 context1->Exit(); 8734 context0->Exit(); 8735 } 8736 8737 8738 static int named_access_count = 0; 8739 static int indexed_access_count = 0; 8740 8741 static bool NamedAccessCounter(Local<v8::Object> global, 8742 Local<Value> name, 8743 v8::AccessType type, 8744 Local<Value> data) { 8745 named_access_count++; 8746 return true; 8747 } 8748 8749 8750 static bool IndexedAccessCounter(Local<v8::Object> global, 8751 uint32_t key, 8752 v8::AccessType type, 8753 Local<Value> data) { 8754 indexed_access_count++; 8755 return true; 8756 } 8757 8758 8759 // This one is too easily disturbed by other tests. 8760 TEST(AccessControlIC) { 8761 named_access_count = 0; 8762 indexed_access_count = 0; 8763 8764 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 8765 v8::HandleScope handle_scope(isolate); 8766 8767 // Create an environment. 8768 v8::Local<Context> context0 = Context::New(isolate); 8769 context0->Enter(); 8770 8771 // Create an object that requires access-check functions to be 8772 // called for cross-domain access. 8773 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(); 8774 object_template->SetAccessCheckCallbacks(NamedAccessCounter, 8775 IndexedAccessCounter); 8776 Local<v8::Object> object = object_template->NewInstance(); 8777 8778 v8::HandleScope scope1(isolate); 8779 8780 // Create another environment. 8781 v8::Local<Context> context1 = Context::New(isolate); 8782 context1->Enter(); 8783 8784 // Make easy access to the object from the other environment. 8785 v8::Handle<v8::Object> global1 = context1->Global(); 8786 global1->Set(v8_str("obj"), object); 8787 8788 v8::Handle<Value> value; 8789 8790 // Check that the named access-control function is called every time. 8791 CompileRun("function testProp(obj) {" 8792 " for (var i = 0; i < 10; i++) obj.prop = 1;" 8793 " for (var j = 0; j < 10; j++) obj.prop;" 8794 " return obj.prop" 8795 "}"); 8796 value = CompileRun("testProp(obj)"); 8797 CHECK(value->IsNumber()); 8798 CHECK_EQ(1, value->Int32Value()); 8799 CHECK_EQ(21, named_access_count); 8800 8801 // Check that the named access-control function is called every time. 8802 CompileRun("var p = 'prop';" 8803 "function testKeyed(obj) {" 8804 " for (var i = 0; i < 10; i++) obj[p] = 1;" 8805 " for (var j = 0; j < 10; j++) obj[p];" 8806 " return obj[p];" 8807 "}"); 8808 // Use obj which requires access checks. No inline caching is used 8809 // in that case. 8810 value = CompileRun("testKeyed(obj)"); 8811 CHECK(value->IsNumber()); 8812 CHECK_EQ(1, value->Int32Value()); 8813 CHECK_EQ(42, named_access_count); 8814 // Force the inline caches into generic state and try again. 8815 CompileRun("testKeyed({ a: 0 })"); 8816 CompileRun("testKeyed({ b: 0 })"); 8817 value = CompileRun("testKeyed(obj)"); 8818 CHECK(value->IsNumber()); 8819 CHECK_EQ(1, value->Int32Value()); 8820 CHECK_EQ(63, named_access_count); 8821 8822 // Check that the indexed access-control function is called every time. 8823 CompileRun("function testIndexed(obj) {" 8824 " for (var i = 0; i < 10; i++) obj[0] = 1;" 8825 " for (var j = 0; j < 10; j++) obj[0];" 8826 " return obj[0]" 8827 "}"); 8828 value = CompileRun("testIndexed(obj)"); 8829 CHECK(value->IsNumber()); 8830 CHECK_EQ(1, value->Int32Value()); 8831 CHECK_EQ(21, indexed_access_count); 8832 // Force the inline caches into generic state. 8833 CompileRun("testIndexed(new Array(1))"); 8834 // Test that the indexed access check is called. 8835 value = CompileRun("testIndexed(obj)"); 8836 CHECK(value->IsNumber()); 8837 CHECK_EQ(1, value->Int32Value()); 8838 CHECK_EQ(42, indexed_access_count); 8839 8840 // Check that the named access check is called when invoking 8841 // functions on an object that requires access checks. 8842 CompileRun("obj.f = function() {}"); 8843 CompileRun("function testCallNormal(obj) {" 8844 " for (var i = 0; i < 10; i++) obj.f();" 8845 "}"); 8846 CompileRun("testCallNormal(obj)"); 8847 CHECK_EQ(74, named_access_count); 8848 8849 // Force obj into slow case. 8850 value = CompileRun("delete obj.prop"); 8851 CHECK(value->BooleanValue()); 8852 // Force inline caches into dictionary probing mode. 8853 CompileRun("var o = { x: 0 }; delete o.x; testProp(o);"); 8854 // Test that the named access check is called. 8855 value = CompileRun("testProp(obj);"); 8856 CHECK(value->IsNumber()); 8857 CHECK_EQ(1, value->Int32Value()); 8858 CHECK_EQ(96, named_access_count); 8859 8860 // Force the call inline cache into dictionary probing mode. 8861 CompileRun("o.f = function() {}; testCallNormal(o)"); 8862 // Test that the named access check is still called for each 8863 // invocation of the function. 8864 value = CompileRun("testCallNormal(obj)"); 8865 CHECK_EQ(106, named_access_count); 8866 8867 context1->Exit(); 8868 context0->Exit(); 8869 } 8870 8871 8872 static bool NamedAccessFlatten(Local<v8::Object> global, 8873 Local<Value> name, 8874 v8::AccessType type, 8875 Local<Value> data) { 8876 char buf[100]; 8877 int len; 8878 8879 CHECK(name->IsString()); 8880 8881 memset(buf, 0x1, sizeof(buf)); 8882 len = name.As<String>()->WriteOneByte(reinterpret_cast<uint8_t*>(buf)); 8883 CHECK_EQ(4, len); 8884 8885 uint16_t buf2[100]; 8886 8887 memset(buf, 0x1, sizeof(buf)); 8888 len = name.As<String>()->Write(buf2); 8889 CHECK_EQ(4, len); 8890 8891 return true; 8892 } 8893 8894 8895 static bool IndexedAccessFlatten(Local<v8::Object> global, 8896 uint32_t key, 8897 v8::AccessType type, 8898 Local<Value> data) { 8899 return true; 8900 } 8901 8902 8903 // Regression test. In access checks, operations that may cause 8904 // garbage collection are not allowed. It used to be the case that 8905 // using the Write operation on a string could cause a garbage 8906 // collection due to flattening of the string. This is no longer the 8907 // case. 8908 THREADED_TEST(AccessControlFlatten) { 8909 named_access_count = 0; 8910 indexed_access_count = 0; 8911 8912 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 8913 v8::HandleScope handle_scope(isolate); 8914 8915 // Create an environment. 8916 v8::Local<Context> context0 = Context::New(isolate); 8917 context0->Enter(); 8918 8919 // Create an object that requires access-check functions to be 8920 // called for cross-domain access. 8921 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(); 8922 object_template->SetAccessCheckCallbacks(NamedAccessFlatten, 8923 IndexedAccessFlatten); 8924 Local<v8::Object> object = object_template->NewInstance(); 8925 8926 v8::HandleScope scope1(isolate); 8927 8928 // Create another environment. 8929 v8::Local<Context> context1 = Context::New(isolate); 8930 context1->Enter(); 8931 8932 // Make easy access to the object from the other environment. 8933 v8::Handle<v8::Object> global1 = context1->Global(); 8934 global1->Set(v8_str("obj"), object); 8935 8936 v8::Handle<Value> value; 8937 8938 value = v8_compile("var p = 'as' + 'df';")->Run(); 8939 value = v8_compile("obj[p];")->Run(); 8940 8941 context1->Exit(); 8942 context0->Exit(); 8943 } 8944 8945 8946 static void AccessControlNamedGetter( 8947 Local<String>, 8948 const v8::PropertyCallbackInfo<v8::Value>& info) { 8949 info.GetReturnValue().Set(42); 8950 } 8951 8952 8953 static void AccessControlNamedSetter( 8954 Local<String>, 8955 Local<Value> value, 8956 const v8::PropertyCallbackInfo<v8::Value>& info) { 8957 info.GetReturnValue().Set(value); 8958 } 8959 8960 8961 static void AccessControlIndexedGetter( 8962 uint32_t index, 8963 const v8::PropertyCallbackInfo<v8::Value>& info) { 8964 info.GetReturnValue().Set(v8_num(42)); 8965 } 8966 8967 8968 static void AccessControlIndexedSetter( 8969 uint32_t, 8970 Local<Value> value, 8971 const v8::PropertyCallbackInfo<v8::Value>& info) { 8972 info.GetReturnValue().Set(value); 8973 } 8974 8975 8976 THREADED_TEST(AccessControlInterceptorIC) { 8977 named_access_count = 0; 8978 indexed_access_count = 0; 8979 8980 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 8981 v8::HandleScope handle_scope(isolate); 8982 8983 // Create an environment. 8984 v8::Local<Context> context0 = Context::New(isolate); 8985 context0->Enter(); 8986 8987 // Create an object that requires access-check functions to be 8988 // called for cross-domain access. The object also has interceptors 8989 // interceptor. 8990 v8::Handle<v8::ObjectTemplate> object_template = v8::ObjectTemplate::New(); 8991 object_template->SetAccessCheckCallbacks(NamedAccessCounter, 8992 IndexedAccessCounter); 8993 object_template->SetNamedPropertyHandler(AccessControlNamedGetter, 8994 AccessControlNamedSetter); 8995 object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter, 8996 AccessControlIndexedSetter); 8997 Local<v8::Object> object = object_template->NewInstance(); 8998 8999 v8::HandleScope scope1(isolate); 9000 9001 // Create another environment. 9002 v8::Local<Context> context1 = Context::New(isolate); 9003 context1->Enter(); 9004 9005 // Make easy access to the object from the other environment. 9006 v8::Handle<v8::Object> global1 = context1->Global(); 9007 global1->Set(v8_str("obj"), object); 9008 9009 v8::Handle<Value> value; 9010 9011 // Check that the named access-control function is called every time 9012 // eventhough there is an interceptor on the object. 9013 value = v8_compile("for (var i = 0; i < 10; i++) obj.x = 1;")->Run(); 9014 value = v8_compile("for (var i = 0; i < 10; i++) obj.x;" 9015 "obj.x")->Run(); 9016 CHECK(value->IsNumber()); 9017 CHECK_EQ(42, value->Int32Value()); 9018 CHECK_EQ(21, named_access_count); 9019 9020 value = v8_compile("var p = 'x';")->Run(); 9021 value = v8_compile("for (var i = 0; i < 10; i++) obj[p] = 1;")->Run(); 9022 value = v8_compile("for (var i = 0; i < 10; i++) obj[p];" 9023 "obj[p]")->Run(); 9024 CHECK(value->IsNumber()); 9025 CHECK_EQ(42, value->Int32Value()); 9026 CHECK_EQ(42, named_access_count); 9027 9028 // Check that the indexed access-control function is called every 9029 // time eventhough there is an interceptor on the object. 9030 value = v8_compile("for (var i = 0; i < 10; i++) obj[0] = 1;")->Run(); 9031 value = v8_compile("for (var i = 0; i < 10; i++) obj[0];" 9032 "obj[0]")->Run(); 9033 CHECK(value->IsNumber()); 9034 CHECK_EQ(42, value->Int32Value()); 9035 CHECK_EQ(21, indexed_access_count); 9036 9037 context1->Exit(); 9038 context0->Exit(); 9039 } 9040 9041 9042 THREADED_TEST(Version) { 9043 v8::V8::GetVersion(); 9044 } 9045 9046 9047 static void InstanceFunctionCallback( 9048 const v8::FunctionCallbackInfo<v8::Value>& args) { 9049 ApiTestFuzzer::Fuzz(); 9050 args.GetReturnValue().Set(v8_num(12)); 9051 } 9052 9053 9054 THREADED_TEST(InstanceProperties) { 9055 LocalContext context; 9056 v8::HandleScope handle_scope(context->GetIsolate()); 9057 9058 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 9059 Local<ObjectTemplate> instance = t->InstanceTemplate(); 9060 9061 instance->Set(v8_str("x"), v8_num(42)); 9062 instance->Set(v8_str("f"), 9063 v8::FunctionTemplate::New(InstanceFunctionCallback)); 9064 9065 Local<Value> o = t->GetFunction()->NewInstance(); 9066 9067 context->Global()->Set(v8_str("i"), o); 9068 Local<Value> value = Script::Compile(v8_str("i.x"))->Run(); 9069 CHECK_EQ(42, value->Int32Value()); 9070 9071 value = Script::Compile(v8_str("i.f()"))->Run(); 9072 CHECK_EQ(12, value->Int32Value()); 9073 } 9074 9075 9076 static void GlobalObjectInstancePropertiesGet( 9077 Local<String> key, 9078 const v8::PropertyCallbackInfo<v8::Value>&) { 9079 ApiTestFuzzer::Fuzz(); 9080 } 9081 9082 9083 THREADED_TEST(GlobalObjectInstanceProperties) { 9084 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 9085 9086 Local<Value> global_object; 9087 9088 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 9089 t->InstanceTemplate()->SetNamedPropertyHandler( 9090 GlobalObjectInstancePropertiesGet); 9091 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 9092 instance_template->Set(v8_str("x"), v8_num(42)); 9093 instance_template->Set(v8_str("f"), 9094 v8::FunctionTemplate::New(InstanceFunctionCallback)); 9095 9096 // The script to check how Crankshaft compiles missing global function 9097 // invocations. function g is not defined and should throw on call. 9098 const char* script = 9099 "function wrapper(call) {" 9100 " var x = 0, y = 1;" 9101 " for (var i = 0; i < 1000; i++) {" 9102 " x += i * 100;" 9103 " y += i * 100;" 9104 " }" 9105 " if (call) g();" 9106 "}" 9107 "for (var i = 0; i < 17; i++) wrapper(false);" 9108 "var thrown = 0;" 9109 "try { wrapper(true); } catch (e) { thrown = 1; };" 9110 "thrown"; 9111 9112 { 9113 LocalContext env(NULL, instance_template); 9114 // Hold on to the global object so it can be used again in another 9115 // environment initialization. 9116 global_object = env->Global(); 9117 9118 Local<Value> value = Script::Compile(v8_str("x"))->Run(); 9119 CHECK_EQ(42, value->Int32Value()); 9120 value = Script::Compile(v8_str("f()"))->Run(); 9121 CHECK_EQ(12, value->Int32Value()); 9122 value = Script::Compile(v8_str(script))->Run(); 9123 CHECK_EQ(1, value->Int32Value()); 9124 } 9125 9126 { 9127 // Create new environment reusing the global object. 9128 LocalContext env(NULL, instance_template, global_object); 9129 Local<Value> value = Script::Compile(v8_str("x"))->Run(); 9130 CHECK_EQ(42, value->Int32Value()); 9131 value = Script::Compile(v8_str("f()"))->Run(); 9132 CHECK_EQ(12, value->Int32Value()); 9133 value = Script::Compile(v8_str(script))->Run(); 9134 CHECK_EQ(1, value->Int32Value()); 9135 } 9136 } 9137 9138 9139 THREADED_TEST(CallKnownGlobalReceiver) { 9140 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 9141 9142 Local<Value> global_object; 9143 9144 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 9145 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 9146 9147 // The script to check that we leave global object not 9148 // global object proxy on stack when we deoptimize from inside 9149 // arguments evaluation. 9150 // To provoke error we need to both force deoptimization 9151 // from arguments evaluation and to force CallIC to take 9152 // CallIC_Miss code path that can't cope with global proxy. 9153 const char* script = 9154 "function bar(x, y) { try { } finally { } }" 9155 "function baz(x) { try { } finally { } }" 9156 "function bom(x) { try { } finally { } }" 9157 "function foo(x) { bar([x], bom(2)); }" 9158 "for (var i = 0; i < 10000; i++) foo(1);" 9159 "foo"; 9160 9161 Local<Value> foo; 9162 { 9163 LocalContext env(NULL, instance_template); 9164 // Hold on to the global object so it can be used again in another 9165 // environment initialization. 9166 global_object = env->Global(); 9167 foo = Script::Compile(v8_str(script))->Run(); 9168 } 9169 9170 { 9171 // Create new environment reusing the global object. 9172 LocalContext env(NULL, instance_template, global_object); 9173 env->Global()->Set(v8_str("foo"), foo); 9174 Script::Compile(v8_str("foo()"))->Run(); 9175 } 9176 } 9177 9178 9179 static void ShadowFunctionCallback( 9180 const v8::FunctionCallbackInfo<v8::Value>& args) { 9181 ApiTestFuzzer::Fuzz(); 9182 args.GetReturnValue().Set(v8_num(42)); 9183 } 9184 9185 9186 static int shadow_y; 9187 static int shadow_y_setter_call_count; 9188 static int shadow_y_getter_call_count; 9189 9190 9191 static void ShadowYSetter(Local<String>, 9192 Local<Value>, 9193 const v8::PropertyCallbackInfo<void>&) { 9194 shadow_y_setter_call_count++; 9195 shadow_y = 42; 9196 } 9197 9198 9199 static void ShadowYGetter(Local<String> name, 9200 const v8::PropertyCallbackInfo<v8::Value>& info) { 9201 ApiTestFuzzer::Fuzz(); 9202 shadow_y_getter_call_count++; 9203 info.GetReturnValue().Set(v8_num(shadow_y)); 9204 } 9205 9206 9207 static void ShadowIndexedGet(uint32_t index, 9208 const v8::PropertyCallbackInfo<v8::Value>&) { 9209 } 9210 9211 9212 static void ShadowNamedGet(Local<String> key, 9213 const v8::PropertyCallbackInfo<v8::Value>&) { 9214 } 9215 9216 9217 THREADED_TEST(ShadowObject) { 9218 shadow_y = shadow_y_setter_call_count = shadow_y_getter_call_count = 0; 9219 v8::HandleScope handle_scope(v8::Isolate::GetCurrent()); 9220 9221 Local<ObjectTemplate> global_template = v8::ObjectTemplate::New(); 9222 LocalContext context(NULL, global_template); 9223 9224 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 9225 t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet); 9226 t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet); 9227 Local<ObjectTemplate> proto = t->PrototypeTemplate(); 9228 Local<ObjectTemplate> instance = t->InstanceTemplate(); 9229 9230 proto->Set(v8_str("f"), 9231 v8::FunctionTemplate::New(ShadowFunctionCallback, Local<Value>())); 9232 proto->Set(v8_str("x"), v8_num(12)); 9233 9234 instance->SetAccessor(v8_str("y"), ShadowYGetter, ShadowYSetter); 9235 9236 Local<Value> o = t->GetFunction()->NewInstance(); 9237 context->Global()->Set(v8_str("__proto__"), o); 9238 9239 Local<Value> value = 9240 Script::Compile(v8_str("this.propertyIsEnumerable(0)"))->Run(); 9241 CHECK(value->IsBoolean()); 9242 CHECK(!value->BooleanValue()); 9243 9244 value = Script::Compile(v8_str("x"))->Run(); 9245 CHECK_EQ(12, value->Int32Value()); 9246 9247 value = Script::Compile(v8_str("f()"))->Run(); 9248 CHECK_EQ(42, value->Int32Value()); 9249 9250 Script::Compile(v8_str("y = 43"))->Run(); 9251 CHECK_EQ(1, shadow_y_setter_call_count); 9252 value = Script::Compile(v8_str("y"))->Run(); 9253 CHECK_EQ(1, shadow_y_getter_call_count); 9254 CHECK_EQ(42, value->Int32Value()); 9255 } 9256 9257 9258 THREADED_TEST(HiddenPrototype) { 9259 LocalContext context; 9260 v8::HandleScope handle_scope(context->GetIsolate()); 9261 9262 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(); 9263 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 9264 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(); 9265 t1->SetHiddenPrototype(true); 9266 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 9267 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(); 9268 t2->SetHiddenPrototype(true); 9269 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 9270 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(); 9271 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 9272 9273 Local<v8::Object> o0 = t0->GetFunction()->NewInstance(); 9274 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 9275 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 9276 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 9277 9278 // Setting the prototype on an object skips hidden prototypes. 9279 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9280 o0->Set(v8_str("__proto__"), o1); 9281 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9282 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 9283 o0->Set(v8_str("__proto__"), o2); 9284 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9285 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 9286 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 9287 o0->Set(v8_str("__proto__"), o3); 9288 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9289 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 9290 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 9291 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value()); 9292 9293 // Getting the prototype of o0 should get the first visible one 9294 // which is o3. Therefore, z should not be defined on the prototype 9295 // object. 9296 Local<Value> proto = o0->Get(v8_str("__proto__")); 9297 CHECK(proto->IsObject()); 9298 CHECK(proto.As<v8::Object>()->Get(v8_str("z"))->IsUndefined()); 9299 } 9300 9301 9302 THREADED_TEST(HiddenPrototypeSet) { 9303 LocalContext context; 9304 v8::HandleScope handle_scope(context->GetIsolate()); 9305 9306 Local<v8::FunctionTemplate> ot = v8::FunctionTemplate::New(); 9307 Local<v8::FunctionTemplate> ht = v8::FunctionTemplate::New(); 9308 ht->SetHiddenPrototype(true); 9309 Local<v8::FunctionTemplate> pt = v8::FunctionTemplate::New(); 9310 ht->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 9311 9312 Local<v8::Object> o = ot->GetFunction()->NewInstance(); 9313 Local<v8::Object> h = ht->GetFunction()->NewInstance(); 9314 Local<v8::Object> p = pt->GetFunction()->NewInstance(); 9315 o->Set(v8_str("__proto__"), h); 9316 h->Set(v8_str("__proto__"), p); 9317 9318 // Setting a property that exists on the hidden prototype goes there. 9319 o->Set(v8_str("x"), v8_num(7)); 9320 CHECK_EQ(7, o->Get(v8_str("x"))->Int32Value()); 9321 CHECK_EQ(7, h->Get(v8_str("x"))->Int32Value()); 9322 CHECK(p->Get(v8_str("x"))->IsUndefined()); 9323 9324 // Setting a new property should not be forwarded to the hidden prototype. 9325 o->Set(v8_str("y"), v8_num(6)); 9326 CHECK_EQ(6, o->Get(v8_str("y"))->Int32Value()); 9327 CHECK(h->Get(v8_str("y"))->IsUndefined()); 9328 CHECK(p->Get(v8_str("y"))->IsUndefined()); 9329 9330 // Setting a property that only exists on a prototype of the hidden prototype 9331 // is treated normally again. 9332 p->Set(v8_str("z"), v8_num(8)); 9333 CHECK_EQ(8, o->Get(v8_str("z"))->Int32Value()); 9334 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value()); 9335 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value()); 9336 o->Set(v8_str("z"), v8_num(9)); 9337 CHECK_EQ(9, o->Get(v8_str("z"))->Int32Value()); 9338 CHECK_EQ(8, h->Get(v8_str("z"))->Int32Value()); 9339 CHECK_EQ(8, p->Get(v8_str("z"))->Int32Value()); 9340 } 9341 9342 9343 // Regression test for issue 2457. 9344 THREADED_TEST(HiddenPrototypeIdentityHash) { 9345 LocalContext context; 9346 v8::HandleScope handle_scope(context->GetIsolate()); 9347 9348 Handle<FunctionTemplate> t = FunctionTemplate::New(); 9349 t->SetHiddenPrototype(true); 9350 t->InstanceTemplate()->Set(v8_str("foo"), v8_num(75)); 9351 Handle<Object> p = t->GetFunction()->NewInstance(); 9352 Handle<Object> o = Object::New(); 9353 o->SetPrototype(p); 9354 9355 int hash = o->GetIdentityHash(); 9356 USE(hash); 9357 o->Set(v8_str("foo"), v8_num(42)); 9358 ASSERT_EQ(hash, o->GetIdentityHash()); 9359 } 9360 9361 9362 THREADED_TEST(SetPrototype) { 9363 LocalContext context; 9364 v8::HandleScope handle_scope(context->GetIsolate()); 9365 9366 Local<v8::FunctionTemplate> t0 = v8::FunctionTemplate::New(); 9367 t0->InstanceTemplate()->Set(v8_str("x"), v8_num(0)); 9368 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(); 9369 t1->SetHiddenPrototype(true); 9370 t1->InstanceTemplate()->Set(v8_str("y"), v8_num(1)); 9371 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(); 9372 t2->SetHiddenPrototype(true); 9373 t2->InstanceTemplate()->Set(v8_str("z"), v8_num(2)); 9374 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(); 9375 t3->InstanceTemplate()->Set(v8_str("u"), v8_num(3)); 9376 9377 Local<v8::Object> o0 = t0->GetFunction()->NewInstance(); 9378 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 9379 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 9380 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 9381 9382 // Setting the prototype on an object does not skip hidden prototypes. 9383 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9384 CHECK(o0->SetPrototype(o1)); 9385 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9386 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 9387 CHECK(o1->SetPrototype(o2)); 9388 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9389 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 9390 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 9391 CHECK(o2->SetPrototype(o3)); 9392 CHECK_EQ(0, o0->Get(v8_str("x"))->Int32Value()); 9393 CHECK_EQ(1, o0->Get(v8_str("y"))->Int32Value()); 9394 CHECK_EQ(2, o0->Get(v8_str("z"))->Int32Value()); 9395 CHECK_EQ(3, o0->Get(v8_str("u"))->Int32Value()); 9396 9397 // Getting the prototype of o0 should get the first visible one 9398 // which is o3. Therefore, z should not be defined on the prototype 9399 // object. 9400 Local<Value> proto = o0->Get(v8_str("__proto__")); 9401 CHECK(proto->IsObject()); 9402 CHECK_EQ(proto.As<v8::Object>(), o3); 9403 9404 // However, Object::GetPrototype ignores hidden prototype. 9405 Local<Value> proto0 = o0->GetPrototype(); 9406 CHECK(proto0->IsObject()); 9407 CHECK_EQ(proto0.As<v8::Object>(), o1); 9408 9409 Local<Value> proto1 = o1->GetPrototype(); 9410 CHECK(proto1->IsObject()); 9411 CHECK_EQ(proto1.As<v8::Object>(), o2); 9412 9413 Local<Value> proto2 = o2->GetPrototype(); 9414 CHECK(proto2->IsObject()); 9415 CHECK_EQ(proto2.As<v8::Object>(), o3); 9416 } 9417 9418 9419 // Getting property names of an object with a prototype chain that 9420 // triggers dictionary elements in GetLocalPropertyNames() shouldn't 9421 // crash the runtime. 9422 THREADED_TEST(Regress91517) { 9423 i::FLAG_allow_natives_syntax = true; 9424 LocalContext context; 9425 v8::HandleScope handle_scope(context->GetIsolate()); 9426 9427 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(); 9428 t1->SetHiddenPrototype(true); 9429 t1->InstanceTemplate()->Set(v8_str("foo"), v8_num(1)); 9430 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(); 9431 t2->SetHiddenPrototype(true); 9432 t2->InstanceTemplate()->Set(v8_str("fuz1"), v8_num(2)); 9433 t2->InstanceTemplate()->Set(v8_str("objects"), v8::Object::New()); 9434 t2->InstanceTemplate()->Set(v8_str("fuz2"), v8_num(2)); 9435 Local<v8::FunctionTemplate> t3 = v8::FunctionTemplate::New(); 9436 t3->SetHiddenPrototype(true); 9437 t3->InstanceTemplate()->Set(v8_str("boo"), v8_num(3)); 9438 Local<v8::FunctionTemplate> t4 = v8::FunctionTemplate::New(); 9439 t4->InstanceTemplate()->Set(v8_str("baz"), v8_num(4)); 9440 9441 // Force dictionary-based properties. 9442 i::ScopedVector<char> name_buf(1024); 9443 for (int i = 1; i <= 1000; i++) { 9444 i::OS::SNPrintF(name_buf, "sdf%d", i); 9445 t2->InstanceTemplate()->Set(v8_str(name_buf.start()), v8_num(2)); 9446 } 9447 9448 Local<v8::Object> o1 = t1->GetFunction()->NewInstance(); 9449 Local<v8::Object> o2 = t2->GetFunction()->NewInstance(); 9450 Local<v8::Object> o3 = t3->GetFunction()->NewInstance(); 9451 Local<v8::Object> o4 = t4->GetFunction()->NewInstance(); 9452 9453 // Create prototype chain of hidden prototypes. 9454 CHECK(o4->SetPrototype(o3)); 9455 CHECK(o3->SetPrototype(o2)); 9456 CHECK(o2->SetPrototype(o1)); 9457 9458 // Call the runtime version of GetLocalPropertyNames() on the natively 9459 // created object through JavaScript. 9460 context->Global()->Set(v8_str("obj"), o4); 9461 CompileRun("var names = %GetLocalPropertyNames(obj, true);"); 9462 9463 ExpectInt32("names.length", 1006); 9464 ExpectTrue("names.indexOf(\"baz\") >= 0"); 9465 ExpectTrue("names.indexOf(\"boo\") >= 0"); 9466 ExpectTrue("names.indexOf(\"foo\") >= 0"); 9467 ExpectTrue("names.indexOf(\"fuz1\") >= 0"); 9468 ExpectTrue("names.indexOf(\"fuz2\") >= 0"); 9469 ExpectFalse("names[1005] == undefined"); 9470 } 9471 9472 9473 THREADED_TEST(FunctionReadOnlyPrototype) { 9474 LocalContext context; 9475 v8::HandleScope handle_scope(context->GetIsolate()); 9476 9477 Local<v8::FunctionTemplate> t1 = v8::FunctionTemplate::New(); 9478 t1->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42)); 9479 t1->ReadOnlyPrototype(); 9480 context->Global()->Set(v8_str("func1"), t1->GetFunction()); 9481 // Configured value of ReadOnly flag. 9482 CHECK(CompileRun( 9483 "(function() {" 9484 " descriptor = Object.getOwnPropertyDescriptor(func1, 'prototype');" 9485 " return (descriptor['writable'] == false);" 9486 "})()")->BooleanValue()); 9487 CHECK_EQ(42, CompileRun("func1.prototype.x")->Int32Value()); 9488 CHECK_EQ(42, 9489 CompileRun("func1.prototype = {}; func1.prototype.x")->Int32Value()); 9490 9491 Local<v8::FunctionTemplate> t2 = v8::FunctionTemplate::New(); 9492 t2->PrototypeTemplate()->Set(v8_str("x"), v8::Integer::New(42)); 9493 context->Global()->Set(v8_str("func2"), t2->GetFunction()); 9494 // Default value of ReadOnly flag. 9495 CHECK(CompileRun( 9496 "(function() {" 9497 " descriptor = Object.getOwnPropertyDescriptor(func2, 'prototype');" 9498 " return (descriptor['writable'] == true);" 9499 "})()")->BooleanValue()); 9500 CHECK_EQ(42, CompileRun("func2.prototype.x")->Int32Value()); 9501 } 9502 9503 9504 THREADED_TEST(SetPrototypeThrows) { 9505 LocalContext context; 9506 v8::HandleScope handle_scope(context->GetIsolate()); 9507 9508 Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 9509 9510 Local<v8::Object> o0 = t->GetFunction()->NewInstance(); 9511 Local<v8::Object> o1 = t->GetFunction()->NewInstance(); 9512 9513 CHECK(o0->SetPrototype(o1)); 9514 // If setting the prototype leads to the cycle, SetPrototype should 9515 // return false and keep VM in sane state. 9516 v8::TryCatch try_catch; 9517 CHECK(!o1->SetPrototype(o0)); 9518 CHECK(!try_catch.HasCaught()); 9519 ASSERT(!i::Isolate::Current()->has_pending_exception()); 9520 9521 CHECK_EQ(42, CompileRun("function f() { return 42; }; f()")->Int32Value()); 9522 } 9523 9524 9525 THREADED_TEST(GetterSetterExceptions) { 9526 LocalContext context; 9527 v8::HandleScope handle_scope(context->GetIsolate()); 9528 CompileRun( 9529 "function Foo() { };" 9530 "function Throw() { throw 5; };" 9531 "var x = { };" 9532 "x.__defineSetter__('set', Throw);" 9533 "x.__defineGetter__('get', Throw);"); 9534 Local<v8::Object> x = 9535 Local<v8::Object>::Cast(context->Global()->Get(v8_str("x"))); 9536 v8::TryCatch try_catch; 9537 x->Set(v8_str("set"), v8::Integer::New(8)); 9538 x->Get(v8_str("get")); 9539 x->Set(v8_str("set"), v8::Integer::New(8)); 9540 x->Get(v8_str("get")); 9541 x->Set(v8_str("set"), v8::Integer::New(8)); 9542 x->Get(v8_str("get")); 9543 x->Set(v8_str("set"), v8::Integer::New(8)); 9544 x->Get(v8_str("get")); 9545 } 9546 9547 9548 THREADED_TEST(Constructor) { 9549 LocalContext context; 9550 v8::HandleScope handle_scope(context->GetIsolate()); 9551 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 9552 templ->SetClassName(v8_str("Fun")); 9553 Local<Function> cons = templ->GetFunction(); 9554 context->Global()->Set(v8_str("Fun"), cons); 9555 Local<v8::Object> inst = cons->NewInstance(); 9556 i::Handle<i::JSObject> obj(v8::Utils::OpenHandle(*inst)); 9557 CHECK(obj->IsJSObject()); 9558 Local<Value> value = CompileRun("(new Fun()).constructor === Fun"); 9559 CHECK(value->BooleanValue()); 9560 } 9561 9562 9563 static void ConstructorCallback( 9564 const v8::FunctionCallbackInfo<v8::Value>& args) { 9565 ApiTestFuzzer::Fuzz(); 9566 Local<Object> This; 9567 9568 if (args.IsConstructCall()) { 9569 Local<Object> Holder = args.Holder(); 9570 This = Object::New(); 9571 Local<Value> proto = Holder->GetPrototype(); 9572 if (proto->IsObject()) { 9573 This->SetPrototype(proto); 9574 } 9575 } else { 9576 This = args.This(); 9577 } 9578 9579 This->Set(v8_str("a"), args[0]); 9580 args.GetReturnValue().Set(This); 9581 } 9582 9583 9584 static void FakeConstructorCallback( 9585 const v8::FunctionCallbackInfo<v8::Value>& args) { 9586 ApiTestFuzzer::Fuzz(); 9587 args.GetReturnValue().Set(args[0]); 9588 } 9589 9590 9591 THREADED_TEST(ConstructorForObject) { 9592 LocalContext context; 9593 v8::HandleScope handle_scope(context->GetIsolate()); 9594 9595 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 9596 instance_template->SetCallAsFunctionHandler(ConstructorCallback); 9597 Local<Object> instance = instance_template->NewInstance(); 9598 context->Global()->Set(v8_str("obj"), instance); 9599 v8::TryCatch try_catch; 9600 Local<Value> value; 9601 CHECK(!try_catch.HasCaught()); 9602 9603 // Call the Object's constructor with a 32-bit signed integer. 9604 value = CompileRun("(function() { var o = new obj(28); return o.a; })()"); 9605 CHECK(!try_catch.HasCaught()); 9606 CHECK(value->IsInt32()); 9607 CHECK_EQ(28, value->Int32Value()); 9608 9609 Local<Value> args1[] = { v8_num(28) }; 9610 Local<Value> value_obj1 = instance->CallAsConstructor(1, args1); 9611 CHECK(value_obj1->IsObject()); 9612 Local<Object> object1 = Local<Object>::Cast(value_obj1); 9613 value = object1->Get(v8_str("a")); 9614 CHECK(value->IsInt32()); 9615 CHECK(!try_catch.HasCaught()); 9616 CHECK_EQ(28, value->Int32Value()); 9617 9618 // Call the Object's constructor with a String. 9619 value = CompileRun( 9620 "(function() { var o = new obj('tipli'); return o.a; })()"); 9621 CHECK(!try_catch.HasCaught()); 9622 CHECK(value->IsString()); 9623 String::Utf8Value string_value1(value->ToString()); 9624 CHECK_EQ("tipli", *string_value1); 9625 9626 Local<Value> args2[] = { v8_str("tipli") }; 9627 Local<Value> value_obj2 = instance->CallAsConstructor(1, args2); 9628 CHECK(value_obj2->IsObject()); 9629 Local<Object> object2 = Local<Object>::Cast(value_obj2); 9630 value = object2->Get(v8_str("a")); 9631 CHECK(!try_catch.HasCaught()); 9632 CHECK(value->IsString()); 9633 String::Utf8Value string_value2(value->ToString()); 9634 CHECK_EQ("tipli", *string_value2); 9635 9636 // Call the Object's constructor with a Boolean. 9637 value = CompileRun("(function() { var o = new obj(true); return o.a; })()"); 9638 CHECK(!try_catch.HasCaught()); 9639 CHECK(value->IsBoolean()); 9640 CHECK_EQ(true, value->BooleanValue()); 9641 9642 Handle<Value> args3[] = { v8::True() }; 9643 Local<Value> value_obj3 = instance->CallAsConstructor(1, args3); 9644 CHECK(value_obj3->IsObject()); 9645 Local<Object> object3 = Local<Object>::Cast(value_obj3); 9646 value = object3->Get(v8_str("a")); 9647 CHECK(!try_catch.HasCaught()); 9648 CHECK(value->IsBoolean()); 9649 CHECK_EQ(true, value->BooleanValue()); 9650 9651 // Call the Object's constructor with undefined. 9652 Handle<Value> args4[] = { v8::Undefined() }; 9653 Local<Value> value_obj4 = instance->CallAsConstructor(1, args4); 9654 CHECK(value_obj4->IsObject()); 9655 Local<Object> object4 = Local<Object>::Cast(value_obj4); 9656 value = object4->Get(v8_str("a")); 9657 CHECK(!try_catch.HasCaught()); 9658 CHECK(value->IsUndefined()); 9659 9660 // Call the Object's constructor with null. 9661 Handle<Value> args5[] = { v8::Null() }; 9662 Local<Value> value_obj5 = instance->CallAsConstructor(1, args5); 9663 CHECK(value_obj5->IsObject()); 9664 Local<Object> object5 = Local<Object>::Cast(value_obj5); 9665 value = object5->Get(v8_str("a")); 9666 CHECK(!try_catch.HasCaught()); 9667 CHECK(value->IsNull()); 9668 } 9669 9670 // Check exception handling when there is no constructor set for the Object. 9671 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 9672 Local<Object> instance = instance_template->NewInstance(); 9673 context->Global()->Set(v8_str("obj2"), instance); 9674 v8::TryCatch try_catch; 9675 Local<Value> value; 9676 CHECK(!try_catch.HasCaught()); 9677 9678 value = CompileRun("new obj2(28)"); 9679 CHECK(try_catch.HasCaught()); 9680 String::Utf8Value exception_value1(try_catch.Exception()); 9681 CHECK_EQ("TypeError: object is not a function", *exception_value1); 9682 try_catch.Reset(); 9683 9684 Local<Value> args[] = { v8_num(29) }; 9685 value = instance->CallAsConstructor(1, args); 9686 CHECK(try_catch.HasCaught()); 9687 String::Utf8Value exception_value2(try_catch.Exception()); 9688 CHECK_EQ("TypeError: #<Object> is not a function", *exception_value2); 9689 try_catch.Reset(); 9690 } 9691 9692 // Check the case when constructor throws exception. 9693 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 9694 instance_template->SetCallAsFunctionHandler(ThrowValue); 9695 Local<Object> instance = instance_template->NewInstance(); 9696 context->Global()->Set(v8_str("obj3"), instance); 9697 v8::TryCatch try_catch; 9698 Local<Value> value; 9699 CHECK(!try_catch.HasCaught()); 9700 9701 value = CompileRun("new obj3(22)"); 9702 CHECK(try_catch.HasCaught()); 9703 String::Utf8Value exception_value1(try_catch.Exception()); 9704 CHECK_EQ("22", *exception_value1); 9705 try_catch.Reset(); 9706 9707 Local<Value> args[] = { v8_num(23) }; 9708 value = instance->CallAsConstructor(1, args); 9709 CHECK(try_catch.HasCaught()); 9710 String::Utf8Value exception_value2(try_catch.Exception()); 9711 CHECK_EQ("23", *exception_value2); 9712 try_catch.Reset(); 9713 } 9714 9715 // Check whether constructor returns with an object or non-object. 9716 { Local<FunctionTemplate> function_template = 9717 FunctionTemplate::New(FakeConstructorCallback); 9718 Local<Function> function = function_template->GetFunction(); 9719 Local<Object> instance1 = function; 9720 context->Global()->Set(v8_str("obj4"), instance1); 9721 v8::TryCatch try_catch; 9722 Local<Value> value; 9723 CHECK(!try_catch.HasCaught()); 9724 9725 CHECK(instance1->IsObject()); 9726 CHECK(instance1->IsFunction()); 9727 9728 value = CompileRun("new obj4(28)"); 9729 CHECK(!try_catch.HasCaught()); 9730 CHECK(value->IsObject()); 9731 9732 Local<Value> args1[] = { v8_num(28) }; 9733 value = instance1->CallAsConstructor(1, args1); 9734 CHECK(!try_catch.HasCaught()); 9735 CHECK(value->IsObject()); 9736 9737 Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 9738 instance_template->SetCallAsFunctionHandler(FakeConstructorCallback); 9739 Local<Object> instance2 = instance_template->NewInstance(); 9740 context->Global()->Set(v8_str("obj5"), instance2); 9741 CHECK(!try_catch.HasCaught()); 9742 9743 CHECK(instance2->IsObject()); 9744 CHECK(!instance2->IsFunction()); 9745 9746 value = CompileRun("new obj5(28)"); 9747 CHECK(!try_catch.HasCaught()); 9748 CHECK(!value->IsObject()); 9749 9750 Local<Value> args2[] = { v8_num(28) }; 9751 value = instance2->CallAsConstructor(1, args2); 9752 CHECK(!try_catch.HasCaught()); 9753 CHECK(!value->IsObject()); 9754 } 9755 } 9756 9757 9758 THREADED_TEST(FunctionDescriptorException) { 9759 LocalContext context; 9760 v8::HandleScope handle_scope(context->GetIsolate()); 9761 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 9762 templ->SetClassName(v8_str("Fun")); 9763 Local<Function> cons = templ->GetFunction(); 9764 context->Global()->Set(v8_str("Fun"), cons); 9765 Local<Value> value = CompileRun( 9766 "function test() {" 9767 " try {" 9768 " (new Fun()).blah()" 9769 " } catch (e) {" 9770 " var str = String(e);" 9771 " if (str.indexOf('TypeError') == -1) return 1;" 9772 " if (str.indexOf('[object Fun]') != -1) return 2;" 9773 " if (str.indexOf('#<Fun>') == -1) return 3;" 9774 " return 0;" 9775 " }" 9776 " return 4;" 9777 "}" 9778 "test();"); 9779 CHECK_EQ(0, value->Int32Value()); 9780 } 9781 9782 9783 THREADED_TEST(EvalAliasedDynamic) { 9784 LocalContext current; 9785 v8::HandleScope scope(current->GetIsolate()); 9786 9787 // Tests where aliased eval can only be resolved dynamically. 9788 Local<Script> script = 9789 Script::Compile(v8_str("function f(x) { " 9790 " var foo = 2;" 9791 " with (x) { return eval('foo'); }" 9792 "}" 9793 "foo = 0;" 9794 "result1 = f(new Object());" 9795 "result2 = f(this);" 9796 "var x = new Object();" 9797 "x.eval = function(x) { return 1; };" 9798 "result3 = f(x);")); 9799 script->Run(); 9800 CHECK_EQ(2, current->Global()->Get(v8_str("result1"))->Int32Value()); 9801 CHECK_EQ(0, current->Global()->Get(v8_str("result2"))->Int32Value()); 9802 CHECK_EQ(1, current->Global()->Get(v8_str("result3"))->Int32Value()); 9803 9804 v8::TryCatch try_catch; 9805 script = 9806 Script::Compile(v8_str("function f(x) { " 9807 " var bar = 2;" 9808 " with (x) { return eval('bar'); }" 9809 "}" 9810 "result4 = f(this)")); 9811 script->Run(); 9812 CHECK(!try_catch.HasCaught()); 9813 CHECK_EQ(2, current->Global()->Get(v8_str("result4"))->Int32Value()); 9814 9815 try_catch.Reset(); 9816 } 9817 9818 9819 THREADED_TEST(CrossEval) { 9820 v8::HandleScope scope(v8::Isolate::GetCurrent()); 9821 LocalContext other; 9822 LocalContext current; 9823 9824 Local<String> token = v8_str("<security token>"); 9825 other->SetSecurityToken(token); 9826 current->SetSecurityToken(token); 9827 9828 // Set up reference from current to other. 9829 current->Global()->Set(v8_str("other"), other->Global()); 9830 9831 // Check that new variables are introduced in other context. 9832 Local<Script> script = 9833 Script::Compile(v8_str("other.eval('var foo = 1234')")); 9834 script->Run(); 9835 Local<Value> foo = other->Global()->Get(v8_str("foo")); 9836 CHECK_EQ(1234, foo->Int32Value()); 9837 CHECK(!current->Global()->Has(v8_str("foo"))); 9838 9839 // Check that writing to non-existing properties introduces them in 9840 // the other context. 9841 script = 9842 Script::Compile(v8_str("other.eval('na = 1234')")); 9843 script->Run(); 9844 CHECK_EQ(1234, other->Global()->Get(v8_str("na"))->Int32Value()); 9845 CHECK(!current->Global()->Has(v8_str("na"))); 9846 9847 // Check that global variables in current context are not visible in other 9848 // context. 9849 v8::TryCatch try_catch; 9850 script = 9851 Script::Compile(v8_str("var bar = 42; other.eval('bar');")); 9852 Local<Value> result = script->Run(); 9853 CHECK(try_catch.HasCaught()); 9854 try_catch.Reset(); 9855 9856 // Check that local variables in current context are not visible in other 9857 // context. 9858 script = 9859 Script::Compile(v8_str("(function() { " 9860 " var baz = 87;" 9861 " return other.eval('baz');" 9862 "})();")); 9863 result = script->Run(); 9864 CHECK(try_catch.HasCaught()); 9865 try_catch.Reset(); 9866 9867 // Check that global variables in the other environment are visible 9868 // when evaluting code. 9869 other->Global()->Set(v8_str("bis"), v8_num(1234)); 9870 script = Script::Compile(v8_str("other.eval('bis')")); 9871 CHECK_EQ(1234, script->Run()->Int32Value()); 9872 CHECK(!try_catch.HasCaught()); 9873 9874 // Check that the 'this' pointer points to the global object evaluating 9875 // code. 9876 other->Global()->Set(v8_str("t"), other->Global()); 9877 script = Script::Compile(v8_str("other.eval('this == t')")); 9878 result = script->Run(); 9879 CHECK(result->IsTrue()); 9880 CHECK(!try_catch.HasCaught()); 9881 9882 // Check that variables introduced in with-statement are not visible in 9883 // other context. 9884 script = 9885 Script::Compile(v8_str("with({x:2}){other.eval('x')}")); 9886 result = script->Run(); 9887 CHECK(try_catch.HasCaught()); 9888 try_catch.Reset(); 9889 9890 // Check that you cannot use 'eval.call' with another object than the 9891 // current global object. 9892 script = 9893 Script::Compile(v8_str("other.y = 1; eval.call(other, 'y')")); 9894 result = script->Run(); 9895 CHECK(try_catch.HasCaught()); 9896 } 9897 9898 9899 // Test that calling eval in a context which has been detached from 9900 // its global throws an exception. This behavior is consistent with 9901 // other JavaScript implementations. 9902 THREADED_TEST(EvalInDetachedGlobal) { 9903 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 9904 v8::HandleScope scope(isolate); 9905 9906 v8::Local<Context> context0 = Context::New(isolate); 9907 v8::Local<Context> context1 = Context::New(isolate); 9908 9909 // Set up function in context0 that uses eval from context0. 9910 context0->Enter(); 9911 v8::Handle<v8::Value> fun = 9912 CompileRun("var x = 42;" 9913 "(function() {" 9914 " var e = eval;" 9915 " return function(s) { return e(s); }" 9916 "})()"); 9917 context0->Exit(); 9918 9919 // Put the function into context1 and call it before and after 9920 // detaching the global. Before detaching, the call succeeds and 9921 // after detaching and exception is thrown. 9922 context1->Enter(); 9923 context1->Global()->Set(v8_str("fun"), fun); 9924 v8::Handle<v8::Value> x_value = CompileRun("fun('x')"); 9925 CHECK_EQ(42, x_value->Int32Value()); 9926 context0->DetachGlobal(); 9927 v8::TryCatch catcher; 9928 x_value = CompileRun("fun('x')"); 9929 CHECK(x_value.IsEmpty()); 9930 CHECK(catcher.HasCaught()); 9931 context1->Exit(); 9932 } 9933 9934 9935 THREADED_TEST(CrossLazyLoad) { 9936 v8::HandleScope scope(v8::Isolate::GetCurrent()); 9937 LocalContext other; 9938 LocalContext current; 9939 9940 Local<String> token = v8_str("<security token>"); 9941 other->SetSecurityToken(token); 9942 current->SetSecurityToken(token); 9943 9944 // Set up reference from current to other. 9945 current->Global()->Set(v8_str("other"), other->Global()); 9946 9947 // Trigger lazy loading in other context. 9948 Local<Script> script = 9949 Script::Compile(v8_str("other.eval('new Date(42)')")); 9950 Local<Value> value = script->Run(); 9951 CHECK_EQ(42.0, value->NumberValue()); 9952 } 9953 9954 9955 static void call_as_function(const v8::FunctionCallbackInfo<v8::Value>& args) { 9956 ApiTestFuzzer::Fuzz(); 9957 if (args.IsConstructCall()) { 9958 if (args[0]->IsInt32()) { 9959 args.GetReturnValue().Set(v8_num(-args[0]->Int32Value())); 9960 return; 9961 } 9962 } 9963 9964 args.GetReturnValue().Set(args[0]); 9965 } 9966 9967 9968 // Test that a call handler can be set for objects which will allow 9969 // non-function objects created through the API to be called as 9970 // functions. 9971 THREADED_TEST(CallAsFunction) { 9972 LocalContext context; 9973 v8::HandleScope scope(context->GetIsolate()); 9974 9975 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 9976 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 9977 instance_template->SetCallAsFunctionHandler(call_as_function); 9978 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 9979 context->Global()->Set(v8_str("obj"), instance); 9980 v8::TryCatch try_catch; 9981 Local<Value> value; 9982 CHECK(!try_catch.HasCaught()); 9983 9984 value = CompileRun("obj(42)"); 9985 CHECK(!try_catch.HasCaught()); 9986 CHECK_EQ(42, value->Int32Value()); 9987 9988 value = CompileRun("(function(o){return o(49)})(obj)"); 9989 CHECK(!try_catch.HasCaught()); 9990 CHECK_EQ(49, value->Int32Value()); 9991 9992 // test special case of call as function 9993 value = CompileRun("[obj]['0'](45)"); 9994 CHECK(!try_catch.HasCaught()); 9995 CHECK_EQ(45, value->Int32Value()); 9996 9997 value = CompileRun("obj.call = Function.prototype.call;" 9998 "obj.call(null, 87)"); 9999 CHECK(!try_catch.HasCaught()); 10000 CHECK_EQ(87, value->Int32Value()); 10001 10002 // Regression tests for bug #1116356: Calling call through call/apply 10003 // must work for non-function receivers. 10004 const char* apply_99 = "Function.prototype.call.apply(obj, [this, 99])"; 10005 value = CompileRun(apply_99); 10006 CHECK(!try_catch.HasCaught()); 10007 CHECK_EQ(99, value->Int32Value()); 10008 10009 const char* call_17 = "Function.prototype.call.call(obj, this, 17)"; 10010 value = CompileRun(call_17); 10011 CHECK(!try_catch.HasCaught()); 10012 CHECK_EQ(17, value->Int32Value()); 10013 10014 // Check that the call-as-function handler can be called through 10015 // new. 10016 value = CompileRun("new obj(43)"); 10017 CHECK(!try_catch.HasCaught()); 10018 CHECK_EQ(-43, value->Int32Value()); 10019 10020 // Check that the call-as-function handler can be called through 10021 // the API. 10022 v8::Handle<Value> args[] = { v8_num(28) }; 10023 value = instance->CallAsFunction(instance, 1, args); 10024 CHECK(!try_catch.HasCaught()); 10025 CHECK_EQ(28, value->Int32Value()); 10026 } 10027 10028 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 10029 Local<ObjectTemplate> instance_template(t->InstanceTemplate()); 10030 USE(instance_template); 10031 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 10032 context->Global()->Set(v8_str("obj2"), instance); 10033 v8::TryCatch try_catch; 10034 Local<Value> value; 10035 CHECK(!try_catch.HasCaught()); 10036 10037 // Call an object without call-as-function handler through the JS 10038 value = CompileRun("obj2(28)"); 10039 CHECK(value.IsEmpty()); 10040 CHECK(try_catch.HasCaught()); 10041 String::Utf8Value exception_value1(try_catch.Exception()); 10042 CHECK_EQ("TypeError: Property 'obj2' of object #<Object> is not a function", 10043 *exception_value1); 10044 try_catch.Reset(); 10045 10046 // Call an object without call-as-function handler through the API 10047 value = CompileRun("obj2(28)"); 10048 v8::Handle<Value> args[] = { v8_num(28) }; 10049 value = instance->CallAsFunction(instance, 1, args); 10050 CHECK(value.IsEmpty()); 10051 CHECK(try_catch.HasCaught()); 10052 String::Utf8Value exception_value2(try_catch.Exception()); 10053 CHECK_EQ("TypeError: [object Object] is not a function", *exception_value2); 10054 try_catch.Reset(); 10055 } 10056 10057 { Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(); 10058 Local<ObjectTemplate> instance_template = t->InstanceTemplate(); 10059 instance_template->SetCallAsFunctionHandler(ThrowValue); 10060 Local<v8::Object> instance = t->GetFunction()->NewInstance(); 10061 context->Global()->Set(v8_str("obj3"), instance); 10062 v8::TryCatch try_catch; 10063 Local<Value> value; 10064 CHECK(!try_catch.HasCaught()); 10065 10066 // Catch the exception which is thrown by call-as-function handler 10067 value = CompileRun("obj3(22)"); 10068 CHECK(try_catch.HasCaught()); 10069 String::Utf8Value exception_value1(try_catch.Exception()); 10070 CHECK_EQ("22", *exception_value1); 10071 try_catch.Reset(); 10072 10073 v8::Handle<Value> args[] = { v8_num(23) }; 10074 value = instance->CallAsFunction(instance, 1, args); 10075 CHECK(try_catch.HasCaught()); 10076 String::Utf8Value exception_value2(try_catch.Exception()); 10077 CHECK_EQ("23", *exception_value2); 10078 try_catch.Reset(); 10079 } 10080 } 10081 10082 10083 // Check whether a non-function object is callable. 10084 THREADED_TEST(CallableObject) { 10085 LocalContext context; 10086 v8::HandleScope scope(context->GetIsolate()); 10087 10088 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 10089 instance_template->SetCallAsFunctionHandler(call_as_function); 10090 Local<Object> instance = instance_template->NewInstance(); 10091 v8::TryCatch try_catch; 10092 10093 CHECK(instance->IsCallable()); 10094 CHECK(!try_catch.HasCaught()); 10095 } 10096 10097 { Local<ObjectTemplate> instance_template = ObjectTemplate::New(); 10098 Local<Object> instance = instance_template->NewInstance(); 10099 v8::TryCatch try_catch; 10100 10101 CHECK(!instance->IsCallable()); 10102 CHECK(!try_catch.HasCaught()); 10103 } 10104 10105 { Local<FunctionTemplate> function_template = 10106 FunctionTemplate::New(call_as_function); 10107 Local<Function> function = function_template->GetFunction(); 10108 Local<Object> instance = function; 10109 v8::TryCatch try_catch; 10110 10111 CHECK(instance->IsCallable()); 10112 CHECK(!try_catch.HasCaught()); 10113 } 10114 10115 { Local<FunctionTemplate> function_template = FunctionTemplate::New(); 10116 Local<Function> function = function_template->GetFunction(); 10117 Local<Object> instance = function; 10118 v8::TryCatch try_catch; 10119 10120 CHECK(instance->IsCallable()); 10121 CHECK(!try_catch.HasCaught()); 10122 } 10123 } 10124 10125 10126 static int CountHandles() { 10127 return v8::HandleScope::NumberOfHandles(); 10128 } 10129 10130 10131 static int Recurse(int depth, int iterations) { 10132 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10133 if (depth == 0) return CountHandles(); 10134 for (int i = 0; i < iterations; i++) { 10135 Local<v8::Number> n(v8::Integer::New(42)); 10136 } 10137 return Recurse(depth - 1, iterations); 10138 } 10139 10140 10141 THREADED_TEST(HandleIteration) { 10142 static const int kIterations = 500; 10143 static const int kNesting = 200; 10144 CHECK_EQ(0, CountHandles()); 10145 { 10146 v8::HandleScope scope1(v8::Isolate::GetCurrent()); 10147 CHECK_EQ(0, CountHandles()); 10148 for (int i = 0; i < kIterations; i++) { 10149 Local<v8::Number> n(v8::Integer::New(42)); 10150 CHECK_EQ(i + 1, CountHandles()); 10151 } 10152 10153 CHECK_EQ(kIterations, CountHandles()); 10154 { 10155 v8::HandleScope scope2(v8::Isolate::GetCurrent()); 10156 for (int j = 0; j < kIterations; j++) { 10157 Local<v8::Number> n(v8::Integer::New(42)); 10158 CHECK_EQ(j + 1 + kIterations, CountHandles()); 10159 } 10160 } 10161 CHECK_EQ(kIterations, CountHandles()); 10162 } 10163 CHECK_EQ(0, CountHandles()); 10164 CHECK_EQ(kNesting * kIterations, Recurse(kNesting, kIterations)); 10165 } 10166 10167 10168 static void InterceptorHasOwnPropertyGetter( 10169 Local<String> name, 10170 const v8::PropertyCallbackInfo<v8::Value>& info) { 10171 ApiTestFuzzer::Fuzz(); 10172 } 10173 10174 10175 THREADED_TEST(InterceptorHasOwnProperty) { 10176 LocalContext context; 10177 v8::HandleScope scope(context->GetIsolate()); 10178 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 10179 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 10180 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter); 10181 Local<Function> function = fun_templ->GetFunction(); 10182 context->Global()->Set(v8_str("constructor"), function); 10183 v8::Handle<Value> value = CompileRun( 10184 "var o = new constructor();" 10185 "o.hasOwnProperty('ostehaps');"); 10186 CHECK_EQ(false, value->BooleanValue()); 10187 value = CompileRun( 10188 "o.ostehaps = 42;" 10189 "o.hasOwnProperty('ostehaps');"); 10190 CHECK_EQ(true, value->BooleanValue()); 10191 value = CompileRun( 10192 "var p = new constructor();" 10193 "p.hasOwnProperty('ostehaps');"); 10194 CHECK_EQ(false, value->BooleanValue()); 10195 } 10196 10197 10198 static void InterceptorHasOwnPropertyGetterGC( 10199 Local<String> name, 10200 const v8::PropertyCallbackInfo<v8::Value>& info) { 10201 ApiTestFuzzer::Fuzz(); 10202 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 10203 } 10204 10205 10206 THREADED_TEST(InterceptorHasOwnPropertyCausingGC) { 10207 LocalContext context; 10208 v8::HandleScope scope(context->GetIsolate()); 10209 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 10210 Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate(); 10211 instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC); 10212 Local<Function> function = fun_templ->GetFunction(); 10213 context->Global()->Set(v8_str("constructor"), function); 10214 // Let's first make some stuff so we can be sure to get a good GC. 10215 CompileRun( 10216 "function makestr(size) {" 10217 " switch (size) {" 10218 " case 1: return 'f';" 10219 " case 2: return 'fo';" 10220 " case 3: return 'foo';" 10221 " }" 10222 " return makestr(size >> 1) + makestr((size + 1) >> 1);" 10223 "}" 10224 "var x = makestr(12345);" 10225 "x = makestr(31415);" 10226 "x = makestr(23456);"); 10227 v8::Handle<Value> value = CompileRun( 10228 "var o = new constructor();" 10229 "o.__proto__ = new String(x);" 10230 "o.hasOwnProperty('ostehaps');"); 10231 CHECK_EQ(false, value->BooleanValue()); 10232 } 10233 10234 10235 typedef void (*NamedPropertyGetter)( 10236 Local<String> property, 10237 const v8::PropertyCallbackInfo<v8::Value>& info); 10238 10239 10240 static void CheckInterceptorLoadIC(NamedPropertyGetter getter, 10241 const char* source, 10242 int expected) { 10243 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10244 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10245 templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data")); 10246 LocalContext context; 10247 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10248 v8::Handle<Value> value = CompileRun(source); 10249 CHECK_EQ(expected, value->Int32Value()); 10250 } 10251 10252 10253 static void InterceptorLoadICGetter( 10254 Local<String> name, 10255 const v8::PropertyCallbackInfo<v8::Value>& info) { 10256 ApiTestFuzzer::Fuzz(); 10257 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 10258 CHECK_EQ(isolate, info.GetIsolate()); 10259 CHECK_EQ(v8_str("data"), info.Data()); 10260 CHECK_EQ(v8_str("x"), name); 10261 info.GetReturnValue().Set(v8::Integer::New(42)); 10262 } 10263 10264 10265 // This test should hit the load IC for the interceptor case. 10266 THREADED_TEST(InterceptorLoadIC) { 10267 CheckInterceptorLoadIC(InterceptorLoadICGetter, 10268 "var result = 0;" 10269 "for (var i = 0; i < 1000; i++) {" 10270 " result = o.x;" 10271 "}", 10272 42); 10273 } 10274 10275 10276 // Below go several tests which verify that JITing for various 10277 // configurations of interceptor and explicit fields works fine 10278 // (those cases are special cased to get better performance). 10279 10280 static void InterceptorLoadXICGetter( 10281 Local<String> name, 10282 const v8::PropertyCallbackInfo<v8::Value>& info) { 10283 ApiTestFuzzer::Fuzz(); 10284 info.GetReturnValue().Set( 10285 v8_str("x")->Equals(name) ? 10286 v8::Handle<v8::Value>(v8::Integer::New(42)) : 10287 v8::Handle<v8::Value>()); 10288 } 10289 10290 10291 THREADED_TEST(InterceptorLoadICWithFieldOnHolder) { 10292 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10293 "var result = 0;" 10294 "o.y = 239;" 10295 "for (var i = 0; i < 1000; i++) {" 10296 " result = o.y;" 10297 "}", 10298 239); 10299 } 10300 10301 10302 THREADED_TEST(InterceptorLoadICWithSubstitutedProto) { 10303 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10304 "var result = 0;" 10305 "o.__proto__ = { 'y': 239 };" 10306 "for (var i = 0; i < 1000; i++) {" 10307 " result = o.y + o.x;" 10308 "}", 10309 239 + 42); 10310 } 10311 10312 10313 THREADED_TEST(InterceptorLoadICWithPropertyOnProto) { 10314 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10315 "var result = 0;" 10316 "o.__proto__.y = 239;" 10317 "for (var i = 0; i < 1000; i++) {" 10318 " result = o.y + o.x;" 10319 "}", 10320 239 + 42); 10321 } 10322 10323 10324 THREADED_TEST(InterceptorLoadICUndefined) { 10325 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10326 "var result = 0;" 10327 "for (var i = 0; i < 1000; i++) {" 10328 " result = (o.y == undefined) ? 239 : 42;" 10329 "}", 10330 239); 10331 } 10332 10333 10334 THREADED_TEST(InterceptorLoadICWithOverride) { 10335 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10336 "fst = new Object(); fst.__proto__ = o;" 10337 "snd = new Object(); snd.__proto__ = fst;" 10338 "var result1 = 0;" 10339 "for (var i = 0; i < 1000; i++) {" 10340 " result1 = snd.x;" 10341 "}" 10342 "fst.x = 239;" 10343 "var result = 0;" 10344 "for (var i = 0; i < 1000; i++) {" 10345 " result = snd.x;" 10346 "}" 10347 "result + result1", 10348 239 + 42); 10349 } 10350 10351 10352 // Test the case when we stored field into 10353 // a stub, but interceptor produced value on its own. 10354 THREADED_TEST(InterceptorLoadICFieldNotNeeded) { 10355 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10356 "proto = new Object();" 10357 "o.__proto__ = proto;" 10358 "proto.x = 239;" 10359 "for (var i = 0; i < 1000; i++) {" 10360 " o.x;" 10361 // Now it should be ICed and keep a reference to x defined on proto 10362 "}" 10363 "var result = 0;" 10364 "for (var i = 0; i < 1000; i++) {" 10365 " result += o.x;" 10366 "}" 10367 "result;", 10368 42 * 1000); 10369 } 10370 10371 10372 // Test the case when we stored field into 10373 // a stub, but it got invalidated later on. 10374 THREADED_TEST(InterceptorLoadICInvalidatedField) { 10375 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10376 "proto1 = new Object();" 10377 "proto2 = new Object();" 10378 "o.__proto__ = proto1;" 10379 "proto1.__proto__ = proto2;" 10380 "proto2.y = 239;" 10381 "for (var i = 0; i < 1000; i++) {" 10382 " o.y;" 10383 // Now it should be ICed and keep a reference to y defined on proto2 10384 "}" 10385 "proto1.y = 42;" 10386 "var result = 0;" 10387 "for (var i = 0; i < 1000; i++) {" 10388 " result += o.y;" 10389 "}" 10390 "result;", 10391 42 * 1000); 10392 } 10393 10394 10395 static int interceptor_load_not_handled_calls = 0; 10396 static void InterceptorLoadNotHandled( 10397 Local<String> name, 10398 const v8::PropertyCallbackInfo<v8::Value>& info) { 10399 ++interceptor_load_not_handled_calls; 10400 } 10401 10402 10403 // Test how post-interceptor lookups are done in the non-cacheable 10404 // case: the interceptor should not be invoked during this lookup. 10405 THREADED_TEST(InterceptorLoadICPostInterceptor) { 10406 interceptor_load_not_handled_calls = 0; 10407 CheckInterceptorLoadIC(InterceptorLoadNotHandled, 10408 "receiver = new Object();" 10409 "receiver.__proto__ = o;" 10410 "proto = new Object();" 10411 "/* Make proto a slow-case object. */" 10412 "for (var i = 0; i < 1000; i++) {" 10413 " proto[\"xxxxxxxx\" + i] = [];" 10414 "}" 10415 "proto.x = 17;" 10416 "o.__proto__ = proto;" 10417 "var result = 0;" 10418 "for (var i = 0; i < 1000; i++) {" 10419 " result += receiver.x;" 10420 "}" 10421 "result;", 10422 17 * 1000); 10423 CHECK_EQ(1000, interceptor_load_not_handled_calls); 10424 } 10425 10426 10427 // Test the case when we stored field into 10428 // a stub, but it got invalidated later on due to override on 10429 // global object which is between interceptor and fields' holders. 10430 THREADED_TEST(InterceptorLoadICInvalidatedFieldViaGlobal) { 10431 CheckInterceptorLoadIC(InterceptorLoadXICGetter, 10432 "o.__proto__ = this;" // set a global to be a proto of o. 10433 "this.__proto__.y = 239;" 10434 "for (var i = 0; i < 10; i++) {" 10435 " if (o.y != 239) throw 'oops: ' + o.y;" 10436 // Now it should be ICed and keep a reference to y defined on field_holder. 10437 "}" 10438 "this.y = 42;" // Assign on a global. 10439 "var result = 0;" 10440 "for (var i = 0; i < 10; i++) {" 10441 " result += o.y;" 10442 "}" 10443 "result;", 10444 42 * 10); 10445 } 10446 10447 10448 static void SetOnThis(Local<String> name, 10449 Local<Value> value, 10450 const v8::PropertyCallbackInfo<void>& info) { 10451 info.This()->ForceSet(name, value); 10452 } 10453 10454 10455 THREADED_TEST(InterceptorLoadICWithCallbackOnHolder) { 10456 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10457 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10458 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 10459 templ->SetAccessor(v8_str("y"), Return239Callback); 10460 LocalContext context; 10461 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10462 10463 // Check the case when receiver and interceptor's holder 10464 // are the same objects. 10465 v8::Handle<Value> value = CompileRun( 10466 "var result = 0;" 10467 "for (var i = 0; i < 7; i++) {" 10468 " result = o.y;" 10469 "}"); 10470 CHECK_EQ(239, value->Int32Value()); 10471 10472 // Check the case when interceptor's holder is in proto chain 10473 // of receiver. 10474 value = CompileRun( 10475 "r = { __proto__: o };" 10476 "var result = 0;" 10477 "for (var i = 0; i < 7; i++) {" 10478 " result = r.y;" 10479 "}"); 10480 CHECK_EQ(239, value->Int32Value()); 10481 } 10482 10483 10484 THREADED_TEST(InterceptorLoadICWithCallbackOnProto) { 10485 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10486 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 10487 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 10488 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(); 10489 templ_p->SetAccessor(v8_str("y"), Return239Callback); 10490 10491 LocalContext context; 10492 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 10493 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 10494 10495 // Check the case when receiver and interceptor's holder 10496 // are the same objects. 10497 v8::Handle<Value> value = CompileRun( 10498 "o.__proto__ = p;" 10499 "var result = 0;" 10500 "for (var i = 0; i < 7; i++) {" 10501 " result = o.x + o.y;" 10502 "}"); 10503 CHECK_EQ(239 + 42, value->Int32Value()); 10504 10505 // Check the case when interceptor's holder is in proto chain 10506 // of receiver. 10507 value = CompileRun( 10508 "r = { __proto__: o };" 10509 "var result = 0;" 10510 "for (var i = 0; i < 7; i++) {" 10511 " result = r.x + r.y;" 10512 "}"); 10513 CHECK_EQ(239 + 42, value->Int32Value()); 10514 } 10515 10516 10517 THREADED_TEST(InterceptorLoadICForCallbackWithOverride) { 10518 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10519 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10520 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 10521 templ->SetAccessor(v8_str("y"), Return239Callback); 10522 10523 LocalContext context; 10524 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10525 10526 v8::Handle<Value> value = CompileRun( 10527 "fst = new Object(); fst.__proto__ = o;" 10528 "snd = new Object(); snd.__proto__ = fst;" 10529 "var result1 = 0;" 10530 "for (var i = 0; i < 7; i++) {" 10531 " result1 = snd.x;" 10532 "}" 10533 "fst.x = 239;" 10534 "var result = 0;" 10535 "for (var i = 0; i < 7; i++) {" 10536 " result = snd.x;" 10537 "}" 10538 "result + result1"); 10539 CHECK_EQ(239 + 42, value->Int32Value()); 10540 } 10541 10542 10543 // Test the case when we stored callback into 10544 // a stub, but interceptor produced value on its own. 10545 THREADED_TEST(InterceptorLoadICCallbackNotNeeded) { 10546 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10547 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 10548 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 10549 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(); 10550 templ_p->SetAccessor(v8_str("y"), Return239Callback); 10551 10552 LocalContext context; 10553 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 10554 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 10555 10556 v8::Handle<Value> value = CompileRun( 10557 "o.__proto__ = p;" 10558 "for (var i = 0; i < 7; i++) {" 10559 " o.x;" 10560 // Now it should be ICed and keep a reference to x defined on p 10561 "}" 10562 "var result = 0;" 10563 "for (var i = 0; i < 7; i++) {" 10564 " result += o.x;" 10565 "}" 10566 "result"); 10567 CHECK_EQ(42 * 7, value->Int32Value()); 10568 } 10569 10570 10571 // Test the case when we stored callback into 10572 // a stub, but it got invalidated later on. 10573 THREADED_TEST(InterceptorLoadICInvalidatedCallback) { 10574 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10575 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 10576 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 10577 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(); 10578 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis); 10579 10580 LocalContext context; 10581 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 10582 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 10583 10584 v8::Handle<Value> value = CompileRun( 10585 "inbetween = new Object();" 10586 "o.__proto__ = inbetween;" 10587 "inbetween.__proto__ = p;" 10588 "for (var i = 0; i < 10; i++) {" 10589 " o.y;" 10590 // Now it should be ICed and keep a reference to y defined on p 10591 "}" 10592 "inbetween.y = 42;" 10593 "var result = 0;" 10594 "for (var i = 0; i < 10; i++) {" 10595 " result += o.y;" 10596 "}" 10597 "result"); 10598 CHECK_EQ(42 * 10, value->Int32Value()); 10599 } 10600 10601 10602 // Test the case when we stored callback into 10603 // a stub, but it got invalidated later on due to override on 10604 // global object which is between interceptor and callbacks' holders. 10605 THREADED_TEST(InterceptorLoadICInvalidatedCallbackViaGlobal) { 10606 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10607 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 10608 templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter); 10609 v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(); 10610 templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis); 10611 10612 LocalContext context; 10613 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 10614 context->Global()->Set(v8_str("p"), templ_p->NewInstance()); 10615 10616 v8::Handle<Value> value = CompileRun( 10617 "o.__proto__ = this;" 10618 "this.__proto__ = p;" 10619 "for (var i = 0; i < 10; i++) {" 10620 " if (o.y != 239) throw 'oops: ' + o.y;" 10621 // Now it should be ICed and keep a reference to y defined on p 10622 "}" 10623 "this.y = 42;" 10624 "var result = 0;" 10625 "for (var i = 0; i < 10; i++) {" 10626 " result += o.y;" 10627 "}" 10628 "result"); 10629 CHECK_EQ(42 * 10, value->Int32Value()); 10630 } 10631 10632 10633 static void InterceptorLoadICGetter0( 10634 Local<String> name, 10635 const v8::PropertyCallbackInfo<v8::Value>& info) { 10636 ApiTestFuzzer::Fuzz(); 10637 CHECK(v8_str("x")->Equals(name)); 10638 info.GetReturnValue().Set(v8::Integer::New(0)); 10639 } 10640 10641 10642 THREADED_TEST(InterceptorReturningZero) { 10643 CheckInterceptorLoadIC(InterceptorLoadICGetter0, 10644 "o.x == undefined ? 1 : 0", 10645 0); 10646 } 10647 10648 10649 static void InterceptorStoreICSetter( 10650 Local<String> key, 10651 Local<Value> value, 10652 const v8::PropertyCallbackInfo<v8::Value>& info) { 10653 CHECK(v8_str("x")->Equals(key)); 10654 CHECK_EQ(42, value->Int32Value()); 10655 info.GetReturnValue().Set(value); 10656 } 10657 10658 10659 // This test should hit the store IC for the interceptor case. 10660 THREADED_TEST(InterceptorStoreIC) { 10661 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10662 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10663 templ->SetNamedPropertyHandler(InterceptorLoadICGetter, 10664 InterceptorStoreICSetter, 10665 0, 0, 0, v8_str("data")); 10666 LocalContext context; 10667 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10668 CompileRun( 10669 "for (var i = 0; i < 1000; i++) {" 10670 " o.x = 42;" 10671 "}"); 10672 } 10673 10674 10675 THREADED_TEST(InterceptorStoreICWithNoSetter) { 10676 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10677 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10678 templ->SetNamedPropertyHandler(InterceptorLoadXICGetter); 10679 LocalContext context; 10680 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10681 v8::Handle<Value> value = CompileRun( 10682 "for (var i = 0; i < 1000; i++) {" 10683 " o.y = 239;" 10684 "}" 10685 "42 + o.y"); 10686 CHECK_EQ(239 + 42, value->Int32Value()); 10687 } 10688 10689 10690 10691 10692 v8::Handle<Value> call_ic_function; 10693 v8::Handle<Value> call_ic_function2; 10694 v8::Handle<Value> call_ic_function3; 10695 10696 static void InterceptorCallICGetter( 10697 Local<String> name, 10698 const v8::PropertyCallbackInfo<v8::Value>& info) { 10699 ApiTestFuzzer::Fuzz(); 10700 CHECK(v8_str("x")->Equals(name)); 10701 info.GetReturnValue().Set(call_ic_function); 10702 } 10703 10704 10705 // This test should hit the call IC for the interceptor case. 10706 THREADED_TEST(InterceptorCallIC) { 10707 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10708 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10709 templ->SetNamedPropertyHandler(InterceptorCallICGetter); 10710 LocalContext context; 10711 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10712 call_ic_function = 10713 v8_compile("function f(x) { return x + 1; }; f")->Run(); 10714 v8::Handle<Value> value = CompileRun( 10715 "var result = 0;" 10716 "for (var i = 0; i < 1000; i++) {" 10717 " result = o.x(41);" 10718 "}"); 10719 CHECK_EQ(42, value->Int32Value()); 10720 } 10721 10722 10723 // This test checks that if interceptor doesn't provide 10724 // a value, we can fetch regular value. 10725 THREADED_TEST(InterceptorCallICSeesOthers) { 10726 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10727 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10728 templ->SetNamedPropertyHandler(NoBlockGetterX); 10729 LocalContext context; 10730 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10731 v8::Handle<Value> value = CompileRun( 10732 "o.x = function f(x) { return x + 1; };" 10733 "var result = 0;" 10734 "for (var i = 0; i < 7; i++) {" 10735 " result = o.x(41);" 10736 "}"); 10737 CHECK_EQ(42, value->Int32Value()); 10738 } 10739 10740 10741 static v8::Handle<Value> call_ic_function4; 10742 static void InterceptorCallICGetter4( 10743 Local<String> name, 10744 const v8::PropertyCallbackInfo<v8::Value>& info) { 10745 ApiTestFuzzer::Fuzz(); 10746 CHECK(v8_str("x")->Equals(name)); 10747 info.GetReturnValue().Set(call_ic_function4); 10748 } 10749 10750 10751 // This test checks that if interceptor provides a function, 10752 // even if we cached shadowed variant, interceptor's function 10753 // is invoked 10754 THREADED_TEST(InterceptorCallICCacheableNotNeeded) { 10755 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10756 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10757 templ->SetNamedPropertyHandler(InterceptorCallICGetter4); 10758 LocalContext context; 10759 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10760 call_ic_function4 = 10761 v8_compile("function f(x) { return x - 1; }; f")->Run(); 10762 v8::Handle<Value> value = CompileRun( 10763 "Object.getPrototypeOf(o).x = function(x) { return x + 1; };" 10764 "var result = 0;" 10765 "for (var i = 0; i < 1000; i++) {" 10766 " result = o.x(42);" 10767 "}"); 10768 CHECK_EQ(41, value->Int32Value()); 10769 } 10770 10771 10772 // Test the case when we stored cacheable lookup into 10773 // a stub, but it got invalidated later on 10774 THREADED_TEST(InterceptorCallICInvalidatedCacheable) { 10775 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10776 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10777 templ->SetNamedPropertyHandler(NoBlockGetterX); 10778 LocalContext context; 10779 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10780 v8::Handle<Value> value = CompileRun( 10781 "proto1 = new Object();" 10782 "proto2 = new Object();" 10783 "o.__proto__ = proto1;" 10784 "proto1.__proto__ = proto2;" 10785 "proto2.y = function(x) { return x + 1; };" 10786 // Invoke it many times to compile a stub 10787 "for (var i = 0; i < 7; i++) {" 10788 " o.y(42);" 10789 "}" 10790 "proto1.y = function(x) { return x - 1; };" 10791 "var result = 0;" 10792 "for (var i = 0; i < 7; i++) {" 10793 " result += o.y(42);" 10794 "}"); 10795 CHECK_EQ(41 * 7, value->Int32Value()); 10796 } 10797 10798 10799 // This test checks that if interceptor doesn't provide a function, 10800 // cached constant function is used 10801 THREADED_TEST(InterceptorCallICConstantFunctionUsed) { 10802 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10803 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10804 templ->SetNamedPropertyHandler(NoBlockGetterX); 10805 LocalContext context; 10806 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10807 v8::Handle<Value> value = CompileRun( 10808 "function inc(x) { return x + 1; };" 10809 "inc(1);" 10810 "o.x = inc;" 10811 "var result = 0;" 10812 "for (var i = 0; i < 1000; i++) {" 10813 " result = o.x(42);" 10814 "}"); 10815 CHECK_EQ(43, value->Int32Value()); 10816 } 10817 10818 10819 static v8::Handle<Value> call_ic_function5; 10820 static void InterceptorCallICGetter5( 10821 Local<String> name, 10822 const v8::PropertyCallbackInfo<v8::Value>& info) { 10823 ApiTestFuzzer::Fuzz(); 10824 if (v8_str("x")->Equals(name)) 10825 info.GetReturnValue().Set(call_ic_function5); 10826 } 10827 10828 10829 // This test checks that if interceptor provides a function, 10830 // even if we cached constant function, interceptor's function 10831 // is invoked 10832 THREADED_TEST(InterceptorCallICConstantFunctionNotNeeded) { 10833 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10834 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10835 templ->SetNamedPropertyHandler(InterceptorCallICGetter5); 10836 LocalContext context; 10837 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10838 call_ic_function5 = 10839 v8_compile("function f(x) { return x - 1; }; f")->Run(); 10840 v8::Handle<Value> value = CompileRun( 10841 "function inc(x) { return x + 1; };" 10842 "inc(1);" 10843 "o.x = inc;" 10844 "var result = 0;" 10845 "for (var i = 0; i < 1000; i++) {" 10846 " result = o.x(42);" 10847 "}"); 10848 CHECK_EQ(41, value->Int32Value()); 10849 } 10850 10851 10852 static v8::Handle<Value> call_ic_function6; 10853 static void InterceptorCallICGetter6( 10854 Local<String> name, 10855 const v8::PropertyCallbackInfo<v8::Value>& info) { 10856 ApiTestFuzzer::Fuzz(); 10857 if (v8_str("x")->Equals(name)) 10858 info.GetReturnValue().Set(call_ic_function6); 10859 } 10860 10861 10862 // Same test as above, except the code is wrapped in a function 10863 // to test the optimized compiler. 10864 THREADED_TEST(InterceptorCallICConstantFunctionNotNeededWrapped) { 10865 i::FLAG_allow_natives_syntax = true; 10866 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10867 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10868 templ->SetNamedPropertyHandler(InterceptorCallICGetter6); 10869 LocalContext context; 10870 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10871 call_ic_function6 = 10872 v8_compile("function f(x) { return x - 1; }; f")->Run(); 10873 v8::Handle<Value> value = CompileRun( 10874 "function inc(x) { return x + 1; };" 10875 "inc(1);" 10876 "o.x = inc;" 10877 "function test() {" 10878 " var result = 0;" 10879 " for (var i = 0; i < 1000; i++) {" 10880 " result = o.x(42);" 10881 " }" 10882 " return result;" 10883 "};" 10884 "test();" 10885 "test();" 10886 "test();" 10887 "%OptimizeFunctionOnNextCall(test);" 10888 "test()"); 10889 CHECK_EQ(41, value->Int32Value()); 10890 } 10891 10892 10893 // Test the case when we stored constant function into 10894 // a stub, but it got invalidated later on 10895 THREADED_TEST(InterceptorCallICInvalidatedConstantFunction) { 10896 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10897 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10898 templ->SetNamedPropertyHandler(NoBlockGetterX); 10899 LocalContext context; 10900 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10901 v8::Handle<Value> value = CompileRun( 10902 "function inc(x) { return x + 1; };" 10903 "inc(1);" 10904 "proto1 = new Object();" 10905 "proto2 = new Object();" 10906 "o.__proto__ = proto1;" 10907 "proto1.__proto__ = proto2;" 10908 "proto2.y = inc;" 10909 // Invoke it many times to compile a stub 10910 "for (var i = 0; i < 7; i++) {" 10911 " o.y(42);" 10912 "}" 10913 "proto1.y = function(x) { return x - 1; };" 10914 "var result = 0;" 10915 "for (var i = 0; i < 7; i++) {" 10916 " result += o.y(42);" 10917 "}"); 10918 CHECK_EQ(41 * 7, value->Int32Value()); 10919 } 10920 10921 10922 // Test the case when we stored constant function into 10923 // a stub, but it got invalidated later on due to override on 10924 // global object which is between interceptor and constant function' holders. 10925 THREADED_TEST(InterceptorCallICInvalidatedConstantFunctionViaGlobal) { 10926 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10927 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 10928 templ->SetNamedPropertyHandler(NoBlockGetterX); 10929 LocalContext context; 10930 context->Global()->Set(v8_str("o"), templ->NewInstance()); 10931 v8::Handle<Value> value = CompileRun( 10932 "function inc(x) { return x + 1; };" 10933 "inc(1);" 10934 "o.__proto__ = this;" 10935 "this.__proto__.y = inc;" 10936 // Invoke it many times to compile a stub 10937 "for (var i = 0; i < 7; i++) {" 10938 " if (o.y(42) != 43) throw 'oops: ' + o.y(42);" 10939 "}" 10940 "this.y = function(x) { return x - 1; };" 10941 "var result = 0;" 10942 "for (var i = 0; i < 7; i++) {" 10943 " result += o.y(42);" 10944 "}"); 10945 CHECK_EQ(41 * 7, value->Int32Value()); 10946 } 10947 10948 10949 // Test the case when actual function to call sits on global object. 10950 THREADED_TEST(InterceptorCallICCachedFromGlobal) { 10951 v8::HandleScope scope(v8::Isolate::GetCurrent()); 10952 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 10953 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 10954 10955 LocalContext context; 10956 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 10957 10958 v8::Handle<Value> value = CompileRun( 10959 "try {" 10960 " o.__proto__ = this;" 10961 " for (var i = 0; i < 10; i++) {" 10962 " var v = o.parseFloat('239');" 10963 " if (v != 239) throw v;" 10964 // Now it should be ICed and keep a reference to parseFloat. 10965 " }" 10966 " var result = 0;" 10967 " for (var i = 0; i < 10; i++) {" 10968 " result += o.parseFloat('239');" 10969 " }" 10970 " result" 10971 "} catch(e) {" 10972 " e" 10973 "};"); 10974 CHECK_EQ(239 * 10, value->Int32Value()); 10975 } 10976 10977 static void InterceptorCallICFastApi( 10978 Local<String> name, 10979 const v8::PropertyCallbackInfo<v8::Value>& info) { 10980 ApiTestFuzzer::Fuzz(); 10981 CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi)); 10982 int* call_count = 10983 reinterpret_cast<int*>(v8::External::Cast(*info.Data())->Value()); 10984 ++(*call_count); 10985 if ((*call_count) % 20 == 0) { 10986 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 10987 } 10988 } 10989 10990 static void FastApiCallback_TrivialSignature( 10991 const v8::FunctionCallbackInfo<v8::Value>& args) { 10992 ApiTestFuzzer::Fuzz(); 10993 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_TrivialSignature)); 10994 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 10995 CHECK_EQ(isolate, args.GetIsolate()); 10996 CHECK_EQ(args.This(), args.Holder()); 10997 CHECK(args.Data()->Equals(v8_str("method_data"))); 10998 args.GetReturnValue().Set(args[0]->Int32Value() + 1); 10999 } 11000 11001 static void FastApiCallback_SimpleSignature( 11002 const v8::FunctionCallbackInfo<v8::Value>& args) { 11003 ApiTestFuzzer::Fuzz(); 11004 CheckReturnValue(args, FUNCTION_ADDR(FastApiCallback_SimpleSignature)); 11005 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 11006 CHECK_EQ(isolate, args.GetIsolate()); 11007 CHECK_EQ(args.This()->GetPrototype(), args.Holder()); 11008 CHECK(args.Data()->Equals(v8_str("method_data"))); 11009 // Note, we're using HasRealNamedProperty instead of Has to avoid 11010 // invoking the interceptor again. 11011 CHECK(args.Holder()->HasRealNamedProperty(v8_str("foo"))); 11012 args.GetReturnValue().Set(args[0]->Int32Value() + 1); 11013 } 11014 11015 11016 // Helper to maximize the odds of object moving. 11017 static void GenerateSomeGarbage() { 11018 CompileRun( 11019 "var garbage;" 11020 "for (var i = 0; i < 1000; i++) {" 11021 " garbage = [1/i, \"garbage\" + i, garbage, {foo: garbage}];" 11022 "}" 11023 "garbage = undefined;"); 11024 } 11025 11026 11027 void DirectApiCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 11028 static int count = 0; 11029 if (count++ % 3 == 0) { 11030 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 11031 // This should move the stub 11032 GenerateSomeGarbage(); // This should ensure the old stub memory is flushed 11033 } 11034 } 11035 11036 11037 THREADED_TEST(CallICFastApi_DirectCall_GCMoveStub) { 11038 LocalContext context; 11039 v8::HandleScope scope(context->GetIsolate()); 11040 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New(); 11041 nativeobject_templ->Set("callback", 11042 v8::FunctionTemplate::New(DirectApiCallback)); 11043 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance(); 11044 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj); 11045 // call the api function multiple times to ensure direct call stub creation. 11046 CompileRun( 11047 "function f() {" 11048 " for (var i = 1; i <= 30; i++) {" 11049 " nativeobject.callback();" 11050 " }" 11051 "}" 11052 "f();"); 11053 } 11054 11055 11056 void ThrowingDirectApiCallback( 11057 const v8::FunctionCallbackInfo<v8::Value>& args) { 11058 v8::ThrowException(v8_str("g")); 11059 } 11060 11061 11062 THREADED_TEST(CallICFastApi_DirectCall_Throw) { 11063 LocalContext context; 11064 v8::HandleScope scope(context->GetIsolate()); 11065 v8::Handle<v8::ObjectTemplate> nativeobject_templ = v8::ObjectTemplate::New(); 11066 nativeobject_templ->Set("callback", 11067 v8::FunctionTemplate::New(ThrowingDirectApiCallback)); 11068 v8::Local<v8::Object> nativeobject_obj = nativeobject_templ->NewInstance(); 11069 context->Global()->Set(v8_str("nativeobject"), nativeobject_obj); 11070 // call the api function multiple times to ensure direct call stub creation. 11071 v8::Handle<Value> result = CompileRun( 11072 "var result = '';" 11073 "function f() {" 11074 " for (var i = 1; i <= 5; i++) {" 11075 " try { nativeobject.callback(); } catch (e) { result += e; }" 11076 " }" 11077 "}" 11078 "f(); result;"); 11079 CHECK_EQ(v8_str("ggggg"), result); 11080 } 11081 11082 11083 static Handle<Value> DoDirectGetter() { 11084 if (++p_getter_count % 3 == 0) { 11085 HEAP->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask); 11086 GenerateSomeGarbage(); 11087 } 11088 return v8_str("Direct Getter Result"); 11089 } 11090 11091 static void DirectGetterCallback( 11092 Local<String> name, 11093 const v8::PropertyCallbackInfo<v8::Value>& info) { 11094 CheckReturnValue(info, FUNCTION_ADDR(DirectGetterCallback)); 11095 info.GetReturnValue().Set(DoDirectGetter()); 11096 } 11097 11098 11099 template<typename Accessor> 11100 static void LoadICFastApi_DirectCall_GCMoveStub(Accessor accessor) { 11101 LocalContext context; 11102 v8::HandleScope scope(context->GetIsolate()); 11103 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(); 11104 obj->SetAccessor(v8_str("p1"), accessor); 11105 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 11106 p_getter_count = 0; 11107 v8::Handle<v8::Value> result = CompileRun( 11108 "function f() {" 11109 " for (var i = 0; i < 30; i++) o1.p1;" 11110 " return o1.p1" 11111 "}" 11112 "f();"); 11113 CHECK_EQ(v8_str("Direct Getter Result"), result); 11114 CHECK_EQ(31, p_getter_count); 11115 } 11116 11117 11118 THREADED_PROFILED_TEST(LoadICFastApi_DirectCall_GCMoveStub) { 11119 LoadICFastApi_DirectCall_GCMoveStub(DirectGetterCallback); 11120 } 11121 11122 11123 void ThrowingDirectGetterCallback( 11124 Local<String> name, 11125 const v8::PropertyCallbackInfo<v8::Value>& info) { 11126 v8::ThrowException(v8_str("g")); 11127 } 11128 11129 11130 THREADED_TEST(LoadICFastApi_DirectCall_Throw) { 11131 LocalContext context; 11132 v8::HandleScope scope(context->GetIsolate()); 11133 v8::Handle<v8::ObjectTemplate> obj = v8::ObjectTemplate::New(); 11134 obj->SetAccessor(v8_str("p1"), ThrowingDirectGetterCallback); 11135 context->Global()->Set(v8_str("o1"), obj->NewInstance()); 11136 v8::Handle<Value> result = CompileRun( 11137 "var result = '';" 11138 "for (var i = 0; i < 5; i++) {" 11139 " try { o1.p1; } catch (e) { result += e; }" 11140 "}" 11141 "result;"); 11142 CHECK_EQ(v8_str("ggggg"), result); 11143 } 11144 11145 11146 THREADED_PROFILED_TEST(InterceptorCallICFastApi_TrivialSignature) { 11147 int interceptor_call_count = 0; 11148 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11149 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11150 v8::Handle<v8::FunctionTemplate> method_templ = 11151 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature, 11152 v8_str("method_data"), 11153 v8::Handle<v8::Signature>()); 11154 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11155 proto_templ->Set(v8_str("method"), method_templ); 11156 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 11157 templ->SetNamedPropertyHandler(InterceptorCallICFastApi, 11158 NULL, NULL, NULL, NULL, 11159 v8::External::New(&interceptor_call_count)); 11160 LocalContext context; 11161 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11162 GenerateSomeGarbage(); 11163 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11164 CompileRun( 11165 "var result = 0;" 11166 "for (var i = 0; i < 100; i++) {" 11167 " result = o.method(41);" 11168 "}"); 11169 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 11170 CHECK_EQ(100, interceptor_call_count); 11171 } 11172 11173 11174 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature) { 11175 int interceptor_call_count = 0; 11176 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11177 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11178 v8::Handle<v8::FunctionTemplate> method_templ = 11179 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 11180 v8_str("method_data"), 11181 v8::Signature::New(fun_templ)); 11182 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11183 proto_templ->Set(v8_str("method"), method_templ); 11184 fun_templ->SetHiddenPrototype(true); 11185 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 11186 templ->SetNamedPropertyHandler(InterceptorCallICFastApi, 11187 NULL, NULL, NULL, NULL, 11188 v8::External::New(&interceptor_call_count)); 11189 LocalContext context; 11190 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11191 GenerateSomeGarbage(); 11192 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11193 CompileRun( 11194 "o.foo = 17;" 11195 "var receiver = {};" 11196 "receiver.__proto__ = o;" 11197 "var result = 0;" 11198 "for (var i = 0; i < 100; i++) {" 11199 " result = receiver.method(41);" 11200 "}"); 11201 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 11202 CHECK_EQ(100, interceptor_call_count); 11203 } 11204 11205 11206 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss1) { 11207 int interceptor_call_count = 0; 11208 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11209 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11210 v8::Handle<v8::FunctionTemplate> method_templ = 11211 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 11212 v8_str("method_data"), 11213 v8::Signature::New(fun_templ)); 11214 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11215 proto_templ->Set(v8_str("method"), method_templ); 11216 fun_templ->SetHiddenPrototype(true); 11217 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 11218 templ->SetNamedPropertyHandler(InterceptorCallICFastApi, 11219 NULL, NULL, NULL, NULL, 11220 v8::External::New(&interceptor_call_count)); 11221 LocalContext context; 11222 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11223 GenerateSomeGarbage(); 11224 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11225 CompileRun( 11226 "o.foo = 17;" 11227 "var receiver = {};" 11228 "receiver.__proto__ = o;" 11229 "var result = 0;" 11230 "var saved_result = 0;" 11231 "for (var i = 0; i < 100; i++) {" 11232 " result = receiver.method(41);" 11233 " if (i == 50) {" 11234 " saved_result = result;" 11235 " receiver = {method: function(x) { return x - 1 }};" 11236 " }" 11237 "}"); 11238 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 11239 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 11240 CHECK_GE(interceptor_call_count, 50); 11241 } 11242 11243 11244 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss2) { 11245 int interceptor_call_count = 0; 11246 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11247 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11248 v8::Handle<v8::FunctionTemplate> method_templ = 11249 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 11250 v8_str("method_data"), 11251 v8::Signature::New(fun_templ)); 11252 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11253 proto_templ->Set(v8_str("method"), method_templ); 11254 fun_templ->SetHiddenPrototype(true); 11255 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 11256 templ->SetNamedPropertyHandler(InterceptorCallICFastApi, 11257 NULL, NULL, NULL, NULL, 11258 v8::External::New(&interceptor_call_count)); 11259 LocalContext context; 11260 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11261 GenerateSomeGarbage(); 11262 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11263 CompileRun( 11264 "o.foo = 17;" 11265 "var receiver = {};" 11266 "receiver.__proto__ = o;" 11267 "var result = 0;" 11268 "var saved_result = 0;" 11269 "for (var i = 0; i < 100; i++) {" 11270 " result = receiver.method(41);" 11271 " if (i == 50) {" 11272 " saved_result = result;" 11273 " o.method = function(x) { return x - 1 };" 11274 " }" 11275 "}"); 11276 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 11277 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 11278 CHECK_GE(interceptor_call_count, 50); 11279 } 11280 11281 11282 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_Miss3) { 11283 int interceptor_call_count = 0; 11284 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11285 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11286 v8::Handle<v8::FunctionTemplate> method_templ = 11287 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 11288 v8_str("method_data"), 11289 v8::Signature::New(fun_templ)); 11290 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11291 proto_templ->Set(v8_str("method"), method_templ); 11292 fun_templ->SetHiddenPrototype(true); 11293 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 11294 templ->SetNamedPropertyHandler(InterceptorCallICFastApi, 11295 NULL, NULL, NULL, NULL, 11296 v8::External::New(&interceptor_call_count)); 11297 LocalContext context; 11298 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11299 GenerateSomeGarbage(); 11300 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11301 v8::TryCatch try_catch; 11302 CompileRun( 11303 "o.foo = 17;" 11304 "var receiver = {};" 11305 "receiver.__proto__ = o;" 11306 "var result = 0;" 11307 "var saved_result = 0;" 11308 "for (var i = 0; i < 100; i++) {" 11309 " result = receiver.method(41);" 11310 " if (i == 50) {" 11311 " saved_result = result;" 11312 " receiver = 333;" 11313 " }" 11314 "}"); 11315 CHECK(try_catch.HasCaught()); 11316 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"), 11317 try_catch.Exception()->ToString()); 11318 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 11319 CHECK_GE(interceptor_call_count, 50); 11320 } 11321 11322 11323 THREADED_PROFILED_TEST(InterceptorCallICFastApi_SimpleSignature_TypeError) { 11324 int interceptor_call_count = 0; 11325 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11326 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11327 v8::Handle<v8::FunctionTemplate> method_templ = 11328 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 11329 v8_str("method_data"), 11330 v8::Signature::New(fun_templ)); 11331 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11332 proto_templ->Set(v8_str("method"), method_templ); 11333 fun_templ->SetHiddenPrototype(true); 11334 v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate(); 11335 templ->SetNamedPropertyHandler(InterceptorCallICFastApi, 11336 NULL, NULL, NULL, NULL, 11337 v8::External::New(&interceptor_call_count)); 11338 LocalContext context; 11339 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11340 GenerateSomeGarbage(); 11341 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11342 v8::TryCatch try_catch; 11343 CompileRun( 11344 "o.foo = 17;" 11345 "var receiver = {};" 11346 "receiver.__proto__ = o;" 11347 "var result = 0;" 11348 "var saved_result = 0;" 11349 "for (var i = 0; i < 100; i++) {" 11350 " result = receiver.method(41);" 11351 " if (i == 50) {" 11352 " saved_result = result;" 11353 " receiver = {method: receiver.method};" 11354 " }" 11355 "}"); 11356 CHECK(try_catch.HasCaught()); 11357 CHECK_EQ(v8_str("TypeError: Illegal invocation"), 11358 try_catch.Exception()->ToString()); 11359 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 11360 CHECK_GE(interceptor_call_count, 50); 11361 } 11362 11363 11364 THREADED_PROFILED_TEST(CallICFastApi_TrivialSignature) { 11365 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11366 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11367 v8::Handle<v8::FunctionTemplate> method_templ = 11368 v8::FunctionTemplate::New(FastApiCallback_TrivialSignature, 11369 v8_str("method_data"), 11370 v8::Handle<v8::Signature>()); 11371 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11372 proto_templ->Set(v8_str("method"), method_templ); 11373 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 11374 USE(templ); 11375 LocalContext context; 11376 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11377 GenerateSomeGarbage(); 11378 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11379 CompileRun( 11380 "var result = 0;" 11381 "for (var i = 0; i < 100; i++) {" 11382 " result = o.method(41);" 11383 "}"); 11384 11385 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 11386 } 11387 11388 11389 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature) { 11390 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11391 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11392 v8::Handle<v8::FunctionTemplate> method_templ = 11393 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 11394 v8_str("method_data"), 11395 v8::Signature::New(fun_templ)); 11396 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11397 proto_templ->Set(v8_str("method"), method_templ); 11398 fun_templ->SetHiddenPrototype(true); 11399 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 11400 CHECK(!templ.IsEmpty()); 11401 LocalContext context; 11402 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11403 GenerateSomeGarbage(); 11404 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11405 CompileRun( 11406 "o.foo = 17;" 11407 "var receiver = {};" 11408 "receiver.__proto__ = o;" 11409 "var result = 0;" 11410 "for (var i = 0; i < 100; i++) {" 11411 " result = receiver.method(41);" 11412 "}"); 11413 11414 CHECK_EQ(42, context->Global()->Get(v8_str("result"))->Int32Value()); 11415 } 11416 11417 11418 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss1) { 11419 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11420 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11421 v8::Handle<v8::FunctionTemplate> method_templ = 11422 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 11423 v8_str("method_data"), 11424 v8::Signature::New(fun_templ)); 11425 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11426 proto_templ->Set(v8_str("method"), method_templ); 11427 fun_templ->SetHiddenPrototype(true); 11428 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 11429 CHECK(!templ.IsEmpty()); 11430 LocalContext context; 11431 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11432 GenerateSomeGarbage(); 11433 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11434 CompileRun( 11435 "o.foo = 17;" 11436 "var receiver = {};" 11437 "receiver.__proto__ = o;" 11438 "var result = 0;" 11439 "var saved_result = 0;" 11440 "for (var i = 0; i < 100; i++) {" 11441 " result = receiver.method(41);" 11442 " if (i == 50) {" 11443 " saved_result = result;" 11444 " receiver = {method: function(x) { return x - 1 }};" 11445 " }" 11446 "}"); 11447 CHECK_EQ(40, context->Global()->Get(v8_str("result"))->Int32Value()); 11448 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 11449 } 11450 11451 11452 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_Miss2) { 11453 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11454 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11455 v8::Handle<v8::FunctionTemplate> method_templ = 11456 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 11457 v8_str("method_data"), 11458 v8::Signature::New(fun_templ)); 11459 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11460 proto_templ->Set(v8_str("method"), method_templ); 11461 fun_templ->SetHiddenPrototype(true); 11462 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 11463 CHECK(!templ.IsEmpty()); 11464 LocalContext context; 11465 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11466 GenerateSomeGarbage(); 11467 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11468 v8::TryCatch try_catch; 11469 CompileRun( 11470 "o.foo = 17;" 11471 "var receiver = {};" 11472 "receiver.__proto__ = o;" 11473 "var result = 0;" 11474 "var saved_result = 0;" 11475 "for (var i = 0; i < 100; i++) {" 11476 " result = receiver.method(41);" 11477 " if (i == 50) {" 11478 " saved_result = result;" 11479 " receiver = 333;" 11480 " }" 11481 "}"); 11482 CHECK(try_catch.HasCaught()); 11483 CHECK_EQ(v8_str("TypeError: Object 333 has no method 'method'"), 11484 try_catch.Exception()->ToString()); 11485 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 11486 } 11487 11488 11489 THREADED_PROFILED_TEST(CallICFastApi_SimpleSignature_TypeError) { 11490 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11491 v8::Handle<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(); 11492 v8::Handle<v8::FunctionTemplate> method_templ = 11493 v8::FunctionTemplate::New(FastApiCallback_SimpleSignature, 11494 v8_str("method_data"), 11495 v8::Signature::New(fun_templ)); 11496 v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate(); 11497 proto_templ->Set(v8_str("method"), method_templ); 11498 fun_templ->SetHiddenPrototype(true); 11499 v8::Handle<v8::ObjectTemplate> templ(fun_templ->InstanceTemplate()); 11500 CHECK(!templ.IsEmpty()); 11501 LocalContext context; 11502 v8::Handle<v8::Function> fun = fun_templ->GetFunction(); 11503 GenerateSomeGarbage(); 11504 context->Global()->Set(v8_str("o"), fun->NewInstance()); 11505 v8::TryCatch try_catch; 11506 CompileRun( 11507 "o.foo = 17;" 11508 "var receiver = {};" 11509 "receiver.__proto__ = o;" 11510 "var result = 0;" 11511 "var saved_result = 0;" 11512 "for (var i = 0; i < 100; i++) {" 11513 " result = receiver.method(41);" 11514 " if (i == 50) {" 11515 " saved_result = result;" 11516 " receiver = Object.create(receiver);" 11517 " }" 11518 "}"); 11519 CHECK(try_catch.HasCaught()); 11520 CHECK_EQ(v8_str("TypeError: Illegal invocation"), 11521 try_catch.Exception()->ToString()); 11522 CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 11523 } 11524 11525 11526 v8::Handle<Value> keyed_call_ic_function; 11527 11528 static void InterceptorKeyedCallICGetter( 11529 Local<String> name, 11530 const v8::PropertyCallbackInfo<v8::Value>& info) { 11531 ApiTestFuzzer::Fuzz(); 11532 if (v8_str("x")->Equals(name)) { 11533 info.GetReturnValue().Set(keyed_call_ic_function); 11534 } 11535 } 11536 11537 11538 // Test the case when we stored cacheable lookup into 11539 // a stub, but the function name changed (to another cacheable function). 11540 THREADED_TEST(InterceptorKeyedCallICKeyChange1) { 11541 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11542 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11543 templ->SetNamedPropertyHandler(NoBlockGetterX); 11544 LocalContext context; 11545 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11546 CompileRun( 11547 "proto = new Object();" 11548 "proto.y = function(x) { return x + 1; };" 11549 "proto.z = function(x) { return x - 1; };" 11550 "o.__proto__ = proto;" 11551 "var result = 0;" 11552 "var method = 'y';" 11553 "for (var i = 0; i < 10; i++) {" 11554 " if (i == 5) { method = 'z'; };" 11555 " result += o[method](41);" 11556 "}"); 11557 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 11558 } 11559 11560 11561 // Test the case when we stored cacheable lookup into 11562 // a stub, but the function name changed (and the new function is present 11563 // both before and after the interceptor in the prototype chain). 11564 THREADED_TEST(InterceptorKeyedCallICKeyChange2) { 11565 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11566 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11567 templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter); 11568 LocalContext context; 11569 context->Global()->Set(v8_str("proto1"), templ->NewInstance()); 11570 keyed_call_ic_function = 11571 v8_compile("function f(x) { return x - 1; }; f")->Run(); 11572 CompileRun( 11573 "o = new Object();" 11574 "proto2 = new Object();" 11575 "o.y = function(x) { return x + 1; };" 11576 "proto2.y = function(x) { return x + 2; };" 11577 "o.__proto__ = proto1;" 11578 "proto1.__proto__ = proto2;" 11579 "var result = 0;" 11580 "var method = 'x';" 11581 "for (var i = 0; i < 10; i++) {" 11582 " if (i == 5) { method = 'y'; };" 11583 " result += o[method](41);" 11584 "}"); 11585 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 11586 } 11587 11588 11589 // Same as InterceptorKeyedCallICKeyChange1 only the cacheable function sit 11590 // on the global object. 11591 THREADED_TEST(InterceptorKeyedCallICKeyChangeOnGlobal) { 11592 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11593 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11594 templ->SetNamedPropertyHandler(NoBlockGetterX); 11595 LocalContext context; 11596 context->Global()->Set(v8_str("o"), templ->NewInstance()); 11597 CompileRun( 11598 "function inc(x) { return x + 1; };" 11599 "inc(1);" 11600 "function dec(x) { return x - 1; };" 11601 "dec(1);" 11602 "o.__proto__ = this;" 11603 "this.__proto__.x = inc;" 11604 "this.__proto__.y = dec;" 11605 "var result = 0;" 11606 "var method = 'x';" 11607 "for (var i = 0; i < 10; i++) {" 11608 " if (i == 5) { method = 'y'; };" 11609 " result += o[method](41);" 11610 "}"); 11611 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 11612 } 11613 11614 11615 // Test the case when actual function to call sits on global object. 11616 THREADED_TEST(InterceptorKeyedCallICFromGlobal) { 11617 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11618 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 11619 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 11620 LocalContext context; 11621 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11622 11623 CompileRun( 11624 "function len(x) { return x.length; };" 11625 "o.__proto__ = this;" 11626 "var m = 'parseFloat';" 11627 "var result = 0;" 11628 "for (var i = 0; i < 10; i++) {" 11629 " if (i == 5) {" 11630 " m = 'len';" 11631 " saved_result = result;" 11632 " };" 11633 " result = o[m]('239');" 11634 "}"); 11635 CHECK_EQ(3, context->Global()->Get(v8_str("result"))->Int32Value()); 11636 CHECK_EQ(239, context->Global()->Get(v8_str("saved_result"))->Int32Value()); 11637 } 11638 11639 11640 // Test the map transition before the interceptor. 11641 THREADED_TEST(InterceptorKeyedCallICMapChangeBefore) { 11642 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11643 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 11644 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 11645 LocalContext context; 11646 context->Global()->Set(v8_str("proto"), templ_o->NewInstance()); 11647 11648 CompileRun( 11649 "var o = new Object();" 11650 "o.__proto__ = proto;" 11651 "o.method = function(x) { return x + 1; };" 11652 "var m = 'method';" 11653 "var result = 0;" 11654 "for (var i = 0; i < 10; i++) {" 11655 " if (i == 5) { o.method = function(x) { return x - 1; }; };" 11656 " result += o[m](41);" 11657 "}"); 11658 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 11659 } 11660 11661 11662 // Test the map transition after the interceptor. 11663 THREADED_TEST(InterceptorKeyedCallICMapChangeAfter) { 11664 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11665 v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(); 11666 templ_o->SetNamedPropertyHandler(NoBlockGetterX); 11667 LocalContext context; 11668 context->Global()->Set(v8_str("o"), templ_o->NewInstance()); 11669 11670 CompileRun( 11671 "var proto = new Object();" 11672 "o.__proto__ = proto;" 11673 "proto.method = function(x) { return x + 1; };" 11674 "var m = 'method';" 11675 "var result = 0;" 11676 "for (var i = 0; i < 10; i++) {" 11677 " if (i == 5) { proto.method = function(x) { return x - 1; }; };" 11678 " result += o[m](41);" 11679 "}"); 11680 CHECK_EQ(42*5 + 40*5, context->Global()->Get(v8_str("result"))->Int32Value()); 11681 } 11682 11683 11684 static int interceptor_call_count = 0; 11685 11686 static void InterceptorICRefErrorGetter( 11687 Local<String> name, 11688 const v8::PropertyCallbackInfo<v8::Value>& info) { 11689 ApiTestFuzzer::Fuzz(); 11690 if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) { 11691 info.GetReturnValue().Set(call_ic_function2); 11692 } 11693 } 11694 11695 11696 // This test should hit load and call ICs for the interceptor case. 11697 // Once in a while, the interceptor will reply that a property was not 11698 // found in which case we should get a reference error. 11699 THREADED_TEST(InterceptorICReferenceErrors) { 11700 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11701 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11702 templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter); 11703 LocalContext context(0, templ, v8::Handle<Value>()); 11704 call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run(); 11705 v8::Handle<Value> value = CompileRun( 11706 "function f() {" 11707 " for (var i = 0; i < 1000; i++) {" 11708 " try { x; } catch(e) { return true; }" 11709 " }" 11710 " return false;" 11711 "};" 11712 "f();"); 11713 CHECK_EQ(true, value->BooleanValue()); 11714 interceptor_call_count = 0; 11715 value = CompileRun( 11716 "function g() {" 11717 " for (var i = 0; i < 1000; i++) {" 11718 " try { x(42); } catch(e) { return true; }" 11719 " }" 11720 " return false;" 11721 "};" 11722 "g();"); 11723 CHECK_EQ(true, value->BooleanValue()); 11724 } 11725 11726 11727 static int interceptor_ic_exception_get_count = 0; 11728 11729 static void InterceptorICExceptionGetter( 11730 Local<String> name, 11731 const v8::PropertyCallbackInfo<v8::Value>& info) { 11732 ApiTestFuzzer::Fuzz(); 11733 if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) { 11734 info.GetReturnValue().Set(call_ic_function3); 11735 } 11736 if (interceptor_ic_exception_get_count == 20) { 11737 v8::ThrowException(v8_num(42)); 11738 return; 11739 } 11740 } 11741 11742 11743 // Test interceptor load/call IC where the interceptor throws an 11744 // exception once in a while. 11745 THREADED_TEST(InterceptorICGetterExceptions) { 11746 interceptor_ic_exception_get_count = 0; 11747 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11748 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11749 templ->SetNamedPropertyHandler(InterceptorICExceptionGetter); 11750 LocalContext context(0, templ, v8::Handle<Value>()); 11751 call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run(); 11752 v8::Handle<Value> value = CompileRun( 11753 "function f() {" 11754 " for (var i = 0; i < 100; i++) {" 11755 " try { x; } catch(e) { return true; }" 11756 " }" 11757 " return false;" 11758 "};" 11759 "f();"); 11760 CHECK_EQ(true, value->BooleanValue()); 11761 interceptor_ic_exception_get_count = 0; 11762 value = CompileRun( 11763 "function f() {" 11764 " for (var i = 0; i < 100; i++) {" 11765 " try { x(42); } catch(e) { return true; }" 11766 " }" 11767 " return false;" 11768 "};" 11769 "f();"); 11770 CHECK_EQ(true, value->BooleanValue()); 11771 } 11772 11773 11774 static int interceptor_ic_exception_set_count = 0; 11775 11776 static void InterceptorICExceptionSetter( 11777 Local<String> key, 11778 Local<Value> value, 11779 const v8::PropertyCallbackInfo<v8::Value>& info) { 11780 ApiTestFuzzer::Fuzz(); 11781 if (++interceptor_ic_exception_set_count > 20) { 11782 v8::ThrowException(v8_num(42)); 11783 } 11784 } 11785 11786 11787 // Test interceptor store IC where the interceptor throws an exception 11788 // once in a while. 11789 THREADED_TEST(InterceptorICSetterExceptions) { 11790 interceptor_ic_exception_set_count = 0; 11791 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11792 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11793 templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter); 11794 LocalContext context(0, templ, v8::Handle<Value>()); 11795 v8::Handle<Value> value = CompileRun( 11796 "function f() {" 11797 " for (var i = 0; i < 100; i++) {" 11798 " try { x = 42; } catch(e) { return true; }" 11799 " }" 11800 " return false;" 11801 "};" 11802 "f();"); 11803 CHECK_EQ(true, value->BooleanValue()); 11804 } 11805 11806 11807 // Test that we ignore null interceptors. 11808 THREADED_TEST(NullNamedInterceptor) { 11809 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11810 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11811 templ->SetNamedPropertyHandler( 11812 static_cast<v8::NamedPropertyGetterCallback>(0)); 11813 LocalContext context; 11814 templ->Set("x", v8_num(42)); 11815 v8::Handle<v8::Object> obj = templ->NewInstance(); 11816 context->Global()->Set(v8_str("obj"), obj); 11817 v8::Handle<Value> value = CompileRun("obj.x"); 11818 CHECK(value->IsInt32()); 11819 CHECK_EQ(42, value->Int32Value()); 11820 } 11821 11822 11823 // Test that we ignore null interceptors. 11824 THREADED_TEST(NullIndexedInterceptor) { 11825 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11826 v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(); 11827 templ->SetIndexedPropertyHandler( 11828 static_cast<v8::IndexedPropertyGetterCallback>(0)); 11829 LocalContext context; 11830 templ->Set("42", v8_num(42)); 11831 v8::Handle<v8::Object> obj = templ->NewInstance(); 11832 context->Global()->Set(v8_str("obj"), obj); 11833 v8::Handle<Value> value = CompileRun("obj[42]"); 11834 CHECK(value->IsInt32()); 11835 CHECK_EQ(42, value->Int32Value()); 11836 } 11837 11838 11839 THREADED_TEST(NamedPropertyHandlerGetterAttributes) { 11840 v8::HandleScope scope(v8::Isolate::GetCurrent()); 11841 v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 11842 templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter); 11843 LocalContext env; 11844 env->Global()->Set(v8_str("obj"), 11845 templ->GetFunction()->NewInstance()); 11846 ExpectTrue("obj.x === 42"); 11847 ExpectTrue("!obj.propertyIsEnumerable('x')"); 11848 } 11849 11850 11851 static void ThrowingGetter(Local<String> name, 11852 const v8::PropertyCallbackInfo<v8::Value>& info) { 11853 ApiTestFuzzer::Fuzz(); 11854 ThrowException(Handle<Value>()); 11855 info.GetReturnValue().SetUndefined(); 11856 } 11857 11858 11859 THREADED_TEST(VariousGetPropertiesAndThrowingCallbacks) { 11860 LocalContext context; 11861 HandleScope scope(context->GetIsolate()); 11862 11863 Local<FunctionTemplate> templ = FunctionTemplate::New(); 11864 Local<ObjectTemplate> instance_templ = templ->InstanceTemplate(); 11865 instance_templ->SetAccessor(v8_str("f"), ThrowingGetter); 11866 11867 Local<Object> instance = templ->GetFunction()->NewInstance(); 11868 11869 Local<Object> another = Object::New(); 11870 another->SetPrototype(instance); 11871 11872 Local<Object> with_js_getter = CompileRun( 11873 "o = {};\n" 11874 "o.__defineGetter__('f', function() { throw undefined; });\n" 11875 "o\n").As<Object>(); 11876 CHECK(!with_js_getter.IsEmpty()); 11877 11878 TryCatch try_catch; 11879 11880 Local<Value> result = instance->GetRealNamedProperty(v8_str("f")); 11881 CHECK(try_catch.HasCaught()); 11882 try_catch.Reset(); 11883 CHECK(result.IsEmpty()); 11884 11885 result = another->GetRealNamedProperty(v8_str("f")); 11886 CHECK(try_catch.HasCaught()); 11887 try_catch.Reset(); 11888 CHECK(result.IsEmpty()); 11889 11890 result = another->GetRealNamedPropertyInPrototypeChain(v8_str("f")); 11891 CHECK(try_catch.HasCaught()); 11892 try_catch.Reset(); 11893 CHECK(result.IsEmpty()); 11894 11895 result = another->Get(v8_str("f")); 11896 CHECK(try_catch.HasCaught()); 11897 try_catch.Reset(); 11898 CHECK(result.IsEmpty()); 11899 11900 result = with_js_getter->GetRealNamedProperty(v8_str("f")); 11901 CHECK(try_catch.HasCaught()); 11902 try_catch.Reset(); 11903 CHECK(result.IsEmpty()); 11904 11905 result = with_js_getter->Get(v8_str("f")); 11906 CHECK(try_catch.HasCaught()); 11907 try_catch.Reset(); 11908 CHECK(result.IsEmpty()); 11909 } 11910 11911 11912 static void ThrowingCallbackWithTryCatch( 11913 const v8::FunctionCallbackInfo<v8::Value>& args) { 11914 TryCatch try_catch; 11915 // Verboseness is important: it triggers message delivery which can call into 11916 // external code. 11917 try_catch.SetVerbose(true); 11918 CompileRun("throw 'from JS';"); 11919 CHECK(try_catch.HasCaught()); 11920 CHECK(!i::Isolate::Current()->has_pending_exception()); 11921 CHECK(!i::Isolate::Current()->has_scheduled_exception()); 11922 } 11923 11924 11925 static int call_depth; 11926 11927 11928 static void WithTryCatch(Handle<Message> message, Handle<Value> data) { 11929 TryCatch try_catch; 11930 } 11931 11932 11933 static void ThrowFromJS(Handle<Message> message, Handle<Value> data) { 11934 if (--call_depth) CompileRun("throw 'ThrowInJS';"); 11935 } 11936 11937 11938 static void ThrowViaApi(Handle<Message> message, Handle<Value> data) { 11939 if (--call_depth) ThrowException(v8_str("ThrowViaApi")); 11940 } 11941 11942 11943 static void WebKitLike(Handle<Message> message, Handle<Value> data) { 11944 Handle<String> errorMessageString = message->Get(); 11945 CHECK(!errorMessageString.IsEmpty()); 11946 message->GetStackTrace(); 11947 message->GetScriptResourceName(); 11948 } 11949 11950 11951 THREADED_TEST(ExceptionsDoNotPropagatePastTryCatch) { 11952 LocalContext context; 11953 HandleScope scope(context->GetIsolate()); 11954 11955 Local<Function> func = 11956 FunctionTemplate::New(ThrowingCallbackWithTryCatch)->GetFunction(); 11957 context->Global()->Set(v8_str("func"), func); 11958 11959 MessageCallback callbacks[] = 11960 { NULL, WebKitLike, ThrowViaApi, ThrowFromJS, WithTryCatch }; 11961 for (unsigned i = 0; i < sizeof(callbacks)/sizeof(callbacks[0]); i++) { 11962 MessageCallback callback = callbacks[i]; 11963 if (callback != NULL) { 11964 V8::AddMessageListener(callback); 11965 } 11966 // Some small number to control number of times message handler should 11967 // throw an exception. 11968 call_depth = 5; 11969 ExpectFalse( 11970 "var thrown = false;\n" 11971 "try { func(); } catch(e) { thrown = true; }\n" 11972 "thrown\n"); 11973 if (callback != NULL) { 11974 V8::RemoveMessageListeners(callback); 11975 } 11976 } 11977 } 11978 11979 11980 static void ParentGetter(Local<String> name, 11981 const v8::PropertyCallbackInfo<v8::Value>& info) { 11982 ApiTestFuzzer::Fuzz(); 11983 info.GetReturnValue().Set(v8_num(1)); 11984 } 11985 11986 11987 static void ChildGetter(Local<String> name, 11988 const v8::PropertyCallbackInfo<v8::Value>& info) { 11989 ApiTestFuzzer::Fuzz(); 11990 info.GetReturnValue().Set(v8_num(42)); 11991 } 11992 11993 11994 THREADED_TEST(Overriding) { 11995 i::FLAG_es5_readonly = true; 11996 LocalContext context; 11997 v8::HandleScope scope(context->GetIsolate()); 11998 11999 // Parent template. 12000 Local<v8::FunctionTemplate> parent_templ = v8::FunctionTemplate::New(); 12001 Local<ObjectTemplate> parent_instance_templ = 12002 parent_templ->InstanceTemplate(); 12003 parent_instance_templ->SetAccessor(v8_str("f"), ParentGetter); 12004 12005 // Template that inherits from the parent template. 12006 Local<v8::FunctionTemplate> child_templ = v8::FunctionTemplate::New(); 12007 Local<ObjectTemplate> child_instance_templ = 12008 child_templ->InstanceTemplate(); 12009 child_templ->Inherit(parent_templ); 12010 // Override 'f'. The child version of 'f' should get called for child 12011 // instances. 12012 child_instance_templ->SetAccessor(v8_str("f"), ChildGetter); 12013 // Add 'g' twice. The 'g' added last should get called for instances. 12014 child_instance_templ->SetAccessor(v8_str("g"), ParentGetter); 12015 child_instance_templ->SetAccessor(v8_str("g"), ChildGetter); 12016 12017 // Add 'h' as an accessor to the proto template with ReadOnly attributes 12018 // so 'h' can be shadowed on the instance object. 12019 Local<ObjectTemplate> child_proto_templ = child_templ->PrototypeTemplate(); 12020 child_proto_templ->SetAccessor(v8_str("h"), ParentGetter, 0, 12021 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly); 12022 12023 // Add 'i' as an accessor to the instance template with ReadOnly attributes 12024 // but the attribute does not have effect because it is duplicated with 12025 // NULL setter. 12026 child_instance_templ->SetAccessor(v8_str("i"), ChildGetter, 0, 12027 v8::Handle<Value>(), v8::DEFAULT, v8::ReadOnly); 12028 12029 12030 12031 // Instantiate the child template. 12032 Local<v8::Object> instance = child_templ->GetFunction()->NewInstance(); 12033 12034 // Check that the child function overrides the parent one. 12035 context->Global()->Set(v8_str("o"), instance); 12036 Local<Value> value = v8_compile("o.f")->Run(); 12037 // Check that the 'g' that was added last is hit. 12038 CHECK_EQ(42, value->Int32Value()); 12039 value = v8_compile("o.g")->Run(); 12040 CHECK_EQ(42, value->Int32Value()); 12041 12042 // Check that 'h' cannot be shadowed. 12043 value = v8_compile("o.h = 3; o.h")->Run(); 12044 CHECK_EQ(1, value->Int32Value()); 12045 12046 // Check that 'i' cannot be shadowed or changed. 12047 value = v8_compile("o.i = 3; o.i")->Run(); 12048 CHECK_EQ(42, value->Int32Value()); 12049 } 12050 12051 12052 static void IsConstructHandler( 12053 const v8::FunctionCallbackInfo<v8::Value>& args) { 12054 ApiTestFuzzer::Fuzz(); 12055 args.GetReturnValue().Set(args.IsConstructCall()); 12056 } 12057 12058 12059 THREADED_TEST(IsConstructCall) { 12060 v8::HandleScope scope(v8::Isolate::GetCurrent()); 12061 12062 // Function template with call handler. 12063 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 12064 templ->SetCallHandler(IsConstructHandler); 12065 12066 LocalContext context; 12067 12068 context->Global()->Set(v8_str("f"), templ->GetFunction()); 12069 Local<Value> value = v8_compile("f()")->Run(); 12070 CHECK(!value->BooleanValue()); 12071 value = v8_compile("new f()")->Run(); 12072 CHECK(value->BooleanValue()); 12073 } 12074 12075 12076 THREADED_TEST(ObjectProtoToString) { 12077 v8::HandleScope scope(v8::Isolate::GetCurrent()); 12078 Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(); 12079 templ->SetClassName(v8_str("MyClass")); 12080 12081 LocalContext context; 12082 12083 Local<String> customized_tostring = v8_str("customized toString"); 12084 12085 // Replace Object.prototype.toString 12086 v8_compile("Object.prototype.toString = function() {" 12087 " return 'customized toString';" 12088 "}")->Run(); 12089 12090 // Normal ToString call should call replaced Object.prototype.toString 12091 Local<v8::Object> instance = templ->GetFunction()->NewInstance(); 12092 Local<String> value = instance->ToString(); 12093 CHECK(value->IsString() && value->Equals(customized_tostring)); 12094 12095 // ObjectProtoToString should not call replace toString function. 12096 value = instance->ObjectProtoToString(); 12097 CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]"))); 12098 12099 // Check global 12100 value = context->Global()->ObjectProtoToString(); 12101 CHECK(value->IsString() && value->Equals(v8_str("[object global]"))); 12102 12103 // Check ordinary object 12104 Local<Value> object = v8_compile("new Object()")->Run(); 12105 value = object.As<v8::Object>()->ObjectProtoToString(); 12106 CHECK(value->IsString() && value->Equals(v8_str("[object Object]"))); 12107 } 12108 12109 12110 THREADED_TEST(ObjectGetConstructorName) { 12111 LocalContext context; 12112 v8::HandleScope scope(context->GetIsolate()); 12113 v8_compile("function Parent() {};" 12114 "function Child() {};" 12115 "Child.prototype = new Parent();" 12116 "var outer = { inner: function() { } };" 12117 "var p = new Parent();" 12118 "var c = new Child();" 12119 "var x = new outer.inner();")->Run(); 12120 12121 Local<v8::Value> p = context->Global()->Get(v8_str("p")); 12122 CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals( 12123 v8_str("Parent"))); 12124 12125 Local<v8::Value> c = context->Global()->Get(v8_str("c")); 12126 CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals( 12127 v8_str("Child"))); 12128 12129 Local<v8::Value> x = context->Global()->Get(v8_str("x")); 12130 CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals( 12131 v8_str("outer.inner"))); 12132 } 12133 12134 12135 bool ApiTestFuzzer::fuzzing_ = false; 12136 i::Semaphore* ApiTestFuzzer::all_tests_done_= 12137 i::OS::CreateSemaphore(0); 12138 int ApiTestFuzzer::active_tests_; 12139 int ApiTestFuzzer::tests_being_run_; 12140 int ApiTestFuzzer::current_; 12141 12142 12143 // We are in a callback and want to switch to another thread (if we 12144 // are currently running the thread fuzzing test). 12145 void ApiTestFuzzer::Fuzz() { 12146 if (!fuzzing_) return; 12147 ApiTestFuzzer* test = RegisterThreadedTest::nth(current_)->fuzzer_; 12148 test->ContextSwitch(); 12149 } 12150 12151 12152 // Let the next thread go. Since it is also waiting on the V8 lock it may 12153 // not start immediately. 12154 bool ApiTestFuzzer::NextThread() { 12155 int test_position = GetNextTestNumber(); 12156 const char* test_name = RegisterThreadedTest::nth(current_)->name(); 12157 if (test_position == current_) { 12158 if (kLogThreading) 12159 printf("Stay with %s\n", test_name); 12160 return false; 12161 } 12162 if (kLogThreading) { 12163 printf("Switch from %s to %s\n", 12164 test_name, 12165 RegisterThreadedTest::nth(test_position)->name()); 12166 } 12167 current_ = test_position; 12168 RegisterThreadedTest::nth(current_)->fuzzer_->gate_->Signal(); 12169 return true; 12170 } 12171 12172 12173 void ApiTestFuzzer::Run() { 12174 // When it is our turn... 12175 gate_->Wait(); 12176 { 12177 // ... get the V8 lock and start running the test. 12178 v8::Locker locker(CcTest::default_isolate()); 12179 CallTest(); 12180 } 12181 // This test finished. 12182 active_ = false; 12183 active_tests_--; 12184 // If it was the last then signal that fact. 12185 if (active_tests_ == 0) { 12186 all_tests_done_->Signal(); 12187 } else { 12188 // Otherwise select a new test and start that. 12189 NextThread(); 12190 } 12191 } 12192 12193 12194 static unsigned linear_congruential_generator; 12195 12196 12197 void ApiTestFuzzer::SetUp(PartOfTest part) { 12198 linear_congruential_generator = i::FLAG_testing_prng_seed; 12199 fuzzing_ = true; 12200 int count = RegisterThreadedTest::count(); 12201 int start = count * part / (LAST_PART + 1); 12202 int end = (count * (part + 1) / (LAST_PART + 1)) - 1; 12203 active_tests_ = tests_being_run_ = end - start + 1; 12204 for (int i = 0; i < tests_being_run_; i++) { 12205 RegisterThreadedTest::nth(i)->fuzzer_ = new ApiTestFuzzer(i + start); 12206 } 12207 for (int i = 0; i < active_tests_; i++) { 12208 RegisterThreadedTest::nth(i)->fuzzer_->Start(); 12209 } 12210 } 12211 12212 12213 static void CallTestNumber(int test_number) { 12214 (RegisterThreadedTest::nth(test_number)->callback())(); 12215 } 12216 12217 12218 void ApiTestFuzzer::RunAllTests() { 12219 // Set off the first test. 12220 current_ = -1; 12221 NextThread(); 12222 // Wait till they are all done. 12223 all_tests_done_->Wait(); 12224 } 12225 12226 12227 int ApiTestFuzzer::GetNextTestNumber() { 12228 int next_test; 12229 do { 12230 next_test = (linear_congruential_generator >> 16) % tests_being_run_; 12231 linear_congruential_generator *= 1664525u; 12232 linear_congruential_generator += 1013904223u; 12233 } while (!RegisterThreadedTest::nth(next_test)->fuzzer_->active_); 12234 return next_test; 12235 } 12236 12237 12238 void ApiTestFuzzer::ContextSwitch() { 12239 // If the new thread is the same as the current thread there is nothing to do. 12240 if (NextThread()) { 12241 // Now it can start. 12242 v8::Unlocker unlocker(CcTest::default_isolate()); 12243 // Wait till someone starts us again. 12244 gate_->Wait(); 12245 // And we're off. 12246 } 12247 } 12248 12249 12250 void ApiTestFuzzer::TearDown() { 12251 fuzzing_ = false; 12252 for (int i = 0; i < RegisterThreadedTest::count(); i++) { 12253 ApiTestFuzzer *fuzzer = RegisterThreadedTest::nth(i)->fuzzer_; 12254 if (fuzzer != NULL) fuzzer->Join(); 12255 } 12256 } 12257 12258 12259 // Lets not be needlessly self-referential. 12260 TEST(Threading1) { 12261 // TODO(mstarzinger): Disabled in GC stress mode for now, we should find the 12262 // correct timeout for this an re-enable this test again 12263 if (i::FLAG_stress_compaction) return; 12264 ApiTestFuzzer::SetUp(ApiTestFuzzer::FIRST_PART); 12265 ApiTestFuzzer::RunAllTests(); 12266 ApiTestFuzzer::TearDown(); 12267 } 12268 12269 12270 TEST(Threading2) { 12271 ApiTestFuzzer::SetUp(ApiTestFuzzer::SECOND_PART); 12272 ApiTestFuzzer::RunAllTests(); 12273 ApiTestFuzzer::TearDown(); 12274 } 12275 12276 12277 TEST(Threading3) { 12278 ApiTestFuzzer::SetUp(ApiTestFuzzer::THIRD_PART); 12279 ApiTestFuzzer::RunAllTests(); 12280 ApiTestFuzzer::TearDown(); 12281 } 12282 12283 12284 TEST(Threading4) { 12285 ApiTestFuzzer::SetUp(ApiTestFuzzer::FOURTH_PART); 12286 ApiTestFuzzer::RunAllTests(); 12287 ApiTestFuzzer::TearDown(); 12288 } 12289 12290 12291 void ApiTestFuzzer::CallTest() { 12292 if (kLogThreading) 12293 printf("Start test %d\n", test_number_); 12294 CallTestNumber(test_number_); 12295 if (kLogThreading) 12296 printf("End test %d\n", test_number_); 12297 } 12298 12299 12300 static void ThrowInJS(const v8::FunctionCallbackInfo<v8::Value>& args) { 12301 CHECK(v8::Locker::IsLocked(CcTest::default_isolate())); 12302 ApiTestFuzzer::Fuzz(); 12303 v8::Unlocker unlocker(CcTest::default_isolate()); 12304 const char* code = "throw 7;"; 12305 { 12306 v8::Locker nested_locker(CcTest::default_isolate()); 12307 v8::HandleScope scope(args.GetIsolate()); 12308 v8::Handle<Value> exception; 12309 { v8::TryCatch try_catch; 12310 v8::Handle<Value> value = CompileRun(code); 12311 CHECK(value.IsEmpty()); 12312 CHECK(try_catch.HasCaught()); 12313 // Make sure to wrap the exception in a new handle because 12314 // the handle returned from the TryCatch is destroyed 12315 // when the TryCatch is destroyed. 12316 exception = Local<Value>::New(try_catch.Exception()); 12317 } 12318 v8::ThrowException(exception); 12319 } 12320 } 12321 12322 12323 static void ThrowInJSNoCatch(const v8::FunctionCallbackInfo<v8::Value>& args) { 12324 CHECK(v8::Locker::IsLocked(CcTest::default_isolate())); 12325 ApiTestFuzzer::Fuzz(); 12326 v8::Unlocker unlocker(CcTest::default_isolate()); 12327 const char* code = "throw 7;"; 12328 { 12329 v8::Locker nested_locker(CcTest::default_isolate()); 12330 v8::HandleScope scope(args.GetIsolate()); 12331 v8::Handle<Value> value = CompileRun(code); 12332 CHECK(value.IsEmpty()); 12333 args.GetReturnValue().Set(v8_str("foo")); 12334 } 12335 } 12336 12337 12338 // These are locking tests that don't need to be run again 12339 // as part of the locking aggregation tests. 12340 TEST(NestedLockers) { 12341 v8::Locker locker(CcTest::default_isolate()); 12342 CHECK(v8::Locker::IsLocked(CcTest::default_isolate())); 12343 LocalContext env; 12344 v8::HandleScope scope(env->GetIsolate()); 12345 Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(ThrowInJS); 12346 Local<Function> fun = fun_templ->GetFunction(); 12347 env->Global()->Set(v8_str("throw_in_js"), fun); 12348 Local<Script> script = v8_compile("(function () {" 12349 " try {" 12350 " throw_in_js();" 12351 " return 42;" 12352 " } catch (e) {" 12353 " return e * 13;" 12354 " }" 12355 "})();"); 12356 CHECK_EQ(91, script->Run()->Int32Value()); 12357 } 12358 12359 12360 // These are locking tests that don't need to be run again 12361 // as part of the locking aggregation tests. 12362 TEST(NestedLockersNoTryCatch) { 12363 v8::Locker locker(CcTest::default_isolate()); 12364 LocalContext env; 12365 v8::HandleScope scope(env->GetIsolate()); 12366 Local<v8::FunctionTemplate> fun_templ = 12367 v8::FunctionTemplate::New(ThrowInJSNoCatch); 12368 Local<Function> fun = fun_templ->GetFunction(); 12369 env->Global()->Set(v8_str("throw_in_js"), fun); 12370 Local<Script> script = v8_compile("(function () {" 12371 " try {" 12372 " throw_in_js();" 12373 " return 42;" 12374 " } catch (e) {" 12375 " return e * 13;" 12376 " }" 12377 "})();"); 12378 CHECK_EQ(91, script->Run()->Int32Value()); 12379 } 12380 12381 12382 THREADED_TEST(RecursiveLocking) { 12383 v8::Locker locker(CcTest::default_isolate()); 12384 { 12385 v8::Locker locker2(CcTest::default_isolate()); 12386 CHECK(v8::Locker::IsLocked(CcTest::default_isolate())); 12387 } 12388 } 12389 12390 12391 static void UnlockForAMoment(const v8::FunctionCallbackInfo<v8::Value>& args) { 12392 ApiTestFuzzer::Fuzz(); 12393 v8::Unlocker unlocker(CcTest::default_isolate()); 12394 } 12395 12396 12397 THREADED_TEST(LockUnlockLock) { 12398 { 12399 v8::Locker locker(CcTest::default_isolate()); 12400 v8::HandleScope scope(CcTest::default_isolate()); 12401 LocalContext env; 12402 Local<v8::FunctionTemplate> fun_templ = 12403 v8::FunctionTemplate::New(UnlockForAMoment); 12404 Local<Function> fun = fun_templ->GetFunction(); 12405 env->Global()->Set(v8_str("unlock_for_a_moment"), fun); 12406 Local<Script> script = v8_compile("(function () {" 12407 " unlock_for_a_moment();" 12408 " return 42;" 12409 "})();"); 12410 CHECK_EQ(42, script->Run()->Int32Value()); 12411 } 12412 { 12413 v8::Locker locker(CcTest::default_isolate()); 12414 v8::HandleScope scope(CcTest::default_isolate()); 12415 LocalContext env; 12416 Local<v8::FunctionTemplate> fun_templ = 12417 v8::FunctionTemplate::New(UnlockForAMoment); 12418 Local<Function> fun = fun_templ->GetFunction(); 12419 env->Global()->Set(v8_str("unlock_for_a_moment"), fun); 12420 Local<Script> script = v8_compile("(function () {" 12421 " unlock_for_a_moment();" 12422 " return 42;" 12423 "})();"); 12424 CHECK_EQ(42, script->Run()->Int32Value()); 12425 } 12426 } 12427 12428 12429 static int GetGlobalObjectsCount() { 12430 i::Isolate::Current()->heap()->EnsureHeapIsIterable(); 12431 int count = 0; 12432 i::HeapIterator it(HEAP); 12433 for (i::HeapObject* object = it.next(); object != NULL; object = it.next()) 12434 if (object->IsJSGlobalObject()) count++; 12435 return count; 12436 } 12437 12438 12439 static void CheckSurvivingGlobalObjectsCount(int expected) { 12440 // We need to collect all garbage twice to be sure that everything 12441 // has been collected. This is because inline caches are cleared in 12442 // the first garbage collection but some of the maps have already 12443 // been marked at that point. Therefore some of the maps are not 12444 // collected until the second garbage collection. 12445 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 12446 HEAP->CollectAllGarbage(i::Heap::kMakeHeapIterableMask); 12447 int count = GetGlobalObjectsCount(); 12448 #ifdef DEBUG 12449 if (count != expected) HEAP->TracePathToGlobal(); 12450 #endif 12451 CHECK_EQ(expected, count); 12452 } 12453 12454 12455 TEST(DontLeakGlobalObjects) { 12456 // Regression test for issues 1139850 and 1174891. 12457 12458 v8::V8::Initialize(); 12459 12460 for (int i = 0; i < 5; i++) { 12461 { v8::HandleScope scope(v8::Isolate::GetCurrent()); 12462 LocalContext context; 12463 } 12464 v8::V8::ContextDisposedNotification(); 12465 CheckSurvivingGlobalObjectsCount(0); 12466 12467 { v8::HandleScope scope(v8::Isolate::GetCurrent()); 12468 LocalContext context; 12469 v8_compile("Date")->Run(); 12470 } 12471 v8::V8::ContextDisposedNotification(); 12472 CheckSurvivingGlobalObjectsCount(0); 12473 12474 { v8::HandleScope scope(v8::Isolate::GetCurrent()); 12475 LocalContext context; 12476 v8_compile("/aaa/")->Run(); 12477 } 12478 v8::V8::ContextDisposedNotification(); 12479 CheckSurvivingGlobalObjectsCount(0); 12480 12481 { v8::HandleScope scope(v8::Isolate::GetCurrent()); 12482 const char* extension_list[] = { "v8/gc" }; 12483 v8::ExtensionConfiguration extensions(1, extension_list); 12484 LocalContext context(&extensions); 12485 v8_compile("gc();")->Run(); 12486 } 12487 v8::V8::ContextDisposedNotification(); 12488 CheckSurvivingGlobalObjectsCount(0); 12489 } 12490 } 12491 12492 12493 v8::Persistent<v8::Object> some_object; 12494 v8::Persistent<v8::Object> bad_handle; 12495 12496 void NewPersistentHandleCallback(v8::Isolate* isolate, 12497 v8::Persistent<v8::Value>* handle, 12498 void*) { 12499 v8::HandleScope scope(isolate); 12500 bad_handle.Reset(isolate, some_object); 12501 handle->Dispose(isolate); 12502 } 12503 12504 12505 THREADED_TEST(NewPersistentHandleFromWeakCallback) { 12506 LocalContext context; 12507 v8::Isolate* isolate = context->GetIsolate(); 12508 12509 v8::Persistent<v8::Object> handle1, handle2; 12510 { 12511 v8::HandleScope scope(isolate); 12512 some_object.Reset(isolate, v8::Object::New()); 12513 handle1.Reset(isolate, v8::Object::New()); 12514 handle2.Reset(isolate, v8::Object::New()); 12515 } 12516 // Note: order is implementation dependent alas: currently 12517 // global handle nodes are processed by PostGarbageCollectionProcessing 12518 // in reverse allocation order, so if second allocated handle is deleted, 12519 // weak callback of the first handle would be able to 'reallocate' it. 12520 handle1.MakeWeak<v8::Value, void>(NULL, NewPersistentHandleCallback); 12521 handle2.Dispose(isolate); 12522 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 12523 } 12524 12525 12526 v8::Persistent<v8::Object> to_be_disposed; 12527 12528 void DisposeAndForceGcCallback(v8::Isolate* isolate, 12529 v8::Persistent<v8::Value>* handle, 12530 void*) { 12531 to_be_disposed.Dispose(isolate); 12532 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 12533 handle->Dispose(isolate); 12534 } 12535 12536 12537 THREADED_TEST(DoNotUseDeletedNodesInSecondLevelGc) { 12538 LocalContext context; 12539 v8::Isolate* isolate = context->GetIsolate(); 12540 12541 v8::Persistent<v8::Object> handle1, handle2; 12542 { 12543 v8::HandleScope scope(isolate); 12544 handle1.Reset(isolate, v8::Object::New()); 12545 handle2.Reset(isolate, v8::Object::New()); 12546 } 12547 handle1.MakeWeak<v8::Value, void>(NULL, DisposeAndForceGcCallback); 12548 to_be_disposed.Reset(isolate, handle2); 12549 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 12550 } 12551 12552 void DisposingCallback(v8::Isolate* isolate, 12553 v8::Persistent<v8::Value>* handle, 12554 void*) { 12555 handle->Dispose(isolate); 12556 } 12557 12558 void HandleCreatingCallback(v8::Isolate* isolate, 12559 v8::Persistent<v8::Value>* handle, 12560 void*) { 12561 v8::HandleScope scope(isolate); 12562 v8::Persistent<v8::Object>(isolate, v8::Object::New()); 12563 handle->Dispose(isolate); 12564 } 12565 12566 12567 THREADED_TEST(NoGlobalHandlesOrphaningDueToWeakCallback) { 12568 LocalContext context; 12569 v8::Isolate* isolate = context->GetIsolate(); 12570 12571 v8::Persistent<v8::Object> handle1, handle2, handle3; 12572 { 12573 v8::HandleScope scope(isolate); 12574 handle3.Reset(isolate, v8::Object::New()); 12575 handle2.Reset(isolate, v8::Object::New()); 12576 handle1.Reset(isolate, v8::Object::New()); 12577 } 12578 handle2.MakeWeak<v8::Value, void>(NULL, DisposingCallback); 12579 handle3.MakeWeak<v8::Value, void>(NULL, HandleCreatingCallback); 12580 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 12581 } 12582 12583 12584 THREADED_TEST(CheckForCrossContextObjectLiterals) { 12585 v8::V8::Initialize(); 12586 12587 const int nof = 2; 12588 const char* sources[nof] = { 12589 "try { [ 2, 3, 4 ].forEach(5); } catch(e) { e.toString(); }", 12590 "Object()" 12591 }; 12592 12593 for (int i = 0; i < nof; i++) { 12594 const char* source = sources[i]; 12595 { v8::HandleScope scope(v8::Isolate::GetCurrent()); 12596 LocalContext context; 12597 CompileRun(source); 12598 } 12599 { v8::HandleScope scope(v8::Isolate::GetCurrent()); 12600 LocalContext context; 12601 CompileRun(source); 12602 } 12603 } 12604 } 12605 12606 12607 static v8::Handle<Value> NestedScope(v8::Local<Context> env) { 12608 v8::HandleScope inner(env->GetIsolate()); 12609 env->Enter(); 12610 v8::Handle<Value> three = v8_num(3); 12611 v8::Handle<Value> value = inner.Close(three); 12612 env->Exit(); 12613 return value; 12614 } 12615 12616 12617 THREADED_TEST(NestedHandleScopeAndContexts) { 12618 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 12619 v8::HandleScope outer(isolate); 12620 v8::Local<Context> env = Context::New(isolate); 12621 env->Enter(); 12622 v8::Handle<Value> value = NestedScope(env); 12623 v8::Handle<String> str(value->ToString()); 12624 CHECK(!str.IsEmpty()); 12625 env->Exit(); 12626 } 12627 12628 12629 static bool MatchPointers(void* key1, void* key2) { 12630 return key1 == key2; 12631 } 12632 12633 12634 struct SymbolInfo { 12635 size_t id; 12636 size_t size; 12637 std::string name; 12638 }; 12639 12640 12641 class SetFunctionEntryHookTest { 12642 public: 12643 SetFunctionEntryHookTest() { 12644 CHECK(instance_ == NULL); 12645 instance_ = this; 12646 } 12647 ~SetFunctionEntryHookTest() { 12648 CHECK(instance_ == this); 12649 instance_ = NULL; 12650 } 12651 void Reset() { 12652 symbols_.clear(); 12653 symbol_locations_.clear(); 12654 invocations_.clear(); 12655 } 12656 void RunTest(); 12657 void OnJitEvent(const v8::JitCodeEvent* event); 12658 static void JitEvent(const v8::JitCodeEvent* event) { 12659 CHECK(instance_ != NULL); 12660 instance_->OnJitEvent(event); 12661 } 12662 12663 void OnEntryHook(uintptr_t function, 12664 uintptr_t return_addr_location); 12665 static void EntryHook(uintptr_t function, 12666 uintptr_t return_addr_location) { 12667 CHECK(instance_ != NULL); 12668 instance_->OnEntryHook(function, return_addr_location); 12669 } 12670 12671 static void RuntimeCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 12672 CHECK(instance_ != NULL); 12673 args.GetReturnValue().Set(v8_num(42)); 12674 } 12675 void RunLoopInNewEnv(v8::Isolate* isolate); 12676 12677 // Records addr as location of symbol. 12678 void InsertSymbolAt(i::Address addr, SymbolInfo* symbol); 12679 12680 // Finds the symbol containing addr 12681 SymbolInfo* FindSymbolForAddr(i::Address addr); 12682 // Returns the number of invocations where the caller name contains 12683 // \p caller_name and the function name contains \p function_name. 12684 int CountInvocations(const char* caller_name, 12685 const char* function_name); 12686 12687 i::Handle<i::JSFunction> foo_func_; 12688 i::Handle<i::JSFunction> bar_func_; 12689 12690 typedef std::map<size_t, SymbolInfo> SymbolMap; 12691 typedef std::map<i::Address, SymbolInfo*> SymbolLocationMap; 12692 typedef std::map<std::pair<SymbolInfo*, SymbolInfo*>, int> InvocationMap; 12693 SymbolMap symbols_; 12694 SymbolLocationMap symbol_locations_; 12695 InvocationMap invocations_; 12696 12697 static SetFunctionEntryHookTest* instance_; 12698 }; 12699 SetFunctionEntryHookTest* SetFunctionEntryHookTest::instance_ = NULL; 12700 12701 12702 // Returns true if addr is in the range [start, start+len). 12703 static bool Overlaps(i::Address start, size_t len, i::Address addr) { 12704 if (start <= addr && start + len > addr) 12705 return true; 12706 12707 return false; 12708 } 12709 12710 void SetFunctionEntryHookTest::InsertSymbolAt(i::Address addr, 12711 SymbolInfo* symbol) { 12712 // Insert the symbol at the new location. 12713 SymbolLocationMap::iterator it = 12714 symbol_locations_.insert(std::make_pair(addr, symbol)).first; 12715 // Now erase symbols to the left and right that overlap this one. 12716 while (it != symbol_locations_.begin()) { 12717 SymbolLocationMap::iterator left = it; 12718 --left; 12719 if (!Overlaps(left->first, left->second->size, addr)) 12720 break; 12721 symbol_locations_.erase(left); 12722 } 12723 12724 // Now erase symbols to the left and right that overlap this one. 12725 while (true) { 12726 SymbolLocationMap::iterator right = it; 12727 ++right; 12728 if (right == symbol_locations_.end()) 12729 break; 12730 if (!Overlaps(addr, symbol->size, right->first)) 12731 break; 12732 symbol_locations_.erase(right); 12733 } 12734 } 12735 12736 12737 void SetFunctionEntryHookTest::OnJitEvent(const v8::JitCodeEvent* event) { 12738 switch (event->type) { 12739 case v8::JitCodeEvent::CODE_ADDED: { 12740 CHECK(event->code_start != NULL); 12741 CHECK_NE(0, static_cast<int>(event->code_len)); 12742 CHECK(event->name.str != NULL); 12743 size_t symbol_id = symbols_.size(); 12744 12745 // Record the new symbol. 12746 SymbolInfo& info = symbols_[symbol_id]; 12747 info.id = symbol_id; 12748 info.size = event->code_len; 12749 info.name.assign(event->name.str, event->name.str + event->name.len); 12750 12751 // And record it's location. 12752 InsertSymbolAt(reinterpret_cast<i::Address>(event->code_start), &info); 12753 } 12754 break; 12755 12756 case v8::JitCodeEvent::CODE_MOVED: { 12757 // We would like to never see code move that we haven't seen before, 12758 // but the code creation event does not happen until the line endings 12759 // have been calculated (this is so that we can report the line in the 12760 // script at which the function source is found, see 12761 // Compiler::RecordFunctionCompilation) and the line endings 12762 // calculations can cause a GC, which can move the newly created code 12763 // before its existence can be logged. 12764 SymbolLocationMap::iterator it( 12765 symbol_locations_.find( 12766 reinterpret_cast<i::Address>(event->code_start))); 12767 if (it != symbol_locations_.end()) { 12768 // Found a symbol at this location, move it. 12769 SymbolInfo* info = it->second; 12770 symbol_locations_.erase(it); 12771 InsertSymbolAt(reinterpret_cast<i::Address>(event->new_code_start), 12772 info); 12773 } 12774 } 12775 default: 12776 break; 12777 } 12778 } 12779 12780 void SetFunctionEntryHookTest::OnEntryHook( 12781 uintptr_t function, uintptr_t return_addr_location) { 12782 // Get the function's code object. 12783 i::Code* function_code = i::Code::GetCodeFromTargetAddress( 12784 reinterpret_cast<i::Address>(function)); 12785 CHECK(function_code != NULL); 12786 12787 // Then try and look up the caller's code object. 12788 i::Address caller = *reinterpret_cast<i::Address*>(return_addr_location); 12789 12790 // Count the invocation. 12791 SymbolInfo* caller_symbol = FindSymbolForAddr(caller); 12792 SymbolInfo* function_symbol = 12793 FindSymbolForAddr(reinterpret_cast<i::Address>(function)); 12794 ++invocations_[std::make_pair(caller_symbol, function_symbol)]; 12795 12796 if (!bar_func_.is_null() && function_code == bar_func_->code()) { 12797 // Check that we have a symbol for the "bar" function at the right location. 12798 SymbolLocationMap::iterator it( 12799 symbol_locations_.find(function_code->instruction_start())); 12800 CHECK(it != symbol_locations_.end()); 12801 } 12802 12803 if (!foo_func_.is_null() && function_code == foo_func_->code()) { 12804 // Check that we have a symbol for "foo" at the right location. 12805 SymbolLocationMap::iterator it( 12806 symbol_locations_.find(function_code->instruction_start())); 12807 CHECK(it != symbol_locations_.end()); 12808 } 12809 } 12810 12811 12812 SymbolInfo* SetFunctionEntryHookTest::FindSymbolForAddr(i::Address addr) { 12813 SymbolLocationMap::iterator it(symbol_locations_.lower_bound(addr)); 12814 // Do we have a direct hit on a symbol? 12815 if (it != symbol_locations_.end()) { 12816 if (it->first == addr) 12817 return it->second; 12818 } 12819 12820 // If not a direct hit, it'll have to be the previous symbol. 12821 if (it == symbol_locations_.begin()) 12822 return NULL; 12823 12824 --it; 12825 size_t offs = addr - it->first; 12826 if (offs < it->second->size) 12827 return it->second; 12828 12829 return NULL; 12830 } 12831 12832 12833 int SetFunctionEntryHookTest::CountInvocations( 12834 const char* caller_name, const char* function_name) { 12835 InvocationMap::iterator it(invocations_.begin()); 12836 int invocations = 0; 12837 for (; it != invocations_.end(); ++it) { 12838 SymbolInfo* caller = it->first.first; 12839 SymbolInfo* function = it->first.second; 12840 12841 // Filter out non-matching functions. 12842 if (function_name != NULL) { 12843 if (function->name.find(function_name) == std::string::npos) 12844 continue; 12845 } 12846 12847 // Filter out non-matching callers. 12848 if (caller_name != NULL) { 12849 if (caller == NULL) 12850 continue; 12851 if (caller->name.find(caller_name) == std::string::npos) 12852 continue; 12853 } 12854 12855 // It matches add the invocation count to the tally. 12856 invocations += it->second; 12857 } 12858 12859 return invocations; 12860 } 12861 12862 12863 void SetFunctionEntryHookTest::RunLoopInNewEnv(v8::Isolate* isolate) { 12864 v8::HandleScope outer(isolate); 12865 v8::Local<Context> env = Context::New(isolate); 12866 env->Enter(); 12867 12868 Local<ObjectTemplate> t = ObjectTemplate::New(); 12869 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(RuntimeCallback)); 12870 env->Global()->Set(v8_str("obj"), t->NewInstance()); 12871 12872 const char* script = 12873 "function bar() {\n" 12874 " var sum = 0;\n" 12875 " for (i = 0; i < 100; ++i)\n" 12876 " sum = foo(i);\n" 12877 " return sum;\n" 12878 "}\n" 12879 "function foo(i) { return i * i; }\n" 12880 "// Invoke on the runtime function.\n" 12881 "obj.asdf()"; 12882 CompileRun(script); 12883 bar_func_ = i::Handle<i::JSFunction>::cast( 12884 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar")))); 12885 ASSERT(!bar_func_.is_null()); 12886 12887 foo_func_ = 12888 i::Handle<i::JSFunction>::cast( 12889 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo")))); 12890 ASSERT(!foo_func_.is_null()); 12891 12892 v8::Handle<v8::Value> value = CompileRun("bar();"); 12893 CHECK(value->IsNumber()); 12894 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value()); 12895 12896 // Test the optimized codegen path. 12897 value = CompileRun("%OptimizeFunctionOnNextCall(foo);" 12898 "bar();"); 12899 CHECK(value->IsNumber()); 12900 CHECK_EQ(9801.0, v8::Number::Cast(*value)->Value()); 12901 12902 env->Exit(); 12903 } 12904 12905 12906 void SetFunctionEntryHookTest::RunTest() { 12907 // Work in a new isolate throughout. 12908 v8::Isolate* isolate = v8::Isolate::New(); 12909 12910 // Test setting the entry hook on the new isolate. 12911 CHECK(v8::V8::SetFunctionEntryHook(isolate, EntryHook)); 12912 12913 // Replacing the hook, once set should fail. 12914 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook)); 12915 12916 { 12917 v8::Isolate::Scope scope(isolate); 12918 12919 v8::V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, JitEvent); 12920 12921 RunLoopInNewEnv(isolate); 12922 12923 // Check the exepected invocation counts. 12924 CHECK_EQ(2, CountInvocations(NULL, "bar")); 12925 CHECK_EQ(200, CountInvocations("bar", "foo")); 12926 CHECK_EQ(200, CountInvocations(NULL, "foo")); 12927 12928 // Verify that we have an entry hook on some specific stubs. 12929 CHECK_NE(0, CountInvocations(NULL, "CEntryStub")); 12930 CHECK_NE(0, CountInvocations(NULL, "JSEntryStub")); 12931 CHECK_NE(0, CountInvocations(NULL, "JSEntryTrampoline")); 12932 } 12933 isolate->Dispose(); 12934 12935 Reset(); 12936 12937 // Make sure a second isolate is unaffected by the previous entry hook. 12938 isolate = v8::Isolate::New(); 12939 { 12940 v8::Isolate::Scope scope(isolate); 12941 12942 // Reset the entry count to zero and set the entry hook. 12943 RunLoopInNewEnv(isolate); 12944 12945 // We should record no invocations in this isolate. 12946 CHECK_EQ(0, static_cast<int>(invocations_.size())); 12947 } 12948 // Since the isolate has been used, we shouldn't be able to set an entry 12949 // hook anymore. 12950 CHECK_EQ(false, v8::V8::SetFunctionEntryHook(isolate, EntryHook)); 12951 12952 isolate->Dispose(); 12953 } 12954 12955 12956 TEST(SetFunctionEntryHook) { 12957 // FunctionEntryHook does not work well with experimental natives. 12958 // Experimental natives are compiled during snapshot deserialization. 12959 // This test breaks because InstallGetter (function from snapshot that 12960 // only gets called from experimental natives) is compiled with entry hooks. 12961 i::FLAG_harmony_typed_arrays = false; 12962 i::FLAG_harmony_array_buffer = false; 12963 12964 i::FLAG_allow_natives_syntax = true; 12965 i::FLAG_use_inlining = false; 12966 12967 SetFunctionEntryHookTest test; 12968 test.RunTest(); 12969 } 12970 12971 12972 static i::HashMap* code_map = NULL; 12973 static i::HashMap* jitcode_line_info = NULL; 12974 static int saw_bar = 0; 12975 static int move_events = 0; 12976 12977 12978 static bool FunctionNameIs(const char* expected, 12979 const v8::JitCodeEvent* event) { 12980 // Log lines for functions are of the general form: 12981 // "LazyCompile:<type><function_name>", where the type is one of 12982 // "*", "~" or "". 12983 static const char kPreamble[] = "LazyCompile:"; 12984 static size_t kPreambleLen = sizeof(kPreamble) - 1; 12985 12986 if (event->name.len < sizeof(kPreamble) - 1 || 12987 strncmp(kPreamble, event->name.str, kPreambleLen) != 0) { 12988 return false; 12989 } 12990 12991 const char* tail = event->name.str + kPreambleLen; 12992 size_t tail_len = event->name.len - kPreambleLen; 12993 size_t expected_len = strlen(expected); 12994 if (tail_len > 1 && (*tail == '*' || *tail == '~')) { 12995 --tail_len; 12996 ++tail; 12997 } 12998 12999 // Check for tails like 'bar :1'. 13000 if (tail_len > expected_len + 2 && 13001 tail[expected_len] == ' ' && 13002 tail[expected_len + 1] == ':' && 13003 tail[expected_len + 2] && 13004 !strncmp(tail, expected, expected_len)) { 13005 return true; 13006 } 13007 13008 if (tail_len != expected_len) 13009 return false; 13010 13011 return strncmp(tail, expected, expected_len) == 0; 13012 } 13013 13014 13015 static void event_handler(const v8::JitCodeEvent* event) { 13016 CHECK(event != NULL); 13017 CHECK(code_map != NULL); 13018 CHECK(jitcode_line_info != NULL); 13019 13020 class DummyJitCodeLineInfo { 13021 }; 13022 13023 switch (event->type) { 13024 case v8::JitCodeEvent::CODE_ADDED: { 13025 CHECK(event->code_start != NULL); 13026 CHECK_NE(0, static_cast<int>(event->code_len)); 13027 CHECK(event->name.str != NULL); 13028 i::HashMap::Entry* entry = 13029 code_map->Lookup(event->code_start, 13030 i::ComputePointerHash(event->code_start), 13031 true); 13032 entry->value = reinterpret_cast<void*>(event->code_len); 13033 13034 if (FunctionNameIs("bar", event)) { 13035 ++saw_bar; 13036 } 13037 } 13038 break; 13039 13040 case v8::JitCodeEvent::CODE_MOVED: { 13041 uint32_t hash = i::ComputePointerHash(event->code_start); 13042 // We would like to never see code move that we haven't seen before, 13043 // but the code creation event does not happen until the line endings 13044 // have been calculated (this is so that we can report the line in the 13045 // script at which the function source is found, see 13046 // Compiler::RecordFunctionCompilation) and the line endings 13047 // calculations can cause a GC, which can move the newly created code 13048 // before its existence can be logged. 13049 i::HashMap::Entry* entry = 13050 code_map->Lookup(event->code_start, hash, false); 13051 if (entry != NULL) { 13052 ++move_events; 13053 13054 CHECK_EQ(reinterpret_cast<void*>(event->code_len), entry->value); 13055 code_map->Remove(event->code_start, hash); 13056 13057 entry = code_map->Lookup(event->new_code_start, 13058 i::ComputePointerHash(event->new_code_start), 13059 true); 13060 CHECK(entry != NULL); 13061 entry->value = reinterpret_cast<void*>(event->code_len); 13062 } 13063 } 13064 break; 13065 13066 case v8::JitCodeEvent::CODE_REMOVED: 13067 // Object/code removal events are currently not dispatched from the GC. 13068 CHECK(false); 13069 break; 13070 13071 // For CODE_START_LINE_INFO_RECORDING event, we will create one 13072 // DummyJitCodeLineInfo data structure pointed by event->user_dat. We 13073 // record it in jitcode_line_info. 13074 case v8::JitCodeEvent::CODE_START_LINE_INFO_RECORDING: { 13075 DummyJitCodeLineInfo* line_info = new DummyJitCodeLineInfo(); 13076 v8::JitCodeEvent* temp_event = const_cast<v8::JitCodeEvent*>(event); 13077 temp_event->user_data = line_info; 13078 i::HashMap::Entry* entry = 13079 jitcode_line_info->Lookup(line_info, 13080 i::ComputePointerHash(line_info), 13081 true); 13082 entry->value = reinterpret_cast<void*>(line_info); 13083 } 13084 break; 13085 // For these two events, we will check whether the event->user_data 13086 // data structure is created before during CODE_START_LINE_INFO_RECORDING 13087 // event. And delete it in CODE_END_LINE_INFO_RECORDING event handling. 13088 case v8::JitCodeEvent::CODE_END_LINE_INFO_RECORDING: { 13089 CHECK(event->user_data != NULL); 13090 uint32_t hash = i::ComputePointerHash(event->user_data); 13091 i::HashMap::Entry* entry = 13092 jitcode_line_info->Lookup(event->user_data, hash, false); 13093 CHECK(entry != NULL); 13094 delete reinterpret_cast<DummyJitCodeLineInfo*>(event->user_data); 13095 } 13096 break; 13097 13098 case v8::JitCodeEvent::CODE_ADD_LINE_POS_INFO: { 13099 CHECK(event->user_data != NULL); 13100 uint32_t hash = i::ComputePointerHash(event->user_data); 13101 i::HashMap::Entry* entry = 13102 jitcode_line_info->Lookup(event->user_data, hash, false); 13103 CHECK(entry != NULL); 13104 } 13105 break; 13106 13107 default: 13108 // Impossible event. 13109 CHECK(false); 13110 break; 13111 } 13112 } 13113 13114 13115 TEST(SetJitCodeEventHandler) { 13116 i::FLAG_stress_compaction = true; 13117 i::FLAG_incremental_marking = false; 13118 const char* script = 13119 "function bar() {" 13120 " var sum = 0;" 13121 " for (i = 0; i < 100; ++i)" 13122 " sum = foo(i);" 13123 " return sum;" 13124 "}" 13125 "function foo(i) { return i * i; };" 13126 "bar();"; 13127 13128 // Run this test in a new isolate to make sure we don't 13129 // have remnants of state from other code. 13130 v8::Isolate* isolate = v8::Isolate::New(); 13131 isolate->Enter(); 13132 13133 { 13134 v8::HandleScope scope(isolate); 13135 i::HashMap code(MatchPointers); 13136 code_map = &code; 13137 13138 i::HashMap lineinfo(MatchPointers); 13139 jitcode_line_info = &lineinfo; 13140 13141 saw_bar = 0; 13142 move_events = 0; 13143 13144 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, event_handler); 13145 13146 // Generate new code objects sparsely distributed across several 13147 // different fragmented code-space pages. 13148 const int kIterations = 10; 13149 for (int i = 0; i < kIterations; ++i) { 13150 LocalContext env; 13151 i::AlwaysAllocateScope always_allocate; 13152 SimulateFullSpace(HEAP->code_space()); 13153 CompileRun(script); 13154 13155 // Keep a strong reference to the code object in the handle scope. 13156 i::Handle<i::Code> bar_code(i::Handle<i::JSFunction>::cast( 13157 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("bar"))))->code()); 13158 i::Handle<i::Code> foo_code(i::Handle<i::JSFunction>::cast( 13159 v8::Utils::OpenHandle(*env->Global()->Get(v8_str("foo"))))->code()); 13160 13161 // Clear the compilation cache to get more wastage. 13162 ISOLATE->compilation_cache()->Clear(); 13163 } 13164 13165 // Force code movement. 13166 HEAP->CollectAllAvailableGarbage("TestSetJitCodeEventHandler"); 13167 13168 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL); 13169 13170 CHECK_LE(kIterations, saw_bar); 13171 CHECK_LT(0, move_events); 13172 13173 code_map = NULL; 13174 jitcode_line_info = NULL; 13175 } 13176 13177 isolate->Exit(); 13178 isolate->Dispose(); 13179 13180 // Do this in a new isolate. 13181 isolate = v8::Isolate::New(); 13182 isolate->Enter(); 13183 13184 // Verify that we get callbacks for existing code objects when we 13185 // request enumeration of existing code. 13186 { 13187 v8::HandleScope scope(isolate); 13188 LocalContext env; 13189 CompileRun(script); 13190 13191 // Now get code through initial iteration. 13192 i::HashMap code(MatchPointers); 13193 code_map = &code; 13194 13195 i::HashMap lineinfo(MatchPointers); 13196 jitcode_line_info = &lineinfo; 13197 13198 V8::SetJitCodeEventHandler(v8::kJitCodeEventEnumExisting, event_handler); 13199 V8::SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL); 13200 13201 jitcode_line_info = NULL; 13202 // We expect that we got some events. Note that if we could get code removal 13203 // notifications, we could compare two collections, one created by listening 13204 // from the time of creation of an isolate, and the other by subscribing 13205 // with EnumExisting. 13206 CHECK_LT(0, code.occupancy()); 13207 13208 code_map = NULL; 13209 } 13210 13211 isolate->Exit(); 13212 isolate->Dispose(); 13213 } 13214 13215 13216 static int64_t cast(intptr_t x) { return static_cast<int64_t>(x); } 13217 13218 13219 THREADED_TEST(ExternalAllocatedMemory) { 13220 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 13221 v8::HandleScope outer(isolate); 13222 v8::Local<Context> env(Context::New(isolate)); 13223 CHECK(!env.IsEmpty()); 13224 const intptr_t kSize = 1024*1024; 13225 int64_t baseline = cast(isolate->AdjustAmountOfExternalAllocatedMemory(0)); 13226 CHECK_EQ(baseline + cast(kSize), 13227 cast(isolate->AdjustAmountOfExternalAllocatedMemory(kSize))); 13228 CHECK_EQ(baseline, 13229 cast(isolate->AdjustAmountOfExternalAllocatedMemory(-kSize))); 13230 } 13231 13232 13233 THREADED_TEST(DisposeEnteredContext) { 13234 LocalContext outer; 13235 v8::Isolate* isolate = outer->GetIsolate(); 13236 v8::Persistent<v8::Context> inner; 13237 { 13238 v8::HandleScope scope(isolate); 13239 inner.Reset(isolate, v8::Context::New(isolate)); 13240 } 13241 v8::HandleScope scope(isolate); 13242 { 13243 // Don't want a handle here, so do this unsafely 13244 v8::Handle<v8::Context> inner_local = 13245 v8::Utils::Convert<i::Object, v8::Context>( 13246 v8::Utils::OpenPersistent(inner)); 13247 inner_local->Enter(); 13248 inner.Dispose(); 13249 inner.Clear(); 13250 inner_local->Exit(); 13251 } 13252 } 13253 13254 13255 // Regression test for issue 54, object templates with internal fields 13256 // but no accessors or interceptors did not get their internal field 13257 // count set on instances. 13258 THREADED_TEST(Regress54) { 13259 LocalContext context; 13260 v8::Isolate* isolate = context->GetIsolate(); 13261 v8::HandleScope outer(isolate); 13262 static v8::Persistent<v8::ObjectTemplate> templ; 13263 if (templ.IsEmpty()) { 13264 v8::HandleScope inner(isolate); 13265 v8::Handle<v8::ObjectTemplate> local = v8::ObjectTemplate::New(); 13266 local->SetInternalFieldCount(1); 13267 templ.Reset(isolate, inner.Close(local)); 13268 } 13269 v8::Handle<v8::Object> result = 13270 v8::Local<v8::ObjectTemplate>::New(isolate, templ)->NewInstance(); 13271 CHECK_EQ(1, result->InternalFieldCount()); 13272 } 13273 13274 13275 // If part of the threaded tests, this test makes ThreadingTest fail 13276 // on mac. 13277 TEST(CatchStackOverflow) { 13278 LocalContext context; 13279 v8::HandleScope scope(context->GetIsolate()); 13280 v8::TryCatch try_catch; 13281 v8::Handle<v8::Script> script = v8::Script::Compile(v8::String::New( 13282 "function f() {" 13283 " return f();" 13284 "}" 13285 "" 13286 "f();")); 13287 v8::Handle<v8::Value> result = script->Run(); 13288 CHECK(result.IsEmpty()); 13289 } 13290 13291 13292 static void CheckTryCatchSourceInfo(v8::Handle<v8::Script> script, 13293 const char* resource_name, 13294 int line_offset) { 13295 v8::HandleScope scope(v8::Isolate::GetCurrent()); 13296 v8::TryCatch try_catch; 13297 v8::Handle<v8::Value> result = script->Run(); 13298 CHECK(result.IsEmpty()); 13299 CHECK(try_catch.HasCaught()); 13300 v8::Handle<v8::Message> message = try_catch.Message(); 13301 CHECK(!message.IsEmpty()); 13302 CHECK_EQ(10 + line_offset, message->GetLineNumber()); 13303 CHECK_EQ(91, message->GetStartPosition()); 13304 CHECK_EQ(92, message->GetEndPosition()); 13305 CHECK_EQ(2, message->GetStartColumn()); 13306 CHECK_EQ(3, message->GetEndColumn()); 13307 v8::String::Utf8Value line(message->GetSourceLine()); 13308 CHECK_EQ(" throw 'nirk';", *line); 13309 v8::String::Utf8Value name(message->GetScriptResourceName()); 13310 CHECK_EQ(resource_name, *name); 13311 } 13312 13313 13314 THREADED_TEST(TryCatchSourceInfo) { 13315 LocalContext context; 13316 v8::HandleScope scope(context->GetIsolate()); 13317 v8::Handle<v8::String> source = v8::String::New( 13318 "function Foo() {\n" 13319 " return Bar();\n" 13320 "}\n" 13321 "\n" 13322 "function Bar() {\n" 13323 " return Baz();\n" 13324 "}\n" 13325 "\n" 13326 "function Baz() {\n" 13327 " throw 'nirk';\n" 13328 "}\n" 13329 "\n" 13330 "Foo();\n"); 13331 13332 const char* resource_name; 13333 v8::Handle<v8::Script> script; 13334 resource_name = "test.js"; 13335 script = v8::Script::Compile(source, v8::String::New(resource_name)); 13336 CheckTryCatchSourceInfo(script, resource_name, 0); 13337 13338 resource_name = "test1.js"; 13339 v8::ScriptOrigin origin1(v8::String::New(resource_name)); 13340 script = v8::Script::Compile(source, &origin1); 13341 CheckTryCatchSourceInfo(script, resource_name, 0); 13342 13343 resource_name = "test2.js"; 13344 v8::ScriptOrigin origin2(v8::String::New(resource_name), v8::Integer::New(7)); 13345 script = v8::Script::Compile(source, &origin2); 13346 CheckTryCatchSourceInfo(script, resource_name, 7); 13347 } 13348 13349 13350 THREADED_TEST(CompilationCache) { 13351 LocalContext context; 13352 v8::HandleScope scope(context->GetIsolate()); 13353 v8::Handle<v8::String> source0 = v8::String::New("1234"); 13354 v8::Handle<v8::String> source1 = v8::String::New("1234"); 13355 v8::Handle<v8::Script> script0 = 13356 v8::Script::Compile(source0, v8::String::New("test.js")); 13357 v8::Handle<v8::Script> script1 = 13358 v8::Script::Compile(source1, v8::String::New("test.js")); 13359 v8::Handle<v8::Script> script2 = 13360 v8::Script::Compile(source0); // different origin 13361 CHECK_EQ(1234, script0->Run()->Int32Value()); 13362 CHECK_EQ(1234, script1->Run()->Int32Value()); 13363 CHECK_EQ(1234, script2->Run()->Int32Value()); 13364 } 13365 13366 13367 static void FunctionNameCallback( 13368 const v8::FunctionCallbackInfo<v8::Value>& args) { 13369 ApiTestFuzzer::Fuzz(); 13370 args.GetReturnValue().Set(v8_num(42)); 13371 } 13372 13373 13374 THREADED_TEST(CallbackFunctionName) { 13375 LocalContext context; 13376 v8::HandleScope scope(context->GetIsolate()); 13377 Local<ObjectTemplate> t = ObjectTemplate::New(); 13378 t->Set(v8_str("asdf"), v8::FunctionTemplate::New(FunctionNameCallback)); 13379 context->Global()->Set(v8_str("obj"), t->NewInstance()); 13380 v8::Handle<v8::Value> value = CompileRun("obj.asdf.name"); 13381 CHECK(value->IsString()); 13382 v8::String::Utf8Value name(value); 13383 CHECK_EQ("asdf", *name); 13384 } 13385 13386 13387 THREADED_TEST(DateAccess) { 13388 LocalContext context; 13389 v8::HandleScope scope(context->GetIsolate()); 13390 v8::Handle<v8::Value> date = v8::Date::New(1224744689038.0); 13391 CHECK(date->IsDate()); 13392 CHECK_EQ(1224744689038.0, date.As<v8::Date>()->ValueOf()); 13393 } 13394 13395 13396 void CheckProperties(v8::Handle<v8::Value> val, int elmc, const char* elmv[]) { 13397 v8::Handle<v8::Object> obj = val.As<v8::Object>(); 13398 v8::Handle<v8::Array> props = obj->GetPropertyNames(); 13399 CHECK_EQ(elmc, props->Length()); 13400 for (int i = 0; i < elmc; i++) { 13401 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i))); 13402 CHECK_EQ(elmv[i], *elm); 13403 } 13404 } 13405 13406 13407 void CheckOwnProperties(v8::Handle<v8::Value> val, 13408 int elmc, 13409 const char* elmv[]) { 13410 v8::Handle<v8::Object> obj = val.As<v8::Object>(); 13411 v8::Handle<v8::Array> props = obj->GetOwnPropertyNames(); 13412 CHECK_EQ(elmc, props->Length()); 13413 for (int i = 0; i < elmc; i++) { 13414 v8::String::Utf8Value elm(props->Get(v8::Integer::New(i))); 13415 CHECK_EQ(elmv[i], *elm); 13416 } 13417 } 13418 13419 13420 THREADED_TEST(PropertyEnumeration) { 13421 LocalContext context; 13422 v8::HandleScope scope(context->GetIsolate()); 13423 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New( 13424 "var result = [];" 13425 "result[0] = {};" 13426 "result[1] = {a: 1, b: 2};" 13427 "result[2] = [1, 2, 3];" 13428 "var proto = {x: 1, y: 2, z: 3};" 13429 "var x = { __proto__: proto, w: 0, z: 1 };" 13430 "result[3] = x;" 13431 "result;"))->Run(); 13432 v8::Handle<v8::Array> elms = obj.As<v8::Array>(); 13433 CHECK_EQ(4, elms->Length()); 13434 int elmc0 = 0; 13435 const char** elmv0 = NULL; 13436 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0); 13437 CheckOwnProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0); 13438 int elmc1 = 2; 13439 const char* elmv1[] = {"a", "b"}; 13440 CheckProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1); 13441 CheckOwnProperties(elms->Get(v8::Integer::New(1)), elmc1, elmv1); 13442 int elmc2 = 3; 13443 const char* elmv2[] = {"0", "1", "2"}; 13444 CheckProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2); 13445 CheckOwnProperties(elms->Get(v8::Integer::New(2)), elmc2, elmv2); 13446 int elmc3 = 4; 13447 const char* elmv3[] = {"w", "z", "x", "y"}; 13448 CheckProperties(elms->Get(v8::Integer::New(3)), elmc3, elmv3); 13449 int elmc4 = 2; 13450 const char* elmv4[] = {"w", "z"}; 13451 CheckOwnProperties(elms->Get(v8::Integer::New(3)), elmc4, elmv4); 13452 } 13453 13454 13455 THREADED_TEST(PropertyEnumeration2) { 13456 LocalContext context; 13457 v8::HandleScope scope(context->GetIsolate()); 13458 v8::Handle<v8::Value> obj = v8::Script::Compile(v8::String::New( 13459 "var result = [];" 13460 "result[0] = {};" 13461 "result[1] = {a: 1, b: 2};" 13462 "result[2] = [1, 2, 3];" 13463 "var proto = {x: 1, y: 2, z: 3};" 13464 "var x = { __proto__: proto, w: 0, z: 1 };" 13465 "result[3] = x;" 13466 "result;"))->Run(); 13467 v8::Handle<v8::Array> elms = obj.As<v8::Array>(); 13468 CHECK_EQ(4, elms->Length()); 13469 int elmc0 = 0; 13470 const char** elmv0 = NULL; 13471 CheckProperties(elms->Get(v8::Integer::New(0)), elmc0, elmv0); 13472 13473 v8::Handle<v8::Value> val = elms->Get(v8::Integer::New(0)); 13474 v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames(); 13475 CHECK_EQ(0, props->Length()); 13476 for (uint32_t i = 0; i < props->Length(); i++) { 13477 printf("p[%d]\n", i); 13478 } 13479 } 13480 13481 static bool NamedSetAccessBlocker(Local<v8::Object> obj, 13482 Local<Value> name, 13483 v8::AccessType type, 13484 Local<Value> data) { 13485 return type != v8::ACCESS_SET; 13486 } 13487 13488 13489 static bool IndexedSetAccessBlocker(Local<v8::Object> obj, 13490 uint32_t key, 13491 v8::AccessType type, 13492 Local<Value> data) { 13493 return type != v8::ACCESS_SET; 13494 } 13495 13496 13497 THREADED_TEST(DisableAccessChecksWhileConfiguring) { 13498 LocalContext context; 13499 v8::HandleScope scope(context->GetIsolate()); 13500 Local<ObjectTemplate> templ = ObjectTemplate::New(); 13501 templ->SetAccessCheckCallbacks(NamedSetAccessBlocker, 13502 IndexedSetAccessBlocker); 13503 templ->Set(v8_str("x"), v8::True()); 13504 Local<v8::Object> instance = templ->NewInstance(); 13505 context->Global()->Set(v8_str("obj"), instance); 13506 Local<Value> value = CompileRun("obj.x"); 13507 CHECK(value->BooleanValue()); 13508 } 13509 13510 13511 static bool NamedGetAccessBlocker(Local<v8::Object> obj, 13512 Local<Value> name, 13513 v8::AccessType type, 13514 Local<Value> data) { 13515 return false; 13516 } 13517 13518 13519 static bool IndexedGetAccessBlocker(Local<v8::Object> obj, 13520 uint32_t key, 13521 v8::AccessType type, 13522 Local<Value> data) { 13523 return false; 13524 } 13525 13526 13527 13528 THREADED_TEST(AccessChecksReenabledCorrectly) { 13529 LocalContext context; 13530 v8::HandleScope scope(context->GetIsolate()); 13531 Local<ObjectTemplate> templ = ObjectTemplate::New(); 13532 templ->SetAccessCheckCallbacks(NamedGetAccessBlocker, 13533 IndexedGetAccessBlocker); 13534 templ->Set(v8_str("a"), v8_str("a")); 13535 // Add more than 8 (see kMaxFastProperties) properties 13536 // so that the constructor will force copying map. 13537 // Cannot sprintf, gcc complains unsafety. 13538 char buf[4]; 13539 for (char i = '0'; i <= '9' ; i++) { 13540 buf[0] = i; 13541 for (char j = '0'; j <= '9'; j++) { 13542 buf[1] = j; 13543 for (char k = '0'; k <= '9'; k++) { 13544 buf[2] = k; 13545 buf[3] = 0; 13546 templ->Set(v8_str(buf), v8::Number::New(k)); 13547 } 13548 } 13549 } 13550 13551 Local<v8::Object> instance_1 = templ->NewInstance(); 13552 context->Global()->Set(v8_str("obj_1"), instance_1); 13553 13554 Local<Value> value_1 = CompileRun("obj_1.a"); 13555 CHECK(value_1->IsUndefined()); 13556 13557 Local<v8::Object> instance_2 = templ->NewInstance(); 13558 context->Global()->Set(v8_str("obj_2"), instance_2); 13559 13560 Local<Value> value_2 = CompileRun("obj_2.a"); 13561 CHECK(value_2->IsUndefined()); 13562 } 13563 13564 13565 // This tests that access check information remains on the global 13566 // object template when creating contexts. 13567 THREADED_TEST(AccessControlRepeatedContextCreation) { 13568 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 13569 v8::HandleScope handle_scope(isolate); 13570 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 13571 global_template->SetAccessCheckCallbacks(NamedSetAccessBlocker, 13572 IndexedSetAccessBlocker); 13573 i::Handle<i::ObjectTemplateInfo> internal_template = 13574 v8::Utils::OpenHandle(*global_template); 13575 CHECK(!internal_template->constructor()->IsUndefined()); 13576 i::Handle<i::FunctionTemplateInfo> constructor( 13577 i::FunctionTemplateInfo::cast(internal_template->constructor())); 13578 CHECK(!constructor->access_check_info()->IsUndefined()); 13579 v8::Local<Context> context0(Context::New(isolate, NULL, global_template)); 13580 CHECK(!context0.IsEmpty()); 13581 CHECK(!constructor->access_check_info()->IsUndefined()); 13582 } 13583 13584 13585 THREADED_TEST(TurnOnAccessCheck) { 13586 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 13587 v8::HandleScope handle_scope(isolate); 13588 13589 // Create an environment with access check to the global object disabled by 13590 // default. 13591 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 13592 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker, 13593 IndexedGetAccessBlocker, 13594 v8::Handle<v8::Value>(), 13595 false); 13596 v8::Local<Context> context = Context::New(isolate, NULL, global_template); 13597 Context::Scope context_scope(context); 13598 13599 // Set up a property and a number of functions. 13600 context->Global()->Set(v8_str("a"), v8_num(1)); 13601 CompileRun("function f1() {return a;}" 13602 "function f2() {return a;}" 13603 "function g1() {return h();}" 13604 "function g2() {return h();}" 13605 "function h() {return 1;}"); 13606 Local<Function> f1 = 13607 Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); 13608 Local<Function> f2 = 13609 Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); 13610 Local<Function> g1 = 13611 Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); 13612 Local<Function> g2 = 13613 Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); 13614 Local<Function> h = 13615 Local<Function>::Cast(context->Global()->Get(v8_str("h"))); 13616 13617 // Get the global object. 13618 v8::Handle<v8::Object> global = context->Global(); 13619 13620 // Call f1 one time and f2 a number of times. This will ensure that f1 still 13621 // uses the runtime system to retreive property a whereas f2 uses global load 13622 // inline cache. 13623 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1))); 13624 for (int i = 0; i < 4; i++) { 13625 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1))); 13626 } 13627 13628 // Same for g1 and g2. 13629 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1))); 13630 for (int i = 0; i < 4; i++) { 13631 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1))); 13632 } 13633 13634 // Detach the global and turn on access check. 13635 context->DetachGlobal(); 13636 context->Global()->TurnOnAccessCheck(); 13637 13638 // Failing access check to property get results in undefined. 13639 CHECK(f1->Call(global, 0, NULL)->IsUndefined()); 13640 CHECK(f2->Call(global, 0, NULL)->IsUndefined()); 13641 13642 // Failing access check to function call results in exception. 13643 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 13644 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 13645 13646 // No failing access check when just returning a constant. 13647 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1))); 13648 } 13649 13650 13651 static const char* kPropertyA = "a"; 13652 static const char* kPropertyH = "h"; 13653 13654 static bool NamedGetAccessBlockAandH(Local<v8::Object> obj, 13655 Local<Value> name, 13656 v8::AccessType type, 13657 Local<Value> data) { 13658 if (!name->IsString()) return false; 13659 i::Handle<i::String> name_handle = 13660 v8::Utils::OpenHandle(String::Cast(*name)); 13661 return !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyA)) 13662 && !name_handle->IsUtf8EqualTo(i::CStrVector(kPropertyH)); 13663 } 13664 13665 13666 THREADED_TEST(TurnOnAccessCheckAndRecompile) { 13667 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 13668 v8::HandleScope handle_scope(isolate); 13669 13670 // Create an environment with access check to the global object disabled by 13671 // default. When the registered access checker will block access to properties 13672 // a and h. 13673 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 13674 global_template->SetAccessCheckCallbacks(NamedGetAccessBlockAandH, 13675 IndexedGetAccessBlocker, 13676 v8::Handle<v8::Value>(), 13677 false); 13678 v8::Local<Context> context = Context::New(isolate, NULL, global_template); 13679 Context::Scope context_scope(context); 13680 13681 // Set up a property and a number of functions. 13682 context->Global()->Set(v8_str("a"), v8_num(1)); 13683 static const char* source = "function f1() {return a;}" 13684 "function f2() {return a;}" 13685 "function g1() {return h();}" 13686 "function g2() {return h();}" 13687 "function h() {return 1;}"; 13688 13689 CompileRun(source); 13690 Local<Function> f1; 13691 Local<Function> f2; 13692 Local<Function> g1; 13693 Local<Function> g2; 13694 Local<Function> h; 13695 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); 13696 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); 13697 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); 13698 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); 13699 h = Local<Function>::Cast(context->Global()->Get(v8_str("h"))); 13700 13701 // Get the global object. 13702 v8::Handle<v8::Object> global = context->Global(); 13703 13704 // Call f1 one time and f2 a number of times. This will ensure that f1 still 13705 // uses the runtime system to retreive property a whereas f2 uses global load 13706 // inline cache. 13707 CHECK(f1->Call(global, 0, NULL)->Equals(v8_num(1))); 13708 for (int i = 0; i < 4; i++) { 13709 CHECK(f2->Call(global, 0, NULL)->Equals(v8_num(1))); 13710 } 13711 13712 // Same for g1 and g2. 13713 CHECK(g1->Call(global, 0, NULL)->Equals(v8_num(1))); 13714 for (int i = 0; i < 4; i++) { 13715 CHECK(g2->Call(global, 0, NULL)->Equals(v8_num(1))); 13716 } 13717 13718 // Detach the global and turn on access check now blocking access to property 13719 // a and function h. 13720 context->DetachGlobal(); 13721 context->Global()->TurnOnAccessCheck(); 13722 13723 // Failing access check to property get results in undefined. 13724 CHECK(f1->Call(global, 0, NULL)->IsUndefined()); 13725 CHECK(f2->Call(global, 0, NULL)->IsUndefined()); 13726 13727 // Failing access check to function call results in exception. 13728 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 13729 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 13730 13731 // No failing access check when just returning a constant. 13732 CHECK(h->Call(global, 0, NULL)->Equals(v8_num(1))); 13733 13734 // Now compile the source again. And get the newly compiled functions, except 13735 // for h for which access is blocked. 13736 CompileRun(source); 13737 f1 = Local<Function>::Cast(context->Global()->Get(v8_str("f1"))); 13738 f2 = Local<Function>::Cast(context->Global()->Get(v8_str("f2"))); 13739 g1 = Local<Function>::Cast(context->Global()->Get(v8_str("g1"))); 13740 g2 = Local<Function>::Cast(context->Global()->Get(v8_str("g2"))); 13741 CHECK(context->Global()->Get(v8_str("h"))->IsUndefined()); 13742 13743 // Failing access check to property get results in undefined. 13744 CHECK(f1->Call(global, 0, NULL)->IsUndefined()); 13745 CHECK(f2->Call(global, 0, NULL)->IsUndefined()); 13746 13747 // Failing access check to function call results in exception. 13748 CHECK(g1->Call(global, 0, NULL).IsEmpty()); 13749 CHECK(g2->Call(global, 0, NULL).IsEmpty()); 13750 } 13751 13752 13753 // This test verifies that pre-compilation (aka preparsing) can be called 13754 // without initializing the whole VM. Thus we cannot run this test in a 13755 // multi-threaded setup. 13756 TEST(PreCompile) { 13757 // TODO(155): This test would break without the initialization of V8. This is 13758 // a workaround for now to make this test not fail. 13759 v8::V8::Initialize(); 13760 const char* script = "function foo(a) { return a+1; }"; 13761 v8::ScriptData* sd = 13762 v8::ScriptData::PreCompile(script, i::StrLength(script)); 13763 CHECK_NE(sd->Length(), 0); 13764 CHECK_NE(sd->Data(), NULL); 13765 CHECK(!sd->HasError()); 13766 delete sd; 13767 } 13768 13769 13770 TEST(PreCompileWithError) { 13771 v8::V8::Initialize(); 13772 const char* script = "function foo(a) { return 1 * * 2; }"; 13773 v8::ScriptData* sd = 13774 v8::ScriptData::PreCompile(script, i::StrLength(script)); 13775 CHECK(sd->HasError()); 13776 delete sd; 13777 } 13778 13779 13780 TEST(Regress31661) { 13781 v8::V8::Initialize(); 13782 const char* script = " The Definintive Guide"; 13783 v8::ScriptData* sd = 13784 v8::ScriptData::PreCompile(script, i::StrLength(script)); 13785 CHECK(sd->HasError()); 13786 delete sd; 13787 } 13788 13789 13790 // Tests that ScriptData can be serialized and deserialized. 13791 TEST(PreCompileSerialization) { 13792 v8::V8::Initialize(); 13793 const char* script = "function foo(a) { return a+1; }"; 13794 v8::ScriptData* sd = 13795 v8::ScriptData::PreCompile(script, i::StrLength(script)); 13796 13797 // Serialize. 13798 int serialized_data_length = sd->Length(); 13799 char* serialized_data = i::NewArray<char>(serialized_data_length); 13800 i::OS::MemCopy(serialized_data, sd->Data(), serialized_data_length); 13801 13802 // Deserialize. 13803 v8::ScriptData* deserialized_sd = 13804 v8::ScriptData::New(serialized_data, serialized_data_length); 13805 13806 // Verify that the original is the same as the deserialized. 13807 CHECK_EQ(sd->Length(), deserialized_sd->Length()); 13808 CHECK_EQ(0, memcmp(sd->Data(), deserialized_sd->Data(), sd->Length())); 13809 CHECK_EQ(sd->HasError(), deserialized_sd->HasError()); 13810 13811 delete sd; 13812 delete deserialized_sd; 13813 } 13814 13815 13816 // Attempts to deserialize bad data. 13817 TEST(PreCompileDeserializationError) { 13818 v8::V8::Initialize(); 13819 const char* data = "DONT CARE"; 13820 int invalid_size = 3; 13821 v8::ScriptData* sd = v8::ScriptData::New(data, invalid_size); 13822 13823 CHECK_EQ(0, sd->Length()); 13824 13825 delete sd; 13826 } 13827 13828 13829 // Attempts to deserialize bad data. 13830 TEST(PreCompileInvalidPreparseDataError) { 13831 v8::V8::Initialize(); 13832 LocalContext context; 13833 v8::HandleScope scope(context->GetIsolate()); 13834 13835 const char* script = "function foo(){ return 5;}\n" 13836 "function bar(){ return 6 + 7;} foo();"; 13837 v8::ScriptData* sd = 13838 v8::ScriptData::PreCompile(script, i::StrLength(script)); 13839 CHECK(!sd->HasError()); 13840 // ScriptDataImpl private implementation details 13841 const int kHeaderSize = i::PreparseDataConstants::kHeaderSize; 13842 const int kFunctionEntrySize = i::FunctionEntry::kSize; 13843 const int kFunctionEntryStartOffset = 0; 13844 const int kFunctionEntryEndOffset = 1; 13845 unsigned* sd_data = 13846 reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data())); 13847 13848 // Overwrite function bar's end position with 0. 13849 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryEndOffset] = 0; 13850 v8::TryCatch try_catch; 13851 13852 Local<String> source = String::New(script); 13853 Local<Script> compiled_script = Script::New(source, NULL, sd); 13854 CHECK(try_catch.HasCaught()); 13855 String::Utf8Value exception_value(try_catch.Message()->Get()); 13856 CHECK_EQ("Uncaught SyntaxError: Invalid preparser data for function bar", 13857 *exception_value); 13858 13859 try_catch.Reset(); 13860 13861 // Overwrite function bar's start position with 200. The function entry 13862 // will not be found when searching for it by position and we should fall 13863 // back on eager compilation. 13864 sd = v8::ScriptData::PreCompile(script, i::StrLength(script)); 13865 sd_data = reinterpret_cast<unsigned*>(const_cast<char*>(sd->Data())); 13866 sd_data[kHeaderSize + 1 * kFunctionEntrySize + kFunctionEntryStartOffset] = 13867 200; 13868 compiled_script = Script::New(source, NULL, sd); 13869 CHECK(!try_catch.HasCaught()); 13870 13871 delete sd; 13872 } 13873 13874 13875 // Verifies that the Handle<String> and const char* versions of the API produce 13876 // the same results (at least for one trivial case). 13877 TEST(PreCompileAPIVariationsAreSame) { 13878 v8::V8::Initialize(); 13879 v8::HandleScope scope(v8::Isolate::GetCurrent()); 13880 13881 const char* cstring = "function foo(a) { return a+1; }"; 13882 13883 v8::ScriptData* sd_from_cstring = 13884 v8::ScriptData::PreCompile(cstring, i::StrLength(cstring)); 13885 13886 TestAsciiResource* resource = new TestAsciiResource(cstring); 13887 v8::ScriptData* sd_from_external_string = v8::ScriptData::PreCompile( 13888 v8::String::NewExternal(resource)); 13889 13890 v8::ScriptData* sd_from_string = v8::ScriptData::PreCompile( 13891 v8::String::New(cstring)); 13892 13893 CHECK_EQ(sd_from_cstring->Length(), sd_from_external_string->Length()); 13894 CHECK_EQ(0, memcmp(sd_from_cstring->Data(), 13895 sd_from_external_string->Data(), 13896 sd_from_cstring->Length())); 13897 13898 CHECK_EQ(sd_from_cstring->Length(), sd_from_string->Length()); 13899 CHECK_EQ(0, memcmp(sd_from_cstring->Data(), 13900 sd_from_string->Data(), 13901 sd_from_cstring->Length())); 13902 13903 13904 delete sd_from_cstring; 13905 delete sd_from_external_string; 13906 delete sd_from_string; 13907 } 13908 13909 13910 // This tests that we do not allow dictionary load/call inline caches 13911 // to use functions that have not yet been compiled. The potential 13912 // problem of loading a function that has not yet been compiled can 13913 // arise because we share code between contexts via the compilation 13914 // cache. 13915 THREADED_TEST(DictionaryICLoadedFunction) { 13916 v8::HandleScope scope(v8::Isolate::GetCurrent()); 13917 // Test LoadIC. 13918 for (int i = 0; i < 2; i++) { 13919 LocalContext context; 13920 context->Global()->Set(v8_str("tmp"), v8::True()); 13921 context->Global()->Delete(v8_str("tmp")); 13922 CompileRun("for (var j = 0; j < 10; j++) new RegExp('');"); 13923 } 13924 // Test CallIC. 13925 for (int i = 0; i < 2; i++) { 13926 LocalContext context; 13927 context->Global()->Set(v8_str("tmp"), v8::True()); 13928 context->Global()->Delete(v8_str("tmp")); 13929 CompileRun("for (var j = 0; j < 10; j++) RegExp('')"); 13930 } 13931 } 13932 13933 13934 // Test that cross-context new calls use the context of the callee to 13935 // create the new JavaScript object. 13936 THREADED_TEST(CrossContextNew) { 13937 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 13938 v8::HandleScope scope(isolate); 13939 v8::Local<Context> context0 = Context::New(isolate); 13940 v8::Local<Context> context1 = Context::New(isolate); 13941 13942 // Allow cross-domain access. 13943 Local<String> token = v8_str("<security token>"); 13944 context0->SetSecurityToken(token); 13945 context1->SetSecurityToken(token); 13946 13947 // Set an 'x' property on the Object prototype and define a 13948 // constructor function in context0. 13949 context0->Enter(); 13950 CompileRun("Object.prototype.x = 42; function C() {};"); 13951 context0->Exit(); 13952 13953 // Call the constructor function from context0 and check that the 13954 // result has the 'x' property. 13955 context1->Enter(); 13956 context1->Global()->Set(v8_str("other"), context0->Global()); 13957 Local<Value> value = CompileRun("var instance = new other.C(); instance.x"); 13958 CHECK(value->IsInt32()); 13959 CHECK_EQ(42, value->Int32Value()); 13960 context1->Exit(); 13961 } 13962 13963 13964 class RegExpInterruptTest { 13965 public: 13966 RegExpInterruptTest() : block_(NULL) {} 13967 ~RegExpInterruptTest() { delete block_; } 13968 void RunTest() { 13969 block_ = i::OS::CreateSemaphore(0); 13970 gc_count_ = 0; 13971 gc_during_regexp_ = 0; 13972 regexp_success_ = false; 13973 gc_success_ = false; 13974 GCThread gc_thread(this); 13975 gc_thread.Start(); 13976 v8::Locker::StartPreemption(1); 13977 13978 LongRunningRegExp(); 13979 { 13980 v8::Unlocker unlock(CcTest::default_isolate()); 13981 gc_thread.Join(); 13982 } 13983 v8::Locker::StopPreemption(); 13984 CHECK(regexp_success_); 13985 CHECK(gc_success_); 13986 } 13987 13988 private: 13989 // Number of garbage collections required. 13990 static const int kRequiredGCs = 5; 13991 13992 class GCThread : public i::Thread { 13993 public: 13994 explicit GCThread(RegExpInterruptTest* test) 13995 : Thread("GCThread"), test_(test) {} 13996 virtual void Run() { 13997 test_->CollectGarbage(); 13998 } 13999 private: 14000 RegExpInterruptTest* test_; 14001 }; 14002 14003 void CollectGarbage() { 14004 block_->Wait(); 14005 while (gc_during_regexp_ < kRequiredGCs) { 14006 { 14007 v8::Locker lock(CcTest::default_isolate()); 14008 // TODO(lrn): Perhaps create some garbage before collecting. 14009 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 14010 gc_count_++; 14011 } 14012 i::OS::Sleep(1); 14013 } 14014 gc_success_ = true; 14015 } 14016 14017 void LongRunningRegExp() { 14018 block_->Signal(); // Enable garbage collection thread on next preemption. 14019 int rounds = 0; 14020 while (gc_during_regexp_ < kRequiredGCs) { 14021 int gc_before = gc_count_; 14022 { 14023 // Match 15-30 "a"'s against 14 and a "b". 14024 const char* c_source = 14025 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" 14026 ".exec('aaaaaaaaaaaaaaab') === null"; 14027 Local<String> source = String::New(c_source); 14028 Local<Script> script = Script::Compile(source); 14029 Local<Value> result = script->Run(); 14030 if (!result->BooleanValue()) { 14031 gc_during_regexp_ = kRequiredGCs; // Allow gc thread to exit. 14032 return; 14033 } 14034 } 14035 { 14036 // Match 15-30 "a"'s against 15 and a "b". 14037 const char* c_source = 14038 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" 14039 ".exec('aaaaaaaaaaaaaaaab')[0] === 'aaaaaaaaaaaaaaaa'"; 14040 Local<String> source = String::New(c_source); 14041 Local<Script> script = Script::Compile(source); 14042 Local<Value> result = script->Run(); 14043 if (!result->BooleanValue()) { 14044 gc_during_regexp_ = kRequiredGCs; 14045 return; 14046 } 14047 } 14048 int gc_after = gc_count_; 14049 gc_during_regexp_ += gc_after - gc_before; 14050 rounds++; 14051 i::OS::Sleep(1); 14052 } 14053 regexp_success_ = true; 14054 } 14055 14056 i::Semaphore* block_; 14057 int gc_count_; 14058 int gc_during_regexp_; 14059 bool regexp_success_; 14060 bool gc_success_; 14061 }; 14062 14063 14064 // Test that a regular expression execution can be interrupted and 14065 // survive a garbage collection. 14066 TEST(RegExpInterruption) { 14067 v8::Locker lock(CcTest::default_isolate()); 14068 v8::V8::Initialize(); 14069 v8::HandleScope scope(CcTest::default_isolate()); 14070 Local<Context> local_env; 14071 { 14072 LocalContext env; 14073 local_env = env.local(); 14074 } 14075 14076 // Local context should still be live. 14077 CHECK(!local_env.IsEmpty()); 14078 local_env->Enter(); 14079 14080 // Should complete without problems. 14081 RegExpInterruptTest().RunTest(); 14082 14083 local_env->Exit(); 14084 } 14085 14086 14087 class ApplyInterruptTest { 14088 public: 14089 ApplyInterruptTest() : block_(NULL) {} 14090 ~ApplyInterruptTest() { delete block_; } 14091 void RunTest() { 14092 block_ = i::OS::CreateSemaphore(0); 14093 gc_count_ = 0; 14094 gc_during_apply_ = 0; 14095 apply_success_ = false; 14096 gc_success_ = false; 14097 GCThread gc_thread(this); 14098 gc_thread.Start(); 14099 v8::Locker::StartPreemption(1); 14100 14101 LongRunningApply(); 14102 { 14103 v8::Unlocker unlock(CcTest::default_isolate()); 14104 gc_thread.Join(); 14105 } 14106 v8::Locker::StopPreemption(); 14107 CHECK(apply_success_); 14108 CHECK(gc_success_); 14109 } 14110 14111 private: 14112 // Number of garbage collections required. 14113 static const int kRequiredGCs = 2; 14114 14115 class GCThread : public i::Thread { 14116 public: 14117 explicit GCThread(ApplyInterruptTest* test) 14118 : Thread("GCThread"), test_(test) {} 14119 virtual void Run() { 14120 test_->CollectGarbage(); 14121 } 14122 private: 14123 ApplyInterruptTest* test_; 14124 }; 14125 14126 void CollectGarbage() { 14127 block_->Wait(); 14128 while (gc_during_apply_ < kRequiredGCs) { 14129 { 14130 v8::Locker lock(CcTest::default_isolate()); 14131 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 14132 gc_count_++; 14133 } 14134 i::OS::Sleep(1); 14135 } 14136 gc_success_ = true; 14137 } 14138 14139 void LongRunningApply() { 14140 block_->Signal(); 14141 int rounds = 0; 14142 while (gc_during_apply_ < kRequiredGCs) { 14143 int gc_before = gc_count_; 14144 { 14145 const char* c_source = 14146 "function do_very_little(bar) {" 14147 " this.foo = bar;" 14148 "}" 14149 "for (var i = 0; i < 100000; i++) {" 14150 " do_very_little.apply(this, ['bar']);" 14151 "}"; 14152 Local<String> source = String::New(c_source); 14153 Local<Script> script = Script::Compile(source); 14154 Local<Value> result = script->Run(); 14155 // Check that no exception was thrown. 14156 CHECK(!result.IsEmpty()); 14157 } 14158 int gc_after = gc_count_; 14159 gc_during_apply_ += gc_after - gc_before; 14160 rounds++; 14161 } 14162 apply_success_ = true; 14163 } 14164 14165 i::Semaphore* block_; 14166 int gc_count_; 14167 int gc_during_apply_; 14168 bool apply_success_; 14169 bool gc_success_; 14170 }; 14171 14172 14173 // Test that nothing bad happens if we get a preemption just when we were 14174 // about to do an apply(). 14175 TEST(ApplyInterruption) { 14176 v8::Locker lock(CcTest::default_isolate()); 14177 v8::V8::Initialize(); 14178 v8::HandleScope scope(CcTest::default_isolate()); 14179 Local<Context> local_env; 14180 { 14181 LocalContext env; 14182 local_env = env.local(); 14183 } 14184 14185 // Local context should still be live. 14186 CHECK(!local_env.IsEmpty()); 14187 local_env->Enter(); 14188 14189 // Should complete without problems. 14190 ApplyInterruptTest().RunTest(); 14191 14192 local_env->Exit(); 14193 } 14194 14195 14196 // Verify that we can clone an object 14197 TEST(ObjectClone) { 14198 LocalContext env; 14199 v8::HandleScope scope(env->GetIsolate()); 14200 14201 const char* sample = 14202 "var rv = {};" \ 14203 "rv.alpha = 'hello';" \ 14204 "rv.beta = 123;" \ 14205 "rv;"; 14206 14207 // Create an object, verify basics. 14208 Local<Value> val = CompileRun(sample); 14209 CHECK(val->IsObject()); 14210 Local<v8::Object> obj = val.As<v8::Object>(); 14211 obj->Set(v8_str("gamma"), v8_str("cloneme")); 14212 14213 CHECK_EQ(v8_str("hello"), obj->Get(v8_str("alpha"))); 14214 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta"))); 14215 CHECK_EQ(v8_str("cloneme"), obj->Get(v8_str("gamma"))); 14216 14217 // Clone it. 14218 Local<v8::Object> clone = obj->Clone(); 14219 CHECK_EQ(v8_str("hello"), clone->Get(v8_str("alpha"))); 14220 CHECK_EQ(v8::Integer::New(123), clone->Get(v8_str("beta"))); 14221 CHECK_EQ(v8_str("cloneme"), clone->Get(v8_str("gamma"))); 14222 14223 // Set a property on the clone, verify each object. 14224 clone->Set(v8_str("beta"), v8::Integer::New(456)); 14225 CHECK_EQ(v8::Integer::New(123), obj->Get(v8_str("beta"))); 14226 CHECK_EQ(v8::Integer::New(456), clone->Get(v8_str("beta"))); 14227 } 14228 14229 14230 class AsciiVectorResource : public v8::String::ExternalAsciiStringResource { 14231 public: 14232 explicit AsciiVectorResource(i::Vector<const char> vector) 14233 : data_(vector) {} 14234 virtual ~AsciiVectorResource() {} 14235 virtual size_t length() const { return data_.length(); } 14236 virtual const char* data() const { return data_.start(); } 14237 private: 14238 i::Vector<const char> data_; 14239 }; 14240 14241 14242 class UC16VectorResource : public v8::String::ExternalStringResource { 14243 public: 14244 explicit UC16VectorResource(i::Vector<const i::uc16> vector) 14245 : data_(vector) {} 14246 virtual ~UC16VectorResource() {} 14247 virtual size_t length() const { return data_.length(); } 14248 virtual const i::uc16* data() const { return data_.start(); } 14249 private: 14250 i::Vector<const i::uc16> data_; 14251 }; 14252 14253 14254 static void MorphAString(i::String* string, 14255 AsciiVectorResource* ascii_resource, 14256 UC16VectorResource* uc16_resource) { 14257 CHECK(i::StringShape(string).IsExternal()); 14258 if (string->IsOneByteRepresentation()) { 14259 // Check old map is not internalized or long. 14260 CHECK(string->map() == HEAP->external_ascii_string_map()); 14261 // Morph external string to be TwoByte string. 14262 string->set_map(HEAP->external_string_map()); 14263 i::ExternalTwoByteString* morphed = 14264 i::ExternalTwoByteString::cast(string); 14265 morphed->set_resource(uc16_resource); 14266 } else { 14267 // Check old map is not internalized or long. 14268 CHECK(string->map() == HEAP->external_string_map()); 14269 // Morph external string to be ASCII string. 14270 string->set_map(HEAP->external_ascii_string_map()); 14271 i::ExternalAsciiString* morphed = 14272 i::ExternalAsciiString::cast(string); 14273 morphed->set_resource(ascii_resource); 14274 } 14275 } 14276 14277 14278 // Test that we can still flatten a string if the components it is built up 14279 // from have been turned into 16 bit strings in the mean time. 14280 THREADED_TEST(MorphCompositeStringTest) { 14281 char utf_buffer[129]; 14282 const char* c_string = "Now is the time for all good men" 14283 " to come to the aid of the party"; 14284 uint16_t* two_byte_string = AsciiToTwoByteString(c_string); 14285 { 14286 LocalContext env; 14287 i::Factory* factory = i::Isolate::Current()->factory(); 14288 v8::HandleScope scope(env->GetIsolate()); 14289 AsciiVectorResource ascii_resource( 14290 i::Vector<const char>(c_string, i::StrLength(c_string))); 14291 UC16VectorResource uc16_resource( 14292 i::Vector<const uint16_t>(two_byte_string, 14293 i::StrLength(c_string))); 14294 14295 Local<String> lhs(v8::Utils::ToLocal( 14296 factory->NewExternalStringFromAscii(&ascii_resource))); 14297 Local<String> rhs(v8::Utils::ToLocal( 14298 factory->NewExternalStringFromAscii(&ascii_resource))); 14299 14300 env->Global()->Set(v8_str("lhs"), lhs); 14301 env->Global()->Set(v8_str("rhs"), rhs); 14302 14303 CompileRun( 14304 "var cons = lhs + rhs;" 14305 "var slice = lhs.substring(1, lhs.length - 1);" 14306 "var slice_on_cons = (lhs + rhs).substring(1, lhs.length *2 - 1);"); 14307 14308 CHECK(lhs->IsOneByte()); 14309 CHECK(rhs->IsOneByte()); 14310 14311 MorphAString(*v8::Utils::OpenHandle(*lhs), &ascii_resource, &uc16_resource); 14312 MorphAString(*v8::Utils::OpenHandle(*rhs), &ascii_resource, &uc16_resource); 14313 14314 // This should UTF-8 without flattening, since everything is ASCII. 14315 Handle<String> cons = v8_compile("cons")->Run().As<String>(); 14316 CHECK_EQ(128, cons->Utf8Length()); 14317 int nchars = -1; 14318 CHECK_EQ(129, cons->WriteUtf8(utf_buffer, -1, &nchars)); 14319 CHECK_EQ(128, nchars); 14320 CHECK_EQ(0, strcmp( 14321 utf_buffer, 14322 "Now is the time for all good men to come to the aid of the party" 14323 "Now is the time for all good men to come to the aid of the party")); 14324 14325 // Now do some stuff to make sure the strings are flattened, etc. 14326 CompileRun( 14327 "/[^a-z]/.test(cons);" 14328 "/[^a-z]/.test(slice);" 14329 "/[^a-z]/.test(slice_on_cons);"); 14330 const char* expected_cons = 14331 "Now is the time for all good men to come to the aid of the party" 14332 "Now is the time for all good men to come to the aid of the party"; 14333 const char* expected_slice = 14334 "ow is the time for all good men to come to the aid of the part"; 14335 const char* expected_slice_on_cons = 14336 "ow is the time for all good men to come to the aid of the party" 14337 "Now is the time for all good men to come to the aid of the part"; 14338 CHECK_EQ(String::New(expected_cons), 14339 env->Global()->Get(v8_str("cons"))); 14340 CHECK_EQ(String::New(expected_slice), 14341 env->Global()->Get(v8_str("slice"))); 14342 CHECK_EQ(String::New(expected_slice_on_cons), 14343 env->Global()->Get(v8_str("slice_on_cons"))); 14344 } 14345 i::DeleteArray(two_byte_string); 14346 } 14347 14348 14349 TEST(CompileExternalTwoByteSource) { 14350 LocalContext context; 14351 v8::HandleScope scope(context->GetIsolate()); 14352 14353 // This is a very short list of sources, which currently is to check for a 14354 // regression caused by r2703. 14355 const char* ascii_sources[] = { 14356 "0.5", 14357 "-0.5", // This mainly testes PushBack in the Scanner. 14358 "--0.5", // This mainly testes PushBack in the Scanner. 14359 NULL 14360 }; 14361 14362 // Compile the sources as external two byte strings. 14363 for (int i = 0; ascii_sources[i] != NULL; i++) { 14364 uint16_t* two_byte_string = AsciiToTwoByteString(ascii_sources[i]); 14365 UC16VectorResource uc16_resource( 14366 i::Vector<const uint16_t>(two_byte_string, 14367 i::StrLength(ascii_sources[i]))); 14368 v8::Local<v8::String> source = v8::String::NewExternal(&uc16_resource); 14369 v8::Script::Compile(source); 14370 i::DeleteArray(two_byte_string); 14371 } 14372 } 14373 14374 14375 class RegExpStringModificationTest { 14376 public: 14377 RegExpStringModificationTest() 14378 : block_(i::OS::CreateSemaphore(0)), 14379 morphs_(0), 14380 morphs_during_regexp_(0), 14381 ascii_resource_(i::Vector<const char>("aaaaaaaaaaaaaab", 15)), 14382 uc16_resource_(i::Vector<const uint16_t>(two_byte_content_, 15)) {} 14383 ~RegExpStringModificationTest() { delete block_; } 14384 void RunTest() { 14385 i::Factory* factory = i::Isolate::Current()->factory(); 14386 14387 regexp_success_ = false; 14388 morph_success_ = false; 14389 14390 // Initialize the contents of two_byte_content_ to be a uc16 representation 14391 // of "aaaaaaaaaaaaaab". 14392 for (int i = 0; i < 14; i++) { 14393 two_byte_content_[i] = 'a'; 14394 } 14395 two_byte_content_[14] = 'b'; 14396 14397 // Create the input string for the regexp - the one we are going to change 14398 // properties of. 14399 input_ = factory->NewExternalStringFromAscii(&ascii_resource_); 14400 14401 // Inject the input as a global variable. 14402 i::Handle<i::String> input_name = 14403 factory->NewStringFromAscii(i::Vector<const char>("input", 5)); 14404 i::Isolate::Current()->native_context()->global_object()->SetProperty( 14405 *input_name, 14406 *input_, 14407 NONE, 14408 i::kNonStrictMode)->ToObjectChecked(); 14409 14410 MorphThread morph_thread(this); 14411 morph_thread.Start(); 14412 v8::Locker::StartPreemption(1); 14413 LongRunningRegExp(); 14414 { 14415 v8::Unlocker unlock(CcTest::default_isolate()); 14416 morph_thread.Join(); 14417 } 14418 v8::Locker::StopPreemption(); 14419 CHECK(regexp_success_); 14420 CHECK(morph_success_); 14421 } 14422 14423 private: 14424 // Number of string modifications required. 14425 static const int kRequiredModifications = 5; 14426 static const int kMaxModifications = 100; 14427 14428 class MorphThread : public i::Thread { 14429 public: 14430 explicit MorphThread(RegExpStringModificationTest* test) 14431 : Thread("MorphThread"), test_(test) {} 14432 virtual void Run() { 14433 test_->MorphString(); 14434 } 14435 private: 14436 RegExpStringModificationTest* test_; 14437 }; 14438 14439 void MorphString() { 14440 block_->Wait(); 14441 while (morphs_during_regexp_ < kRequiredModifications && 14442 morphs_ < kMaxModifications) { 14443 { 14444 v8::Locker lock(CcTest::default_isolate()); 14445 // Swap string between ascii and two-byte representation. 14446 i::String* string = *input_; 14447 MorphAString(string, &ascii_resource_, &uc16_resource_); 14448 morphs_++; 14449 } 14450 i::OS::Sleep(1); 14451 } 14452 morph_success_ = true; 14453 } 14454 14455 void LongRunningRegExp() { 14456 block_->Signal(); // Enable morphing thread on next preemption. 14457 while (morphs_during_regexp_ < kRequiredModifications && 14458 morphs_ < kMaxModifications) { 14459 int morphs_before = morphs_; 14460 { 14461 v8::HandleScope scope(v8::Isolate::GetCurrent()); 14462 // Match 15-30 "a"'s against 14 and a "b". 14463 const char* c_source = 14464 "/a?a?a?a?a?a?a?a?a?a?a?a?a?a?aaaaaaaaaaaaaaaa/" 14465 ".exec(input) === null"; 14466 Local<String> source = String::New(c_source); 14467 Local<Script> script = Script::Compile(source); 14468 Local<Value> result = script->Run(); 14469 CHECK(result->IsTrue()); 14470 } 14471 int morphs_after = morphs_; 14472 morphs_during_regexp_ += morphs_after - morphs_before; 14473 } 14474 regexp_success_ = true; 14475 } 14476 14477 i::uc16 two_byte_content_[15]; 14478 i::Semaphore* block_; 14479 int morphs_; 14480 int morphs_during_regexp_; 14481 bool regexp_success_; 14482 bool morph_success_; 14483 i::Handle<i::String> input_; 14484 AsciiVectorResource ascii_resource_; 14485 UC16VectorResource uc16_resource_; 14486 }; 14487 14488 14489 // Test that a regular expression execution can be interrupted and 14490 // the string changed without failing. 14491 TEST(RegExpStringModification) { 14492 v8::Locker lock(CcTest::default_isolate()); 14493 v8::V8::Initialize(); 14494 v8::HandleScope scope(CcTest::default_isolate()); 14495 Local<Context> local_env; 14496 { 14497 LocalContext env; 14498 local_env = env.local(); 14499 } 14500 14501 // Local context should still be live. 14502 CHECK(!local_env.IsEmpty()); 14503 local_env->Enter(); 14504 14505 // Should complete without problems. 14506 RegExpStringModificationTest().RunTest(); 14507 14508 local_env->Exit(); 14509 } 14510 14511 14512 // Test that we cannot set a property on the global object if there 14513 // is a read-only property in the prototype chain. 14514 TEST(ReadOnlyPropertyInGlobalProto) { 14515 i::FLAG_es5_readonly = true; 14516 v8::HandleScope scope(v8::Isolate::GetCurrent()); 14517 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 14518 LocalContext context(0, templ); 14519 v8::Handle<v8::Object> global = context->Global(); 14520 v8::Handle<v8::Object> global_proto = 14521 v8::Handle<v8::Object>::Cast(global->Get(v8_str("__proto__"))); 14522 global_proto->Set(v8_str("x"), v8::Integer::New(0), v8::ReadOnly); 14523 global_proto->Set(v8_str("y"), v8::Integer::New(0), v8::ReadOnly); 14524 // Check without 'eval' or 'with'. 14525 v8::Handle<v8::Value> res = 14526 CompileRun("function f() { x = 42; return x; }; f()"); 14527 CHECK_EQ(v8::Integer::New(0), res); 14528 // Check with 'eval'. 14529 res = CompileRun("function f() { eval('1'); y = 43; return y; }; f()"); 14530 CHECK_EQ(v8::Integer::New(0), res); 14531 // Check with 'with'. 14532 res = CompileRun("function f() { with (this) { y = 44 }; return y; }; f()"); 14533 CHECK_EQ(v8::Integer::New(0), res); 14534 } 14535 14536 static int force_set_set_count = 0; 14537 static int force_set_get_count = 0; 14538 bool pass_on_get = false; 14539 14540 static void ForceSetGetter(v8::Local<v8::String> name, 14541 const v8::PropertyCallbackInfo<v8::Value>& info) { 14542 force_set_get_count++; 14543 if (pass_on_get) { 14544 return; 14545 } 14546 info.GetReturnValue().Set(3); 14547 } 14548 14549 static void ForceSetSetter(v8::Local<v8::String> name, 14550 v8::Local<v8::Value> value, 14551 const v8::PropertyCallbackInfo<void>& info) { 14552 force_set_set_count++; 14553 } 14554 14555 static void ForceSetInterceptSetter( 14556 v8::Local<v8::String> name, 14557 v8::Local<v8::Value> value, 14558 const v8::PropertyCallbackInfo<v8::Value>& info) { 14559 force_set_set_count++; 14560 info.GetReturnValue().SetUndefined(); 14561 } 14562 14563 14564 TEST(ForceSet) { 14565 force_set_get_count = 0; 14566 force_set_set_count = 0; 14567 pass_on_get = false; 14568 14569 v8::HandleScope scope(v8::Isolate::GetCurrent()); 14570 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 14571 v8::Handle<v8::String> access_property = v8::String::New("a"); 14572 templ->SetAccessor(access_property, ForceSetGetter, ForceSetSetter); 14573 LocalContext context(NULL, templ); 14574 v8::Handle<v8::Object> global = context->Global(); 14575 14576 // Ordinary properties 14577 v8::Handle<v8::String> simple_property = v8::String::New("p"); 14578 global->Set(simple_property, v8::Int32::New(4), v8::ReadOnly); 14579 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 14580 // This should fail because the property is read-only 14581 global->Set(simple_property, v8::Int32::New(5)); 14582 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 14583 // This should succeed even though the property is read-only 14584 global->ForceSet(simple_property, v8::Int32::New(6)); 14585 CHECK_EQ(6, global->Get(simple_property)->Int32Value()); 14586 14587 // Accessors 14588 CHECK_EQ(0, force_set_set_count); 14589 CHECK_EQ(0, force_set_get_count); 14590 CHECK_EQ(3, global->Get(access_property)->Int32Value()); 14591 // CHECK_EQ the property shouldn't override it, just call the setter 14592 // which in this case does nothing. 14593 global->Set(access_property, v8::Int32::New(7)); 14594 CHECK_EQ(3, global->Get(access_property)->Int32Value()); 14595 CHECK_EQ(1, force_set_set_count); 14596 CHECK_EQ(2, force_set_get_count); 14597 // Forcing the property to be set should override the accessor without 14598 // calling it 14599 global->ForceSet(access_property, v8::Int32::New(8)); 14600 CHECK_EQ(8, global->Get(access_property)->Int32Value()); 14601 CHECK_EQ(1, force_set_set_count); 14602 CHECK_EQ(2, force_set_get_count); 14603 } 14604 14605 14606 TEST(ForceSetWithInterceptor) { 14607 force_set_get_count = 0; 14608 force_set_set_count = 0; 14609 pass_on_get = false; 14610 14611 v8::HandleScope scope(v8::Isolate::GetCurrent()); 14612 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 14613 templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter); 14614 LocalContext context(NULL, templ); 14615 v8::Handle<v8::Object> global = context->Global(); 14616 14617 v8::Handle<v8::String> some_property = v8::String::New("a"); 14618 CHECK_EQ(0, force_set_set_count); 14619 CHECK_EQ(0, force_set_get_count); 14620 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 14621 // Setting the property shouldn't override it, just call the setter 14622 // which in this case does nothing. 14623 global->Set(some_property, v8::Int32::New(7)); 14624 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 14625 CHECK_EQ(1, force_set_set_count); 14626 CHECK_EQ(2, force_set_get_count); 14627 // Getting the property when the interceptor returns an empty handle 14628 // should yield undefined, since the property isn't present on the 14629 // object itself yet. 14630 pass_on_get = true; 14631 CHECK(global->Get(some_property)->IsUndefined()); 14632 CHECK_EQ(1, force_set_set_count); 14633 CHECK_EQ(3, force_set_get_count); 14634 // Forcing the property to be set should cause the value to be 14635 // set locally without calling the interceptor. 14636 global->ForceSet(some_property, v8::Int32::New(8)); 14637 CHECK_EQ(8, global->Get(some_property)->Int32Value()); 14638 CHECK_EQ(1, force_set_set_count); 14639 CHECK_EQ(4, force_set_get_count); 14640 // Reenabling the interceptor should cause it to take precedence over 14641 // the property 14642 pass_on_get = false; 14643 CHECK_EQ(3, global->Get(some_property)->Int32Value()); 14644 CHECK_EQ(1, force_set_set_count); 14645 CHECK_EQ(5, force_set_get_count); 14646 // The interceptor should also work for other properties 14647 CHECK_EQ(3, global->Get(v8::String::New("b"))->Int32Value()); 14648 CHECK_EQ(1, force_set_set_count); 14649 CHECK_EQ(6, force_set_get_count); 14650 } 14651 14652 14653 THREADED_TEST(ForceDelete) { 14654 v8::HandleScope scope(v8::Isolate::GetCurrent()); 14655 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 14656 LocalContext context(NULL, templ); 14657 v8::Handle<v8::Object> global = context->Global(); 14658 14659 // Ordinary properties 14660 v8::Handle<v8::String> simple_property = v8::String::New("p"); 14661 global->Set(simple_property, v8::Int32::New(4), v8::DontDelete); 14662 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 14663 // This should fail because the property is dont-delete. 14664 CHECK(!global->Delete(simple_property)); 14665 CHECK_EQ(4, global->Get(simple_property)->Int32Value()); 14666 // This should succeed even though the property is dont-delete. 14667 CHECK(global->ForceDelete(simple_property)); 14668 CHECK(global->Get(simple_property)->IsUndefined()); 14669 } 14670 14671 14672 static int force_delete_interceptor_count = 0; 14673 static bool pass_on_delete = false; 14674 14675 14676 static void ForceDeleteDeleter( 14677 v8::Local<v8::String> name, 14678 const v8::PropertyCallbackInfo<v8::Boolean>& info) { 14679 force_delete_interceptor_count++; 14680 if (pass_on_delete) return; 14681 info.GetReturnValue().Set(true); 14682 } 14683 14684 14685 THREADED_TEST(ForceDeleteWithInterceptor) { 14686 force_delete_interceptor_count = 0; 14687 pass_on_delete = false; 14688 14689 v8::HandleScope scope(v8::Isolate::GetCurrent()); 14690 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 14691 templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter); 14692 LocalContext context(NULL, templ); 14693 v8::Handle<v8::Object> global = context->Global(); 14694 14695 v8::Handle<v8::String> some_property = v8::String::New("a"); 14696 global->Set(some_property, v8::Integer::New(42), v8::DontDelete); 14697 14698 // Deleting a property should get intercepted and nothing should 14699 // happen. 14700 CHECK_EQ(0, force_delete_interceptor_count); 14701 CHECK(global->Delete(some_property)); 14702 CHECK_EQ(1, force_delete_interceptor_count); 14703 CHECK_EQ(42, global->Get(some_property)->Int32Value()); 14704 // Deleting the property when the interceptor returns an empty 14705 // handle should not delete the property since it is DontDelete. 14706 pass_on_delete = true; 14707 CHECK(!global->Delete(some_property)); 14708 CHECK_EQ(2, force_delete_interceptor_count); 14709 CHECK_EQ(42, global->Get(some_property)->Int32Value()); 14710 // Forcing the property to be deleted should delete the value 14711 // without calling the interceptor. 14712 CHECK(global->ForceDelete(some_property)); 14713 CHECK(global->Get(some_property)->IsUndefined()); 14714 CHECK_EQ(2, force_delete_interceptor_count); 14715 } 14716 14717 14718 // Make sure that forcing a delete invalidates any IC stubs, so we 14719 // don't read the hole value. 14720 THREADED_TEST(ForceDeleteIC) { 14721 LocalContext context; 14722 v8::HandleScope scope(context->GetIsolate()); 14723 // Create a DontDelete variable on the global object. 14724 CompileRun("this.__proto__ = { foo: 'horse' };" 14725 "var foo = 'fish';" 14726 "function f() { return foo.length; }"); 14727 // Initialize the IC for foo in f. 14728 CompileRun("for (var i = 0; i < 4; i++) f();"); 14729 // Make sure the value of foo is correct before the deletion. 14730 CHECK_EQ(4, CompileRun("f()")->Int32Value()); 14731 // Force the deletion of foo. 14732 CHECK(context->Global()->ForceDelete(v8_str("foo"))); 14733 // Make sure the value for foo is read from the prototype, and that 14734 // we don't get in trouble with reading the deleted cell value 14735 // sentinel. 14736 CHECK_EQ(5, CompileRun("f()")->Int32Value()); 14737 } 14738 14739 14740 TEST(InlinedFunctionAcrossContexts) { 14741 i::FLAG_allow_natives_syntax = true; 14742 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 14743 v8::HandleScope outer_scope(isolate); 14744 v8::Local<v8::Context> ctx1 = v8::Context::New(isolate); 14745 v8::Local<v8::Context> ctx2 = v8::Context::New(isolate); 14746 ctx1->Enter(); 14747 14748 { 14749 v8::HandleScope inner_scope(v8::Isolate::GetCurrent()); 14750 CompileRun("var G = 42; function foo() { return G; }"); 14751 v8::Local<v8::Value> foo = ctx1->Global()->Get(v8_str("foo")); 14752 ctx2->Enter(); 14753 ctx2->Global()->Set(v8_str("o"), foo); 14754 v8::Local<v8::Value> res = CompileRun( 14755 "function f() { return o(); }" 14756 "for (var i = 0; i < 10; ++i) f();" 14757 "%OptimizeFunctionOnNextCall(f);" 14758 "f();"); 14759 CHECK_EQ(42, res->Int32Value()); 14760 ctx2->Exit(); 14761 v8::Handle<v8::String> G_property = v8::String::New("G"); 14762 CHECK(ctx1->Global()->ForceDelete(G_property)); 14763 ctx2->Enter(); 14764 ExpectString( 14765 "(function() {" 14766 " try {" 14767 " return f();" 14768 " } catch(e) {" 14769 " return e.toString();" 14770 " }" 14771 " })()", 14772 "ReferenceError: G is not defined"); 14773 ctx2->Exit(); 14774 ctx1->Exit(); 14775 } 14776 } 14777 14778 14779 static v8::Local<Context> calling_context0; 14780 static v8::Local<Context> calling_context1; 14781 static v8::Local<Context> calling_context2; 14782 14783 14784 // Check that the call to the callback is initiated in 14785 // calling_context2, the directly calling context is calling_context1 14786 // and the callback itself is in calling_context0. 14787 static void GetCallingContextCallback( 14788 const v8::FunctionCallbackInfo<v8::Value>& args) { 14789 ApiTestFuzzer::Fuzz(); 14790 CHECK(Context::GetCurrent() == calling_context0); 14791 CHECK(args.GetIsolate()->GetCurrentContext() == calling_context0); 14792 CHECK(Context::GetCalling() == calling_context1); 14793 CHECK(Context::GetEntered() == calling_context2); 14794 args.GetReturnValue().Set(42); 14795 } 14796 14797 14798 THREADED_TEST(GetCurrentContextWhenNotInContext) { 14799 i::Isolate* isolate = i::Isolate::Current(); 14800 CHECK(isolate != NULL); 14801 CHECK(isolate->context() == NULL); 14802 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate); 14803 v8::HandleScope scope(v8_isolate); 14804 // The following should not crash, but return an empty handle. 14805 v8::Local<v8::Context> current = v8_isolate->GetCurrentContext(); 14806 CHECK(current.IsEmpty()); 14807 } 14808 14809 14810 THREADED_TEST(GetCallingContext) { 14811 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 14812 v8::HandleScope scope(isolate); 14813 14814 Local<Context> calling_context0(Context::New(isolate)); 14815 Local<Context> calling_context1(Context::New(isolate)); 14816 Local<Context> calling_context2(Context::New(isolate)); 14817 ::calling_context0 = calling_context0; 14818 ::calling_context1 = calling_context1; 14819 ::calling_context2 = calling_context2; 14820 14821 // Allow cross-domain access. 14822 Local<String> token = v8_str("<security token>"); 14823 calling_context0->SetSecurityToken(token); 14824 calling_context1->SetSecurityToken(token); 14825 calling_context2->SetSecurityToken(token); 14826 14827 // Create an object with a C++ callback in context0. 14828 calling_context0->Enter(); 14829 Local<v8::FunctionTemplate> callback_templ = 14830 v8::FunctionTemplate::New(GetCallingContextCallback); 14831 calling_context0->Global()->Set(v8_str("callback"), 14832 callback_templ->GetFunction()); 14833 calling_context0->Exit(); 14834 14835 // Expose context0 in context1 and set up a function that calls the 14836 // callback function. 14837 calling_context1->Enter(); 14838 calling_context1->Global()->Set(v8_str("context0"), 14839 calling_context0->Global()); 14840 CompileRun("function f() { context0.callback() }"); 14841 calling_context1->Exit(); 14842 14843 // Expose context1 in context2 and call the callback function in 14844 // context0 indirectly through f in context1. 14845 calling_context2->Enter(); 14846 calling_context2->Global()->Set(v8_str("context1"), 14847 calling_context1->Global()); 14848 CompileRun("context1.f()"); 14849 calling_context2->Exit(); 14850 ::calling_context0.Clear(); 14851 ::calling_context1.Clear(); 14852 ::calling_context2.Clear(); 14853 } 14854 14855 14856 // Check that a variable declaration with no explicit initialization 14857 // value does shadow an existing property in the prototype chain. 14858 THREADED_TEST(InitGlobalVarInProtoChain) { 14859 i::FLAG_es52_globals = true; 14860 LocalContext context; 14861 v8::HandleScope scope(context->GetIsolate()); 14862 // Introduce a variable in the prototype chain. 14863 CompileRun("__proto__.x = 42"); 14864 v8::Handle<v8::Value> result = CompileRun("var x = 43; x"); 14865 CHECK(!result->IsUndefined()); 14866 CHECK_EQ(43, result->Int32Value()); 14867 } 14868 14869 14870 // Regression test for issue 398. 14871 // If a function is added to an object, creating a constant function 14872 // field, and the result is cloned, replacing the constant function on the 14873 // original should not affect the clone. 14874 // See http://code.google.com/p/v8/issues/detail?id=398 14875 THREADED_TEST(ReplaceConstantFunction) { 14876 LocalContext context; 14877 v8::HandleScope scope(context->GetIsolate()); 14878 v8::Handle<v8::Object> obj = v8::Object::New(); 14879 v8::Handle<v8::FunctionTemplate> func_templ = v8::FunctionTemplate::New(); 14880 v8::Handle<v8::String> foo_string = v8::String::New("foo"); 14881 obj->Set(foo_string, func_templ->GetFunction()); 14882 v8::Handle<v8::Object> obj_clone = obj->Clone(); 14883 obj_clone->Set(foo_string, v8::String::New("Hello")); 14884 CHECK(!obj->Get(foo_string)->IsUndefined()); 14885 } 14886 14887 14888 // Regression test for http://crbug.com/16276. 14889 THREADED_TEST(Regress16276) { 14890 LocalContext context; 14891 v8::HandleScope scope(context->GetIsolate()); 14892 // Force the IC in f to be a dictionary load IC. 14893 CompileRun("function f(obj) { return obj.x; }\n" 14894 "var obj = { x: { foo: 42 }, y: 87 };\n" 14895 "var x = obj.x;\n" 14896 "delete obj.y;\n" 14897 "for (var i = 0; i < 5; i++) f(obj);"); 14898 // Detach the global object to make 'this' refer directly to the 14899 // global object (not the proxy), and make sure that the dictionary 14900 // load IC doesn't mess up loading directly from the global object. 14901 context->DetachGlobal(); 14902 CHECK_EQ(42, CompileRun("f(this).foo")->Int32Value()); 14903 } 14904 14905 14906 THREADED_TEST(PixelArray) { 14907 LocalContext context; 14908 i::Factory* factory = i::Isolate::Current()->factory(); 14909 v8::HandleScope scope(context->GetIsolate()); 14910 const int kElementCount = 260; 14911 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount)); 14912 i::Handle<i::ExternalPixelArray> pixels = 14913 i::Handle<i::ExternalPixelArray>::cast( 14914 factory->NewExternalArray(kElementCount, 14915 v8::kExternalPixelArray, 14916 pixel_data)); 14917 // Force GC to trigger verification. 14918 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 14919 for (int i = 0; i < kElementCount; i++) { 14920 pixels->set(i, i % 256); 14921 } 14922 // Force GC to trigger verification. 14923 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 14924 for (int i = 0; i < kElementCount; i++) { 14925 CHECK_EQ(i % 256, pixels->get_scalar(i)); 14926 CHECK_EQ(i % 256, pixel_data[i]); 14927 } 14928 14929 v8::Handle<v8::Object> obj = v8::Object::New(); 14930 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 14931 // Set the elements to be the pixels. 14932 // jsobj->set_elements(*pixels); 14933 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount); 14934 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); 14935 obj->Set(v8_str("field"), v8::Int32::New(1503)); 14936 context->Global()->Set(v8_str("pixels"), obj); 14937 v8::Handle<v8::Value> result = CompileRun("pixels.field"); 14938 CHECK_EQ(1503, result->Int32Value()); 14939 result = CompileRun("pixels[1]"); 14940 CHECK_EQ(1, result->Int32Value()); 14941 14942 result = CompileRun("var sum = 0;" 14943 "for (var i = 0; i < 8; i++) {" 14944 " sum += pixels[i] = pixels[i] = -i;" 14945 "}" 14946 "sum;"); 14947 CHECK_EQ(-28, result->Int32Value()); 14948 14949 result = CompileRun("var sum = 0;" 14950 "for (var i = 0; i < 8; i++) {" 14951 " sum += pixels[i] = pixels[i] = 0;" 14952 "}" 14953 "sum;"); 14954 CHECK_EQ(0, result->Int32Value()); 14955 14956 result = CompileRun("var sum = 0;" 14957 "for (var i = 0; i < 8; i++) {" 14958 " sum += pixels[i] = pixels[i] = 255;" 14959 "}" 14960 "sum;"); 14961 CHECK_EQ(8 * 255, result->Int32Value()); 14962 14963 result = CompileRun("var sum = 0;" 14964 "for (var i = 0; i < 8; i++) {" 14965 " sum += pixels[i] = pixels[i] = 256 + i;" 14966 "}" 14967 "sum;"); 14968 CHECK_EQ(2076, result->Int32Value()); 14969 14970 result = CompileRun("var sum = 0;" 14971 "for (var i = 0; i < 8; i++) {" 14972 " sum += pixels[i] = pixels[i] = i;" 14973 "}" 14974 "sum;"); 14975 CHECK_EQ(28, result->Int32Value()); 14976 14977 result = CompileRun("var sum = 0;" 14978 "for (var i = 0; i < 8; i++) {" 14979 " sum += pixels[i];" 14980 "}" 14981 "sum;"); 14982 CHECK_EQ(28, result->Int32Value()); 14983 14984 i::Handle<i::Smi> value(i::Smi::FromInt(2), 14985 reinterpret_cast<i::Isolate*>(context->GetIsolate())); 14986 i::Handle<i::Object> no_failure; 14987 no_failure = 14988 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode); 14989 ASSERT(!no_failure.is_null()); 14990 i::USE(no_failure); 14991 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); 14992 *value.location() = i::Smi::FromInt(256); 14993 no_failure = 14994 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode); 14995 ASSERT(!no_failure.is_null()); 14996 i::USE(no_failure); 14997 CHECK_EQ(255, 14998 i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); 14999 *value.location() = i::Smi::FromInt(-1); 15000 no_failure = 15001 i::JSObject::SetElement(jsobj, 1, value, NONE, i::kNonStrictMode); 15002 ASSERT(!no_failure.is_null()); 15003 i::USE(no_failure); 15004 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); 15005 15006 result = CompileRun("for (var i = 0; i < 8; i++) {" 15007 " pixels[i] = (i * 65) - 109;" 15008 "}" 15009 "pixels[1] + pixels[6];"); 15010 CHECK_EQ(255, result->Int32Value()); 15011 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value()); 15012 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); 15013 CHECK_EQ(21, 15014 i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value()); 15015 CHECK_EQ(86, 15016 i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value()); 15017 CHECK_EQ(151, 15018 i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value()); 15019 CHECK_EQ(216, 15020 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value()); 15021 CHECK_EQ(255, 15022 i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value()); 15023 CHECK_EQ(255, 15024 i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value()); 15025 result = CompileRun("var sum = 0;" 15026 "for (var i = 0; i < 8; i++) {" 15027 " sum += pixels[i];" 15028 "}" 15029 "sum;"); 15030 CHECK_EQ(984, result->Int32Value()); 15031 15032 result = CompileRun("for (var i = 0; i < 8; i++) {" 15033 " pixels[i] = (i * 1.1);" 15034 "}" 15035 "pixels[1] + pixels[6];"); 15036 CHECK_EQ(8, result->Int32Value()); 15037 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(0)->ToObjectChecked())->value()); 15038 CHECK_EQ(1, i::Smi::cast(jsobj->GetElement(1)->ToObjectChecked())->value()); 15039 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(2)->ToObjectChecked())->value()); 15040 CHECK_EQ(3, i::Smi::cast(jsobj->GetElement(3)->ToObjectChecked())->value()); 15041 CHECK_EQ(4, i::Smi::cast(jsobj->GetElement(4)->ToObjectChecked())->value()); 15042 CHECK_EQ(6, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value()); 15043 CHECK_EQ(7, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value()); 15044 CHECK_EQ(8, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value()); 15045 15046 result = CompileRun("for (var i = 0; i < 8; i++) {" 15047 " pixels[7] = undefined;" 15048 "}" 15049 "pixels[7];"); 15050 CHECK_EQ(0, result->Int32Value()); 15051 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(7)->ToObjectChecked())->value()); 15052 15053 result = CompileRun("for (var i = 0; i < 8; i++) {" 15054 " pixels[6] = '2.3';" 15055 "}" 15056 "pixels[6];"); 15057 CHECK_EQ(2, result->Int32Value()); 15058 CHECK_EQ(2, i::Smi::cast(jsobj->GetElement(6)->ToObjectChecked())->value()); 15059 15060 result = CompileRun("for (var i = 0; i < 8; i++) {" 15061 " pixels[5] = NaN;" 15062 "}" 15063 "pixels[5];"); 15064 CHECK_EQ(0, result->Int32Value()); 15065 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value()); 15066 15067 result = CompileRun("for (var i = 0; i < 8; i++) {" 15068 " pixels[8] = Infinity;" 15069 "}" 15070 "pixels[8];"); 15071 CHECK_EQ(255, result->Int32Value()); 15072 CHECK_EQ(255, 15073 i::Smi::cast(jsobj->GetElement(8)->ToObjectChecked())->value()); 15074 15075 result = CompileRun("for (var i = 0; i < 8; i++) {" 15076 " pixels[9] = -Infinity;" 15077 "}" 15078 "pixels[9];"); 15079 CHECK_EQ(0, result->Int32Value()); 15080 CHECK_EQ(0, i::Smi::cast(jsobj->GetElement(9)->ToObjectChecked())->value()); 15081 15082 result = CompileRun("pixels[3] = 33;" 15083 "delete pixels[3];" 15084 "pixels[3];"); 15085 CHECK_EQ(33, result->Int32Value()); 15086 15087 result = CompileRun("pixels[0] = 10; pixels[1] = 11;" 15088 "pixels[2] = 12; pixels[3] = 13;" 15089 "pixels.__defineGetter__('2'," 15090 "function() { return 120; });" 15091 "pixels[2];"); 15092 CHECK_EQ(12, result->Int32Value()); 15093 15094 result = CompileRun("var js_array = new Array(40);" 15095 "js_array[0] = 77;" 15096 "js_array;"); 15097 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 15098 15099 result = CompileRun("pixels[1] = 23;" 15100 "pixels.__proto__ = [];" 15101 "js_array.__proto__ = pixels;" 15102 "js_array.concat(pixels);"); 15103 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 15104 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value()); 15105 15106 result = CompileRun("pixels[1] = 23;"); 15107 CHECK_EQ(23, result->Int32Value()); 15108 15109 // Test for index greater than 255. Regression test for: 15110 // http://code.google.com/p/chromium/issues/detail?id=26337. 15111 result = CompileRun("pixels[256] = 255;"); 15112 CHECK_EQ(255, result->Int32Value()); 15113 result = CompileRun("var i = 0;" 15114 "for (var j = 0; j < 8; j++) { i = pixels[256]; }" 15115 "i"); 15116 CHECK_EQ(255, result->Int32Value()); 15117 15118 // Make sure that pixel array ICs recognize when a non-pixel array 15119 // is passed to it. 15120 result = CompileRun("function pa_load(p) {" 15121 " var sum = 0;" 15122 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 15123 " return sum;" 15124 "}" 15125 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15126 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }" 15127 "just_ints = new Object();" 15128 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 15129 "for (var i = 0; i < 10; ++i) {" 15130 " result = pa_load(just_ints);" 15131 "}" 15132 "result"); 15133 CHECK_EQ(32640, result->Int32Value()); 15134 15135 // Make sure that pixel array ICs recognize out-of-bound accesses. 15136 result = CompileRun("function pa_load(p, start) {" 15137 " var sum = 0;" 15138 " for (var j = start; j < 256; j++) { sum += p[j]; }" 15139 " return sum;" 15140 "}" 15141 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15142 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }" 15143 "for (var i = 0; i < 10; ++i) {" 15144 " result = pa_load(pixels,-10);" 15145 "}" 15146 "result"); 15147 CHECK_EQ(0, result->Int32Value()); 15148 15149 // Make sure that generic ICs properly handles a pixel array. 15150 result = CompileRun("function pa_load(p) {" 15151 " var sum = 0;" 15152 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 15153 " return sum;" 15154 "}" 15155 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15156 "just_ints = new Object();" 15157 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 15158 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }" 15159 "for (var i = 0; i < 10; ++i) {" 15160 " result = pa_load(pixels);" 15161 "}" 15162 "result"); 15163 CHECK_EQ(32640, result->Int32Value()); 15164 15165 // Make sure that generic load ICs recognize out-of-bound accesses in 15166 // pixel arrays. 15167 result = CompileRun("function pa_load(p, start) {" 15168 " var sum = 0;" 15169 " for (var j = start; j < 256; j++) { sum += p[j]; }" 15170 " return sum;" 15171 "}" 15172 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15173 "just_ints = new Object();" 15174 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 15175 "for (var i = 0; i < 10; ++i) { pa_load(just_ints,0); }" 15176 "for (var i = 0; i < 10; ++i) { pa_load(pixels,0); }" 15177 "for (var i = 0; i < 10; ++i) {" 15178 " result = pa_load(pixels,-10);" 15179 "}" 15180 "result"); 15181 CHECK_EQ(0, result->Int32Value()); 15182 15183 // Make sure that generic ICs properly handles other types than pixel 15184 // arrays (that the inlined fast pixel array test leaves the right information 15185 // in the right registers). 15186 result = CompileRun("function pa_load(p) {" 15187 " var sum = 0;" 15188 " for (var j = 0; j < 256; j++) { sum += p[j]; }" 15189 " return sum;" 15190 "}" 15191 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15192 "just_ints = new Object();" 15193 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 15194 "for (var i = 0; i < 10; ++i) { pa_load(just_ints); }" 15195 "for (var i = 0; i < 10; ++i) { pa_load(pixels); }" 15196 "sparse_array = new Object();" 15197 "for (var i = 0; i < 256; ++i) { sparse_array[i] = i; }" 15198 "sparse_array[1000000] = 3;" 15199 "for (var i = 0; i < 10; ++i) {" 15200 " result = pa_load(sparse_array);" 15201 "}" 15202 "result"); 15203 CHECK_EQ(32640, result->Int32Value()); 15204 15205 // Make sure that pixel array store ICs clamp values correctly. 15206 result = CompileRun("function pa_store(p) {" 15207 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }" 15208 "}" 15209 "pa_store(pixels);" 15210 "var sum = 0;" 15211 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 15212 "sum"); 15213 CHECK_EQ(48896, result->Int32Value()); 15214 15215 // Make sure that pixel array stores correctly handle accesses outside 15216 // of the pixel array.. 15217 result = CompileRun("function pa_store(p,start) {" 15218 " for (var j = 0; j < 256; j++) {" 15219 " p[j+start] = j * 2;" 15220 " }" 15221 "}" 15222 "pa_store(pixels,0);" 15223 "pa_store(pixels,-128);" 15224 "var sum = 0;" 15225 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 15226 "sum"); 15227 CHECK_EQ(65280, result->Int32Value()); 15228 15229 // Make sure that the generic store stub correctly handle accesses outside 15230 // of the pixel array.. 15231 result = CompileRun("function pa_store(p,start) {" 15232 " for (var j = 0; j < 256; j++) {" 15233 " p[j+start] = j * 2;" 15234 " }" 15235 "}" 15236 "pa_store(pixels,0);" 15237 "just_ints = new Object();" 15238 "for (var i = 0; i < 256; ++i) { just_ints[i] = i; }" 15239 "pa_store(just_ints, 0);" 15240 "pa_store(pixels,-128);" 15241 "var sum = 0;" 15242 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 15243 "sum"); 15244 CHECK_EQ(65280, result->Int32Value()); 15245 15246 // Make sure that the generic keyed store stub clamps pixel array values 15247 // correctly. 15248 result = CompileRun("function pa_store(p) {" 15249 " for (var j = 0; j < 256; j++) { p[j] = j * 2; }" 15250 "}" 15251 "pa_store(pixels);" 15252 "just_ints = new Object();" 15253 "pa_store(just_ints);" 15254 "pa_store(pixels);" 15255 "var sum = 0;" 15256 "for (var j = 0; j < 256; j++) { sum += pixels[j]; }" 15257 "sum"); 15258 CHECK_EQ(48896, result->Int32Value()); 15259 15260 // Make sure that pixel array loads are optimized by crankshaft. 15261 result = CompileRun("function pa_load(p) {" 15262 " var sum = 0;" 15263 " for (var i=0; i<256; ++i) {" 15264 " sum += p[i];" 15265 " }" 15266 " return sum; " 15267 "}" 15268 "for (var i = 0; i < 256; ++i) { pixels[i] = i; }" 15269 "for (var i = 0; i < 5000; ++i) {" 15270 " result = pa_load(pixels);" 15271 "}" 15272 "result"); 15273 CHECK_EQ(32640, result->Int32Value()); 15274 15275 // Make sure that pixel array stores are optimized by crankshaft. 15276 result = CompileRun("function pa_init(p) {" 15277 "for (var i = 0; i < 256; ++i) { p[i] = i; }" 15278 "}" 15279 "function pa_load(p) {" 15280 " var sum = 0;" 15281 " for (var i=0; i<256; ++i) {" 15282 " sum += p[i];" 15283 " }" 15284 " return sum; " 15285 "}" 15286 "for (var i = 0; i < 5000; ++i) {" 15287 " pa_init(pixels);" 15288 "}" 15289 "result = pa_load(pixels);" 15290 "result"); 15291 CHECK_EQ(32640, result->Int32Value()); 15292 15293 free(pixel_data); 15294 } 15295 15296 15297 THREADED_TEST(PixelArrayInfo) { 15298 LocalContext context; 15299 v8::HandleScope scope(context->GetIsolate()); 15300 for (int size = 0; size < 100; size += 10) { 15301 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(size)); 15302 v8::Handle<v8::Object> obj = v8::Object::New(); 15303 obj->SetIndexedPropertiesToPixelData(pixel_data, size); 15304 CHECK(obj->HasIndexedPropertiesInPixelData()); 15305 CHECK_EQ(pixel_data, obj->GetIndexedPropertiesPixelData()); 15306 CHECK_EQ(size, obj->GetIndexedPropertiesPixelDataLength()); 15307 free(pixel_data); 15308 } 15309 } 15310 15311 15312 static void NotHandledIndexedPropertyGetter( 15313 uint32_t index, 15314 const v8::PropertyCallbackInfo<v8::Value>& info) { 15315 ApiTestFuzzer::Fuzz(); 15316 } 15317 15318 15319 static void NotHandledIndexedPropertySetter( 15320 uint32_t index, 15321 Local<Value> value, 15322 const v8::PropertyCallbackInfo<v8::Value>& info) { 15323 ApiTestFuzzer::Fuzz(); 15324 } 15325 15326 15327 THREADED_TEST(PixelArrayWithInterceptor) { 15328 LocalContext context; 15329 i::Factory* factory = i::Isolate::Current()->factory(); 15330 v8::HandleScope scope(context->GetIsolate()); 15331 const int kElementCount = 260; 15332 uint8_t* pixel_data = reinterpret_cast<uint8_t*>(malloc(kElementCount)); 15333 i::Handle<i::ExternalPixelArray> pixels = 15334 i::Handle<i::ExternalPixelArray>::cast( 15335 factory->NewExternalArray(kElementCount, 15336 v8::kExternalPixelArray, 15337 pixel_data)); 15338 for (int i = 0; i < kElementCount; i++) { 15339 pixels->set(i, i % 256); 15340 } 15341 v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(); 15342 templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter, 15343 NotHandledIndexedPropertySetter); 15344 v8::Handle<v8::Object> obj = templ->NewInstance(); 15345 obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount); 15346 context->Global()->Set(v8_str("pixels"), obj); 15347 v8::Handle<v8::Value> result = CompileRun("pixels[1]"); 15348 CHECK_EQ(1, result->Int32Value()); 15349 result = CompileRun("var sum = 0;" 15350 "for (var i = 0; i < 8; i++) {" 15351 " sum += pixels[i] = pixels[i] = -i;" 15352 "}" 15353 "sum;"); 15354 CHECK_EQ(-28, result->Int32Value()); 15355 result = CompileRun("pixels.hasOwnProperty('1')"); 15356 CHECK(result->BooleanValue()); 15357 free(pixel_data); 15358 } 15359 15360 15361 static int ExternalArrayElementSize(v8::ExternalArrayType array_type) { 15362 switch (array_type) { 15363 case v8::kExternalByteArray: 15364 case v8::kExternalUnsignedByteArray: 15365 case v8::kExternalPixelArray: 15366 return 1; 15367 break; 15368 case v8::kExternalShortArray: 15369 case v8::kExternalUnsignedShortArray: 15370 return 2; 15371 break; 15372 case v8::kExternalIntArray: 15373 case v8::kExternalUnsignedIntArray: 15374 case v8::kExternalFloatArray: 15375 return 4; 15376 break; 15377 case v8::kExternalDoubleArray: 15378 return 8; 15379 break; 15380 default: 15381 UNREACHABLE(); 15382 return -1; 15383 } 15384 UNREACHABLE(); 15385 return -1; 15386 } 15387 15388 15389 template <class ExternalArrayClass, class ElementType> 15390 static void ObjectWithExternalArrayTestHelper( 15391 Handle<Context> context, 15392 v8::Handle<Object> obj, 15393 int element_count, 15394 v8::ExternalArrayType array_type, 15395 int64_t low, int64_t high) { 15396 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 15397 obj->Set(v8_str("field"), v8::Int32::New(1503)); 15398 context->Global()->Set(v8_str("ext_array"), obj); 15399 v8::Handle<v8::Value> result = CompileRun("ext_array.field"); 15400 CHECK_EQ(1503, result->Int32Value()); 15401 result = CompileRun("ext_array[1]"); 15402 CHECK_EQ(1, result->Int32Value()); 15403 15404 // Check pass through of assigned smis 15405 result = CompileRun("var sum = 0;" 15406 "for (var i = 0; i < 8; i++) {" 15407 " sum += ext_array[i] = ext_array[i] = -i;" 15408 "}" 15409 "sum;"); 15410 CHECK_EQ(-28, result->Int32Value()); 15411 15412 // Check assigned smis 15413 result = CompileRun("for (var i = 0; i < 8; i++) {" 15414 " ext_array[i] = i;" 15415 "}" 15416 "var sum = 0;" 15417 "for (var i = 0; i < 8; i++) {" 15418 " sum += ext_array[i];" 15419 "}" 15420 "sum;"); 15421 CHECK_EQ(28, result->Int32Value()); 15422 15423 // Check assigned smis in reverse order 15424 result = CompileRun("for (var i = 8; --i >= 0; ) {" 15425 " ext_array[i] = i;" 15426 "}" 15427 "var sum = 0;" 15428 "for (var i = 0; i < 8; i++) {" 15429 " sum += ext_array[i];" 15430 "}" 15431 "sum;"); 15432 CHECK_EQ(28, result->Int32Value()); 15433 15434 // Check pass through of assigned HeapNumbers 15435 result = CompileRun("var sum = 0;" 15436 "for (var i = 0; i < 16; i+=2) {" 15437 " sum += ext_array[i] = ext_array[i] = (-i * 0.5);" 15438 "}" 15439 "sum;"); 15440 CHECK_EQ(-28, result->Int32Value()); 15441 15442 // Check assigned HeapNumbers 15443 result = CompileRun("for (var i = 0; i < 16; i+=2) {" 15444 " ext_array[i] = (i * 0.5);" 15445 "}" 15446 "var sum = 0;" 15447 "for (var i = 0; i < 16; i+=2) {" 15448 " sum += ext_array[i];" 15449 "}" 15450 "sum;"); 15451 CHECK_EQ(28, result->Int32Value()); 15452 15453 // Check assigned HeapNumbers in reverse order 15454 result = CompileRun("for (var i = 14; i >= 0; i-=2) {" 15455 " ext_array[i] = (i * 0.5);" 15456 "}" 15457 "var sum = 0;" 15458 "for (var i = 0; i < 16; i+=2) {" 15459 " sum += ext_array[i];" 15460 "}" 15461 "sum;"); 15462 CHECK_EQ(28, result->Int32Value()); 15463 15464 i::ScopedVector<char> test_buf(1024); 15465 15466 // Check legal boundary conditions. 15467 // The repeated loads and stores ensure the ICs are exercised. 15468 const char* boundary_program = 15469 "var res = 0;" 15470 "for (var i = 0; i < 16; i++) {" 15471 " ext_array[i] = %lld;" 15472 " if (i > 8) {" 15473 " res = ext_array[i];" 15474 " }" 15475 "}" 15476 "res;"; 15477 i::OS::SNPrintF(test_buf, 15478 boundary_program, 15479 low); 15480 result = CompileRun(test_buf.start()); 15481 CHECK_EQ(low, result->IntegerValue()); 15482 15483 i::OS::SNPrintF(test_buf, 15484 boundary_program, 15485 high); 15486 result = CompileRun(test_buf.start()); 15487 CHECK_EQ(high, result->IntegerValue()); 15488 15489 // Check misprediction of type in IC. 15490 result = CompileRun("var tmp_array = ext_array;" 15491 "var sum = 0;" 15492 "for (var i = 0; i < 8; i++) {" 15493 " tmp_array[i] = i;" 15494 " sum += tmp_array[i];" 15495 " if (i == 4) {" 15496 " tmp_array = {};" 15497 " }" 15498 "}" 15499 "sum;"); 15500 // Force GC to trigger verification. 15501 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 15502 CHECK_EQ(28, result->Int32Value()); 15503 15504 // Make sure out-of-range loads do not throw. 15505 i::OS::SNPrintF(test_buf, 15506 "var caught_exception = false;" 15507 "try {" 15508 " ext_array[%d];" 15509 "} catch (e) {" 15510 " caught_exception = true;" 15511 "}" 15512 "caught_exception;", 15513 element_count); 15514 result = CompileRun(test_buf.start()); 15515 CHECK_EQ(false, result->BooleanValue()); 15516 15517 // Make sure out-of-range stores do not throw. 15518 i::OS::SNPrintF(test_buf, 15519 "var caught_exception = false;" 15520 "try {" 15521 " ext_array[%d] = 1;" 15522 "} catch (e) {" 15523 " caught_exception = true;" 15524 "}" 15525 "caught_exception;", 15526 element_count); 15527 result = CompileRun(test_buf.start()); 15528 CHECK_EQ(false, result->BooleanValue()); 15529 15530 // Check other boundary conditions, values and operations. 15531 result = CompileRun("for (var i = 0; i < 8; i++) {" 15532 " ext_array[7] = undefined;" 15533 "}" 15534 "ext_array[7];"); 15535 CHECK_EQ(0, result->Int32Value()); 15536 if (array_type == v8::kExternalDoubleArray || 15537 array_type == v8::kExternalFloatArray) { 15538 CHECK_EQ( 15539 static_cast<int>(i::OS::nan_value()), 15540 static_cast<int>(jsobj->GetElement(7)->ToObjectChecked()->Number())); 15541 } else { 15542 CHECK_EQ(0, static_cast<int>( 15543 jsobj->GetElement(7)->ToObjectChecked()->Number())); 15544 } 15545 15546 result = CompileRun("for (var i = 0; i < 8; i++) {" 15547 " ext_array[6] = '2.3';" 15548 "}" 15549 "ext_array[6];"); 15550 CHECK_EQ(2, result->Int32Value()); 15551 CHECK_EQ( 15552 2, static_cast<int>(jsobj->GetElement(6)->ToObjectChecked()->Number())); 15553 15554 if (array_type != v8::kExternalFloatArray && 15555 array_type != v8::kExternalDoubleArray) { 15556 // Though the specification doesn't state it, be explicit about 15557 // converting NaNs and +/-Infinity to zero. 15558 result = CompileRun("for (var i = 0; i < 8; i++) {" 15559 " ext_array[i] = 5;" 15560 "}" 15561 "for (var i = 0; i < 8; i++) {" 15562 " ext_array[i] = NaN;" 15563 "}" 15564 "ext_array[5];"); 15565 CHECK_EQ(0, result->Int32Value()); 15566 CHECK_EQ(0, 15567 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value()); 15568 15569 result = CompileRun("for (var i = 0; i < 8; i++) {" 15570 " ext_array[i] = 5;" 15571 "}" 15572 "for (var i = 0; i < 8; i++) {" 15573 " ext_array[i] = Infinity;" 15574 "}" 15575 "ext_array[5];"); 15576 int expected_value = 15577 (array_type == v8::kExternalPixelArray) ? 255 : 0; 15578 CHECK_EQ(expected_value, result->Int32Value()); 15579 CHECK_EQ(expected_value, 15580 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value()); 15581 15582 result = CompileRun("for (var i = 0; i < 8; i++) {" 15583 " ext_array[i] = 5;" 15584 "}" 15585 "for (var i = 0; i < 8; i++) {" 15586 " ext_array[i] = -Infinity;" 15587 "}" 15588 "ext_array[5];"); 15589 CHECK_EQ(0, result->Int32Value()); 15590 CHECK_EQ(0, 15591 i::Smi::cast(jsobj->GetElement(5)->ToObjectChecked())->value()); 15592 15593 // Check truncation behavior of integral arrays. 15594 const char* unsigned_data = 15595 "var source_data = [0.6, 10.6];" 15596 "var expected_results = [0, 10];"; 15597 const char* signed_data = 15598 "var source_data = [0.6, 10.6, -0.6, -10.6];" 15599 "var expected_results = [0, 10, 0, -10];"; 15600 const char* pixel_data = 15601 "var source_data = [0.6, 10.6];" 15602 "var expected_results = [1, 11];"; 15603 bool is_unsigned = 15604 (array_type == v8::kExternalUnsignedByteArray || 15605 array_type == v8::kExternalUnsignedShortArray || 15606 array_type == v8::kExternalUnsignedIntArray); 15607 bool is_pixel_data = array_type == v8::kExternalPixelArray; 15608 15609 i::OS::SNPrintF(test_buf, 15610 "%s" 15611 "var all_passed = true;" 15612 "for (var i = 0; i < source_data.length; i++) {" 15613 " for (var j = 0; j < 8; j++) {" 15614 " ext_array[j] = source_data[i];" 15615 " }" 15616 " all_passed = all_passed &&" 15617 " (ext_array[5] == expected_results[i]);" 15618 "}" 15619 "all_passed;", 15620 (is_unsigned ? 15621 unsigned_data : 15622 (is_pixel_data ? pixel_data : signed_data))); 15623 result = CompileRun(test_buf.start()); 15624 CHECK_EQ(true, result->BooleanValue()); 15625 } 15626 15627 i::Handle<ExternalArrayClass> array( 15628 ExternalArrayClass::cast(jsobj->elements())); 15629 for (int i = 0; i < element_count; i++) { 15630 array->set(i, static_cast<ElementType>(i)); 15631 } 15632 15633 // Test complex assignments 15634 result = CompileRun("function ee_op_test_complex_func(sum) {" 15635 " for (var i = 0; i < 40; ++i) {" 15636 " sum += (ext_array[i] += 1);" 15637 " sum += (ext_array[i] -= 1);" 15638 " } " 15639 " return sum;" 15640 "}" 15641 "sum=0;" 15642 "for (var i=0;i<10000;++i) {" 15643 " sum=ee_op_test_complex_func(sum);" 15644 "}" 15645 "sum;"); 15646 CHECK_EQ(16000000, result->Int32Value()); 15647 15648 // Test count operations 15649 result = CompileRun("function ee_op_test_count_func(sum) {" 15650 " for (var i = 0; i < 40; ++i) {" 15651 " sum += (++ext_array[i]);" 15652 " sum += (--ext_array[i]);" 15653 " } " 15654 " return sum;" 15655 "}" 15656 "sum=0;" 15657 "for (var i=0;i<10000;++i) {" 15658 " sum=ee_op_test_count_func(sum);" 15659 "}" 15660 "sum;"); 15661 CHECK_EQ(16000000, result->Int32Value()); 15662 15663 result = CompileRun("ext_array[3] = 33;" 15664 "delete ext_array[3];" 15665 "ext_array[3];"); 15666 CHECK_EQ(33, result->Int32Value()); 15667 15668 result = CompileRun("ext_array[0] = 10; ext_array[1] = 11;" 15669 "ext_array[2] = 12; ext_array[3] = 13;" 15670 "ext_array.__defineGetter__('2'," 15671 "function() { return 120; });" 15672 "ext_array[2];"); 15673 CHECK_EQ(12, result->Int32Value()); 15674 15675 result = CompileRun("var js_array = new Array(40);" 15676 "js_array[0] = 77;" 15677 "js_array;"); 15678 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 15679 15680 result = CompileRun("ext_array[1] = 23;" 15681 "ext_array.__proto__ = [];" 15682 "js_array.__proto__ = ext_array;" 15683 "js_array.concat(ext_array);"); 15684 CHECK_EQ(77, v8::Object::Cast(*result)->Get(v8_str("0"))->Int32Value()); 15685 CHECK_EQ(23, v8::Object::Cast(*result)->Get(v8_str("1"))->Int32Value()); 15686 15687 result = CompileRun("ext_array[1] = 23;"); 15688 CHECK_EQ(23, result->Int32Value()); 15689 } 15690 15691 15692 template <class ExternalArrayClass, class ElementType> 15693 static void ExternalArrayTestHelper(v8::ExternalArrayType array_type, 15694 int64_t low, 15695 int64_t high) { 15696 LocalContext context; 15697 i::Factory* factory = i::Isolate::Current()->factory(); 15698 v8::HandleScope scope(context->GetIsolate()); 15699 const int kElementCount = 40; 15700 int element_size = ExternalArrayElementSize(array_type); 15701 ElementType* array_data = 15702 static_cast<ElementType*>(malloc(kElementCount * element_size)); 15703 i::Handle<ExternalArrayClass> array = 15704 i::Handle<ExternalArrayClass>::cast( 15705 factory->NewExternalArray(kElementCount, array_type, array_data)); 15706 // Force GC to trigger verification. 15707 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 15708 for (int i = 0; i < kElementCount; i++) { 15709 array->set(i, static_cast<ElementType>(i)); 15710 } 15711 // Force GC to trigger verification. 15712 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 15713 for (int i = 0; i < kElementCount; i++) { 15714 CHECK_EQ(static_cast<int64_t>(i), 15715 static_cast<int64_t>(array->get_scalar(i))); 15716 CHECK_EQ(static_cast<int64_t>(i), static_cast<int64_t>(array_data[i])); 15717 } 15718 15719 v8::Handle<v8::Object> obj = v8::Object::New(); 15720 i::Handle<i::JSObject> jsobj = v8::Utils::OpenHandle(*obj); 15721 // Set the elements to be the external array. 15722 obj->SetIndexedPropertiesToExternalArrayData(array_data, 15723 array_type, 15724 kElementCount); 15725 CHECK_EQ( 15726 1, static_cast<int>(jsobj->GetElement(1)->ToObjectChecked()->Number())); 15727 15728 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>( 15729 context.local(), obj, kElementCount, array_type, low, high); 15730 15731 v8::Handle<v8::Value> result; 15732 15733 // Test more complex manipulations which cause eax to contain values 15734 // that won't be completely overwritten by loads from the arrays. 15735 // This catches bugs in the instructions used for the KeyedLoadIC 15736 // for byte and word types. 15737 { 15738 const int kXSize = 300; 15739 const int kYSize = 300; 15740 const int kLargeElementCount = kXSize * kYSize * 4; 15741 ElementType* large_array_data = 15742 static_cast<ElementType*>(malloc(kLargeElementCount * element_size)); 15743 v8::Handle<v8::Object> large_obj = v8::Object::New(); 15744 // Set the elements to be the external array. 15745 large_obj->SetIndexedPropertiesToExternalArrayData(large_array_data, 15746 array_type, 15747 kLargeElementCount); 15748 context->Global()->Set(v8_str("large_array"), large_obj); 15749 // Initialize contents of a few rows. 15750 for (int x = 0; x < 300; x++) { 15751 int row = 0; 15752 int offset = row * 300 * 4; 15753 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 15754 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 15755 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 15756 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 15757 row = 150; 15758 offset = row * 300 * 4; 15759 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 15760 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 15761 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 15762 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 15763 row = 298; 15764 offset = row * 300 * 4; 15765 large_array_data[offset + 4 * x + 0] = (ElementType) 127; 15766 large_array_data[offset + 4 * x + 1] = (ElementType) 0; 15767 large_array_data[offset + 4 * x + 2] = (ElementType) 0; 15768 large_array_data[offset + 4 * x + 3] = (ElementType) 127; 15769 } 15770 // The goal of the code below is to make "offset" large enough 15771 // that the computation of the index (which goes into eax) has 15772 // high bits set which will not be overwritten by a byte or short 15773 // load. 15774 result = CompileRun("var failed = false;" 15775 "var offset = 0;" 15776 "for (var i = 0; i < 300; i++) {" 15777 " if (large_array[4 * i] != 127 ||" 15778 " large_array[4 * i + 1] != 0 ||" 15779 " large_array[4 * i + 2] != 0 ||" 15780 " large_array[4 * i + 3] != 127) {" 15781 " failed = true;" 15782 " }" 15783 "}" 15784 "offset = 150 * 300 * 4;" 15785 "for (var i = 0; i < 300; i++) {" 15786 " if (large_array[offset + 4 * i] != 127 ||" 15787 " large_array[offset + 4 * i + 1] != 0 ||" 15788 " large_array[offset + 4 * i + 2] != 0 ||" 15789 " large_array[offset + 4 * i + 3] != 127) {" 15790 " failed = true;" 15791 " }" 15792 "}" 15793 "offset = 298 * 300 * 4;" 15794 "for (var i = 0; i < 300; i++) {" 15795 " if (large_array[offset + 4 * i] != 127 ||" 15796 " large_array[offset + 4 * i + 1] != 0 ||" 15797 " large_array[offset + 4 * i + 2] != 0 ||" 15798 " large_array[offset + 4 * i + 3] != 127) {" 15799 " failed = true;" 15800 " }" 15801 "}" 15802 "!failed;"); 15803 CHECK_EQ(true, result->BooleanValue()); 15804 free(large_array_data); 15805 } 15806 15807 // The "" property descriptor is overloaded to store information about 15808 // the external array. Ensure that setting and accessing the "" property 15809 // works (it should overwrite the information cached about the external 15810 // array in the DescriptorArray) in various situations. 15811 result = CompileRun("ext_array[''] = 23; ext_array['']"); 15812 CHECK_EQ(23, result->Int32Value()); 15813 15814 // Property "" set after the external array is associated with the object. 15815 { 15816 v8::Handle<v8::Object> obj2 = v8::Object::New(); 15817 obj2->Set(v8_str("ee_test_field"), v8::Int32::New(256)); 15818 obj2->Set(v8_str(""), v8::Int32::New(1503)); 15819 // Set the elements to be the external array. 15820 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 15821 array_type, 15822 kElementCount); 15823 context->Global()->Set(v8_str("ext_array"), obj2); 15824 result = CompileRun("ext_array['']"); 15825 CHECK_EQ(1503, result->Int32Value()); 15826 } 15827 15828 // Property "" set after the external array is associated with the object. 15829 { 15830 v8::Handle<v8::Object> obj2 = v8::Object::New(); 15831 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256)); 15832 // Set the elements to be the external array. 15833 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 15834 array_type, 15835 kElementCount); 15836 obj2->Set(v8_str(""), v8::Int32::New(1503)); 15837 context->Global()->Set(v8_str("ext_array"), obj2); 15838 result = CompileRun("ext_array['']"); 15839 CHECK_EQ(1503, result->Int32Value()); 15840 } 15841 15842 // Should reuse the map from previous test. 15843 { 15844 v8::Handle<v8::Object> obj2 = v8::Object::New(); 15845 obj2->Set(v8_str("ee_test_field_2"), v8::Int32::New(256)); 15846 // Set the elements to be the external array. Should re-use the map 15847 // from previous test. 15848 obj2->SetIndexedPropertiesToExternalArrayData(array_data, 15849 array_type, 15850 kElementCount); 15851 context->Global()->Set(v8_str("ext_array"), obj2); 15852 result = CompileRun("ext_array['']"); 15853 } 15854 15855 // Property "" is a constant function that shouldn't not be interfered with 15856 // when an external array is set. 15857 { 15858 v8::Handle<v8::Object> obj2 = v8::Object::New(); 15859 // Start 15860 obj2->Set(v8_str("ee_test_field3"), v8::Int32::New(256)); 15861 15862 // Add a constant function to an object. 15863 context->Global()->Set(v8_str("ext_array"), obj2); 15864 result = CompileRun("ext_array[''] = function() {return 1503;};" 15865 "ext_array['']();"); 15866 15867 // Add an external array transition to the same map that 15868 // has the constant transition. 15869 v8::Handle<v8::Object> obj3 = v8::Object::New(); 15870 obj3->Set(v8_str("ee_test_field3"), v8::Int32::New(256)); 15871 obj3->SetIndexedPropertiesToExternalArrayData(array_data, 15872 array_type, 15873 kElementCount); 15874 context->Global()->Set(v8_str("ext_array"), obj3); 15875 } 15876 15877 // If a external array transition is in the map, it should get clobbered 15878 // by a constant function. 15879 { 15880 // Add an external array transition. 15881 v8::Handle<v8::Object> obj3 = v8::Object::New(); 15882 obj3->Set(v8_str("ee_test_field4"), v8::Int32::New(256)); 15883 obj3->SetIndexedPropertiesToExternalArrayData(array_data, 15884 array_type, 15885 kElementCount); 15886 15887 // Add a constant function to the same map that just got an external array 15888 // transition. 15889 v8::Handle<v8::Object> obj2 = v8::Object::New(); 15890 obj2->Set(v8_str("ee_test_field4"), v8::Int32::New(256)); 15891 context->Global()->Set(v8_str("ext_array"), obj2); 15892 result = CompileRun("ext_array[''] = function() {return 1503;};" 15893 "ext_array['']();"); 15894 } 15895 15896 free(array_data); 15897 } 15898 15899 15900 THREADED_TEST(ExternalByteArray) { 15901 ExternalArrayTestHelper<i::ExternalByteArray, int8_t>( 15902 v8::kExternalByteArray, 15903 -128, 15904 127); 15905 } 15906 15907 15908 THREADED_TEST(ExternalUnsignedByteArray) { 15909 ExternalArrayTestHelper<i::ExternalUnsignedByteArray, uint8_t>( 15910 v8::kExternalUnsignedByteArray, 15911 0, 15912 255); 15913 } 15914 15915 15916 THREADED_TEST(ExternalPixelArray) { 15917 ExternalArrayTestHelper<i::ExternalPixelArray, uint8_t>( 15918 v8::kExternalPixelArray, 15919 0, 15920 255); 15921 } 15922 15923 15924 THREADED_TEST(ExternalShortArray) { 15925 ExternalArrayTestHelper<i::ExternalShortArray, int16_t>( 15926 v8::kExternalShortArray, 15927 -32768, 15928 32767); 15929 } 15930 15931 15932 THREADED_TEST(ExternalUnsignedShortArray) { 15933 ExternalArrayTestHelper<i::ExternalUnsignedShortArray, uint16_t>( 15934 v8::kExternalUnsignedShortArray, 15935 0, 15936 65535); 15937 } 15938 15939 15940 THREADED_TEST(ExternalIntArray) { 15941 ExternalArrayTestHelper<i::ExternalIntArray, int32_t>( 15942 v8::kExternalIntArray, 15943 INT_MIN, // -2147483648 15944 INT_MAX); // 2147483647 15945 } 15946 15947 15948 THREADED_TEST(ExternalUnsignedIntArray) { 15949 ExternalArrayTestHelper<i::ExternalUnsignedIntArray, uint32_t>( 15950 v8::kExternalUnsignedIntArray, 15951 0, 15952 UINT_MAX); // 4294967295 15953 } 15954 15955 15956 THREADED_TEST(ExternalFloatArray) { 15957 ExternalArrayTestHelper<i::ExternalFloatArray, float>( 15958 v8::kExternalFloatArray, 15959 -500, 15960 500); 15961 } 15962 15963 15964 THREADED_TEST(ExternalDoubleArray) { 15965 ExternalArrayTestHelper<i::ExternalDoubleArray, double>( 15966 v8::kExternalDoubleArray, 15967 -500, 15968 500); 15969 } 15970 15971 15972 THREADED_TEST(ExternalArrays) { 15973 TestExternalByteArray(); 15974 TestExternalUnsignedByteArray(); 15975 TestExternalShortArray(); 15976 TestExternalUnsignedShortArray(); 15977 TestExternalIntArray(); 15978 TestExternalUnsignedIntArray(); 15979 TestExternalFloatArray(); 15980 } 15981 15982 15983 void ExternalArrayInfoTestHelper(v8::ExternalArrayType array_type) { 15984 LocalContext context; 15985 v8::HandleScope scope(context->GetIsolate()); 15986 for (int size = 0; size < 100; size += 10) { 15987 int element_size = ExternalArrayElementSize(array_type); 15988 void* external_data = malloc(size * element_size); 15989 v8::Handle<v8::Object> obj = v8::Object::New(); 15990 obj->SetIndexedPropertiesToExternalArrayData( 15991 external_data, array_type, size); 15992 CHECK(obj->HasIndexedPropertiesInExternalArrayData()); 15993 CHECK_EQ(external_data, obj->GetIndexedPropertiesExternalArrayData()); 15994 CHECK_EQ(array_type, obj->GetIndexedPropertiesExternalArrayDataType()); 15995 CHECK_EQ(size, obj->GetIndexedPropertiesExternalArrayDataLength()); 15996 free(external_data); 15997 } 15998 } 15999 16000 16001 THREADED_TEST(ExternalArrayInfo) { 16002 ExternalArrayInfoTestHelper(v8::kExternalByteArray); 16003 ExternalArrayInfoTestHelper(v8::kExternalUnsignedByteArray); 16004 ExternalArrayInfoTestHelper(v8::kExternalShortArray); 16005 ExternalArrayInfoTestHelper(v8::kExternalUnsignedShortArray); 16006 ExternalArrayInfoTestHelper(v8::kExternalIntArray); 16007 ExternalArrayInfoTestHelper(v8::kExternalUnsignedIntArray); 16008 ExternalArrayInfoTestHelper(v8::kExternalFloatArray); 16009 ExternalArrayInfoTestHelper(v8::kExternalDoubleArray); 16010 ExternalArrayInfoTestHelper(v8::kExternalPixelArray); 16011 } 16012 16013 16014 void ExternalArrayLimitTestHelper(v8::ExternalArrayType array_type, int size) { 16015 v8::Handle<v8::Object> obj = v8::Object::New(); 16016 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 16017 last_location = last_message = NULL; 16018 obj->SetIndexedPropertiesToExternalArrayData(NULL, array_type, size); 16019 CHECK(!obj->HasIndexedPropertiesInExternalArrayData()); 16020 CHECK_NE(NULL, last_location); 16021 CHECK_NE(NULL, last_message); 16022 } 16023 16024 16025 TEST(ExternalArrayLimits) { 16026 LocalContext context; 16027 v8::HandleScope scope(context->GetIsolate()); 16028 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0x40000000); 16029 ExternalArrayLimitTestHelper(v8::kExternalByteArray, 0xffffffff); 16030 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0x40000000); 16031 ExternalArrayLimitTestHelper(v8::kExternalUnsignedByteArray, 0xffffffff); 16032 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0x40000000); 16033 ExternalArrayLimitTestHelper(v8::kExternalShortArray, 0xffffffff); 16034 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0x40000000); 16035 ExternalArrayLimitTestHelper(v8::kExternalUnsignedShortArray, 0xffffffff); 16036 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0x40000000); 16037 ExternalArrayLimitTestHelper(v8::kExternalIntArray, 0xffffffff); 16038 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0x40000000); 16039 ExternalArrayLimitTestHelper(v8::kExternalUnsignedIntArray, 0xffffffff); 16040 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0x40000000); 16041 ExternalArrayLimitTestHelper(v8::kExternalFloatArray, 0xffffffff); 16042 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0x40000000); 16043 ExternalArrayLimitTestHelper(v8::kExternalDoubleArray, 0xffffffff); 16044 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0x40000000); 16045 ExternalArrayLimitTestHelper(v8::kExternalPixelArray, 0xffffffff); 16046 } 16047 16048 16049 template <typename ElementType, typename TypedArray, 16050 class ExternalArrayClass> 16051 void TypedArrayTestHelper(v8::ExternalArrayType array_type, 16052 int64_t low, int64_t high) { 16053 const int kElementCount = 50; 16054 16055 i::ScopedVector<ElementType> backing_store(kElementCount+2); 16056 16057 LocalContext env; 16058 v8::Isolate* isolate = env->GetIsolate(); 16059 v8::HandleScope handle_scope(isolate); 16060 16061 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New( 16062 backing_store.start(), (kElementCount+2)*sizeof(ElementType)); 16063 Local<TypedArray> ta = 16064 TypedArray::New(ab, 2*sizeof(ElementType), kElementCount); 16065 CheckInternalFieldsAreZero<v8::ArrayBufferView>(ta); 16066 CHECK_EQ(kElementCount, static_cast<int>(ta->Length())); 16067 CHECK_EQ(2*sizeof(ElementType), static_cast<int>(ta->ByteOffset())); 16068 CHECK_EQ(kElementCount*sizeof(ElementType), 16069 static_cast<int>(ta->ByteLength())); 16070 CHECK_EQ(ab, ta->Buffer()); 16071 16072 ElementType* data = backing_store.start() + 2; 16073 for (int i = 0; i < kElementCount; i++) { 16074 data[i] = static_cast<ElementType>(i); 16075 } 16076 16077 ObjectWithExternalArrayTestHelper<ExternalArrayClass, ElementType>( 16078 env.local(), ta, kElementCount, array_type, low, high); 16079 } 16080 16081 16082 THREADED_TEST(Uint8Array) { 16083 TypedArrayTestHelper<uint8_t, v8::Uint8Array, i::ExternalUnsignedByteArray>( 16084 v8::kExternalUnsignedByteArray, 0, 0xFF); 16085 } 16086 16087 16088 THREADED_TEST(Int8Array) { 16089 TypedArrayTestHelper<int8_t, v8::Int8Array, i::ExternalByteArray>( 16090 v8::kExternalByteArray, -0x80, 0x7F); 16091 } 16092 16093 16094 THREADED_TEST(Uint16Array) { 16095 TypedArrayTestHelper<uint16_t, 16096 v8::Uint16Array, 16097 i::ExternalUnsignedShortArray>( 16098 v8::kExternalUnsignedShortArray, 0, 0xFFFF); 16099 } 16100 16101 16102 THREADED_TEST(Int16Array) { 16103 TypedArrayTestHelper<int16_t, v8::Int16Array, i::ExternalShortArray>( 16104 v8::kExternalShortArray, -0x8000, 0x7FFF); 16105 } 16106 16107 16108 THREADED_TEST(Uint32Array) { 16109 TypedArrayTestHelper<uint32_t, v8::Uint32Array, i::ExternalUnsignedIntArray>( 16110 v8::kExternalUnsignedIntArray, 0, UINT_MAX); 16111 } 16112 16113 16114 THREADED_TEST(Int32Array) { 16115 TypedArrayTestHelper<int32_t, v8::Int32Array, i::ExternalIntArray>( 16116 v8::kExternalIntArray, INT_MIN, INT_MAX); 16117 } 16118 16119 16120 THREADED_TEST(Float32Array) { 16121 TypedArrayTestHelper<float, v8::Float32Array, i::ExternalFloatArray>( 16122 v8::kExternalFloatArray, -500, 500); 16123 } 16124 16125 16126 THREADED_TEST(Float64Array) { 16127 TypedArrayTestHelper<double, v8::Float64Array, i::ExternalDoubleArray>( 16128 v8::kExternalDoubleArray, -500, 500); 16129 } 16130 16131 16132 THREADED_TEST(Uint8ClampedArray) { 16133 TypedArrayTestHelper<uint8_t, v8::Uint8ClampedArray, i::ExternalPixelArray>( 16134 v8::kExternalPixelArray, 0, 0xFF); 16135 } 16136 16137 16138 THREADED_TEST(DataView) { 16139 const int kSize = 50; 16140 16141 i::ScopedVector<uint8_t> backing_store(kSize+2); 16142 16143 LocalContext env; 16144 v8::Isolate* isolate = env->GetIsolate(); 16145 v8::HandleScope handle_scope(isolate); 16146 16147 Local<v8::ArrayBuffer> ab = v8::ArrayBuffer::New( 16148 backing_store.start(), 2 + kSize); 16149 Local<v8::DataView> dv = 16150 v8::DataView::New(ab, 2, kSize); 16151 CheckInternalFieldsAreZero<v8::ArrayBufferView>(dv); 16152 CHECK_EQ(2, static_cast<int>(dv->ByteOffset())); 16153 CHECK_EQ(kSize, static_cast<int>(dv->ByteLength())); 16154 CHECK_EQ(ab, dv->Buffer()); 16155 } 16156 16157 16158 #define IS_ARRAY_BUFFER_VIEW_TEST(View) \ 16159 THREADED_TEST(Is##View) { \ 16160 i::FLAG_harmony_array_buffer = true; \ 16161 i::FLAG_harmony_typed_arrays = true; \ 16162 LocalContext env; \ 16163 v8::Isolate* isolate = env->GetIsolate(); \ 16164 v8::HandleScope handle_scope(isolate); \ 16165 \ 16166 Handle<Value> result = CompileRun( \ 16167 "var ab = new ArrayBuffer(128);" \ 16168 "new " #View "(ab)"); \ 16169 CHECK(result->IsArrayBufferView()); \ 16170 CHECK(result->Is##View()); \ 16171 CheckInternalFieldsAreZero<v8::ArrayBufferView>(result.As<v8::View>()); \ 16172 } 16173 16174 IS_ARRAY_BUFFER_VIEW_TEST(Uint8Array) 16175 IS_ARRAY_BUFFER_VIEW_TEST(Int8Array) 16176 IS_ARRAY_BUFFER_VIEW_TEST(Uint16Array) 16177 IS_ARRAY_BUFFER_VIEW_TEST(Int16Array) 16178 IS_ARRAY_BUFFER_VIEW_TEST(Uint32Array) 16179 IS_ARRAY_BUFFER_VIEW_TEST(Int32Array) 16180 IS_ARRAY_BUFFER_VIEW_TEST(Float32Array) 16181 IS_ARRAY_BUFFER_VIEW_TEST(Float64Array) 16182 IS_ARRAY_BUFFER_VIEW_TEST(Uint8ClampedArray) 16183 IS_ARRAY_BUFFER_VIEW_TEST(DataView) 16184 16185 #undef IS_ARRAY_BUFFER_VIEW_TEST 16186 16187 16188 16189 THREADED_TEST(ScriptContextDependence) { 16190 LocalContext c1; 16191 v8::HandleScope scope(c1->GetIsolate()); 16192 const char *source = "foo"; 16193 v8::Handle<v8::Script> dep = v8::Script::Compile(v8::String::New(source)); 16194 v8::Handle<v8::Script> indep = v8::Script::New(v8::String::New(source)); 16195 c1->Global()->Set(v8::String::New("foo"), v8::Integer::New(100)); 16196 CHECK_EQ(dep->Run()->Int32Value(), 100); 16197 CHECK_EQ(indep->Run()->Int32Value(), 100); 16198 LocalContext c2; 16199 c2->Global()->Set(v8::String::New("foo"), v8::Integer::New(101)); 16200 CHECK_EQ(dep->Run()->Int32Value(), 100); 16201 CHECK_EQ(indep->Run()->Int32Value(), 101); 16202 } 16203 16204 16205 THREADED_TEST(StackTrace) { 16206 LocalContext context; 16207 v8::HandleScope scope(context->GetIsolate()); 16208 v8::TryCatch try_catch; 16209 const char *source = "function foo() { FAIL.FAIL; }; foo();"; 16210 v8::Handle<v8::String> src = v8::String::New(source); 16211 v8::Handle<v8::String> origin = v8::String::New("stack-trace-test"); 16212 v8::Script::New(src, origin)->Run(); 16213 CHECK(try_catch.HasCaught()); 16214 v8::String::Utf8Value stack(try_catch.StackTrace()); 16215 CHECK(strstr(*stack, "at foo (stack-trace-test") != NULL); 16216 } 16217 16218 16219 // Checks that a StackFrame has certain expected values. 16220 void checkStackFrame(const char* expected_script_name, 16221 const char* expected_func_name, int expected_line_number, 16222 int expected_column, bool is_eval, bool is_constructor, 16223 v8::Handle<v8::StackFrame> frame) { 16224 v8::HandleScope scope(v8::Isolate::GetCurrent()); 16225 v8::String::Utf8Value func_name(frame->GetFunctionName()); 16226 v8::String::Utf8Value script_name(frame->GetScriptName()); 16227 if (*script_name == NULL) { 16228 // The situation where there is no associated script, like for evals. 16229 CHECK(expected_script_name == NULL); 16230 } else { 16231 CHECK(strstr(*script_name, expected_script_name) != NULL); 16232 } 16233 CHECK(strstr(*func_name, expected_func_name) != NULL); 16234 CHECK_EQ(expected_line_number, frame->GetLineNumber()); 16235 CHECK_EQ(expected_column, frame->GetColumn()); 16236 CHECK_EQ(is_eval, frame->IsEval()); 16237 CHECK_EQ(is_constructor, frame->IsConstructor()); 16238 } 16239 16240 16241 void AnalyzeStackInNativeCode(const v8::FunctionCallbackInfo<v8::Value>& args) { 16242 v8::HandleScope scope(args.GetIsolate()); 16243 const char* origin = "capture-stack-trace-test"; 16244 const int kOverviewTest = 1; 16245 const int kDetailedTest = 2; 16246 16247 ASSERT(args.Length() == 1); 16248 16249 int testGroup = args[0]->Int32Value(); 16250 if (testGroup == kOverviewTest) { 16251 v8::Handle<v8::StackTrace> stackTrace = 16252 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview); 16253 CHECK_EQ(4, stackTrace->GetFrameCount()); 16254 checkStackFrame(origin, "bar", 2, 10, false, false, 16255 stackTrace->GetFrame(0)); 16256 checkStackFrame(origin, "foo", 6, 3, false, false, 16257 stackTrace->GetFrame(1)); 16258 // This is the source string inside the eval which has the call to foo. 16259 checkStackFrame(NULL, "", 1, 5, false, false, 16260 stackTrace->GetFrame(2)); 16261 // The last frame is an anonymous function which has the initial eval call. 16262 checkStackFrame(origin, "", 8, 7, false, false, 16263 stackTrace->GetFrame(3)); 16264 16265 CHECK(stackTrace->AsArray()->IsArray()); 16266 } else if (testGroup == kDetailedTest) { 16267 v8::Handle<v8::StackTrace> stackTrace = 16268 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); 16269 CHECK_EQ(4, stackTrace->GetFrameCount()); 16270 checkStackFrame(origin, "bat", 4, 22, false, false, 16271 stackTrace->GetFrame(0)); 16272 checkStackFrame(origin, "baz", 8, 3, false, true, 16273 stackTrace->GetFrame(1)); 16274 #ifdef ENABLE_DEBUGGER_SUPPORT 16275 bool is_eval = true; 16276 #else // ENABLE_DEBUGGER_SUPPORT 16277 bool is_eval = false; 16278 #endif // ENABLE_DEBUGGER_SUPPORT 16279 16280 // This is the source string inside the eval which has the call to baz. 16281 checkStackFrame(NULL, "", 1, 5, is_eval, false, 16282 stackTrace->GetFrame(2)); 16283 // The last frame is an anonymous function which has the initial eval call. 16284 checkStackFrame(origin, "", 10, 1, false, false, 16285 stackTrace->GetFrame(3)); 16286 16287 CHECK(stackTrace->AsArray()->IsArray()); 16288 } 16289 } 16290 16291 16292 // Tests the C++ StackTrace API. 16293 // TODO(3074796): Reenable this as a THREADED_TEST once it passes. 16294 // THREADED_TEST(CaptureStackTrace) { 16295 TEST(CaptureStackTrace) { 16296 v8::HandleScope scope(v8::Isolate::GetCurrent()); 16297 v8::Handle<v8::String> origin = v8::String::New("capture-stack-trace-test"); 16298 Local<ObjectTemplate> templ = ObjectTemplate::New(); 16299 templ->Set(v8_str("AnalyzeStackInNativeCode"), 16300 v8::FunctionTemplate::New(AnalyzeStackInNativeCode)); 16301 LocalContext context(0, templ); 16302 16303 // Test getting OVERVIEW information. Should ignore information that is not 16304 // script name, function name, line number, and column offset. 16305 const char *overview_source = 16306 "function bar() {\n" 16307 " var y; AnalyzeStackInNativeCode(1);\n" 16308 "}\n" 16309 "function foo() {\n" 16310 "\n" 16311 " bar();\n" 16312 "}\n" 16313 "var x;eval('new foo();');"; 16314 v8::Handle<v8::String> overview_src = v8::String::New(overview_source); 16315 v8::Handle<Value> overview_result( 16316 v8::Script::New(overview_src, origin)->Run()); 16317 CHECK(!overview_result.IsEmpty()); 16318 CHECK(overview_result->IsObject()); 16319 16320 // Test getting DETAILED information. 16321 const char *detailed_source = 16322 "function bat() {AnalyzeStackInNativeCode(2);\n" 16323 "}\n" 16324 "\n" 16325 "function baz() {\n" 16326 " bat();\n" 16327 "}\n" 16328 "eval('new baz();');"; 16329 v8::Handle<v8::String> detailed_src = v8::String::New(detailed_source); 16330 // Make the script using a non-zero line and column offset. 16331 v8::Handle<v8::Integer> line_offset = v8::Integer::New(3); 16332 v8::Handle<v8::Integer> column_offset = v8::Integer::New(5); 16333 v8::ScriptOrigin detailed_origin(origin, line_offset, column_offset); 16334 v8::Handle<v8::Script> detailed_script( 16335 v8::Script::New(detailed_src, &detailed_origin)); 16336 v8::Handle<Value> detailed_result(detailed_script->Run()); 16337 CHECK(!detailed_result.IsEmpty()); 16338 CHECK(detailed_result->IsObject()); 16339 } 16340 16341 16342 static void StackTraceForUncaughtExceptionListener( 16343 v8::Handle<v8::Message> message, 16344 v8::Handle<Value>) { 16345 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 16346 CHECK_EQ(2, stack_trace->GetFrameCount()); 16347 checkStackFrame("origin", "foo", 2, 3, false, false, 16348 stack_trace->GetFrame(0)); 16349 checkStackFrame("origin", "bar", 5, 3, false, false, 16350 stack_trace->GetFrame(1)); 16351 } 16352 16353 16354 TEST(CaptureStackTraceForUncaughtException) { 16355 report_count = 0; 16356 LocalContext env; 16357 v8::HandleScope scope(env->GetIsolate()); 16358 v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener); 16359 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 16360 16361 Script::Compile(v8_str("function foo() {\n" 16362 " throw 1;\n" 16363 "};\n" 16364 "function bar() {\n" 16365 " foo();\n" 16366 "};"), 16367 v8_str("origin"))->Run(); 16368 v8::Local<v8::Object> global = env->Global(); 16369 Local<Value> trouble = global->Get(v8_str("bar")); 16370 CHECK(trouble->IsFunction()); 16371 Function::Cast(*trouble)->Call(global, 0, NULL); 16372 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 16373 v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener); 16374 } 16375 16376 16377 TEST(CaptureStackTraceForUncaughtExceptionAndSetters) { 16378 LocalContext env; 16379 v8::HandleScope scope(env->GetIsolate()); 16380 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true, 16381 1024, 16382 v8::StackTrace::kDetailed); 16383 16384 CompileRun( 16385 "var setters = ['column', 'lineNumber', 'scriptName',\n" 16386 " 'scriptNameOrSourceURL', 'functionName', 'isEval',\n" 16387 " 'isConstructor'];\n" 16388 "for (var i = 0; i < setters.length; i++) {\n" 16389 " var prop = setters[i];\n" 16390 " Object.prototype.__defineSetter__(prop, function() { throw prop; });\n" 16391 "}\n"); 16392 CompileRun("throw 'exception';"); 16393 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 16394 } 16395 16396 16397 static void RethrowStackTraceHandler(v8::Handle<v8::Message> message, 16398 v8::Handle<v8::Value> data) { 16399 // Use the frame where JavaScript is called from. 16400 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 16401 CHECK(!stack_trace.IsEmpty()); 16402 int frame_count = stack_trace->GetFrameCount(); 16403 CHECK_EQ(3, frame_count); 16404 int line_number[] = {1, 2, 5}; 16405 for (int i = 0; i < frame_count; i++) { 16406 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber()); 16407 } 16408 } 16409 16410 16411 // Test that we only return the stack trace at the site where the exception 16412 // is first thrown (not where it is rethrown). 16413 TEST(RethrowStackTrace) { 16414 LocalContext env; 16415 v8::HandleScope scope(env->GetIsolate()); 16416 // We make sure that 16417 // - the stack trace of the ReferenceError in g() is reported. 16418 // - the stack trace is not overwritten when e1 is rethrown by t(). 16419 // - the stack trace of e2 does not overwrite that of e1. 16420 const char* source = 16421 "function g() { error; } \n" 16422 "function f() { g(); } \n" 16423 "function t(e) { throw e; } \n" 16424 "try { \n" 16425 " f(); \n" 16426 "} catch (e1) { \n" 16427 " try { \n" 16428 " error; \n" 16429 " } catch (e2) { \n" 16430 " t(e1); \n" 16431 " } \n" 16432 "} \n"; 16433 v8::V8::AddMessageListener(RethrowStackTraceHandler); 16434 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 16435 CompileRun(source); 16436 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 16437 v8::V8::RemoveMessageListeners(RethrowStackTraceHandler); 16438 } 16439 16440 16441 static void RethrowPrimitiveStackTraceHandler(v8::Handle<v8::Message> message, 16442 v8::Handle<v8::Value> data) { 16443 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 16444 CHECK(!stack_trace.IsEmpty()); 16445 int frame_count = stack_trace->GetFrameCount(); 16446 CHECK_EQ(2, frame_count); 16447 int line_number[] = {3, 7}; 16448 for (int i = 0; i < frame_count; i++) { 16449 CHECK_EQ(line_number[i], stack_trace->GetFrame(i)->GetLineNumber()); 16450 } 16451 } 16452 16453 16454 // Test that we do not recognize identity for primitive exceptions. 16455 TEST(RethrowPrimitiveStackTrace) { 16456 LocalContext env; 16457 v8::HandleScope scope(env->GetIsolate()); 16458 // We do not capture stack trace for non Error objects on creation time. 16459 // Instead, we capture the stack trace on last throw. 16460 const char* source = 16461 "function g() { throw 404; } \n" 16462 "function f() { g(); } \n" 16463 "function t(e) { throw e; } \n" 16464 "try { \n" 16465 " f(); \n" 16466 "} catch (e1) { \n" 16467 " t(e1) \n" 16468 "} \n"; 16469 v8::V8::AddMessageListener(RethrowPrimitiveStackTraceHandler); 16470 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 16471 CompileRun(source); 16472 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 16473 v8::V8::RemoveMessageListeners(RethrowPrimitiveStackTraceHandler); 16474 } 16475 16476 16477 static void RethrowExistingStackTraceHandler(v8::Handle<v8::Message> message, 16478 v8::Handle<v8::Value> data) { 16479 // Use the frame where JavaScript is called from. 16480 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 16481 CHECK(!stack_trace.IsEmpty()); 16482 CHECK_EQ(1, stack_trace->GetFrameCount()); 16483 CHECK_EQ(1, stack_trace->GetFrame(0)->GetLineNumber()); 16484 } 16485 16486 16487 // Test that the stack trace is captured when the error object is created and 16488 // not where it is thrown. 16489 TEST(RethrowExistingStackTrace) { 16490 LocalContext env; 16491 v8::HandleScope scope(env->GetIsolate()); 16492 const char* source = 16493 "var e = new Error(); \n" 16494 "throw e; \n"; 16495 v8::V8::AddMessageListener(RethrowExistingStackTraceHandler); 16496 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 16497 CompileRun(source); 16498 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 16499 v8::V8::RemoveMessageListeners(RethrowExistingStackTraceHandler); 16500 } 16501 16502 16503 static void RethrowBogusErrorStackTraceHandler(v8::Handle<v8::Message> message, 16504 v8::Handle<v8::Value> data) { 16505 // Use the frame where JavaScript is called from. 16506 v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace(); 16507 CHECK(!stack_trace.IsEmpty()); 16508 CHECK_EQ(1, stack_trace->GetFrameCount()); 16509 CHECK_EQ(2, stack_trace->GetFrame(0)->GetLineNumber()); 16510 } 16511 16512 16513 // Test that the stack trace is captured where the bogus Error object is thrown. 16514 TEST(RethrowBogusErrorStackTrace) { 16515 LocalContext env; 16516 v8::HandleScope scope(env->GetIsolate()); 16517 const char* source = 16518 "var e = {__proto__: new Error()} \n" 16519 "throw e; \n"; 16520 v8::V8::AddMessageListener(RethrowBogusErrorStackTraceHandler); 16521 v8::V8::SetCaptureStackTraceForUncaughtExceptions(true); 16522 CompileRun(source); 16523 v8::V8::SetCaptureStackTraceForUncaughtExceptions(false); 16524 v8::V8::RemoveMessageListeners(RethrowBogusErrorStackTraceHandler); 16525 } 16526 16527 16528 void AnalyzeStackOfEvalWithSourceURL( 16529 const v8::FunctionCallbackInfo<v8::Value>& args) { 16530 v8::HandleScope scope(args.GetIsolate()); 16531 v8::Handle<v8::StackTrace> stackTrace = 16532 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); 16533 CHECK_EQ(5, stackTrace->GetFrameCount()); 16534 v8::Handle<v8::String> url = v8_str("eval_url"); 16535 for (int i = 0; i < 3; i++) { 16536 v8::Handle<v8::String> name = 16537 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 16538 CHECK(!name.IsEmpty()); 16539 CHECK_EQ(url, name); 16540 } 16541 } 16542 16543 16544 TEST(SourceURLInStackTrace) { 16545 v8::HandleScope scope(v8::Isolate::GetCurrent()); 16546 Local<ObjectTemplate> templ = ObjectTemplate::New(); 16547 templ->Set(v8_str("AnalyzeStackOfEvalWithSourceURL"), 16548 v8::FunctionTemplate::New(AnalyzeStackOfEvalWithSourceURL)); 16549 LocalContext context(0, templ); 16550 16551 const char *source = 16552 "function outer() {\n" 16553 "function bar() {\n" 16554 " AnalyzeStackOfEvalWithSourceURL();\n" 16555 "}\n" 16556 "function foo() {\n" 16557 "\n" 16558 " bar();\n" 16559 "}\n" 16560 "foo();\n" 16561 "}\n" 16562 "eval('(' + outer +')()%s');"; 16563 16564 i::ScopedVector<char> code(1024); 16565 i::OS::SNPrintF(code, source, "//# sourceURL=eval_url"); 16566 CHECK(CompileRun(code.start())->IsUndefined()); 16567 i::OS::SNPrintF(code, source, "//@ sourceURL=eval_url"); 16568 CHECK(CompileRun(code.start())->IsUndefined()); 16569 } 16570 16571 16572 void AnalyzeStackOfInlineScriptWithSourceURL( 16573 const v8::FunctionCallbackInfo<v8::Value>& args) { 16574 v8::HandleScope scope(args.GetIsolate()); 16575 v8::Handle<v8::StackTrace> stackTrace = 16576 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); 16577 CHECK_EQ(4, stackTrace->GetFrameCount()); 16578 v8::Handle<v8::String> url = v8_str("url"); 16579 for (int i = 0; i < 3; i++) { 16580 v8::Handle<v8::String> name = 16581 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 16582 CHECK(!name.IsEmpty()); 16583 CHECK_EQ(url, name); 16584 } 16585 } 16586 16587 16588 TEST(InlineScriptWithSourceURLInStackTrace) { 16589 v8::HandleScope scope(v8::Isolate::GetCurrent()); 16590 Local<ObjectTemplate> templ = ObjectTemplate::New(); 16591 templ->Set(v8_str("AnalyzeStackOfInlineScriptWithSourceURL"), 16592 v8::FunctionTemplate::New( 16593 AnalyzeStackOfInlineScriptWithSourceURL)); 16594 LocalContext context(0, templ); 16595 16596 const char *source = 16597 "function outer() {\n" 16598 "function bar() {\n" 16599 " AnalyzeStackOfInlineScriptWithSourceURL();\n" 16600 "}\n" 16601 "function foo() {\n" 16602 "\n" 16603 " bar();\n" 16604 "}\n" 16605 "foo();\n" 16606 "}\n" 16607 "outer()\n%s"; 16608 16609 i::ScopedVector<char> code(1024); 16610 i::OS::SNPrintF(code, source, "//# sourceURL=source_url"); 16611 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); 16612 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url"); 16613 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 1)->IsUndefined()); 16614 } 16615 16616 16617 void AnalyzeStackOfDynamicScriptWithSourceURL( 16618 const v8::FunctionCallbackInfo<v8::Value>& args) { 16619 v8::HandleScope scope(args.GetIsolate()); 16620 v8::Handle<v8::StackTrace> stackTrace = 16621 v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed); 16622 CHECK_EQ(4, stackTrace->GetFrameCount()); 16623 v8::Handle<v8::String> url = v8_str("source_url"); 16624 for (int i = 0; i < 3; i++) { 16625 v8::Handle<v8::String> name = 16626 stackTrace->GetFrame(i)->GetScriptNameOrSourceURL(); 16627 CHECK(!name.IsEmpty()); 16628 CHECK_EQ(url, name); 16629 } 16630 } 16631 16632 16633 TEST(DynamicWithSourceURLInStackTrace) { 16634 v8::HandleScope scope(v8::Isolate::GetCurrent()); 16635 Local<ObjectTemplate> templ = ObjectTemplate::New(); 16636 templ->Set(v8_str("AnalyzeStackOfDynamicScriptWithSourceURL"), 16637 v8::FunctionTemplate::New( 16638 AnalyzeStackOfDynamicScriptWithSourceURL)); 16639 LocalContext context(0, templ); 16640 16641 const char *source = 16642 "function outer() {\n" 16643 "function bar() {\n" 16644 " AnalyzeStackOfDynamicScriptWithSourceURL();\n" 16645 "}\n" 16646 "function foo() {\n" 16647 "\n" 16648 " bar();\n" 16649 "}\n" 16650 "foo();\n" 16651 "}\n" 16652 "outer()\n%s"; 16653 16654 i::ScopedVector<char> code(1024); 16655 i::OS::SNPrintF(code, source, "//# sourceURL=source_url"); 16656 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); 16657 i::OS::SNPrintF(code, source, "//@ sourceURL=source_url"); 16658 CHECK(CompileRunWithOrigin(code.start(), "url", 0, 0)->IsUndefined()); 16659 } 16660 16661 16662 static void CreateGarbageInOldSpace() { 16663 i::Factory* factory = i::Isolate::Current()->factory(); 16664 v8::HandleScope scope(v8::Isolate::GetCurrent()); 16665 i::AlwaysAllocateScope always_allocate; 16666 for (int i = 0; i < 1000; i++) { 16667 factory->NewFixedArray(1000, i::TENURED); 16668 } 16669 } 16670 16671 16672 // Test that idle notification can be handled and eventually returns true. 16673 TEST(IdleNotification) { 16674 const intptr_t MB = 1024 * 1024; 16675 LocalContext env; 16676 v8::HandleScope scope(env->GetIsolate()); 16677 intptr_t initial_size = HEAP->SizeOfObjects(); 16678 CreateGarbageInOldSpace(); 16679 intptr_t size_with_garbage = HEAP->SizeOfObjects(); 16680 CHECK_GT(size_with_garbage, initial_size + MB); 16681 bool finished = false; 16682 for (int i = 0; i < 200 && !finished; i++) { 16683 finished = v8::V8::IdleNotification(); 16684 } 16685 intptr_t final_size = HEAP->SizeOfObjects(); 16686 CHECK(finished); 16687 CHECK_LT(final_size, initial_size + 1); 16688 } 16689 16690 16691 // Test that idle notification can be handled and eventually collects garbage. 16692 TEST(IdleNotificationWithSmallHint) { 16693 const intptr_t MB = 1024 * 1024; 16694 const int IdlePauseInMs = 900; 16695 LocalContext env; 16696 v8::HandleScope scope(env->GetIsolate()); 16697 intptr_t initial_size = HEAP->SizeOfObjects(); 16698 CreateGarbageInOldSpace(); 16699 intptr_t size_with_garbage = HEAP->SizeOfObjects(); 16700 CHECK_GT(size_with_garbage, initial_size + MB); 16701 bool finished = false; 16702 for (int i = 0; i < 200 && !finished; i++) { 16703 finished = v8::V8::IdleNotification(IdlePauseInMs); 16704 } 16705 intptr_t final_size = HEAP->SizeOfObjects(); 16706 CHECK(finished); 16707 CHECK_LT(final_size, initial_size + 1); 16708 } 16709 16710 16711 // Test that idle notification can be handled and eventually collects garbage. 16712 TEST(IdleNotificationWithLargeHint) { 16713 const intptr_t MB = 1024 * 1024; 16714 const int IdlePauseInMs = 900; 16715 LocalContext env; 16716 v8::HandleScope scope(env->GetIsolate()); 16717 intptr_t initial_size = HEAP->SizeOfObjects(); 16718 CreateGarbageInOldSpace(); 16719 intptr_t size_with_garbage = HEAP->SizeOfObjects(); 16720 CHECK_GT(size_with_garbage, initial_size + MB); 16721 bool finished = false; 16722 for (int i = 0; i < 200 && !finished; i++) { 16723 finished = v8::V8::IdleNotification(IdlePauseInMs); 16724 } 16725 intptr_t final_size = HEAP->SizeOfObjects(); 16726 CHECK(finished); 16727 CHECK_LT(final_size, initial_size + 1); 16728 } 16729 16730 16731 TEST(Regress2107) { 16732 const intptr_t MB = 1024 * 1024; 16733 const int kShortIdlePauseInMs = 100; 16734 const int kLongIdlePauseInMs = 1000; 16735 LocalContext env; 16736 v8::Isolate* isolate = env->GetIsolate(); 16737 v8::HandleScope scope(env->GetIsolate()); 16738 intptr_t initial_size = HEAP->SizeOfObjects(); 16739 // Send idle notification to start a round of incremental GCs. 16740 v8::V8::IdleNotification(kShortIdlePauseInMs); 16741 // Emulate 7 page reloads. 16742 for (int i = 0; i < 7; i++) { 16743 { 16744 v8::HandleScope inner_scope(env->GetIsolate()); 16745 v8::Local<v8::Context> ctx = v8::Context::New(isolate); 16746 ctx->Enter(); 16747 CreateGarbageInOldSpace(); 16748 ctx->Exit(); 16749 } 16750 v8::V8::ContextDisposedNotification(); 16751 v8::V8::IdleNotification(kLongIdlePauseInMs); 16752 } 16753 // Create garbage and check that idle notification still collects it. 16754 CreateGarbageInOldSpace(); 16755 intptr_t size_with_garbage = HEAP->SizeOfObjects(); 16756 CHECK_GT(size_with_garbage, initial_size + MB); 16757 bool finished = false; 16758 for (int i = 0; i < 200 && !finished; i++) { 16759 finished = v8::V8::IdleNotification(kShortIdlePauseInMs); 16760 } 16761 intptr_t final_size = HEAP->SizeOfObjects(); 16762 CHECK_LT(final_size, initial_size + 1); 16763 } 16764 16765 static uint32_t* stack_limit; 16766 16767 static void GetStackLimitCallback( 16768 const v8::FunctionCallbackInfo<v8::Value>& args) { 16769 stack_limit = reinterpret_cast<uint32_t*>( 16770 i::Isolate::Current()->stack_guard()->real_climit()); 16771 } 16772 16773 16774 // Uses the address of a local variable to determine the stack top now. 16775 // Given a size, returns an address that is that far from the current 16776 // top of stack. 16777 static uint32_t* ComputeStackLimit(uint32_t size) { 16778 uint32_t* answer = &size - (size / sizeof(size)); 16779 // If the size is very large and the stack is very near the bottom of 16780 // memory then the calculation above may wrap around and give an address 16781 // that is above the (downwards-growing) stack. In that case we return 16782 // a very low address. 16783 if (answer > &size) return reinterpret_cast<uint32_t*>(sizeof(size)); 16784 return answer; 16785 } 16786 16787 16788 // We need at least 165kB for an x64 debug build with clang and ASAN. 16789 static const int stack_breathing_room = 256 * i::KB; 16790 16791 16792 TEST(SetResourceConstraints) { 16793 uint32_t* set_limit = ComputeStackLimit(stack_breathing_room); 16794 16795 // Set stack limit. 16796 v8::ResourceConstraints constraints; 16797 constraints.set_stack_limit(set_limit); 16798 CHECK(v8::SetResourceConstraints(&constraints)); 16799 16800 // Execute a script. 16801 LocalContext env; 16802 v8::HandleScope scope(env->GetIsolate()); 16803 Local<v8::FunctionTemplate> fun_templ = 16804 v8::FunctionTemplate::New(GetStackLimitCallback); 16805 Local<Function> fun = fun_templ->GetFunction(); 16806 env->Global()->Set(v8_str("get_stack_limit"), fun); 16807 CompileRun("get_stack_limit();"); 16808 16809 CHECK(stack_limit == set_limit); 16810 } 16811 16812 16813 TEST(SetResourceConstraintsInThread) { 16814 uint32_t* set_limit; 16815 { 16816 v8::Locker locker(CcTest::default_isolate()); 16817 set_limit = ComputeStackLimit(stack_breathing_room); 16818 16819 // Set stack limit. 16820 v8::ResourceConstraints constraints; 16821 constraints.set_stack_limit(set_limit); 16822 CHECK(v8::SetResourceConstraints(&constraints)); 16823 16824 // Execute a script. 16825 v8::HandleScope scope(CcTest::default_isolate()); 16826 LocalContext env; 16827 Local<v8::FunctionTemplate> fun_templ = 16828 v8::FunctionTemplate::New(GetStackLimitCallback); 16829 Local<Function> fun = fun_templ->GetFunction(); 16830 env->Global()->Set(v8_str("get_stack_limit"), fun); 16831 CompileRun("get_stack_limit();"); 16832 16833 CHECK(stack_limit == set_limit); 16834 } 16835 { 16836 v8::Locker locker(CcTest::default_isolate()); 16837 CHECK(stack_limit == set_limit); 16838 } 16839 } 16840 16841 16842 THREADED_TEST(GetHeapStatistics) { 16843 LocalContext c1; 16844 v8::HandleScope scope(c1->GetIsolate()); 16845 v8::HeapStatistics heap_statistics; 16846 CHECK_EQ(static_cast<int>(heap_statistics.total_heap_size()), 0); 16847 CHECK_EQ(static_cast<int>(heap_statistics.used_heap_size()), 0); 16848 c1->GetIsolate()->GetHeapStatistics(&heap_statistics); 16849 CHECK_NE(static_cast<int>(heap_statistics.total_heap_size()), 0); 16850 CHECK_NE(static_cast<int>(heap_statistics.used_heap_size()), 0); 16851 } 16852 16853 16854 class VisitorImpl : public v8::ExternalResourceVisitor { 16855 public: 16856 explicit VisitorImpl(TestResource** resource) { 16857 for (int i = 0; i < 4; i++) { 16858 resource_[i] = resource[i]; 16859 found_resource_[i] = false; 16860 } 16861 } 16862 virtual ~VisitorImpl() {} 16863 virtual void VisitExternalString(v8::Handle<v8::String> string) { 16864 if (!string->IsExternal()) { 16865 CHECK(string->IsExternalAscii()); 16866 return; 16867 } 16868 v8::String::ExternalStringResource* resource = 16869 string->GetExternalStringResource(); 16870 CHECK(resource); 16871 for (int i = 0; i < 4; i++) { 16872 if (resource_[i] == resource) { 16873 CHECK(!found_resource_[i]); 16874 found_resource_[i] = true; 16875 } 16876 } 16877 } 16878 void CheckVisitedResources() { 16879 for (int i = 0; i < 4; i++) { 16880 CHECK(found_resource_[i]); 16881 } 16882 } 16883 16884 private: 16885 v8::String::ExternalStringResource* resource_[4]; 16886 bool found_resource_[4]; 16887 }; 16888 16889 16890 TEST(VisitExternalStrings) { 16891 LocalContext env; 16892 v8::HandleScope scope(env->GetIsolate()); 16893 const char* string = "Some string"; 16894 uint16_t* two_byte_string = AsciiToTwoByteString(string); 16895 TestResource* resource[4]; 16896 resource[0] = new TestResource(two_byte_string); 16897 v8::Local<v8::String> string0 = v8::String::NewExternal(resource[0]); 16898 resource[1] = new TestResource(two_byte_string); 16899 v8::Local<v8::String> string1 = v8::String::NewExternal(resource[1]); 16900 16901 // Externalized symbol. 16902 resource[2] = new TestResource(two_byte_string); 16903 v8::Local<v8::String> string2 = v8::String::NewSymbol(string); 16904 CHECK(string2->MakeExternal(resource[2])); 16905 16906 // Symbolized External. 16907 resource[3] = new TestResource(AsciiToTwoByteString("Some other string")); 16908 v8::Local<v8::String> string3 = v8::String::NewExternal(resource[3]); 16909 HEAP->CollectAllAvailableGarbage(); // Tenure string. 16910 // Turn into a symbol. 16911 i::Handle<i::String> string3_i = v8::Utils::OpenHandle(*string3); 16912 CHECK(!HEAP->InternalizeString(*string3_i)->IsFailure()); 16913 CHECK(string3_i->IsInternalizedString()); 16914 16915 // We need to add usages for string* to avoid warnings in GCC 4.7 16916 CHECK(string0->IsExternal()); 16917 CHECK(string1->IsExternal()); 16918 CHECK(string2->IsExternal()); 16919 CHECK(string3->IsExternal()); 16920 16921 VisitorImpl visitor(resource); 16922 v8::V8::VisitExternalResources(&visitor); 16923 visitor.CheckVisitedResources(); 16924 } 16925 16926 16927 static double DoubleFromBits(uint64_t value) { 16928 double target; 16929 i::OS::MemCopy(&target, &value, sizeof(target)); 16930 return target; 16931 } 16932 16933 16934 static uint64_t DoubleToBits(double value) { 16935 uint64_t target; 16936 i::OS::MemCopy(&target, &value, sizeof(target)); 16937 return target; 16938 } 16939 16940 16941 static double DoubleToDateTime(double input) { 16942 double date_limit = 864e13; 16943 if (std::isnan(input) || input < -date_limit || input > date_limit) { 16944 return i::OS::nan_value(); 16945 } 16946 return (input < 0) ? -(floor(-input)) : floor(input); 16947 } 16948 16949 16950 // We don't have a consistent way to write 64-bit constants syntactically, so we 16951 // split them into two 32-bit constants and combine them programmatically. 16952 static double DoubleFromBits(uint32_t high_bits, uint32_t low_bits) { 16953 return DoubleFromBits((static_cast<uint64_t>(high_bits) << 32) | low_bits); 16954 } 16955 16956 16957 THREADED_TEST(QuietSignalingNaNs) { 16958 LocalContext context; 16959 v8::HandleScope scope(context->GetIsolate()); 16960 v8::TryCatch try_catch; 16961 16962 // Special double values. 16963 double snan = DoubleFromBits(0x7ff00000, 0x00000001); 16964 double qnan = DoubleFromBits(0x7ff80000, 0x00000000); 16965 double infinity = DoubleFromBits(0x7ff00000, 0x00000000); 16966 double max_normal = DoubleFromBits(0x7fefffff, 0xffffffffu); 16967 double min_normal = DoubleFromBits(0x00100000, 0x00000000); 16968 double max_denormal = DoubleFromBits(0x000fffff, 0xffffffffu); 16969 double min_denormal = DoubleFromBits(0x00000000, 0x00000001); 16970 16971 // Date values are capped at +/-100000000 days (times 864e5 ms per day) 16972 // on either side of the epoch. 16973 double date_limit = 864e13; 16974 16975 double test_values[] = { 16976 snan, 16977 qnan, 16978 infinity, 16979 max_normal, 16980 date_limit + 1, 16981 date_limit, 16982 min_normal, 16983 max_denormal, 16984 min_denormal, 16985 0, 16986 -0, 16987 -min_denormal, 16988 -max_denormal, 16989 -min_normal, 16990 -date_limit, 16991 -date_limit - 1, 16992 -max_normal, 16993 -infinity, 16994 -qnan, 16995 -snan 16996 }; 16997 int num_test_values = 20; 16998 16999 for (int i = 0; i < num_test_values; i++) { 17000 double test_value = test_values[i]; 17001 17002 // Check that Number::New preserves non-NaNs and quiets SNaNs. 17003 v8::Handle<v8::Value> number = v8::Number::New(test_value); 17004 double stored_number = number->NumberValue(); 17005 if (!std::isnan(test_value)) { 17006 CHECK_EQ(test_value, stored_number); 17007 } else { 17008 uint64_t stored_bits = DoubleToBits(stored_number); 17009 // Check if quiet nan (bits 51..62 all set). 17010 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR) 17011 // Most significant fraction bit for quiet nan is set to 0 17012 // on MIPS architecture. Allowed by IEEE-754. 17013 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); 17014 #else 17015 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 17016 #endif 17017 } 17018 17019 // Check that Date::New preserves non-NaNs in the date range and 17020 // quiets SNaNs. 17021 v8::Handle<v8::Value> date = v8::Date::New(test_value); 17022 double expected_stored_date = DoubleToDateTime(test_value); 17023 double stored_date = date->NumberValue(); 17024 if (!std::isnan(expected_stored_date)) { 17025 CHECK_EQ(expected_stored_date, stored_date); 17026 } else { 17027 uint64_t stored_bits = DoubleToBits(stored_date); 17028 // Check if quiet nan (bits 51..62 all set). 17029 #if defined(V8_TARGET_ARCH_MIPS) && !defined(USE_SIMULATOR) 17030 // Most significant fraction bit for quiet nan is set to 0 17031 // on MIPS architecture. Allowed by IEEE-754. 17032 CHECK_EQ(0xffe, static_cast<int>((stored_bits >> 51) & 0xfff)); 17033 #else 17034 CHECK_EQ(0xfff, static_cast<int>((stored_bits >> 51) & 0xfff)); 17035 #endif 17036 } 17037 } 17038 } 17039 17040 17041 static void SpaghettiIncident( 17042 const v8::FunctionCallbackInfo<v8::Value>& args) { 17043 v8::HandleScope scope(args.GetIsolate()); 17044 v8::TryCatch tc; 17045 v8::Handle<v8::String> str(args[0]->ToString()); 17046 USE(str); 17047 if (tc.HasCaught()) 17048 tc.ReThrow(); 17049 } 17050 17051 17052 // Test that an exception can be propagated down through a spaghetti 17053 // stack using ReThrow. 17054 THREADED_TEST(SpaghettiStackReThrow) { 17055 v8::HandleScope scope(v8::Isolate::GetCurrent()); 17056 LocalContext context; 17057 context->Global()->Set( 17058 v8::String::New("s"), 17059 v8::FunctionTemplate::New(SpaghettiIncident)->GetFunction()); 17060 v8::TryCatch try_catch; 17061 CompileRun( 17062 "var i = 0;" 17063 "var o = {" 17064 " toString: function () {" 17065 " if (i == 10) {" 17066 " throw 'Hey!';" 17067 " } else {" 17068 " i++;" 17069 " return s(o);" 17070 " }" 17071 " }" 17072 "};" 17073 "s(o);"); 17074 CHECK(try_catch.HasCaught()); 17075 v8::String::Utf8Value value(try_catch.Exception()); 17076 CHECK_EQ(0, strcmp(*value, "Hey!")); 17077 } 17078 17079 17080 TEST(Regress528) { 17081 v8::V8::Initialize(); 17082 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 17083 v8::HandleScope scope(isolate); 17084 v8::Local<Context> other_context; 17085 int gc_count; 17086 17087 // Create a context used to keep the code from aging in the compilation 17088 // cache. 17089 other_context = Context::New(isolate); 17090 17091 // Context-dependent context data creates reference from the compilation 17092 // cache to the global object. 17093 const char* source_simple = "1"; 17094 { 17095 v8::HandleScope scope(isolate); 17096 v8::Local<Context> context = Context::New(isolate); 17097 17098 context->Enter(); 17099 Local<v8::String> obj = v8::String::New(""); 17100 context->SetEmbedderData(0, obj); 17101 CompileRun(source_simple); 17102 context->Exit(); 17103 } 17104 v8::V8::ContextDisposedNotification(); 17105 for (gc_count = 1; gc_count < 10; gc_count++) { 17106 other_context->Enter(); 17107 CompileRun(source_simple); 17108 other_context->Exit(); 17109 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 17110 if (GetGlobalObjectsCount() == 1) break; 17111 } 17112 CHECK_GE(2, gc_count); 17113 CHECK_EQ(1, GetGlobalObjectsCount()); 17114 17115 // Eval in a function creates reference from the compilation cache to the 17116 // global object. 17117 const char* source_eval = "function f(){eval('1')}; f()"; 17118 { 17119 v8::HandleScope scope(isolate); 17120 v8::Local<Context> context = Context::New(isolate); 17121 17122 context->Enter(); 17123 CompileRun(source_eval); 17124 context->Exit(); 17125 } 17126 v8::V8::ContextDisposedNotification(); 17127 for (gc_count = 1; gc_count < 10; gc_count++) { 17128 other_context->Enter(); 17129 CompileRun(source_eval); 17130 other_context->Exit(); 17131 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 17132 if (GetGlobalObjectsCount() == 1) break; 17133 } 17134 CHECK_GE(2, gc_count); 17135 CHECK_EQ(1, GetGlobalObjectsCount()); 17136 17137 // Looking up the line number for an exception creates reference from the 17138 // compilation cache to the global object. 17139 const char* source_exception = "function f(){throw 1;} f()"; 17140 { 17141 v8::HandleScope scope(isolate); 17142 v8::Local<Context> context = Context::New(isolate); 17143 17144 context->Enter(); 17145 v8::TryCatch try_catch; 17146 CompileRun(source_exception); 17147 CHECK(try_catch.HasCaught()); 17148 v8::Handle<v8::Message> message = try_catch.Message(); 17149 CHECK(!message.IsEmpty()); 17150 CHECK_EQ(1, message->GetLineNumber()); 17151 context->Exit(); 17152 } 17153 v8::V8::ContextDisposedNotification(); 17154 for (gc_count = 1; gc_count < 10; gc_count++) { 17155 other_context->Enter(); 17156 CompileRun(source_exception); 17157 other_context->Exit(); 17158 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 17159 if (GetGlobalObjectsCount() == 1) break; 17160 } 17161 CHECK_GE(2, gc_count); 17162 CHECK_EQ(1, GetGlobalObjectsCount()); 17163 17164 v8::V8::ContextDisposedNotification(); 17165 } 17166 17167 17168 THREADED_TEST(ScriptOrigin) { 17169 LocalContext env; 17170 v8::HandleScope scope(env->GetIsolate()); 17171 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test")); 17172 v8::Handle<v8::String> script = v8::String::New( 17173 "function f() {}\n\nfunction g() {}"); 17174 v8::Script::Compile(script, &origin)->Run(); 17175 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 17176 env->Global()->Get(v8::String::New("f"))); 17177 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 17178 env->Global()->Get(v8::String::New("g"))); 17179 17180 v8::ScriptOrigin script_origin_f = f->GetScriptOrigin(); 17181 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_f.ResourceName())); 17182 CHECK_EQ(0, script_origin_f.ResourceLineOffset()->Int32Value()); 17183 17184 v8::ScriptOrigin script_origin_g = g->GetScriptOrigin(); 17185 CHECK_EQ("test", *v8::String::Utf8Value(script_origin_g.ResourceName())); 17186 CHECK_EQ(0, script_origin_g.ResourceLineOffset()->Int32Value()); 17187 } 17188 17189 17190 THREADED_TEST(FunctionGetInferredName) { 17191 LocalContext env; 17192 v8::HandleScope scope(env->GetIsolate()); 17193 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test")); 17194 v8::Handle<v8::String> script = v8::String::New( 17195 "var foo = { bar : { baz : function() {}}}; var f = foo.bar.baz;"); 17196 v8::Script::Compile(script, &origin)->Run(); 17197 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 17198 env->Global()->Get(v8::String::New("f"))); 17199 CHECK_EQ("foo.bar.baz", *v8::String::Utf8Value(f->GetInferredName())); 17200 } 17201 17202 17203 THREADED_TEST(ScriptLineNumber) { 17204 LocalContext env; 17205 v8::HandleScope scope(env->GetIsolate()); 17206 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test")); 17207 v8::Handle<v8::String> script = v8::String::New( 17208 "function f() {}\n\nfunction g() {}"); 17209 v8::Script::Compile(script, &origin)->Run(); 17210 v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast( 17211 env->Global()->Get(v8::String::New("f"))); 17212 v8::Local<v8::Function> g = v8::Local<v8::Function>::Cast( 17213 env->Global()->Get(v8::String::New("g"))); 17214 CHECK_EQ(0, f->GetScriptLineNumber()); 17215 CHECK_EQ(2, g->GetScriptLineNumber()); 17216 } 17217 17218 17219 THREADED_TEST(ScriptColumnNumber) { 17220 LocalContext env; 17221 v8::HandleScope scope(env->GetIsolate()); 17222 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"), 17223 v8::Integer::New(3), v8::Integer::New(2)); 17224 v8::Handle<v8::String> script = v8::String::New( 17225 "function foo() {}\n\n function bar() {}"); 17226 v8::Script::Compile(script, &origin)->Run(); 17227 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 17228 env->Global()->Get(v8::String::New("foo"))); 17229 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( 17230 env->Global()->Get(v8::String::New("bar"))); 17231 CHECK_EQ(14, foo->GetScriptColumnNumber()); 17232 CHECK_EQ(17, bar->GetScriptColumnNumber()); 17233 } 17234 17235 17236 THREADED_TEST(FunctionGetScriptId) { 17237 LocalContext env; 17238 v8::HandleScope scope(env->GetIsolate()); 17239 v8::ScriptOrigin origin = v8::ScriptOrigin(v8::String::New("test"), 17240 v8::Integer::New(3), v8::Integer::New(2)); 17241 v8::Handle<v8::String> scriptSource = v8::String::New( 17242 "function foo() {}\n\n function bar() {}"); 17243 v8::Local<v8::Script> script(v8::Script::Compile(scriptSource, &origin)); 17244 script->Run(); 17245 v8::Local<v8::Function> foo = v8::Local<v8::Function>::Cast( 17246 env->Global()->Get(v8::String::New("foo"))); 17247 v8::Local<v8::Function> bar = v8::Local<v8::Function>::Cast( 17248 env->Global()->Get(v8::String::New("bar"))); 17249 CHECK_EQ(script->Id(), foo->GetScriptId()); 17250 CHECK_EQ(script->Id(), bar->GetScriptId()); 17251 } 17252 17253 17254 static void GetterWhichReturns42( 17255 Local<String> name, 17256 const v8::PropertyCallbackInfo<v8::Value>& info) { 17257 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 17258 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 17259 info.GetReturnValue().Set(v8_num(42)); 17260 } 17261 17262 17263 static void SetterWhichSetsYOnThisTo23( 17264 Local<String> name, 17265 Local<Value> value, 17266 const v8::PropertyCallbackInfo<void>& info) { 17267 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 17268 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 17269 info.This()->Set(v8_str("y"), v8_num(23)); 17270 } 17271 17272 17273 void FooGetInterceptor(Local<String> name, 17274 const v8::PropertyCallbackInfo<v8::Value>& info) { 17275 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 17276 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 17277 if (!name->Equals(v8_str("foo"))) return; 17278 info.GetReturnValue().Set(v8_num(42)); 17279 } 17280 17281 17282 void FooSetInterceptor(Local<String> name, 17283 Local<Value> value, 17284 const v8::PropertyCallbackInfo<v8::Value>& info) { 17285 CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject()); 17286 CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject()); 17287 if (!name->Equals(v8_str("foo"))) return; 17288 info.This()->Set(v8_str("y"), v8_num(23)); 17289 info.GetReturnValue().Set(v8_num(23)); 17290 } 17291 17292 17293 TEST(SetterOnConstructorPrototype) { 17294 v8::HandleScope scope(v8::Isolate::GetCurrent()); 17295 Local<ObjectTemplate> templ = ObjectTemplate::New(); 17296 templ->SetAccessor(v8_str("x"), 17297 GetterWhichReturns42, 17298 SetterWhichSetsYOnThisTo23); 17299 LocalContext context; 17300 context->Global()->Set(v8_str("P"), templ->NewInstance()); 17301 CompileRun("function C1() {" 17302 " this.x = 23;" 17303 "};" 17304 "C1.prototype = P;" 17305 "function C2() {" 17306 " this.x = 23" 17307 "};" 17308 "C2.prototype = { };" 17309 "C2.prototype.__proto__ = P;"); 17310 17311 v8::Local<v8::Script> script; 17312 script = v8::Script::Compile(v8_str("new C1();")); 17313 for (int i = 0; i < 10; i++) { 17314 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 17315 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value()); 17316 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value()); 17317 } 17318 17319 script = v8::Script::Compile(v8_str("new C2();")); 17320 for (int i = 0; i < 10; i++) { 17321 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run()); 17322 CHECK_EQ(42, c2->Get(v8_str("x"))->Int32Value()); 17323 CHECK_EQ(23, c2->Get(v8_str("y"))->Int32Value()); 17324 } 17325 } 17326 17327 17328 static void NamedPropertyGetterWhichReturns42( 17329 Local<String> name, 17330 const v8::PropertyCallbackInfo<v8::Value>& info) { 17331 info.GetReturnValue().Set(v8_num(42)); 17332 } 17333 17334 17335 static void NamedPropertySetterWhichSetsYOnThisTo23( 17336 Local<String> name, 17337 Local<Value> value, 17338 const v8::PropertyCallbackInfo<v8::Value>& info) { 17339 if (name->Equals(v8_str("x"))) { 17340 info.This()->Set(v8_str("y"), v8_num(23)); 17341 } 17342 } 17343 17344 17345 THREADED_TEST(InterceptorOnConstructorPrototype) { 17346 v8::HandleScope scope(v8::Isolate::GetCurrent()); 17347 Local<ObjectTemplate> templ = ObjectTemplate::New(); 17348 templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42, 17349 NamedPropertySetterWhichSetsYOnThisTo23); 17350 LocalContext context; 17351 context->Global()->Set(v8_str("P"), templ->NewInstance()); 17352 CompileRun("function C1() {" 17353 " this.x = 23;" 17354 "};" 17355 "C1.prototype = P;" 17356 "function C2() {" 17357 " this.x = 23" 17358 "};" 17359 "C2.prototype = { };" 17360 "C2.prototype.__proto__ = P;"); 17361 17362 v8::Local<v8::Script> script; 17363 script = v8::Script::Compile(v8_str("new C1();")); 17364 for (int i = 0; i < 10; i++) { 17365 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 17366 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value()); 17367 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value()); 17368 } 17369 17370 script = v8::Script::Compile(v8_str("new C2();")); 17371 for (int i = 0; i < 10; i++) { 17372 v8::Handle<v8::Object> c2 = v8::Handle<v8::Object>::Cast(script->Run()); 17373 CHECK_EQ(23, c2->Get(v8_str("x"))->Int32Value()); 17374 CHECK_EQ(42, c2->Get(v8_str("y"))->Int32Value()); 17375 } 17376 } 17377 17378 17379 TEST(Regress618) { 17380 const char* source = "function C1() {" 17381 " this.x = 23;" 17382 "};" 17383 "C1.prototype = P;"; 17384 17385 LocalContext context; 17386 v8::HandleScope scope(context->GetIsolate()); 17387 v8::Local<v8::Script> script; 17388 17389 // Use a simple object as prototype. 17390 v8::Local<v8::Object> prototype = v8::Object::New(); 17391 prototype->Set(v8_str("y"), v8_num(42)); 17392 context->Global()->Set(v8_str("P"), prototype); 17393 17394 // This compile will add the code to the compilation cache. 17395 CompileRun(source); 17396 17397 script = v8::Script::Compile(v8_str("new C1();")); 17398 // Allow enough iterations for the inobject slack tracking logic 17399 // to finalize instance size and install the fast construct stub. 17400 for (int i = 0; i < 256; i++) { 17401 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 17402 CHECK_EQ(23, c1->Get(v8_str("x"))->Int32Value()); 17403 CHECK_EQ(42, c1->Get(v8_str("y"))->Int32Value()); 17404 } 17405 17406 // Use an API object with accessors as prototype. 17407 Local<ObjectTemplate> templ = ObjectTemplate::New(); 17408 templ->SetAccessor(v8_str("x"), 17409 GetterWhichReturns42, 17410 SetterWhichSetsYOnThisTo23); 17411 context->Global()->Set(v8_str("P"), templ->NewInstance()); 17412 17413 // This compile will get the code from the compilation cache. 17414 CompileRun(source); 17415 17416 script = v8::Script::Compile(v8_str("new C1();")); 17417 for (int i = 0; i < 10; i++) { 17418 v8::Handle<v8::Object> c1 = v8::Handle<v8::Object>::Cast(script->Run()); 17419 CHECK_EQ(42, c1->Get(v8_str("x"))->Int32Value()); 17420 CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value()); 17421 } 17422 } 17423 17424 int prologue_call_count = 0; 17425 int epilogue_call_count = 0; 17426 int prologue_call_count_second = 0; 17427 int epilogue_call_count_second = 0; 17428 17429 void PrologueCallback(v8::GCType, v8::GCCallbackFlags) { 17430 ++prologue_call_count; 17431 } 17432 17433 17434 void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) { 17435 ++epilogue_call_count; 17436 } 17437 17438 17439 void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) { 17440 ++prologue_call_count_second; 17441 } 17442 17443 17444 void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) { 17445 ++epilogue_call_count_second; 17446 } 17447 17448 17449 TEST(GCCallbacks) { 17450 LocalContext context; 17451 17452 v8::V8::AddGCPrologueCallback(PrologueCallback); 17453 v8::V8::AddGCEpilogueCallback(EpilogueCallback); 17454 CHECK_EQ(0, prologue_call_count); 17455 CHECK_EQ(0, epilogue_call_count); 17456 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 17457 CHECK_EQ(1, prologue_call_count); 17458 CHECK_EQ(1, epilogue_call_count); 17459 v8::V8::AddGCPrologueCallback(PrologueCallbackSecond); 17460 v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond); 17461 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 17462 CHECK_EQ(2, prologue_call_count); 17463 CHECK_EQ(2, epilogue_call_count); 17464 CHECK_EQ(1, prologue_call_count_second); 17465 CHECK_EQ(1, epilogue_call_count_second); 17466 v8::V8::RemoveGCPrologueCallback(PrologueCallback); 17467 v8::V8::RemoveGCEpilogueCallback(EpilogueCallback); 17468 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 17469 CHECK_EQ(2, prologue_call_count); 17470 CHECK_EQ(2, epilogue_call_count); 17471 CHECK_EQ(2, prologue_call_count_second); 17472 CHECK_EQ(2, epilogue_call_count_second); 17473 v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond); 17474 v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond); 17475 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 17476 CHECK_EQ(2, prologue_call_count); 17477 CHECK_EQ(2, epilogue_call_count); 17478 CHECK_EQ(2, prologue_call_count_second); 17479 CHECK_EQ(2, epilogue_call_count_second); 17480 } 17481 17482 17483 THREADED_TEST(AddToJSFunctionResultCache) { 17484 i::FLAG_stress_compaction = false; 17485 i::FLAG_allow_natives_syntax = true; 17486 v8::HandleScope scope(v8::Isolate::GetCurrent()); 17487 17488 LocalContext context; 17489 17490 const char* code = 17491 "(function() {" 17492 " var key0 = 'a';" 17493 " var key1 = 'b';" 17494 " var r0 = %_GetFromCache(0, key0);" 17495 " var r1 = %_GetFromCache(0, key1);" 17496 " var r0_ = %_GetFromCache(0, key0);" 17497 " if (r0 !== r0_)" 17498 " return 'Different results for ' + key0 + ': ' + r0 + ' vs. ' + r0_;" 17499 " var r1_ = %_GetFromCache(0, key1);" 17500 " if (r1 !== r1_)" 17501 " return 'Different results for ' + key1 + ': ' + r1 + ' vs. ' + r1_;" 17502 " return 'PASSED';" 17503 "})()"; 17504 HEAP->ClearJSFunctionResultCaches(); 17505 ExpectString(code, "PASSED"); 17506 } 17507 17508 17509 static const int k0CacheSize = 16; 17510 17511 THREADED_TEST(FillJSFunctionResultCache) { 17512 i::FLAG_allow_natives_syntax = true; 17513 LocalContext context; 17514 v8::HandleScope scope(context->GetIsolate()); 17515 17516 const char* code = 17517 "(function() {" 17518 " var k = 'a';" 17519 " var r = %_GetFromCache(0, k);" 17520 " for (var i = 0; i < 16; i++) {" 17521 " %_GetFromCache(0, 'a' + i);" 17522 " };" 17523 " if (r === %_GetFromCache(0, k))" 17524 " return 'FAILED: k0CacheSize is too small';" 17525 " return 'PASSED';" 17526 "})()"; 17527 HEAP->ClearJSFunctionResultCaches(); 17528 ExpectString(code, "PASSED"); 17529 } 17530 17531 17532 THREADED_TEST(RoundRobinGetFromCache) { 17533 i::FLAG_allow_natives_syntax = true; 17534 LocalContext context; 17535 v8::HandleScope scope(context->GetIsolate()); 17536 17537 const char* code = 17538 "(function() {" 17539 " var keys = [];" 17540 " for (var i = 0; i < 16; i++) keys.push(i);" 17541 " var values = [];" 17542 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);" 17543 " for (var i = 0; i < 16; i++) {" 17544 " var v = %_GetFromCache(0, keys[i]);" 17545 " if (v.toString() !== values[i].toString())" 17546 " return 'Wrong value for ' + " 17547 " keys[i] + ': ' + v + ' vs. ' + values[i];" 17548 " };" 17549 " return 'PASSED';" 17550 "})()"; 17551 HEAP->ClearJSFunctionResultCaches(); 17552 ExpectString(code, "PASSED"); 17553 } 17554 17555 17556 THREADED_TEST(ReverseGetFromCache) { 17557 i::FLAG_allow_natives_syntax = true; 17558 LocalContext context; 17559 v8::HandleScope scope(context->GetIsolate()); 17560 17561 const char* code = 17562 "(function() {" 17563 " var keys = [];" 17564 " for (var i = 0; i < 16; i++) keys.push(i);" 17565 " var values = [];" 17566 " for (var i = 0; i < 16; i++) values[i] = %_GetFromCache(0, keys[i]);" 17567 " for (var i = 15; i >= 16; i--) {" 17568 " var v = %_GetFromCache(0, keys[i]);" 17569 " if (v !== values[i])" 17570 " return 'Wrong value for ' + " 17571 " keys[i] + ': ' + v + ' vs. ' + values[i];" 17572 " };" 17573 " return 'PASSED';" 17574 "})()"; 17575 HEAP->ClearJSFunctionResultCaches(); 17576 ExpectString(code, "PASSED"); 17577 } 17578 17579 17580 THREADED_TEST(TestEviction) { 17581 i::FLAG_allow_natives_syntax = true; 17582 LocalContext context; 17583 v8::HandleScope scope(context->GetIsolate()); 17584 17585 const char* code = 17586 "(function() {" 17587 " for (var i = 0; i < 2*16; i++) {" 17588 " %_GetFromCache(0, 'a' + i);" 17589 " };" 17590 " return 'PASSED';" 17591 "})()"; 17592 HEAP->ClearJSFunctionResultCaches(); 17593 ExpectString(code, "PASSED"); 17594 } 17595 17596 17597 THREADED_TEST(TwoByteStringInAsciiCons) { 17598 // See Chromium issue 47824. 17599 LocalContext context; 17600 v8::HandleScope scope(context->GetIsolate()); 17601 17602 const char* init_code = 17603 "var str1 = 'abelspendabel';" 17604 "var str2 = str1 + str1 + str1;" 17605 "str2;"; 17606 Local<Value> result = CompileRun(init_code); 17607 17608 Local<Value> indexof = CompileRun("str2.indexOf('els')"); 17609 Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')"); 17610 17611 CHECK(result->IsString()); 17612 i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result)); 17613 int length = string->length(); 17614 CHECK(string->IsOneByteRepresentation()); 17615 17616 FlattenString(string); 17617 i::Handle<i::String> flat_string = FlattenGetString(string); 17618 17619 CHECK(string->IsOneByteRepresentation()); 17620 CHECK(flat_string->IsOneByteRepresentation()); 17621 17622 // Create external resource. 17623 uint16_t* uc16_buffer = new uint16_t[length + 1]; 17624 17625 i::String::WriteToFlat(*flat_string, uc16_buffer, 0, length); 17626 uc16_buffer[length] = 0; 17627 17628 TestResource resource(uc16_buffer); 17629 17630 flat_string->MakeExternal(&resource); 17631 17632 CHECK(flat_string->IsTwoByteRepresentation()); 17633 17634 // If the cons string has been short-circuited, skip the following checks. 17635 if (!string.is_identical_to(flat_string)) { 17636 // At this point, we should have a Cons string which is flat and ASCII, 17637 // with a first half that is a two-byte string (although it only contains 17638 // ASCII characters). This is a valid sequence of steps, and it can happen 17639 // in real pages. 17640 CHECK(string->IsOneByteRepresentation()); 17641 i::ConsString* cons = i::ConsString::cast(*string); 17642 CHECK_EQ(0, cons->second()->length()); 17643 CHECK(cons->first()->IsTwoByteRepresentation()); 17644 } 17645 17646 // Check that some string operations work. 17647 17648 // Atom RegExp. 17649 Local<Value> reresult = CompileRun("str2.match(/abel/g).length;"); 17650 CHECK_EQ(6, reresult->Int32Value()); 17651 17652 // Nonatom RegExp. 17653 reresult = CompileRun("str2.match(/abe./g).length;"); 17654 CHECK_EQ(6, reresult->Int32Value()); 17655 17656 reresult = CompileRun("str2.search(/bel/g);"); 17657 CHECK_EQ(1, reresult->Int32Value()); 17658 17659 reresult = CompileRun("str2.search(/be./g);"); 17660 CHECK_EQ(1, reresult->Int32Value()); 17661 17662 ExpectTrue("/bel/g.test(str2);"); 17663 17664 ExpectTrue("/be./g.test(str2);"); 17665 17666 reresult = CompileRun("/bel/g.exec(str2);"); 17667 CHECK(!reresult->IsNull()); 17668 17669 reresult = CompileRun("/be./g.exec(str2);"); 17670 CHECK(!reresult->IsNull()); 17671 17672 ExpectString("str2.substring(2, 10);", "elspenda"); 17673 17674 ExpectString("str2.substring(2, 20);", "elspendabelabelspe"); 17675 17676 ExpectString("str2.charAt(2);", "e"); 17677 17678 ExpectObject("str2.indexOf('els');", indexof); 17679 17680 ExpectObject("str2.lastIndexOf('dab');", lastindexof); 17681 17682 reresult = CompileRun("str2.charCodeAt(2);"); 17683 CHECK_EQ(static_cast<int32_t>('e'), reresult->Int32Value()); 17684 } 17685 17686 17687 TEST(ContainsOnlyOneByte) { 17688 v8::V8::Initialize(); 17689 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 17690 v8::HandleScope scope(isolate); 17691 // Make a buffer long enough that it won't automatically be converted. 17692 const int length = 512; 17693 // Ensure word aligned assignment. 17694 const int aligned_length = length*sizeof(uintptr_t)/sizeof(uint16_t); 17695 i::SmartArrayPointer<uintptr_t> 17696 aligned_contents(new uintptr_t[aligned_length]); 17697 uint16_t* string_contents = reinterpret_cast<uint16_t*>(*aligned_contents); 17698 // Set to contain only one byte. 17699 for (int i = 0; i < length-1; i++) { 17700 string_contents[i] = 0x41; 17701 } 17702 string_contents[length-1] = 0; 17703 // Simple case. 17704 Handle<String> string; 17705 string = String::NewExternal(new TestResource(string_contents)); 17706 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 17707 // Counter example. 17708 string = String::NewFromTwoByte(isolate, string_contents); 17709 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte()); 17710 // Test left right and balanced cons strings. 17711 Handle<String> base = String::NewFromUtf8(isolate, "a"); 17712 Handle<String> left = base; 17713 Handle<String> right = base; 17714 for (int i = 0; i < 1000; i++) { 17715 left = String::Concat(base, left); 17716 right = String::Concat(right, base); 17717 } 17718 Handle<String> balanced = String::Concat(left, base); 17719 balanced = String::Concat(balanced, right); 17720 Handle<String> cons_strings[] = {left, balanced, right}; 17721 Handle<String> two_byte = 17722 String::NewExternal(new TestResource(string_contents)); 17723 for (size_t i = 0; i < ARRAY_SIZE(cons_strings); i++) { 17724 // Base assumptions. 17725 string = cons_strings[i]; 17726 CHECK(string->IsOneByte() && string->ContainsOnlyOneByte()); 17727 // Test left and right concatentation. 17728 string = String::Concat(two_byte, cons_strings[i]); 17729 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 17730 string = String::Concat(cons_strings[i], two_byte); 17731 CHECK(!string->IsOneByte() && string->ContainsOnlyOneByte()); 17732 } 17733 // Set bits in different positions 17734 // for strings of different lengths and alignments. 17735 for (int alignment = 0; alignment < 7; alignment++) { 17736 for (int size = 2; alignment + size < length; size *= 2) { 17737 int zero_offset = size + alignment; 17738 string_contents[zero_offset] = 0; 17739 for (int i = 0; i < size; i++) { 17740 int shift = 8 + (i % 7); 17741 string_contents[alignment + i] = 1 << shift; 17742 string = 17743 String::NewExternal(new TestResource(string_contents + alignment)); 17744 CHECK_EQ(size, string->Length()); 17745 CHECK(!string->ContainsOnlyOneByte()); 17746 string_contents[alignment + i] = 0x41; 17747 } 17748 string_contents[zero_offset] = 0x41; 17749 } 17750 } 17751 } 17752 17753 17754 // Failed access check callback that performs a GC on each invocation. 17755 void FailedAccessCheckCallbackGC(Local<v8::Object> target, 17756 v8::AccessType type, 17757 Local<v8::Value> data) { 17758 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 17759 } 17760 17761 17762 TEST(GCInFailedAccessCheckCallback) { 17763 // Install a failed access check callback that performs a GC on each 17764 // invocation. Then force the callback to be called from va 17765 17766 v8::V8::Initialize(); 17767 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckCallbackGC); 17768 17769 v8::HandleScope scope(v8::Isolate::GetCurrent()); 17770 17771 // Create an ObjectTemplate for global objects and install access 17772 // check callbacks that will block access. 17773 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 17774 global_template->SetAccessCheckCallbacks(NamedGetAccessBlocker, 17775 IndexedGetAccessBlocker, 17776 v8::Handle<v8::Value>(), 17777 false); 17778 17779 // Create a context and set an x property on it's global object. 17780 LocalContext context0(NULL, global_template); 17781 context0->Global()->Set(v8_str("x"), v8_num(42)); 17782 v8::Handle<v8::Object> global0 = context0->Global(); 17783 17784 // Create a context with a different security token so that the 17785 // failed access check callback will be called on each access. 17786 LocalContext context1(NULL, global_template); 17787 context1->Global()->Set(v8_str("other"), global0); 17788 17789 // Get property with failed access check. 17790 ExpectUndefined("other.x"); 17791 17792 // Get element with failed access check. 17793 ExpectUndefined("other[0]"); 17794 17795 // Set property with failed access check. 17796 v8::Handle<v8::Value> result = CompileRun("other.x = new Object()"); 17797 CHECK(result->IsObject()); 17798 17799 // Set element with failed access check. 17800 result = CompileRun("other[0] = new Object()"); 17801 CHECK(result->IsObject()); 17802 17803 // Get property attribute with failed access check. 17804 ExpectFalse("\'x\' in other"); 17805 17806 // Get property attribute for element with failed access check. 17807 ExpectFalse("0 in other"); 17808 17809 // Delete property. 17810 ExpectFalse("delete other.x"); 17811 17812 // Delete element. 17813 CHECK_EQ(false, global0->Delete(0)); 17814 17815 // DefineAccessor. 17816 CHECK_EQ(false, 17817 global0->SetAccessor(v8_str("x"), GetXValue, NULL, v8_str("x"))); 17818 17819 // Define JavaScript accessor. 17820 ExpectUndefined("Object.prototype.__defineGetter__.call(" 17821 " other, \'x\', function() { return 42; })"); 17822 17823 // LookupAccessor. 17824 ExpectUndefined("Object.prototype.__lookupGetter__.call(" 17825 " other, \'x\')"); 17826 17827 // HasLocalElement. 17828 ExpectFalse("Object.prototype.hasOwnProperty.call(other, \'0\')"); 17829 17830 CHECK_EQ(false, global0->HasRealIndexedProperty(0)); 17831 CHECK_EQ(false, global0->HasRealNamedProperty(v8_str("x"))); 17832 CHECK_EQ(false, global0->HasRealNamedCallbackProperty(v8_str("x"))); 17833 17834 // Reset the failed access check callback so it does not influence 17835 // the other tests. 17836 v8::V8::SetFailedAccessCheckCallbackFunction(NULL); 17837 } 17838 17839 17840 TEST(DefaultIsolateGetCurrent) { 17841 CHECK(v8::Isolate::GetCurrent() != NULL); 17842 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 17843 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate()); 17844 printf("*** %s\n", "DefaultIsolateGetCurrent success"); 17845 } 17846 17847 17848 TEST(IsolateNewDispose) { 17849 v8::Isolate* current_isolate = v8::Isolate::GetCurrent(); 17850 v8::Isolate* isolate = v8::Isolate::New(); 17851 CHECK(isolate != NULL); 17852 CHECK(!reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate()); 17853 CHECK(current_isolate != isolate); 17854 CHECK(current_isolate == v8::Isolate::GetCurrent()); 17855 17856 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 17857 last_location = last_message = NULL; 17858 isolate->Dispose(); 17859 CHECK_EQ(last_location, NULL); 17860 CHECK_EQ(last_message, NULL); 17861 } 17862 17863 17864 TEST(IsolateEnterExitDefault) { 17865 v8::Isolate* current_isolate = v8::Isolate::GetCurrent(); 17866 CHECK(current_isolate != NULL); // Default isolate. 17867 v8::HandleScope scope(current_isolate); 17868 LocalContext context; 17869 ExpectString("'hello'", "hello"); 17870 current_isolate->Enter(); 17871 ExpectString("'still working'", "still working"); 17872 current_isolate->Exit(); 17873 ExpectString("'still working 2'", "still working 2"); 17874 current_isolate->Exit(); 17875 // Default isolate is always, well, 'default current'. 17876 CHECK_EQ(v8::Isolate::GetCurrent(), current_isolate); 17877 // Still working since default isolate is auto-entering any thread 17878 // that has no isolate and attempts to execute V8 APIs. 17879 ExpectString("'still working 3'", "still working 3"); 17880 } 17881 17882 17883 TEST(DisposeDefaultIsolate) { 17884 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 17885 17886 // Run some V8 code to trigger default isolate to become 'current'. 17887 v8::HandleScope scope(v8::Isolate::GetCurrent()); 17888 LocalContext context; 17889 ExpectString("'run some V8'", "run some V8"); 17890 17891 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 17892 CHECK(reinterpret_cast<i::Isolate*>(isolate)->IsDefaultIsolate()); 17893 last_location = last_message = NULL; 17894 isolate->Dispose(); 17895 // It is not possible to dispose default isolate via Isolate API. 17896 CHECK_NE(last_location, NULL); 17897 CHECK_NE(last_message, NULL); 17898 } 17899 17900 17901 TEST(RunDefaultAndAnotherIsolate) { 17902 v8::HandleScope scope(v8::Isolate::GetCurrent()); 17903 LocalContext context; 17904 17905 // Enter new isolate. 17906 v8::Isolate* isolate = v8::Isolate::New(); 17907 CHECK(isolate); 17908 isolate->Enter(); 17909 { // Need this block because subsequent Exit() will deallocate Heap, 17910 // so we need all scope objects to be deconstructed when it happens. 17911 v8::HandleScope scope_new(isolate); 17912 LocalContext context_new; 17913 17914 // Run something in new isolate. 17915 CompileRun("var foo = 153;"); 17916 ExpectTrue("function f() { return foo == 153; }; f()"); 17917 } 17918 isolate->Exit(); 17919 17920 // This runs automatically in default isolate. 17921 // Variables in another isolate should be not available. 17922 ExpectTrue("function f() {" 17923 " try {" 17924 " foo;" 17925 " return false;" 17926 " } catch(e) {" 17927 " return true;" 17928 " }" 17929 "};" 17930 "var bar = 371;" 17931 "f()"); 17932 17933 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 17934 last_location = last_message = NULL; 17935 isolate->Dispose(); 17936 CHECK_EQ(last_location, NULL); 17937 CHECK_EQ(last_message, NULL); 17938 17939 // Check that default isolate still runs. 17940 ExpectTrue("function f() { return bar == 371; }; f()"); 17941 } 17942 17943 17944 TEST(DisposeIsolateWhenInUse) { 17945 v8::Isolate* isolate = v8::Isolate::New(); 17946 CHECK(isolate); 17947 isolate->Enter(); 17948 v8::HandleScope scope(isolate); 17949 LocalContext context; 17950 // Run something in this isolate. 17951 ExpectTrue("true"); 17952 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 17953 last_location = last_message = NULL; 17954 // Still entered, should fail. 17955 isolate->Dispose(); 17956 CHECK_NE(last_location, NULL); 17957 CHECK_NE(last_message, NULL); 17958 } 17959 17960 17961 TEST(RunTwoIsolatesOnSingleThread) { 17962 // Run isolate 1. 17963 v8::Isolate* isolate1 = v8::Isolate::New(); 17964 isolate1->Enter(); 17965 v8::Persistent<v8::Context> context1; 17966 { 17967 v8::HandleScope scope(isolate1); 17968 context1.Reset(isolate1, Context::New(isolate1)); 17969 } 17970 17971 { 17972 v8::HandleScope scope(isolate1); 17973 v8::Local<v8::Context> context = 17974 v8::Local<v8::Context>::New(isolate1, context1); 17975 v8::Context::Scope context_scope(context); 17976 // Run something in new isolate. 17977 CompileRun("var foo = 'isolate 1';"); 17978 ExpectString("function f() { return foo; }; f()", "isolate 1"); 17979 } 17980 17981 // Run isolate 2. 17982 v8::Isolate* isolate2 = v8::Isolate::New(); 17983 v8::Persistent<v8::Context> context2; 17984 17985 { 17986 v8::Isolate::Scope iscope(isolate2); 17987 v8::HandleScope scope(isolate2); 17988 context2.Reset(isolate2, Context::New(isolate2)); 17989 v8::Local<v8::Context> context = 17990 v8::Local<v8::Context>::New(isolate2, context2); 17991 v8::Context::Scope context_scope(context); 17992 17993 // Run something in new isolate. 17994 CompileRun("var foo = 'isolate 2';"); 17995 ExpectString("function f() { return foo; }; f()", "isolate 2"); 17996 } 17997 17998 { 17999 v8::HandleScope scope(isolate1); 18000 v8::Local<v8::Context> context = 18001 v8::Local<v8::Context>::New(isolate1, context1); 18002 v8::Context::Scope context_scope(context); 18003 // Now again in isolate 1 18004 ExpectString("function f() { return foo; }; f()", "isolate 1"); 18005 } 18006 18007 isolate1->Exit(); 18008 18009 // Run some stuff in default isolate. 18010 v8::Persistent<v8::Context> context_default; 18011 { 18012 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 18013 v8::Isolate::Scope iscope(isolate); 18014 v8::HandleScope scope(isolate); 18015 context_default.Reset(isolate, Context::New(isolate)); 18016 } 18017 18018 { 18019 v8::HandleScope scope(v8::Isolate::GetCurrent()); 18020 v8::Local<v8::Context> context = 18021 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context_default); 18022 v8::Context::Scope context_scope(context); 18023 // Variables in other isolates should be not available, verify there 18024 // is an exception. 18025 ExpectTrue("function f() {" 18026 " try {" 18027 " foo;" 18028 " return false;" 18029 " } catch(e) {" 18030 " return true;" 18031 " }" 18032 "};" 18033 "var isDefaultIsolate = true;" 18034 "f()"); 18035 } 18036 18037 isolate1->Enter(); 18038 18039 { 18040 v8::Isolate::Scope iscope(isolate2); 18041 v8::HandleScope scope(v8::Isolate::GetCurrent()); 18042 v8::Local<v8::Context> context = 18043 v8::Local<v8::Context>::New(isolate2, context2); 18044 v8::Context::Scope context_scope(context); 18045 ExpectString("function f() { return foo; }; f()", "isolate 2"); 18046 } 18047 18048 { 18049 v8::HandleScope scope(v8::Isolate::GetCurrent()); 18050 v8::Local<v8::Context> context = 18051 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context1); 18052 v8::Context::Scope context_scope(context); 18053 ExpectString("function f() { return foo; }; f()", "isolate 1"); 18054 } 18055 18056 { 18057 v8::Isolate::Scope iscope(isolate2); 18058 context2.Dispose(); 18059 } 18060 18061 context1.Dispose(); 18062 isolate1->Exit(); 18063 18064 v8::V8::SetFatalErrorHandler(StoringErrorCallback); 18065 last_location = last_message = NULL; 18066 18067 isolate1->Dispose(); 18068 CHECK_EQ(last_location, NULL); 18069 CHECK_EQ(last_message, NULL); 18070 18071 isolate2->Dispose(); 18072 CHECK_EQ(last_location, NULL); 18073 CHECK_EQ(last_message, NULL); 18074 18075 // Check that default isolate still runs. 18076 { 18077 v8::HandleScope scope(v8::Isolate::GetCurrent()); 18078 v8::Local<v8::Context> context = 18079 v8::Local<v8::Context>::New(v8::Isolate::GetCurrent(), context_default); 18080 v8::Context::Scope context_scope(context); 18081 ExpectTrue("function f() { return isDefaultIsolate; }; f()"); 18082 } 18083 } 18084 18085 18086 static int CalcFibonacci(v8::Isolate* isolate, int limit) { 18087 v8::Isolate::Scope isolate_scope(isolate); 18088 v8::HandleScope scope(isolate); 18089 LocalContext context; 18090 i::ScopedVector<char> code(1024); 18091 i::OS::SNPrintF(code, "function fib(n) {" 18092 " if (n <= 2) return 1;" 18093 " return fib(n-1) + fib(n-2);" 18094 "}" 18095 "fib(%d)", limit); 18096 Local<Value> value = CompileRun(code.start()); 18097 CHECK(value->IsNumber()); 18098 return static_cast<int>(value->NumberValue()); 18099 } 18100 18101 class IsolateThread : public v8::internal::Thread { 18102 public: 18103 IsolateThread(v8::Isolate* isolate, int fib_limit) 18104 : Thread("IsolateThread"), 18105 isolate_(isolate), 18106 fib_limit_(fib_limit), 18107 result_(0) { } 18108 18109 void Run() { 18110 result_ = CalcFibonacci(isolate_, fib_limit_); 18111 } 18112 18113 int result() { return result_; } 18114 18115 private: 18116 v8::Isolate* isolate_; 18117 int fib_limit_; 18118 int result_; 18119 }; 18120 18121 18122 TEST(MultipleIsolatesOnIndividualThreads) { 18123 v8::Isolate* isolate1 = v8::Isolate::New(); 18124 v8::Isolate* isolate2 = v8::Isolate::New(); 18125 18126 IsolateThread thread1(isolate1, 21); 18127 IsolateThread thread2(isolate2, 12); 18128 18129 // Compute some fibonacci numbers on 3 threads in 3 isolates. 18130 thread1.Start(); 18131 thread2.Start(); 18132 18133 int result1 = CalcFibonacci(v8::Isolate::GetCurrent(), 21); 18134 int result2 = CalcFibonacci(v8::Isolate::GetCurrent(), 12); 18135 18136 thread1.Join(); 18137 thread2.Join(); 18138 18139 // Compare results. The actual fibonacci numbers for 12 and 21 are taken 18140 // (I'm lazy!) from http://en.wikipedia.org/wiki/Fibonacci_number 18141 CHECK_EQ(result1, 10946); 18142 CHECK_EQ(result2, 144); 18143 CHECK_EQ(result1, thread1.result()); 18144 CHECK_EQ(result2, thread2.result()); 18145 18146 isolate1->Dispose(); 18147 isolate2->Dispose(); 18148 } 18149 18150 18151 TEST(IsolateDifferentContexts) { 18152 v8::Isolate* isolate = v8::Isolate::New(); 18153 Local<v8::Context> context; 18154 { 18155 v8::Isolate::Scope isolate_scope(isolate); 18156 v8::HandleScope handle_scope(isolate); 18157 context = v8::Context::New(isolate); 18158 v8::Context::Scope context_scope(context); 18159 Local<Value> v = CompileRun("2"); 18160 CHECK(v->IsNumber()); 18161 CHECK_EQ(2, static_cast<int>(v->NumberValue())); 18162 } 18163 { 18164 v8::Isolate::Scope isolate_scope(isolate); 18165 v8::HandleScope handle_scope(isolate); 18166 context = v8::Context::New(isolate); 18167 v8::Context::Scope context_scope(context); 18168 Local<Value> v = CompileRun("22"); 18169 CHECK(v->IsNumber()); 18170 CHECK_EQ(22, static_cast<int>(v->NumberValue())); 18171 } 18172 } 18173 18174 class InitDefaultIsolateThread : public v8::internal::Thread { 18175 public: 18176 enum TestCase { 18177 IgnoreOOM, 18178 SetResourceConstraints, 18179 SetFatalHandler, 18180 SetCounterFunction, 18181 SetCreateHistogramFunction, 18182 SetAddHistogramSampleFunction 18183 }; 18184 18185 explicit InitDefaultIsolateThread(TestCase testCase) 18186 : Thread("InitDefaultIsolateThread"), 18187 testCase_(testCase), 18188 result_(false) { } 18189 18190 void Run() { 18191 switch (testCase_) { 18192 case IgnoreOOM: 18193 v8::V8::IgnoreOutOfMemoryException(); 18194 break; 18195 18196 case SetResourceConstraints: { 18197 static const int K = 1024; 18198 v8::ResourceConstraints constraints; 18199 constraints.set_max_young_space_size(256 * K); 18200 constraints.set_max_old_space_size(4 * K * K); 18201 v8::SetResourceConstraints(&constraints); 18202 break; 18203 } 18204 18205 case SetFatalHandler: 18206 v8::V8::SetFatalErrorHandler(NULL); 18207 break; 18208 18209 case SetCounterFunction: 18210 v8::V8::SetCounterFunction(NULL); 18211 break; 18212 18213 case SetCreateHistogramFunction: 18214 v8::V8::SetCreateHistogramFunction(NULL); 18215 break; 18216 18217 case SetAddHistogramSampleFunction: 18218 v8::V8::SetAddHistogramSampleFunction(NULL); 18219 break; 18220 } 18221 result_ = true; 18222 } 18223 18224 bool result() { return result_; } 18225 18226 private: 18227 TestCase testCase_; 18228 bool result_; 18229 }; 18230 18231 18232 static void InitializeTestHelper(InitDefaultIsolateThread::TestCase testCase) { 18233 InitDefaultIsolateThread thread(testCase); 18234 thread.Start(); 18235 thread.Join(); 18236 CHECK_EQ(thread.result(), true); 18237 } 18238 18239 18240 TEST(InitializeDefaultIsolateOnSecondaryThread1) { 18241 InitializeTestHelper(InitDefaultIsolateThread::IgnoreOOM); 18242 } 18243 18244 18245 TEST(InitializeDefaultIsolateOnSecondaryThread2) { 18246 InitializeTestHelper(InitDefaultIsolateThread::SetResourceConstraints); 18247 } 18248 18249 18250 TEST(InitializeDefaultIsolateOnSecondaryThread3) { 18251 InitializeTestHelper(InitDefaultIsolateThread::SetFatalHandler); 18252 } 18253 18254 18255 TEST(InitializeDefaultIsolateOnSecondaryThread4) { 18256 InitializeTestHelper(InitDefaultIsolateThread::SetCounterFunction); 18257 } 18258 18259 18260 TEST(InitializeDefaultIsolateOnSecondaryThread5) { 18261 InitializeTestHelper(InitDefaultIsolateThread::SetCreateHistogramFunction); 18262 } 18263 18264 18265 TEST(InitializeDefaultIsolateOnSecondaryThread6) { 18266 InitializeTestHelper(InitDefaultIsolateThread::SetAddHistogramSampleFunction); 18267 } 18268 18269 18270 TEST(StringCheckMultipleContexts) { 18271 const char* code = 18272 "(function() { return \"a\".charAt(0); })()"; 18273 18274 { 18275 // Run the code twice in the first context to initialize the call IC. 18276 LocalContext context1; 18277 v8::HandleScope scope(context1->GetIsolate()); 18278 ExpectString(code, "a"); 18279 ExpectString(code, "a"); 18280 } 18281 18282 { 18283 // Change the String.prototype in the second context and check 18284 // that the right function gets called. 18285 LocalContext context2; 18286 v8::HandleScope scope(context2->GetIsolate()); 18287 CompileRun("String.prototype.charAt = function() { return \"not a\"; }"); 18288 ExpectString(code, "not a"); 18289 } 18290 } 18291 18292 18293 TEST(NumberCheckMultipleContexts) { 18294 const char* code = 18295 "(function() { return (42).toString(); })()"; 18296 18297 { 18298 // Run the code twice in the first context to initialize the call IC. 18299 LocalContext context1; 18300 v8::HandleScope scope(context1->GetIsolate()); 18301 ExpectString(code, "42"); 18302 ExpectString(code, "42"); 18303 } 18304 18305 { 18306 // Change the Number.prototype in the second context and check 18307 // that the right function gets called. 18308 LocalContext context2; 18309 v8::HandleScope scope(context2->GetIsolate()); 18310 CompileRun("Number.prototype.toString = function() { return \"not 42\"; }"); 18311 ExpectString(code, "not 42"); 18312 } 18313 } 18314 18315 18316 TEST(BooleanCheckMultipleContexts) { 18317 const char* code = 18318 "(function() { return true.toString(); })()"; 18319 18320 { 18321 // Run the code twice in the first context to initialize the call IC. 18322 LocalContext context1; 18323 v8::HandleScope scope(context1->GetIsolate()); 18324 ExpectString(code, "true"); 18325 ExpectString(code, "true"); 18326 } 18327 18328 { 18329 // Change the Boolean.prototype in the second context and check 18330 // that the right function gets called. 18331 LocalContext context2; 18332 v8::HandleScope scope(context2->GetIsolate()); 18333 CompileRun("Boolean.prototype.toString = function() { return \"\"; }"); 18334 ExpectString(code, ""); 18335 } 18336 } 18337 18338 18339 TEST(DontDeleteCellLoadIC) { 18340 const char* function_code = 18341 "function readCell() { while (true) { return cell; } }"; 18342 18343 { 18344 // Run the code twice in the first context to initialize the load 18345 // IC for a don't delete cell. 18346 LocalContext context1; 18347 v8::HandleScope scope(context1->GetIsolate()); 18348 CompileRun("var cell = \"first\";"); 18349 ExpectBoolean("delete cell", false); 18350 CompileRun(function_code); 18351 ExpectString("readCell()", "first"); 18352 ExpectString("readCell()", "first"); 18353 } 18354 18355 { 18356 // Use a deletable cell in the second context. 18357 LocalContext context2; 18358 v8::HandleScope scope(context2->GetIsolate()); 18359 CompileRun("cell = \"second\";"); 18360 CompileRun(function_code); 18361 ExpectString("readCell()", "second"); 18362 ExpectBoolean("delete cell", true); 18363 ExpectString("(function() {" 18364 " try {" 18365 " return readCell();" 18366 " } catch(e) {" 18367 " return e.toString();" 18368 " }" 18369 "})()", 18370 "ReferenceError: cell is not defined"); 18371 CompileRun("cell = \"new_second\";"); 18372 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 18373 ExpectString("readCell()", "new_second"); 18374 ExpectString("readCell()", "new_second"); 18375 } 18376 } 18377 18378 18379 TEST(DontDeleteCellLoadICForceDelete) { 18380 const char* function_code = 18381 "function readCell() { while (true) { return cell; } }"; 18382 18383 // Run the code twice to initialize the load IC for a don't delete 18384 // cell. 18385 LocalContext context; 18386 v8::HandleScope scope(context->GetIsolate()); 18387 CompileRun("var cell = \"value\";"); 18388 ExpectBoolean("delete cell", false); 18389 CompileRun(function_code); 18390 ExpectString("readCell()", "value"); 18391 ExpectString("readCell()", "value"); 18392 18393 // Delete the cell using the API and check the inlined code works 18394 // correctly. 18395 CHECK(context->Global()->ForceDelete(v8_str("cell"))); 18396 ExpectString("(function() {" 18397 " try {" 18398 " return readCell();" 18399 " } catch(e) {" 18400 " return e.toString();" 18401 " }" 18402 "})()", 18403 "ReferenceError: cell is not defined"); 18404 } 18405 18406 18407 TEST(DontDeleteCellLoadICAPI) { 18408 const char* function_code = 18409 "function readCell() { while (true) { return cell; } }"; 18410 18411 // Run the code twice to initialize the load IC for a don't delete 18412 // cell created using the API. 18413 LocalContext context; 18414 v8::HandleScope scope(context->GetIsolate()); 18415 context->Global()->Set(v8_str("cell"), v8_str("value"), v8::DontDelete); 18416 ExpectBoolean("delete cell", false); 18417 CompileRun(function_code); 18418 ExpectString("readCell()", "value"); 18419 ExpectString("readCell()", "value"); 18420 18421 // Delete the cell using the API and check the inlined code works 18422 // correctly. 18423 CHECK(context->Global()->ForceDelete(v8_str("cell"))); 18424 ExpectString("(function() {" 18425 " try {" 18426 " return readCell();" 18427 " } catch(e) {" 18428 " return e.toString();" 18429 " }" 18430 "})()", 18431 "ReferenceError: cell is not defined"); 18432 } 18433 18434 18435 class Visitor42 : public v8::PersistentHandleVisitor { 18436 public: 18437 explicit Visitor42(v8::Persistent<v8::Object>* object) 18438 : counter_(0), object_(object) { } 18439 18440 virtual void VisitPersistentHandle(Persistent<Value>* value, 18441 uint16_t class_id) { 18442 if (class_id != 42) return; 18443 CHECK_EQ(42, value->WrapperClassId()); 18444 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 18445 v8::HandleScope handle_scope(isolate); 18446 v8::Handle<v8::Value> handle = v8::Local<v8::Value>::New(isolate, *value); 18447 v8::Handle<v8::Value> object = 18448 v8::Local<v8::Object>::New(isolate, *object_); 18449 CHECK(handle->IsObject()); 18450 CHECK_EQ(Handle<Object>::Cast(handle), object); 18451 ++counter_; 18452 } 18453 18454 int counter_; 18455 v8::Persistent<v8::Object>* object_; 18456 }; 18457 18458 18459 TEST(PersistentHandleVisitor) { 18460 LocalContext context; 18461 v8::Isolate* isolate = context->GetIsolate(); 18462 v8::HandleScope scope(isolate); 18463 v8::Persistent<v8::Object> object(isolate, v8::Object::New()); 18464 CHECK_EQ(0, object.WrapperClassId(isolate)); 18465 object.SetWrapperClassId(isolate, 42); 18466 CHECK_EQ(42, object.WrapperClassId(isolate)); 18467 18468 Visitor42 visitor(&object); 18469 v8::V8::VisitHandlesWithClassIds(&visitor); 18470 CHECK_EQ(1, visitor.counter_); 18471 18472 object.Dispose(isolate); 18473 } 18474 18475 18476 TEST(WrapperClassId) { 18477 LocalContext context; 18478 v8::Isolate* isolate = context->GetIsolate(); 18479 v8::HandleScope scope(isolate); 18480 v8::Persistent<v8::Object> object(isolate, v8::Object::New()); 18481 CHECK_EQ(0, object.WrapperClassId(isolate)); 18482 object.SetWrapperClassId(isolate, 65535); 18483 CHECK_EQ(65535, object.WrapperClassId(isolate)); 18484 object.Dispose(isolate); 18485 } 18486 18487 18488 TEST(PersistentHandleInNewSpaceVisitor) { 18489 LocalContext context; 18490 v8::Isolate* isolate = context->GetIsolate(); 18491 v8::HandleScope scope(isolate); 18492 v8::Persistent<v8::Object> object1(isolate, v8::Object::New()); 18493 CHECK_EQ(0, object1.WrapperClassId(isolate)); 18494 object1.SetWrapperClassId(isolate, 42); 18495 CHECK_EQ(42, object1.WrapperClassId(isolate)); 18496 18497 HEAP->CollectAllGarbage(i::Heap::kNoGCFlags); 18498 18499 v8::Persistent<v8::Object> object2(isolate, v8::Object::New()); 18500 CHECK_EQ(0, object2.WrapperClassId(isolate)); 18501 object2.SetWrapperClassId(isolate, 42); 18502 CHECK_EQ(42, object2.WrapperClassId(isolate)); 18503 18504 Visitor42 visitor(&object2); 18505 v8::V8::VisitHandlesForPartialDependence(isolate, &visitor); 18506 CHECK_EQ(1, visitor.counter_); 18507 18508 object1.Dispose(isolate); 18509 object2.Dispose(isolate); 18510 } 18511 18512 18513 TEST(RegExp) { 18514 LocalContext context; 18515 v8::HandleScope scope(context->GetIsolate()); 18516 18517 v8::Handle<v8::RegExp> re = v8::RegExp::New(v8_str("foo"), v8::RegExp::kNone); 18518 CHECK(re->IsRegExp()); 18519 CHECK(re->GetSource()->Equals(v8_str("foo"))); 18520 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 18521 18522 re = v8::RegExp::New(v8_str("bar"), 18523 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 18524 v8::RegExp::kGlobal)); 18525 CHECK(re->IsRegExp()); 18526 CHECK(re->GetSource()->Equals(v8_str("bar"))); 18527 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kGlobal, 18528 static_cast<int>(re->GetFlags())); 18529 18530 re = v8::RegExp::New(v8_str("baz"), 18531 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 18532 v8::RegExp::kMultiline)); 18533 CHECK(re->IsRegExp()); 18534 CHECK(re->GetSource()->Equals(v8_str("baz"))); 18535 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline, 18536 static_cast<int>(re->GetFlags())); 18537 18538 re = CompileRun("/quux/").As<v8::RegExp>(); 18539 CHECK(re->IsRegExp()); 18540 CHECK(re->GetSource()->Equals(v8_str("quux"))); 18541 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 18542 18543 re = CompileRun("/quux/gm").As<v8::RegExp>(); 18544 CHECK(re->IsRegExp()); 18545 CHECK(re->GetSource()->Equals(v8_str("quux"))); 18546 CHECK_EQ(v8::RegExp::kGlobal | v8::RegExp::kMultiline, 18547 static_cast<int>(re->GetFlags())); 18548 18549 // Override the RegExp constructor and check the API constructor 18550 // still works. 18551 CompileRun("RegExp = function() {}"); 18552 18553 re = v8::RegExp::New(v8_str("foobar"), v8::RegExp::kNone); 18554 CHECK(re->IsRegExp()); 18555 CHECK(re->GetSource()->Equals(v8_str("foobar"))); 18556 CHECK_EQ(v8::RegExp::kNone, re->GetFlags()); 18557 18558 re = v8::RegExp::New(v8_str("foobarbaz"), 18559 static_cast<v8::RegExp::Flags>(v8::RegExp::kIgnoreCase | 18560 v8::RegExp::kMultiline)); 18561 CHECK(re->IsRegExp()); 18562 CHECK(re->GetSource()->Equals(v8_str("foobarbaz"))); 18563 CHECK_EQ(v8::RegExp::kIgnoreCase | v8::RegExp::kMultiline, 18564 static_cast<int>(re->GetFlags())); 18565 18566 context->Global()->Set(v8_str("re"), re); 18567 ExpectTrue("re.test('FoobarbaZ')"); 18568 18569 // RegExps are objects on which you can set properties. 18570 re->Set(v8_str("property"), v8::Integer::New(32)); 18571 v8::Handle<v8::Value> value(CompileRun("re.property")); 18572 CHECK_EQ(32, value->Int32Value()); 18573 18574 v8::TryCatch try_catch; 18575 re = v8::RegExp::New(v8_str("foo["), v8::RegExp::kNone); 18576 CHECK(re.IsEmpty()); 18577 CHECK(try_catch.HasCaught()); 18578 context->Global()->Set(v8_str("ex"), try_catch.Exception()); 18579 ExpectTrue("ex instanceof SyntaxError"); 18580 } 18581 18582 18583 THREADED_TEST(Equals) { 18584 LocalContext localContext; 18585 v8::HandleScope handleScope(localContext->GetIsolate()); 18586 18587 v8::Handle<v8::Object> globalProxy = localContext->Global(); 18588 v8::Handle<Value> global = globalProxy->GetPrototype(); 18589 18590 CHECK(global->StrictEquals(global)); 18591 CHECK(!global->StrictEquals(globalProxy)); 18592 CHECK(!globalProxy->StrictEquals(global)); 18593 CHECK(globalProxy->StrictEquals(globalProxy)); 18594 18595 CHECK(global->Equals(global)); 18596 CHECK(!global->Equals(globalProxy)); 18597 CHECK(!globalProxy->Equals(global)); 18598 CHECK(globalProxy->Equals(globalProxy)); 18599 } 18600 18601 18602 static void Getter(v8::Local<v8::String> property, 18603 const v8::PropertyCallbackInfo<v8::Value>& info ) { 18604 info.GetReturnValue().Set(v8_str("42!")); 18605 } 18606 18607 18608 static void Enumerator(const v8::PropertyCallbackInfo<v8::Array>& info) { 18609 v8::Handle<v8::Array> result = v8::Array::New(); 18610 result->Set(0, v8_str("universalAnswer")); 18611 info.GetReturnValue().Set(result); 18612 } 18613 18614 18615 TEST(NamedEnumeratorAndForIn) { 18616 LocalContext context; 18617 v8::HandleScope handle_scope(context->GetIsolate()); 18618 v8::Context::Scope context_scope(context.local()); 18619 18620 v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(); 18621 tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator); 18622 context->Global()->Set(v8_str("o"), tmpl->NewInstance()); 18623 v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun( 18624 "var result = []; for (var k in o) result.push(k); result")); 18625 CHECK_EQ(1, result->Length()); 18626 CHECK_EQ(v8_str("universalAnswer"), result->Get(0)); 18627 } 18628 18629 18630 TEST(DefinePropertyPostDetach) { 18631 LocalContext context; 18632 v8::HandleScope scope(context->GetIsolate()); 18633 v8::Handle<v8::Object> proxy = context->Global(); 18634 v8::Handle<v8::Function> define_property = 18635 CompileRun("(function() {" 18636 " Object.defineProperty(" 18637 " this," 18638 " 1," 18639 " { configurable: true, enumerable: true, value: 3 });" 18640 "})").As<Function>(); 18641 context->DetachGlobal(); 18642 define_property->Call(proxy, 0, NULL); 18643 } 18644 18645 18646 static void InstallContextId(v8::Handle<Context> context, int id) { 18647 Context::Scope scope(context); 18648 CompileRun("Object.prototype").As<Object>()-> 18649 Set(v8_str("context_id"), v8::Integer::New(id)); 18650 } 18651 18652 18653 static void CheckContextId(v8::Handle<Object> object, int expected) { 18654 CHECK_EQ(expected, object->Get(v8_str("context_id"))->Int32Value()); 18655 } 18656 18657 18658 THREADED_TEST(CreationContext) { 18659 HandleScope handle_scope(v8::Isolate::GetCurrent()); 18660 Handle<Context> context1 = Context::New(v8::Isolate::GetCurrent()); 18661 InstallContextId(context1, 1); 18662 Handle<Context> context2 = Context::New(v8::Isolate::GetCurrent()); 18663 InstallContextId(context2, 2); 18664 Handle<Context> context3 = Context::New(v8::Isolate::GetCurrent()); 18665 InstallContextId(context3, 3); 18666 18667 Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(); 18668 18669 Local<Object> object1; 18670 Local<Function> func1; 18671 { 18672 Context::Scope scope(context1); 18673 object1 = Object::New(); 18674 func1 = tmpl->GetFunction(); 18675 } 18676 18677 Local<Object> object2; 18678 Local<Function> func2; 18679 { 18680 Context::Scope scope(context2); 18681 object2 = Object::New(); 18682 func2 = tmpl->GetFunction(); 18683 } 18684 18685 Local<Object> instance1; 18686 Local<Object> instance2; 18687 18688 { 18689 Context::Scope scope(context3); 18690 instance1 = func1->NewInstance(); 18691 instance2 = func2->NewInstance(); 18692 } 18693 18694 CHECK(object1->CreationContext() == context1); 18695 CheckContextId(object1, 1); 18696 CHECK(func1->CreationContext() == context1); 18697 CheckContextId(func1, 1); 18698 CHECK(instance1->CreationContext() == context1); 18699 CheckContextId(instance1, 1); 18700 CHECK(object2->CreationContext() == context2); 18701 CheckContextId(object2, 2); 18702 CHECK(func2->CreationContext() == context2); 18703 CheckContextId(func2, 2); 18704 CHECK(instance2->CreationContext() == context2); 18705 CheckContextId(instance2, 2); 18706 18707 { 18708 Context::Scope scope(context1); 18709 CHECK(object1->CreationContext() == context1); 18710 CheckContextId(object1, 1); 18711 CHECK(func1->CreationContext() == context1); 18712 CheckContextId(func1, 1); 18713 CHECK(instance1->CreationContext() == context1); 18714 CheckContextId(instance1, 1); 18715 CHECK(object2->CreationContext() == context2); 18716 CheckContextId(object2, 2); 18717 CHECK(func2->CreationContext() == context2); 18718 CheckContextId(func2, 2); 18719 CHECK(instance2->CreationContext() == context2); 18720 CheckContextId(instance2, 2); 18721 } 18722 18723 { 18724 Context::Scope scope(context2); 18725 CHECK(object1->CreationContext() == context1); 18726 CheckContextId(object1, 1); 18727 CHECK(func1->CreationContext() == context1); 18728 CheckContextId(func1, 1); 18729 CHECK(instance1->CreationContext() == context1); 18730 CheckContextId(instance1, 1); 18731 CHECK(object2->CreationContext() == context2); 18732 CheckContextId(object2, 2); 18733 CHECK(func2->CreationContext() == context2); 18734 CheckContextId(func2, 2); 18735 CHECK(instance2->CreationContext() == context2); 18736 CheckContextId(instance2, 2); 18737 } 18738 } 18739 18740 18741 THREADED_TEST(CreationContextOfJsFunction) { 18742 HandleScope handle_scope(v8::Isolate::GetCurrent()); 18743 Handle<Context> context = Context::New(v8::Isolate::GetCurrent()); 18744 InstallContextId(context, 1); 18745 18746 Local<Object> function; 18747 { 18748 Context::Scope scope(context); 18749 function = CompileRun("function foo() {}; foo").As<Object>(); 18750 } 18751 18752 CHECK(function->CreationContext() == context); 18753 CheckContextId(function, 1); 18754 } 18755 18756 18757 void HasOwnPropertyIndexedPropertyGetter( 18758 uint32_t index, 18759 const v8::PropertyCallbackInfo<v8::Value>& info) { 18760 if (index == 42) info.GetReturnValue().Set(v8_str("yes")); 18761 } 18762 18763 18764 void HasOwnPropertyNamedPropertyGetter( 18765 Local<String> property, 18766 const v8::PropertyCallbackInfo<v8::Value>& info) { 18767 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes")); 18768 } 18769 18770 18771 void HasOwnPropertyIndexedPropertyQuery( 18772 uint32_t index, const v8::PropertyCallbackInfo<v8::Integer>& info) { 18773 if (index == 42) info.GetReturnValue().Set(1); 18774 } 18775 18776 18777 void HasOwnPropertyNamedPropertyQuery( 18778 Local<String> property, 18779 const v8::PropertyCallbackInfo<v8::Integer>& info) { 18780 if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1); 18781 } 18782 18783 18784 void HasOwnPropertyNamedPropertyQuery2( 18785 Local<String> property, 18786 const v8::PropertyCallbackInfo<v8::Integer>& info) { 18787 if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1); 18788 } 18789 18790 18791 void HasOwnPropertyAccessorGetter( 18792 Local<String> property, 18793 const v8::PropertyCallbackInfo<v8::Value>& info) { 18794 info.GetReturnValue().Set(v8_str("yes")); 18795 } 18796 18797 18798 TEST(HasOwnProperty) { 18799 LocalContext env; 18800 v8::HandleScope scope(env->GetIsolate()); 18801 { // Check normal properties and defined getters. 18802 Handle<Value> value = CompileRun( 18803 "function Foo() {" 18804 " this.foo = 11;" 18805 " this.__defineGetter__('baz', function() { return 1; });" 18806 "};" 18807 "function Bar() { " 18808 " this.bar = 13;" 18809 " this.__defineGetter__('bla', function() { return 2; });" 18810 "};" 18811 "Bar.prototype = new Foo();" 18812 "new Bar();"); 18813 CHECK(value->IsObject()); 18814 Handle<Object> object = value->ToObject(); 18815 CHECK(object->Has(v8_str("foo"))); 18816 CHECK(!object->HasOwnProperty(v8_str("foo"))); 18817 CHECK(object->HasOwnProperty(v8_str("bar"))); 18818 CHECK(object->Has(v8_str("baz"))); 18819 CHECK(!object->HasOwnProperty(v8_str("baz"))); 18820 CHECK(object->HasOwnProperty(v8_str("bla"))); 18821 } 18822 { // Check named getter interceptors. 18823 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 18824 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter); 18825 Handle<Object> instance = templ->NewInstance(); 18826 CHECK(!instance->HasOwnProperty(v8_str("42"))); 18827 CHECK(instance->HasOwnProperty(v8_str("foo"))); 18828 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 18829 } 18830 { // Check indexed getter interceptors. 18831 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 18832 templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter); 18833 Handle<Object> instance = templ->NewInstance(); 18834 CHECK(instance->HasOwnProperty(v8_str("42"))); 18835 CHECK(!instance->HasOwnProperty(v8_str("43"))); 18836 CHECK(!instance->HasOwnProperty(v8_str("foo"))); 18837 } 18838 { // Check named query interceptors. 18839 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 18840 templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery); 18841 Handle<Object> instance = templ->NewInstance(); 18842 CHECK(instance->HasOwnProperty(v8_str("foo"))); 18843 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 18844 } 18845 { // Check indexed query interceptors. 18846 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 18847 templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery); 18848 Handle<Object> instance = templ->NewInstance(); 18849 CHECK(instance->HasOwnProperty(v8_str("42"))); 18850 CHECK(!instance->HasOwnProperty(v8_str("41"))); 18851 } 18852 { // Check callbacks. 18853 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 18854 templ->SetAccessor(v8_str("foo"), HasOwnPropertyAccessorGetter); 18855 Handle<Object> instance = templ->NewInstance(); 18856 CHECK(instance->HasOwnProperty(v8_str("foo"))); 18857 CHECK(!instance->HasOwnProperty(v8_str("bar"))); 18858 } 18859 { // Check that query wins on disagreement. 18860 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 18861 templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter, 18862 0, 18863 HasOwnPropertyNamedPropertyQuery2); 18864 Handle<Object> instance = templ->NewInstance(); 18865 CHECK(!instance->HasOwnProperty(v8_str("foo"))); 18866 CHECK(instance->HasOwnProperty(v8_str("bar"))); 18867 } 18868 } 18869 18870 18871 TEST(IndexedInterceptorWithStringProto) { 18872 v8::HandleScope scope(v8::Isolate::GetCurrent()); 18873 Handle<ObjectTemplate> templ = ObjectTemplate::New(); 18874 templ->SetIndexedPropertyHandler(NULL, 18875 NULL, 18876 HasOwnPropertyIndexedPropertyQuery); 18877 LocalContext context; 18878 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 18879 CompileRun("var s = new String('foobar'); obj.__proto__ = s;"); 18880 // These should be intercepted. 18881 CHECK(CompileRun("42 in obj")->BooleanValue()); 18882 CHECK(CompileRun("'42' in obj")->BooleanValue()); 18883 // These should fall through to the String prototype. 18884 CHECK(CompileRun("0 in obj")->BooleanValue()); 18885 CHECK(CompileRun("'0' in obj")->BooleanValue()); 18886 // And these should both fail. 18887 CHECK(!CompileRun("32 in obj")->BooleanValue()); 18888 CHECK(!CompileRun("'32' in obj")->BooleanValue()); 18889 } 18890 18891 18892 void CheckCodeGenerationAllowed() { 18893 Handle<Value> result = CompileRun("eval('42')"); 18894 CHECK_EQ(42, result->Int32Value()); 18895 result = CompileRun("(function(e) { return e('42'); })(eval)"); 18896 CHECK_EQ(42, result->Int32Value()); 18897 result = CompileRun("var f = new Function('return 42'); f()"); 18898 CHECK_EQ(42, result->Int32Value()); 18899 } 18900 18901 18902 void CheckCodeGenerationDisallowed() { 18903 TryCatch try_catch; 18904 18905 Handle<Value> result = CompileRun("eval('42')"); 18906 CHECK(result.IsEmpty()); 18907 CHECK(try_catch.HasCaught()); 18908 try_catch.Reset(); 18909 18910 result = CompileRun("(function(e) { return e('42'); })(eval)"); 18911 CHECK(result.IsEmpty()); 18912 CHECK(try_catch.HasCaught()); 18913 try_catch.Reset(); 18914 18915 result = CompileRun("var f = new Function('return 42'); f()"); 18916 CHECK(result.IsEmpty()); 18917 CHECK(try_catch.HasCaught()); 18918 } 18919 18920 18921 bool CodeGenerationAllowed(Local<Context> context) { 18922 ApiTestFuzzer::Fuzz(); 18923 return true; 18924 } 18925 18926 18927 bool CodeGenerationDisallowed(Local<Context> context) { 18928 ApiTestFuzzer::Fuzz(); 18929 return false; 18930 } 18931 18932 18933 THREADED_TEST(AllowCodeGenFromStrings) { 18934 LocalContext context; 18935 v8::HandleScope scope(context->GetIsolate()); 18936 18937 // eval and the Function constructor allowed by default. 18938 CHECK(context->IsCodeGenerationFromStringsAllowed()); 18939 CheckCodeGenerationAllowed(); 18940 18941 // Disallow eval and the Function constructor. 18942 context->AllowCodeGenerationFromStrings(false); 18943 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 18944 CheckCodeGenerationDisallowed(); 18945 18946 // Allow again. 18947 context->AllowCodeGenerationFromStrings(true); 18948 CheckCodeGenerationAllowed(); 18949 18950 // Disallow but setting a global callback that will allow the calls. 18951 context->AllowCodeGenerationFromStrings(false); 18952 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationAllowed); 18953 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 18954 CheckCodeGenerationAllowed(); 18955 18956 // Set a callback that disallows the code generation. 18957 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed); 18958 CHECK(!context->IsCodeGenerationFromStringsAllowed()); 18959 CheckCodeGenerationDisallowed(); 18960 } 18961 18962 18963 TEST(SetErrorMessageForCodeGenFromStrings) { 18964 LocalContext context; 18965 v8::HandleScope scope(context->GetIsolate()); 18966 TryCatch try_catch; 18967 18968 Handle<String> message = v8_str("Message") ; 18969 Handle<String> expected_message = v8_str("Uncaught EvalError: Message"); 18970 V8::SetAllowCodeGenerationFromStringsCallback(&CodeGenerationDisallowed); 18971 context->AllowCodeGenerationFromStrings(false); 18972 context->SetErrorMessageForCodeGenerationFromStrings(message); 18973 Handle<Value> result = CompileRun("eval('42')"); 18974 CHECK(result.IsEmpty()); 18975 CHECK(try_catch.HasCaught()); 18976 Handle<String> actual_message = try_catch.Message()->Get(); 18977 CHECK(expected_message->Equals(actual_message)); 18978 } 18979 18980 18981 static void NonObjectThis(const v8::FunctionCallbackInfo<v8::Value>& args) { 18982 } 18983 18984 18985 THREADED_TEST(CallAPIFunctionOnNonObject) { 18986 LocalContext context; 18987 v8::HandleScope scope(context->GetIsolate()); 18988 Handle<FunctionTemplate> templ = v8::FunctionTemplate::New(NonObjectThis); 18989 Handle<Function> function = templ->GetFunction(); 18990 context->Global()->Set(v8_str("f"), function); 18991 TryCatch try_catch; 18992 CompileRun("f.call(2)"); 18993 } 18994 18995 18996 // Regression test for issue 1470. 18997 THREADED_TEST(ReadOnlyIndexedProperties) { 18998 v8::HandleScope scope(v8::Isolate::GetCurrent()); 18999 Local<ObjectTemplate> templ = ObjectTemplate::New(); 19000 19001 LocalContext context; 19002 Local<v8::Object> obj = templ->NewInstance(); 19003 context->Global()->Set(v8_str("obj"), obj); 19004 obj->Set(v8_str("1"), v8_str("DONT_CHANGE"), v8::ReadOnly); 19005 obj->Set(v8_str("1"), v8_str("foobar")); 19006 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("1"))); 19007 obj->Set(v8_num(2), v8_str("DONT_CHANGE"), v8::ReadOnly); 19008 obj->Set(v8_num(2), v8_str("foobar")); 19009 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_num(2))); 19010 19011 // Test non-smi case. 19012 obj->Set(v8_str("2000000000"), v8_str("DONT_CHANGE"), v8::ReadOnly); 19013 obj->Set(v8_str("2000000000"), v8_str("foobar")); 19014 CHECK_EQ(v8_str("DONT_CHANGE"), obj->Get(v8_str("2000000000"))); 19015 } 19016 19017 19018 THREADED_TEST(Regress1516) { 19019 LocalContext context; 19020 v8::HandleScope scope(context->GetIsolate()); 19021 19022 { v8::HandleScope temp_scope(context->GetIsolate()); 19023 CompileRun("({'a': 0})"); 19024 } 19025 19026 int elements; 19027 { i::MapCache* map_cache = 19028 i::MapCache::cast(i::Isolate::Current()->context()->map_cache()); 19029 elements = map_cache->NumberOfElements(); 19030 CHECK_LE(1, elements); 19031 } 19032 19033 i::Isolate::Current()->heap()->CollectAllGarbage( 19034 i::Heap::kAbortIncrementalMarkingMask); 19035 { i::Object* raw_map_cache = i::Isolate::Current()->context()->map_cache(); 19036 if (raw_map_cache != i::Isolate::Current()->heap()->undefined_value()) { 19037 i::MapCache* map_cache = i::MapCache::cast(raw_map_cache); 19038 CHECK_GT(elements, map_cache->NumberOfElements()); 19039 } 19040 } 19041 } 19042 19043 19044 static bool BlockProtoNamedSecurityTestCallback(Local<v8::Object> global, 19045 Local<Value> name, 19046 v8::AccessType type, 19047 Local<Value> data) { 19048 // Only block read access to __proto__. 19049 if (type == v8::ACCESS_GET && 19050 name->IsString() && 19051 name->ToString()->Length() == 9 && 19052 name->ToString()->Utf8Length() == 9) { 19053 char buffer[10]; 19054 CHECK_EQ(10, name->ToString()->WriteUtf8(buffer)); 19055 return strncmp(buffer, "__proto__", 9) != 0; 19056 } 19057 19058 return true; 19059 } 19060 19061 19062 THREADED_TEST(Regress93759) { 19063 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 19064 HandleScope scope(isolate); 19065 19066 // Template for object with security check. 19067 Local<ObjectTemplate> no_proto_template = v8::ObjectTemplate::New(); 19068 // We don't do indexing, so any callback can be used for that. 19069 no_proto_template->SetAccessCheckCallbacks( 19070 BlockProtoNamedSecurityTestCallback, 19071 IndexedSecurityTestCallback); 19072 19073 // Templates for objects with hidden prototypes and possibly security check. 19074 Local<FunctionTemplate> hidden_proto_template = v8::FunctionTemplate::New(); 19075 hidden_proto_template->SetHiddenPrototype(true); 19076 19077 Local<FunctionTemplate> protected_hidden_proto_template = 19078 v8::FunctionTemplate::New(); 19079 protected_hidden_proto_template->InstanceTemplate()->SetAccessCheckCallbacks( 19080 BlockProtoNamedSecurityTestCallback, 19081 IndexedSecurityTestCallback); 19082 protected_hidden_proto_template->SetHiddenPrototype(true); 19083 19084 // Context for "foreign" objects used in test. 19085 Local<Context> context = v8::Context::New(isolate); 19086 context->Enter(); 19087 19088 // Plain object, no security check. 19089 Local<Object> simple_object = Object::New(); 19090 19091 // Object with explicit security check. 19092 Local<Object> protected_object = 19093 no_proto_template->NewInstance(); 19094 19095 // JSGlobalProxy object, always have security check. 19096 Local<Object> proxy_object = 19097 context->Global(); 19098 19099 // Global object, the prototype of proxy_object. No security checks. 19100 Local<Object> global_object = 19101 proxy_object->GetPrototype()->ToObject(); 19102 19103 // Hidden prototype without security check. 19104 Local<Object> hidden_prototype = 19105 hidden_proto_template->GetFunction()->NewInstance(); 19106 Local<Object> object_with_hidden = 19107 Object::New(); 19108 object_with_hidden->SetPrototype(hidden_prototype); 19109 19110 // Hidden prototype with security check on the hidden prototype. 19111 Local<Object> protected_hidden_prototype = 19112 protected_hidden_proto_template->GetFunction()->NewInstance(); 19113 Local<Object> object_with_protected_hidden = 19114 Object::New(); 19115 object_with_protected_hidden->SetPrototype(protected_hidden_prototype); 19116 19117 context->Exit(); 19118 19119 // Template for object for second context. Values to test are put on it as 19120 // properties. 19121 Local<ObjectTemplate> global_template = ObjectTemplate::New(); 19122 global_template->Set(v8_str("simple"), simple_object); 19123 global_template->Set(v8_str("protected"), protected_object); 19124 global_template->Set(v8_str("global"), global_object); 19125 global_template->Set(v8_str("proxy"), proxy_object); 19126 global_template->Set(v8_str("hidden"), object_with_hidden); 19127 global_template->Set(v8_str("phidden"), object_with_protected_hidden); 19128 19129 LocalContext context2(NULL, global_template); 19130 19131 Local<Value> result1 = CompileRun("Object.getPrototypeOf(simple)"); 19132 CHECK(result1->Equals(simple_object->GetPrototype())); 19133 19134 Local<Value> result2 = CompileRun("Object.getPrototypeOf(protected)"); 19135 CHECK(result2->Equals(Undefined())); 19136 19137 Local<Value> result3 = CompileRun("Object.getPrototypeOf(global)"); 19138 CHECK(result3->Equals(global_object->GetPrototype())); 19139 19140 Local<Value> result4 = CompileRun("Object.getPrototypeOf(proxy)"); 19141 CHECK(result4->Equals(Undefined())); 19142 19143 Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)"); 19144 CHECK(result5->Equals( 19145 object_with_hidden->GetPrototype()->ToObject()->GetPrototype())); 19146 19147 Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)"); 19148 CHECK(result6->Equals(Undefined())); 19149 } 19150 19151 19152 THREADED_TEST(Regress125988) { 19153 v8::HandleScope scope(v8::Isolate::GetCurrent()); 19154 Handle<FunctionTemplate> intercept = FunctionTemplate::New(); 19155 AddInterceptor(intercept, EmptyInterceptorGetter, EmptyInterceptorSetter); 19156 LocalContext env; 19157 env->Global()->Set(v8_str("Intercept"), intercept->GetFunction()); 19158 CompileRun("var a = new Object();" 19159 "var b = new Intercept();" 19160 "var c = new Object();" 19161 "c.__proto__ = b;" 19162 "b.__proto__ = a;" 19163 "a.x = 23;" 19164 "for (var i = 0; i < 3; i++) c.x;"); 19165 ExpectBoolean("c.hasOwnProperty('x')", false); 19166 ExpectInt32("c.x", 23); 19167 CompileRun("a.y = 42;" 19168 "for (var i = 0; i < 3; i++) c.x;"); 19169 ExpectBoolean("c.hasOwnProperty('x')", false); 19170 ExpectInt32("c.x", 23); 19171 ExpectBoolean("c.hasOwnProperty('y')", false); 19172 ExpectInt32("c.y", 42); 19173 } 19174 19175 19176 static void TestReceiver(Local<Value> expected_result, 19177 Local<Value> expected_receiver, 19178 const char* code) { 19179 Local<Value> result = CompileRun(code); 19180 CHECK(result->IsObject()); 19181 CHECK(expected_receiver->Equals(result->ToObject()->Get(1))); 19182 CHECK(expected_result->Equals(result->ToObject()->Get(0))); 19183 } 19184 19185 19186 THREADED_TEST(ForeignFunctionReceiver) { 19187 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 19188 HandleScope scope(isolate); 19189 19190 // Create two contexts with different "id" properties ('i' and 'o'). 19191 // Call a function both from its own context and from a the foreign 19192 // context, and see what "this" is bound to (returning both "this" 19193 // and "this.id" for comparison). 19194 19195 Local<Context> foreign_context = v8::Context::New(isolate); 19196 foreign_context->Enter(); 19197 Local<Value> foreign_function = 19198 CompileRun("function func() { return { 0: this.id, " 19199 " 1: this, " 19200 " toString: function() { " 19201 " return this[0];" 19202 " }" 19203 " };" 19204 "}" 19205 "var id = 'i';" 19206 "func;"); 19207 CHECK(foreign_function->IsFunction()); 19208 foreign_context->Exit(); 19209 19210 LocalContext context; 19211 19212 Local<String> password = v8_str("Password"); 19213 // Don't get hit by security checks when accessing foreign_context's 19214 // global receiver (aka. global proxy). 19215 context->SetSecurityToken(password); 19216 foreign_context->SetSecurityToken(password); 19217 19218 Local<String> i = v8_str("i"); 19219 Local<String> o = v8_str("o"); 19220 Local<String> id = v8_str("id"); 19221 19222 CompileRun("function ownfunc() { return { 0: this.id, " 19223 " 1: this, " 19224 " toString: function() { " 19225 " return this[0];" 19226 " }" 19227 " };" 19228 "}" 19229 "var id = 'o';" 19230 "ownfunc"); 19231 context->Global()->Set(v8_str("func"), foreign_function); 19232 19233 // Sanity check the contexts. 19234 CHECK(i->Equals(foreign_context->Global()->Get(id))); 19235 CHECK(o->Equals(context->Global()->Get(id))); 19236 19237 // Checking local function's receiver. 19238 // Calling function using its call/apply methods. 19239 TestReceiver(o, context->Global(), "ownfunc.call()"); 19240 TestReceiver(o, context->Global(), "ownfunc.apply()"); 19241 // Making calls through built-in functions. 19242 TestReceiver(o, context->Global(), "[1].map(ownfunc)[0]"); 19243 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/,ownfunc)[1]"))); 19244 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[1]"))); 19245 CHECK(o->Equals(CompileRun("'abcbd'.replace(/b/g,ownfunc)[3]"))); 19246 // Calling with environment record as base. 19247 TestReceiver(o, context->Global(), "ownfunc()"); 19248 // Calling with no base. 19249 TestReceiver(o, context->Global(), "(1,ownfunc)()"); 19250 19251 // Checking foreign function return value. 19252 // Calling function using its call/apply methods. 19253 TestReceiver(i, foreign_context->Global(), "func.call()"); 19254 TestReceiver(i, foreign_context->Global(), "func.apply()"); 19255 // Calling function using another context's call/apply methods. 19256 TestReceiver(i, foreign_context->Global(), 19257 "Function.prototype.call.call(func)"); 19258 TestReceiver(i, foreign_context->Global(), 19259 "Function.prototype.call.apply(func)"); 19260 TestReceiver(i, foreign_context->Global(), 19261 "Function.prototype.apply.call(func)"); 19262 TestReceiver(i, foreign_context->Global(), 19263 "Function.prototype.apply.apply(func)"); 19264 // Making calls through built-in functions. 19265 TestReceiver(i, foreign_context->Global(), "[1].map(func)[0]"); 19266 // ToString(func()) is func()[0], i.e., the returned this.id. 19267 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/,func)[1]"))); 19268 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[1]"))); 19269 CHECK(i->Equals(CompileRun("'abcbd'.replace(/b/g,func)[3]"))); 19270 19271 // TODO(1547): Make the following also return "i". 19272 // Calling with environment record as base. 19273 TestReceiver(o, context->Global(), "func()"); 19274 // Calling with no base. 19275 TestReceiver(o, context->Global(), "(1,func)()"); 19276 } 19277 19278 19279 uint8_t callback_fired = 0; 19280 19281 19282 void CallCompletedCallback1() { 19283 i::OS::Print("Firing callback 1.\n"); 19284 callback_fired ^= 1; // Toggle first bit. 19285 } 19286 19287 19288 void CallCompletedCallback2() { 19289 i::OS::Print("Firing callback 2.\n"); 19290 callback_fired ^= 2; // Toggle second bit. 19291 } 19292 19293 19294 void RecursiveCall(const v8::FunctionCallbackInfo<v8::Value>& args) { 19295 int32_t level = args[0]->Int32Value(); 19296 if (level < 3) { 19297 level++; 19298 i::OS::Print("Entering recursion level %d.\n", level); 19299 char script[64]; 19300 i::Vector<char> script_vector(script, sizeof(script)); 19301 i::OS::SNPrintF(script_vector, "recursion(%d)", level); 19302 CompileRun(script_vector.start()); 19303 i::OS::Print("Leaving recursion level %d.\n", level); 19304 CHECK_EQ(0, callback_fired); 19305 } else { 19306 i::OS::Print("Recursion ends.\n"); 19307 CHECK_EQ(0, callback_fired); 19308 } 19309 } 19310 19311 19312 TEST(CallCompletedCallback) { 19313 LocalContext env; 19314 v8::HandleScope scope(env->GetIsolate()); 19315 v8::Handle<v8::FunctionTemplate> recursive_runtime = 19316 v8::FunctionTemplate::New(RecursiveCall); 19317 env->Global()->Set(v8_str("recursion"), 19318 recursive_runtime->GetFunction()); 19319 // Adding the same callback a second time has no effect. 19320 v8::V8::AddCallCompletedCallback(CallCompletedCallback1); 19321 v8::V8::AddCallCompletedCallback(CallCompletedCallback1); 19322 v8::V8::AddCallCompletedCallback(CallCompletedCallback2); 19323 i::OS::Print("--- Script (1) ---\n"); 19324 Local<Script> script = 19325 v8::Script::Compile(v8::String::New("recursion(0)")); 19326 script->Run(); 19327 CHECK_EQ(3, callback_fired); 19328 19329 i::OS::Print("\n--- Script (2) ---\n"); 19330 callback_fired = 0; 19331 v8::V8::RemoveCallCompletedCallback(CallCompletedCallback1); 19332 script->Run(); 19333 CHECK_EQ(2, callback_fired); 19334 19335 i::OS::Print("\n--- Function ---\n"); 19336 callback_fired = 0; 19337 Local<Function> recursive_function = 19338 Local<Function>::Cast(env->Global()->Get(v8_str("recursion"))); 19339 v8::Handle<Value> args[] = { v8_num(0) }; 19340 recursive_function->Call(env->Global(), 1, args); 19341 CHECK_EQ(2, callback_fired); 19342 } 19343 19344 19345 void CallCompletedCallbackNoException() { 19346 v8::HandleScope scope(v8::Isolate::GetCurrent()); 19347 CompileRun("1+1;"); 19348 } 19349 19350 19351 void CallCompletedCallbackException() { 19352 v8::HandleScope scope(v8::Isolate::GetCurrent()); 19353 CompileRun("throw 'second exception';"); 19354 } 19355 19356 19357 TEST(CallCompletedCallbackOneException) { 19358 LocalContext env; 19359 v8::HandleScope scope(env->GetIsolate()); 19360 v8::V8::AddCallCompletedCallback(CallCompletedCallbackNoException); 19361 CompileRun("throw 'exception';"); 19362 } 19363 19364 19365 TEST(CallCompletedCallbackTwoExceptions) { 19366 LocalContext env; 19367 v8::HandleScope scope(env->GetIsolate()); 19368 v8::V8::AddCallCompletedCallback(CallCompletedCallbackException); 19369 CompileRun("throw 'first exception';"); 19370 } 19371 19372 19373 static int probes_counter = 0; 19374 static int misses_counter = 0; 19375 static int updates_counter = 0; 19376 19377 19378 static int* LookupCounter(const char* name) { 19379 if (strcmp(name, "c:V8.MegamorphicStubCacheProbes") == 0) { 19380 return &probes_counter; 19381 } else if (strcmp(name, "c:V8.MegamorphicStubCacheMisses") == 0) { 19382 return &misses_counter; 19383 } else if (strcmp(name, "c:V8.MegamorphicStubCacheUpdates") == 0) { 19384 return &updates_counter; 19385 } 19386 return NULL; 19387 } 19388 19389 19390 static const char* kMegamorphicTestProgram = 19391 "function ClassA() { };" 19392 "function ClassB() { };" 19393 "ClassA.prototype.foo = function() { };" 19394 "ClassB.prototype.foo = function() { };" 19395 "function fooify(obj) { obj.foo(); };" 19396 "var a = new ClassA();" 19397 "var b = new ClassB();" 19398 "for (var i = 0; i < 10000; i++) {" 19399 " fooify(a);" 19400 " fooify(b);" 19401 "}"; 19402 19403 19404 static void StubCacheHelper(bool primary) { 19405 V8::SetCounterFunction(LookupCounter); 19406 USE(kMegamorphicTestProgram); 19407 #ifdef DEBUG 19408 i::FLAG_native_code_counters = true; 19409 if (primary) { 19410 i::FLAG_test_primary_stub_cache = true; 19411 } else { 19412 i::FLAG_test_secondary_stub_cache = true; 19413 } 19414 i::FLAG_crankshaft = false; 19415 LocalContext env; 19416 v8::HandleScope scope(env->GetIsolate()); 19417 int initial_probes = probes_counter; 19418 int initial_misses = misses_counter; 19419 int initial_updates = updates_counter; 19420 CompileRun(kMegamorphicTestProgram); 19421 int probes = probes_counter - initial_probes; 19422 int misses = misses_counter - initial_misses; 19423 int updates = updates_counter - initial_updates; 19424 CHECK_LT(updates, 10); 19425 CHECK_LT(misses, 10); 19426 CHECK_GE(probes, 10000); 19427 #endif 19428 } 19429 19430 19431 TEST(SecondaryStubCache) { 19432 StubCacheHelper(true); 19433 } 19434 19435 19436 TEST(PrimaryStubCache) { 19437 StubCacheHelper(false); 19438 } 19439 19440 19441 TEST(StaticGetters) { 19442 LocalContext context; 19443 i::Factory* factory = i::Isolate::Current()->factory(); 19444 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 19445 v8::HandleScope scope(isolate); 19446 i::Handle<i::Object> undefined_value = factory->undefined_value(); 19447 CHECK(*v8::Utils::OpenHandle(*v8::Undefined()) == *undefined_value); 19448 CHECK(*v8::Utils::OpenHandle(*v8::Undefined(isolate)) == *undefined_value); 19449 i::Handle<i::Object> null_value = factory->null_value(); 19450 CHECK(*v8::Utils::OpenHandle(*v8::Null()) == *null_value); 19451 CHECK(*v8::Utils::OpenHandle(*v8::Null(isolate)) == *null_value); 19452 i::Handle<i::Object> true_value = factory->true_value(); 19453 CHECK(*v8::Utils::OpenHandle(*v8::True()) == *true_value); 19454 CHECK(*v8::Utils::OpenHandle(*v8::True(isolate)) == *true_value); 19455 i::Handle<i::Object> false_value = factory->false_value(); 19456 CHECK(*v8::Utils::OpenHandle(*v8::False()) == *false_value); 19457 CHECK(*v8::Utils::OpenHandle(*v8::False(isolate)) == *false_value); 19458 } 19459 19460 19461 TEST(IsolateEmbedderData) { 19462 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 19463 CHECK_EQ(NULL, isolate->GetData()); 19464 CHECK_EQ(NULL, ISOLATE->GetData()); 19465 static void* data1 = reinterpret_cast<void*>(0xacce55ed); 19466 isolate->SetData(data1); 19467 CHECK_EQ(data1, isolate->GetData()); 19468 CHECK_EQ(data1, ISOLATE->GetData()); 19469 static void* data2 = reinterpret_cast<void*>(0xdecea5ed); 19470 ISOLATE->SetData(data2); 19471 CHECK_EQ(data2, isolate->GetData()); 19472 CHECK_EQ(data2, ISOLATE->GetData()); 19473 ISOLATE->TearDown(); 19474 CHECK_EQ(data2, isolate->GetData()); 19475 CHECK_EQ(data2, ISOLATE->GetData()); 19476 } 19477 19478 19479 TEST(StringEmpty) { 19480 LocalContext context; 19481 i::Factory* factory = i::Isolate::Current()->factory(); 19482 v8::Isolate* isolate = v8::Isolate::GetCurrent(); 19483 v8::HandleScope scope(isolate); 19484 i::Handle<i::Object> empty_string = factory->empty_string(); 19485 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty()) == *empty_string); 19486 CHECK(*v8::Utils::OpenHandle(*v8::String::Empty(isolate)) == *empty_string); 19487 } 19488 19489 19490 static int instance_checked_getter_count = 0; 19491 static void InstanceCheckedGetter( 19492 Local<String> name, 19493 const v8::PropertyCallbackInfo<v8::Value>& info) { 19494 CHECK_EQ(name, v8_str("foo")); 19495 instance_checked_getter_count++; 19496 info.GetReturnValue().Set(v8_num(11)); 19497 } 19498 19499 19500 static int instance_checked_setter_count = 0; 19501 static void InstanceCheckedSetter(Local<String> name, 19502 Local<Value> value, 19503 const v8::PropertyCallbackInfo<void>& info) { 19504 CHECK_EQ(name, v8_str("foo")); 19505 CHECK_EQ(value, v8_num(23)); 19506 instance_checked_setter_count++; 19507 } 19508 19509 19510 static void CheckInstanceCheckedResult(int getters, 19511 int setters, 19512 bool expects_callbacks, 19513 TryCatch* try_catch) { 19514 if (expects_callbacks) { 19515 CHECK(!try_catch->HasCaught()); 19516 CHECK_EQ(getters, instance_checked_getter_count); 19517 CHECK_EQ(setters, instance_checked_setter_count); 19518 } else { 19519 CHECK(try_catch->HasCaught()); 19520 CHECK_EQ(0, instance_checked_getter_count); 19521 CHECK_EQ(0, instance_checked_setter_count); 19522 } 19523 try_catch->Reset(); 19524 } 19525 19526 19527 static void CheckInstanceCheckedAccessors(bool expects_callbacks) { 19528 instance_checked_getter_count = 0; 19529 instance_checked_setter_count = 0; 19530 TryCatch try_catch; 19531 19532 // Test path through generic runtime code. 19533 CompileRun("obj.foo"); 19534 CheckInstanceCheckedResult(1, 0, expects_callbacks, &try_catch); 19535 CompileRun("obj.foo = 23"); 19536 CheckInstanceCheckedResult(1, 1, expects_callbacks, &try_catch); 19537 19538 // Test path through generated LoadIC and StoredIC. 19539 CompileRun("function test_get(o) { o.foo; }" 19540 "test_get(obj);"); 19541 CheckInstanceCheckedResult(2, 1, expects_callbacks, &try_catch); 19542 CompileRun("test_get(obj);"); 19543 CheckInstanceCheckedResult(3, 1, expects_callbacks, &try_catch); 19544 CompileRun("test_get(obj);"); 19545 CheckInstanceCheckedResult(4, 1, expects_callbacks, &try_catch); 19546 CompileRun("function test_set(o) { o.foo = 23; }" 19547 "test_set(obj);"); 19548 CheckInstanceCheckedResult(4, 2, expects_callbacks, &try_catch); 19549 CompileRun("test_set(obj);"); 19550 CheckInstanceCheckedResult(4, 3, expects_callbacks, &try_catch); 19551 CompileRun("test_set(obj);"); 19552 CheckInstanceCheckedResult(4, 4, expects_callbacks, &try_catch); 19553 19554 // Test path through optimized code. 19555 CompileRun("%OptimizeFunctionOnNextCall(test_get);" 19556 "test_get(obj);"); 19557 CheckInstanceCheckedResult(5, 4, expects_callbacks, &try_catch); 19558 CompileRun("%OptimizeFunctionOnNextCall(test_set);" 19559 "test_set(obj);"); 19560 CheckInstanceCheckedResult(5, 5, expects_callbacks, &try_catch); 19561 19562 // Cleanup so that closures start out fresh in next check. 19563 CompileRun("%DeoptimizeFunction(test_get);" 19564 "%ClearFunctionTypeFeedback(test_get);" 19565 "%DeoptimizeFunction(test_set);" 19566 "%ClearFunctionTypeFeedback(test_set);"); 19567 } 19568 19569 19570 THREADED_TEST(InstanceCheckOnInstanceAccessor) { 19571 v8::internal::FLAG_allow_natives_syntax = true; 19572 LocalContext context; 19573 v8::HandleScope scope(context->GetIsolate()); 19574 19575 Local<FunctionTemplate> templ = FunctionTemplate::New(); 19576 Local<ObjectTemplate> inst = templ->InstanceTemplate(); 19577 inst->SetAccessor(v8_str("foo"), 19578 InstanceCheckedGetter, InstanceCheckedSetter, 19579 Handle<Value>(), 19580 v8::DEFAULT, 19581 v8::None, 19582 v8::AccessorSignature::New(templ)); 19583 context->Global()->Set(v8_str("f"), templ->GetFunction()); 19584 19585 printf("Testing positive ...\n"); 19586 CompileRun("var obj = new f();"); 19587 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 19588 CheckInstanceCheckedAccessors(true); 19589 19590 printf("Testing negative ...\n"); 19591 CompileRun("var obj = {};" 19592 "obj.__proto__ = new f();"); 19593 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); 19594 CheckInstanceCheckedAccessors(false); 19595 } 19596 19597 19598 THREADED_TEST(InstanceCheckOnInstanceAccessorWithInterceptor) { 19599 v8::internal::FLAG_allow_natives_syntax = true; 19600 LocalContext context; 19601 v8::HandleScope scope(context->GetIsolate()); 19602 19603 Local<FunctionTemplate> templ = FunctionTemplate::New(); 19604 Local<ObjectTemplate> inst = templ->InstanceTemplate(); 19605 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 19606 inst->SetAccessor(v8_str("foo"), 19607 InstanceCheckedGetter, InstanceCheckedSetter, 19608 Handle<Value>(), 19609 v8::DEFAULT, 19610 v8::None, 19611 v8::AccessorSignature::New(templ)); 19612 context->Global()->Set(v8_str("f"), templ->GetFunction()); 19613 19614 printf("Testing positive ...\n"); 19615 CompileRun("var obj = new f();"); 19616 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 19617 CheckInstanceCheckedAccessors(true); 19618 19619 printf("Testing negative ...\n"); 19620 CompileRun("var obj = {};" 19621 "obj.__proto__ = new f();"); 19622 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); 19623 CheckInstanceCheckedAccessors(false); 19624 } 19625 19626 19627 THREADED_TEST(InstanceCheckOnPrototypeAccessor) { 19628 v8::internal::FLAG_allow_natives_syntax = true; 19629 LocalContext context; 19630 v8::HandleScope scope(context->GetIsolate()); 19631 19632 Local<FunctionTemplate> templ = FunctionTemplate::New(); 19633 Local<ObjectTemplate> proto = templ->PrototypeTemplate(); 19634 proto->SetAccessor(v8_str("foo"), 19635 InstanceCheckedGetter, InstanceCheckedSetter, 19636 Handle<Value>(), 19637 v8::DEFAULT, 19638 v8::None, 19639 v8::AccessorSignature::New(templ)); 19640 context->Global()->Set(v8_str("f"), templ->GetFunction()); 19641 19642 printf("Testing positive ...\n"); 19643 CompileRun("var obj = new f();"); 19644 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 19645 CheckInstanceCheckedAccessors(true); 19646 19647 printf("Testing negative ...\n"); 19648 CompileRun("var obj = {};" 19649 "obj.__proto__ = new f();"); 19650 CHECK(!templ->HasInstance(context->Global()->Get(v8_str("obj")))); 19651 CheckInstanceCheckedAccessors(false); 19652 19653 printf("Testing positive with modified prototype chain ...\n"); 19654 CompileRun("var obj = new f();" 19655 "var pro = {};" 19656 "pro.__proto__ = obj.__proto__;" 19657 "obj.__proto__ = pro;"); 19658 CHECK(templ->HasInstance(context->Global()->Get(v8_str("obj")))); 19659 CheckInstanceCheckedAccessors(true); 19660 } 19661 19662 19663 TEST(TryFinallyMessage) { 19664 LocalContext context; 19665 v8::HandleScope scope(context->GetIsolate()); 19666 { 19667 // Test that the original error message is not lost if there is a 19668 // recursive call into Javascript is done in the finally block, e.g. to 19669 // initialize an IC. (crbug.com/129171) 19670 TryCatch try_catch; 19671 const char* trigger_ic = 19672 "try { \n" 19673 " throw new Error('test'); \n" 19674 "} finally { \n" 19675 " var x = 0; \n" 19676 " x++; \n" // Trigger an IC initialization here. 19677 "} \n"; 19678 CompileRun(trigger_ic); 19679 CHECK(try_catch.HasCaught()); 19680 Local<Message> message = try_catch.Message(); 19681 CHECK(!message.IsEmpty()); 19682 CHECK_EQ(2, message->GetLineNumber()); 19683 } 19684 19685 { 19686 // Test that the original exception message is indeed overwritten if 19687 // a new error is thrown in the finally block. 19688 TryCatch try_catch; 19689 const char* throw_again = 19690 "try { \n" 19691 " throw new Error('test'); \n" 19692 "} finally { \n" 19693 " var x = 0; \n" 19694 " x++; \n" 19695 " throw new Error('again'); \n" // This is the new uncaught error. 19696 "} \n"; 19697 CompileRun(throw_again); 19698 CHECK(try_catch.HasCaught()); 19699 Local<Message> message = try_catch.Message(); 19700 CHECK(!message.IsEmpty()); 19701 CHECK_EQ(6, message->GetLineNumber()); 19702 } 19703 } 19704 19705 19706 static void Helper137002(bool do_store, 19707 bool polymorphic, 19708 bool remove_accessor, 19709 bool interceptor) { 19710 LocalContext context; 19711 Local<ObjectTemplate> templ = ObjectTemplate::New(); 19712 if (interceptor) { 19713 templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor); 19714 } else { 19715 templ->SetAccessor(v8_str("foo"), 19716 GetterWhichReturns42, 19717 SetterWhichSetsYOnThisTo23); 19718 } 19719 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 19720 19721 // Turn monomorphic on slow object with native accessor, then turn 19722 // polymorphic, finally optimize to create negative lookup and fail. 19723 CompileRun(do_store ? 19724 "function f(x) { x.foo = void 0; }" : 19725 "function f(x) { return x.foo; }"); 19726 CompileRun("obj.y = void 0;"); 19727 if (!interceptor) { 19728 CompileRun("%OptimizeObjectForAddingMultipleProperties(obj, 1);"); 19729 } 19730 CompileRun("obj.__proto__ = null;" 19731 "f(obj); f(obj); f(obj);"); 19732 if (polymorphic) { 19733 CompileRun("f({});"); 19734 } 19735 CompileRun("obj.y = void 0;" 19736 "%OptimizeFunctionOnNextCall(f);"); 19737 if (remove_accessor) { 19738 CompileRun("delete obj.foo;"); 19739 } 19740 CompileRun("var result = f(obj);"); 19741 if (do_store) { 19742 CompileRun("result = obj.y;"); 19743 } 19744 if (remove_accessor && !interceptor) { 19745 CHECK(context->Global()->Get(v8_str("result"))->IsUndefined()); 19746 } else { 19747 CHECK_EQ(do_store ? 23 : 42, 19748 context->Global()->Get(v8_str("result"))->Int32Value()); 19749 } 19750 } 19751 19752 19753 THREADED_TEST(Regress137002a) { 19754 i::FLAG_allow_natives_syntax = true; 19755 i::FLAG_compilation_cache = false; 19756 v8::HandleScope scope(v8::Isolate::GetCurrent()); 19757 for (int i = 0; i < 16; i++) { 19758 Helper137002(i & 8, i & 4, i & 2, i & 1); 19759 } 19760 } 19761 19762 19763 THREADED_TEST(Regress137002b) { 19764 i::FLAG_allow_natives_syntax = true; 19765 LocalContext context; 19766 v8::HandleScope scope(context->GetIsolate()); 19767 Local<ObjectTemplate> templ = ObjectTemplate::New(); 19768 templ->SetAccessor(v8_str("foo"), 19769 GetterWhichReturns42, 19770 SetterWhichSetsYOnThisTo23); 19771 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 19772 19773 // Turn monomorphic on slow object with native accessor, then just 19774 // delete the property and fail. 19775 CompileRun("function load(x) { return x.foo; }" 19776 "function store(x) { x.foo = void 0; }" 19777 "function keyed_load(x, key) { return x[key]; }" 19778 // Second version of function has a different source (add void 0) 19779 // so that it does not share code with the first version. This 19780 // ensures that the ICs are monomorphic. 19781 "function load2(x) { void 0; return x.foo; }" 19782 "function store2(x) { void 0; x.foo = void 0; }" 19783 "function keyed_load2(x, key) { void 0; return x[key]; }" 19784 19785 "obj.y = void 0;" 19786 "obj.__proto__ = null;" 19787 "var subobj = {};" 19788 "subobj.y = void 0;" 19789 "subobj.__proto__ = obj;" 19790 "%OptimizeObjectForAddingMultipleProperties(obj, 1);" 19791 19792 // Make the ICs monomorphic. 19793 "load(obj); load(obj);" 19794 "load2(subobj); load2(subobj);" 19795 "store(obj); store(obj);" 19796 "store2(subobj); store2(subobj);" 19797 "keyed_load(obj, 'foo'); keyed_load(obj, 'foo');" 19798 "keyed_load2(subobj, 'foo'); keyed_load2(subobj, 'foo');" 19799 19800 // Actually test the shiny new ICs and better not crash. This 19801 // serves as a regression test for issue 142088 as well. 19802 "load(obj);" 19803 "load2(subobj);" 19804 "store(obj);" 19805 "store2(subobj);" 19806 "keyed_load(obj, 'foo');" 19807 "keyed_load2(subobj, 'foo');" 19808 19809 // Delete the accessor. It better not be called any more now. 19810 "delete obj.foo;" 19811 "obj.y = void 0;" 19812 "subobj.y = void 0;" 19813 19814 "var load_result = load(obj);" 19815 "var load_result2 = load2(subobj);" 19816 "var keyed_load_result = keyed_load(obj, 'foo');" 19817 "var keyed_load_result2 = keyed_load2(subobj, 'foo');" 19818 "store(obj);" 19819 "store2(subobj);" 19820 "var y_from_obj = obj.y;" 19821 "var y_from_subobj = subobj.y;"); 19822 CHECK(context->Global()->Get(v8_str("load_result"))->IsUndefined()); 19823 CHECK(context->Global()->Get(v8_str("load_result2"))->IsUndefined()); 19824 CHECK(context->Global()->Get(v8_str("keyed_load_result"))->IsUndefined()); 19825 CHECK(context->Global()->Get(v8_str("keyed_load_result2"))->IsUndefined()); 19826 CHECK(context->Global()->Get(v8_str("y_from_obj"))->IsUndefined()); 19827 CHECK(context->Global()->Get(v8_str("y_from_subobj"))->IsUndefined()); 19828 } 19829 19830 19831 THREADED_TEST(Regress142088) { 19832 i::FLAG_allow_natives_syntax = true; 19833 LocalContext context; 19834 v8::HandleScope scope(context->GetIsolate()); 19835 Local<ObjectTemplate> templ = ObjectTemplate::New(); 19836 templ->SetAccessor(v8_str("foo"), 19837 GetterWhichReturns42, 19838 SetterWhichSetsYOnThisTo23); 19839 context->Global()->Set(v8_str("obj"), templ->NewInstance()); 19840 19841 CompileRun("function load(x) { return x.foo; }" 19842 "var o = Object.create(obj);" 19843 "%OptimizeObjectForAddingMultipleProperties(obj, 1);" 19844 "load(o); load(o); load(o); load(o);"); 19845 } 19846 19847 19848 THREADED_TEST(Regress137496) { 19849 i::FLAG_expose_gc = true; 19850 LocalContext context; 19851 v8::HandleScope scope(context->GetIsolate()); 19852 19853 // Compile a try-finally clause where the finally block causes a GC 19854 // while there still is a message pending for external reporting. 19855 TryCatch try_catch; 19856 try_catch.SetVerbose(true); 19857 CompileRun("try { throw new Error(); } finally { gc(); }"); 19858 CHECK(try_catch.HasCaught()); 19859 } 19860 19861 19862 THREADED_TEST(Regress149912) { 19863 LocalContext context; 19864 v8::HandleScope scope(context->GetIsolate()); 19865 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 19866 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 19867 context->Global()->Set(v8_str("Bug"), templ->GetFunction()); 19868 CompileRun("Number.prototype.__proto__ = new Bug; var x = 0; x.foo();"); 19869 } 19870 19871 19872 THREADED_TEST(Regress157124) { 19873 LocalContext context; 19874 v8::HandleScope scope(context->GetIsolate()); 19875 Local<ObjectTemplate> templ = ObjectTemplate::New(); 19876 Local<Object> obj = templ->NewInstance(); 19877 obj->GetIdentityHash(); 19878 obj->DeleteHiddenValue(v8_str("Bug")); 19879 } 19880 19881 19882 THREADED_TEST(Regress2535) { 19883 i::FLAG_harmony_collections = true; 19884 LocalContext context; 19885 v8::HandleScope scope(context->GetIsolate()); 19886 Local<Value> set_value = CompileRun("new Set();"); 19887 Local<Object> set_object(Local<Object>::Cast(set_value)); 19888 CHECK_EQ(0, set_object->InternalFieldCount()); 19889 Local<Value> map_value = CompileRun("new Map();"); 19890 Local<Object> map_object(Local<Object>::Cast(map_value)); 19891 CHECK_EQ(0, map_object->InternalFieldCount()); 19892 } 19893 19894 19895 THREADED_TEST(Regress2746) { 19896 LocalContext context; 19897 v8::HandleScope scope(context->GetIsolate()); 19898 Local<Object> obj = Object::New(); 19899 Local<String> key = String::New("key"); 19900 obj->SetHiddenValue(key, v8::Undefined()); 19901 Local<Value> value = obj->GetHiddenValue(key); 19902 CHECK(!value.IsEmpty()); 19903 CHECK(value->IsUndefined()); 19904 } 19905 19906 19907 THREADED_TEST(Regress260106) { 19908 LocalContext context; 19909 v8::HandleScope scope(context->GetIsolate()); 19910 Local<FunctionTemplate> templ = FunctionTemplate::New(DummyCallHandler); 19911 CompileRun("for (var i = 0; i < 128; i++) Object.prototype[i] = 0;"); 19912 Local<Function> function = templ->GetFunction(); 19913 CHECK(!function.IsEmpty()); 19914 CHECK(function->IsFunction()); 19915 } 19916 19917 19918 THREADED_TEST(JSONParseObject) { 19919 LocalContext context; 19920 HandleScope scope(context->GetIsolate()); 19921 Local<Value> obj = v8::JSON::Parse(v8_str("{\"x\":42}")); 19922 Handle<Object> global = context->Global(); 19923 global->Set(v8_str("obj"), obj); 19924 ExpectString("JSON.stringify(obj)", "{\"x\":42}"); 19925 } 19926 19927 19928 THREADED_TEST(JSONParseNumber) { 19929 LocalContext context; 19930 HandleScope scope(context->GetIsolate()); 19931 Local<Value> obj = v8::JSON::Parse(v8_str("42")); 19932 Handle<Object> global = context->Global(); 19933 global->Set(v8_str("obj"), obj); 19934 ExpectString("JSON.stringify(obj)", "42"); 19935 } 19936 19937 19938 #ifndef WIN32 19939 class ThreadInterruptTest { 19940 public: 19941 ThreadInterruptTest() : sem_(NULL), sem_value_(0) { } 19942 ~ThreadInterruptTest() { delete sem_; } 19943 19944 void RunTest() { 19945 sem_ = i::OS::CreateSemaphore(0); 19946 19947 InterruptThread i_thread(this); 19948 i_thread.Start(); 19949 19950 sem_->Wait(); 19951 CHECK_EQ(kExpectedValue, sem_value_); 19952 } 19953 19954 private: 19955 static const int kExpectedValue = 1; 19956 19957 class InterruptThread : public i::Thread { 19958 public: 19959 explicit InterruptThread(ThreadInterruptTest* test) 19960 : Thread("InterruptThread"), test_(test) {} 19961 19962 virtual void Run() { 19963 struct sigaction action; 19964 19965 // Ensure that we'll enter waiting condition 19966 i::OS::Sleep(100); 19967 19968 // Setup signal handler 19969 memset(&action, 0, sizeof(action)); 19970 action.sa_handler = SignalHandler; 19971 sigaction(SIGCHLD, &action, NULL); 19972 19973 // Send signal 19974 kill(getpid(), SIGCHLD); 19975 19976 // Ensure that if wait has returned because of error 19977 i::OS::Sleep(100); 19978 19979 // Set value and signal semaphore 19980 test_->sem_value_ = 1; 19981 test_->sem_->Signal(); 19982 } 19983 19984 static void SignalHandler(int signal) { 19985 } 19986 19987 private: 19988 ThreadInterruptTest* test_; 19989 }; 19990 19991 i::Semaphore* sem_; 19992 volatile int sem_value_; 19993 }; 19994 19995 19996 THREADED_TEST(SemaphoreInterruption) { 19997 ThreadInterruptTest().RunTest(); 19998 } 19999 20000 20001 static bool NamedAccessAlwaysBlocked(Local<v8::Object> global, 20002 Local<Value> name, 20003 v8::AccessType type, 20004 Local<Value> data) { 20005 i::PrintF("Named access blocked.\n"); 20006 return false; 20007 } 20008 20009 20010 static bool IndexAccessAlwaysBlocked(Local<v8::Object> global, 20011 uint32_t key, 20012 v8::AccessType type, 20013 Local<Value> data) { 20014 i::PrintF("Indexed access blocked.\n"); 20015 return false; 20016 } 20017 20018 20019 void UnreachableCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 20020 CHECK(false); 20021 } 20022 20023 20024 TEST(JSONStringifyAccessCheck) { 20025 v8::V8::Initialize(); 20026 v8::HandleScope scope(v8::Isolate::GetCurrent()); 20027 20028 // Create an ObjectTemplate for global objects and install access 20029 // check callbacks that will block access. 20030 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 20031 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked, 20032 IndexAccessAlwaysBlocked); 20033 20034 // Create a context and set an x property on it's global object. 20035 LocalContext context0(NULL, global_template); 20036 v8::Handle<v8::Object> global0 = context0->Global(); 20037 global0->Set(v8_str("x"), v8_num(42)); 20038 ExpectString("JSON.stringify(this)", "{\"x\":42}"); 20039 20040 for (int i = 0; i < 2; i++) { 20041 if (i == 1) { 20042 // Install a toJSON function on the second run. 20043 v8::Handle<v8::FunctionTemplate> toJSON = 20044 v8::FunctionTemplate::New(UnreachableCallback); 20045 20046 global0->Set(v8_str("toJSON"), toJSON->GetFunction()); 20047 } 20048 // Create a context with a different security token so that the 20049 // failed access check callback will be called on each access. 20050 LocalContext context1(NULL, global_template); 20051 context1->Global()->Set(v8_str("other"), global0); 20052 20053 ExpectString("JSON.stringify(other)", "{}"); 20054 ExpectString("JSON.stringify({ 'a' : other, 'b' : ['c'] })", 20055 "{\"a\":{},\"b\":[\"c\"]}"); 20056 ExpectString("JSON.stringify([other, 'b', 'c'])", 20057 "[{},\"b\",\"c\"]"); 20058 20059 v8::Handle<v8::Array> array = v8::Array::New(2); 20060 array->Set(0, v8_str("a")); 20061 array->Set(1, v8_str("b")); 20062 context1->Global()->Set(v8_str("array"), array); 20063 ExpectString("JSON.stringify(array)", "[\"a\",\"b\"]"); 20064 array->TurnOnAccessCheck(); 20065 ExpectString("JSON.stringify(array)", "[]"); 20066 ExpectString("JSON.stringify([array])", "[[]]"); 20067 ExpectString("JSON.stringify({'a' : array})", "{\"a\":[]}"); 20068 } 20069 } 20070 20071 20072 bool access_check_fail_thrown = false; 20073 bool catch_callback_called = false; 20074 20075 20076 // Failed access check callback that performs a GC on each invocation. 20077 void FailedAccessCheckThrows(Local<v8::Object> target, 20078 v8::AccessType type, 20079 Local<v8::Value> data) { 20080 access_check_fail_thrown = true; 20081 i::PrintF("Access check failed. Error thrown.\n"); 20082 v8::ThrowException(v8::Exception::Error(v8_str("cross context"))); 20083 } 20084 20085 20086 void CatcherCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 20087 for (int i = 0; i < args.Length(); i++) { 20088 i::PrintF("%s\n", *String::Utf8Value(args[i])); 20089 } 20090 catch_callback_called = true; 20091 } 20092 20093 20094 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) { 20095 args[0]->ToObject()->HasOwnProperty(args[1]->ToString()); 20096 } 20097 20098 20099 void CheckCorrectThrow(const char* script) { 20100 // Test that the script, when wrapped into a try-catch, triggers the catch 20101 // clause due to failed access check throwing an exception. 20102 // The subsequent try-catch should run without any exception. 20103 access_check_fail_thrown = false; 20104 catch_callback_called = false; 20105 i::ScopedVector<char> source(1024); 20106 i::OS::SNPrintF(source, "try { %s; } catch (e) { catcher(e); }", script); 20107 CompileRun(source.start()); 20108 CHECK(access_check_fail_thrown); 20109 CHECK(catch_callback_called); 20110 20111 access_check_fail_thrown = false; 20112 catch_callback_called = false; 20113 CompileRun("try { [1, 2, 3].sort(); } catch (e) { catcher(e) };"); 20114 CHECK(!access_check_fail_thrown); 20115 CHECK(!catch_callback_called); 20116 } 20117 20118 20119 TEST(AccessCheckThrows) { 20120 i::FLAG_allow_natives_syntax = true; 20121 v8::V8::Initialize(); 20122 v8::V8::SetFailedAccessCheckCallbackFunction(&FailedAccessCheckThrows); 20123 v8::HandleScope scope(v8::Isolate::GetCurrent()); 20124 20125 // Create an ObjectTemplate for global objects and install access 20126 // check callbacks that will block access. 20127 v8::Handle<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New(); 20128 global_template->SetAccessCheckCallbacks(NamedAccessAlwaysBlocked, 20129 IndexAccessAlwaysBlocked); 20130 20131 // Create a context and set an x property on it's global object. 20132 LocalContext context0(NULL, global_template); 20133 context0->Global()->Set(v8_str("x"), v8_num(42)); 20134 v8::Handle<v8::Object> global0 = context0->Global(); 20135 20136 // Create a context with a different security token so that the 20137 // failed access check callback will be called on each access. 20138 LocalContext context1(NULL, global_template); 20139 context1->Global()->Set(v8_str("other"), global0); 20140 20141 v8::Handle<v8::FunctionTemplate> catcher_fun = 20142 v8::FunctionTemplate::New(CatcherCallback); 20143 context1->Global()->Set(v8_str("catcher"), catcher_fun->GetFunction()); 20144 20145 v8::Handle<v8::FunctionTemplate> has_own_property_fun = 20146 v8::FunctionTemplate::New(HasOwnPropertyCallback); 20147 context1->Global()->Set(v8_str("has_own_property"), 20148 has_own_property_fun->GetFunction()); 20149 20150 { v8::TryCatch try_catch; 20151 access_check_fail_thrown = false; 20152 CompileRun("other.x;"); 20153 CHECK(access_check_fail_thrown); 20154 CHECK(try_catch.HasCaught()); 20155 } 20156 20157 CheckCorrectThrow("other.x"); 20158 CheckCorrectThrow("other[1]"); 20159 CheckCorrectThrow("JSON.stringify(other)"); 20160 CheckCorrectThrow("has_own_property(other, 'x')"); 20161 CheckCorrectThrow("%GetProperty(other, 'x')"); 20162 CheckCorrectThrow("%SetProperty(other, 'x', 'foo', 1, 0)"); 20163 CheckCorrectThrow("%IgnoreAttributesAndSetProperty(other, 'x', 'foo')"); 20164 CheckCorrectThrow("%DeleteProperty(other, 'x', 0)"); 20165 CheckCorrectThrow("%DeleteProperty(other, '1', 0)"); 20166 CheckCorrectThrow("%HasLocalProperty(other, 'x')"); 20167 CheckCorrectThrow("%HasProperty(other, 'x')"); 20168 CheckCorrectThrow("%HasElement(other, 1)"); 20169 CheckCorrectThrow("%IsPropertyEnumerable(other, 'x')"); 20170 CheckCorrectThrow("%GetPropertyNames(other)"); 20171 CheckCorrectThrow("%GetLocalPropertyNames(other, true)"); 20172 CheckCorrectThrow("%DefineOrRedefineAccessorProperty(" 20173 "other, 'x', null, null, 1)"); 20174 } 20175 20176 20177 THREADED_TEST(Regress256330) { 20178 i::FLAG_allow_natives_syntax = true; 20179 LocalContext context; 20180 v8::HandleScope scope(context->GetIsolate()); 20181 Handle<FunctionTemplate> templ = FunctionTemplate::New(); 20182 AddInterceptor(templ, EmptyInterceptorGetter, EmptyInterceptorSetter); 20183 context->Global()->Set(v8_str("Bug"), templ->GetFunction()); 20184 CompileRun("\"use strict\"; var o = new Bug;" 20185 "function f(o) { o.x = 10; };" 20186 "f(o); f(o); f(o);" 20187 "%OptimizeFunctionOnNextCall(f);" 20188 "f(o);"); 20189 ExpectBoolean("%GetOptimizationStatus(f) != 2", true); 20190 } 20191 20192 20193 #endif // WIN32 20194