1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 2 3 #include <stdlib.h> 4 5 #include "v8.h" 6 7 #include "execution.h" 8 #include "factory.h" 9 #include "macro-assembler.h" 10 #include "global-handles.h" 11 #include "cctest.h" 12 13 using namespace v8::internal; 14 15 static v8::Persistent<v8::Context> env; 16 17 static void InitializeVM() { 18 if (env.IsEmpty()) env = v8::Context::New(); 19 v8::HandleScope scope; 20 env->Enter(); 21 } 22 23 24 static void CheckMap(Map* map, int type, int instance_size) { 25 CHECK(map->IsHeapObject()); 26 #ifdef DEBUG 27 CHECK(HEAP->Contains(map)); 28 #endif 29 CHECK_EQ(HEAP->meta_map(), map->map()); 30 CHECK_EQ(type, map->instance_type()); 31 CHECK_EQ(instance_size, map->instance_size()); 32 } 33 34 35 TEST(HeapMaps) { 36 InitializeVM(); 37 CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize); 38 CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize); 39 CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel); 40 CheckMap(HEAP->string_map(), STRING_TYPE, kVariableSizeSentinel); 41 } 42 43 44 static void CheckOddball(Object* obj, const char* string) { 45 CHECK(obj->IsOddball()); 46 bool exc; 47 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc); 48 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string))); 49 } 50 51 52 static void CheckSmi(int value, const char* string) { 53 bool exc; 54 Object* print_string = 55 *Execution::ToString(Handle<Object>(Smi::FromInt(value)), &exc); 56 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string))); 57 } 58 59 60 static void CheckNumber(double value, const char* string) { 61 Object* obj = HEAP->NumberFromDouble(value)->ToObjectChecked(); 62 CHECK(obj->IsNumber()); 63 bool exc; 64 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc); 65 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string))); 66 } 67 68 69 static void CheckFindCodeObject() { 70 // Test FindCodeObject 71 #define __ assm. 72 73 Assembler assm(Isolate::Current(), NULL, 0); 74 75 __ nop(); // supported on all architectures 76 77 CodeDesc desc; 78 assm.GetCode(&desc); 79 Object* code = HEAP->CreateCode( 80 desc, 81 Code::ComputeFlags(Code::STUB), 82 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked(); 83 CHECK(code->IsCode()); 84 85 HeapObject* obj = HeapObject::cast(code); 86 Address obj_addr = obj->address(); 87 88 for (int i = 0; i < obj->Size(); i += kPointerSize) { 89 Object* found = HEAP->FindCodeObject(obj_addr + i); 90 CHECK_EQ(code, found); 91 } 92 93 Object* copy = HEAP->CreateCode( 94 desc, 95 Code::ComputeFlags(Code::STUB), 96 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked(); 97 CHECK(copy->IsCode()); 98 HeapObject* obj_copy = HeapObject::cast(copy); 99 Object* not_right = HEAP->FindCodeObject(obj_copy->address() + 100 obj_copy->Size() / 2); 101 CHECK(not_right != code); 102 } 103 104 105 TEST(HeapObjects) { 106 InitializeVM(); 107 108 v8::HandleScope sc; 109 Object* value = HEAP->NumberFromDouble(1.000123)->ToObjectChecked(); 110 CHECK(value->IsHeapNumber()); 111 CHECK(value->IsNumber()); 112 CHECK_EQ(1.000123, value->Number()); 113 114 value = HEAP->NumberFromDouble(1.0)->ToObjectChecked(); 115 CHECK(value->IsSmi()); 116 CHECK(value->IsNumber()); 117 CHECK_EQ(1.0, value->Number()); 118 119 value = HEAP->NumberFromInt32(1024)->ToObjectChecked(); 120 CHECK(value->IsSmi()); 121 CHECK(value->IsNumber()); 122 CHECK_EQ(1024.0, value->Number()); 123 124 value = HEAP->NumberFromInt32(Smi::kMinValue)->ToObjectChecked(); 125 CHECK(value->IsSmi()); 126 CHECK(value->IsNumber()); 127 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value()); 128 129 value = HEAP->NumberFromInt32(Smi::kMaxValue)->ToObjectChecked(); 130 CHECK(value->IsSmi()); 131 CHECK(value->IsNumber()); 132 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value()); 133 134 #ifndef V8_TARGET_ARCH_X64 135 // TODO(lrn): We need a NumberFromIntptr function in order to test this. 136 value = HEAP->NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked(); 137 CHECK(value->IsHeapNumber()); 138 CHECK(value->IsNumber()); 139 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number()); 140 #endif 141 142 MaybeObject* maybe_value = 143 HEAP->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1); 144 value = maybe_value->ToObjectChecked(); 145 CHECK(value->IsHeapNumber()); 146 CHECK(value->IsNumber()); 147 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1), 148 value->Number()); 149 150 // nan oddball checks 151 CHECK(HEAP->nan_value()->IsNumber()); 152 CHECK(isnan(HEAP->nan_value()->Number())); 153 154 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest ")); 155 CHECK(s->IsString()); 156 CHECK_EQ(10, s->length()); 157 158 String* object_symbol = String::cast(HEAP->Object_symbol()); 159 CHECK( 160 Isolate::Current()->context()->global()->HasLocalProperty(object_symbol)); 161 162 // Check ToString for oddballs 163 CheckOddball(HEAP->true_value(), "true"); 164 CheckOddball(HEAP->false_value(), "false"); 165 CheckOddball(HEAP->null_value(), "null"); 166 CheckOddball(HEAP->undefined_value(), "undefined"); 167 168 // Check ToString for Smis 169 CheckSmi(0, "0"); 170 CheckSmi(42, "42"); 171 CheckSmi(-42, "-42"); 172 173 // Check ToString for Numbers 174 CheckNumber(1.1, "1.1"); 175 176 CheckFindCodeObject(); 177 } 178 179 180 TEST(Tagging) { 181 InitializeVM(); 182 int request = 24; 183 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request))); 184 CHECK(Smi::FromInt(42)->IsSmi()); 185 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure()); 186 CHECK_EQ(NEW_SPACE, 187 Failure::RetryAfterGC(NEW_SPACE)->allocation_space()); 188 CHECK_EQ(OLD_POINTER_SPACE, 189 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space()); 190 CHECK(Failure::Exception()->IsFailure()); 191 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi()); 192 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi()); 193 } 194 195 196 TEST(GarbageCollection) { 197 InitializeVM(); 198 199 v8::HandleScope sc; 200 // Check GC. 201 HEAP->CollectGarbage(NEW_SPACE); 202 203 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction"); 204 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot"); 205 Handle<String> prop_namex = FACTORY->LookupAsciiSymbol("theSlotx"); 206 Handle<String> obj_name = FACTORY->LookupAsciiSymbol("theObject"); 207 208 { 209 v8::HandleScope inner_scope; 210 // Allocate a function and keep it in global object's property. 211 Handle<JSFunction> function = 212 FACTORY->NewFunction(name, FACTORY->undefined_value()); 213 Handle<Map> initial_map = 214 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); 215 function->set_initial_map(*initial_map); 216 Isolate::Current()->context()->global()->SetProperty( 217 *name, *function, NONE, kNonStrictMode)->ToObjectChecked(); 218 // Allocate an object. Unrooted after leaving the scope. 219 Handle<JSObject> obj = FACTORY->NewJSObject(function); 220 obj->SetProperty( 221 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked(); 222 obj->SetProperty( 223 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked(); 224 225 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name)); 226 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex)); 227 } 228 229 HEAP->CollectGarbage(NEW_SPACE); 230 231 // Function should be alive. 232 CHECK(Isolate::Current()->context()->global()->HasLocalProperty(*name)); 233 // Check function is retained. 234 Object* func_value = Isolate::Current()->context()->global()-> 235 GetProperty(*name)->ToObjectChecked(); 236 CHECK(func_value->IsJSFunction()); 237 Handle<JSFunction> function(JSFunction::cast(func_value)); 238 239 { 240 HandleScope inner_scope; 241 // Allocate another object, make it reachable from global. 242 Handle<JSObject> obj = FACTORY->NewJSObject(function); 243 Isolate::Current()->context()->global()->SetProperty( 244 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked(); 245 obj->SetProperty( 246 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked(); 247 } 248 249 // After gc, it should survive. 250 HEAP->CollectGarbage(NEW_SPACE); 251 252 CHECK(Isolate::Current()->context()->global()->HasLocalProperty(*obj_name)); 253 CHECK(Isolate::Current()->context()->global()-> 254 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject()); 255 Object* obj = Isolate::Current()->context()->global()-> 256 GetProperty(*obj_name)->ToObjectChecked(); 257 JSObject* js_obj = JSObject::cast(obj); 258 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name)); 259 } 260 261 262 static void VerifyStringAllocation(const char* string) { 263 v8::HandleScope scope; 264 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string)); 265 CHECK_EQ(StrLength(string), s->length()); 266 for (int index = 0; index < s->length(); index++) { 267 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index)); 268 } 269 } 270 271 272 TEST(String) { 273 InitializeVM(); 274 275 VerifyStringAllocation("a"); 276 VerifyStringAllocation("ab"); 277 VerifyStringAllocation("abc"); 278 VerifyStringAllocation("abcd"); 279 VerifyStringAllocation("fiskerdrengen er paa havet"); 280 } 281 282 283 TEST(LocalHandles) { 284 InitializeVM(); 285 286 v8::HandleScope scope; 287 const char* name = "Kasper the spunky"; 288 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name)); 289 CHECK_EQ(StrLength(name), string->length()); 290 } 291 292 293 TEST(GlobalHandles) { 294 InitializeVM(); 295 GlobalHandles* global_handles = Isolate::Current()->global_handles(); 296 297 Handle<Object> h1; 298 Handle<Object> h2; 299 Handle<Object> h3; 300 Handle<Object> h4; 301 302 { 303 HandleScope scope; 304 305 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk")); 306 Handle<Object> u = FACTORY->NewNumber(1.12344); 307 308 h1 = global_handles->Create(*i); 309 h2 = global_handles->Create(*u); 310 h3 = global_handles->Create(*i); 311 h4 = global_handles->Create(*u); 312 } 313 314 // after gc, it should survive 315 HEAP->CollectGarbage(NEW_SPACE); 316 317 CHECK((*h1)->IsString()); 318 CHECK((*h2)->IsHeapNumber()); 319 CHECK((*h3)->IsString()); 320 CHECK((*h4)->IsHeapNumber()); 321 322 CHECK_EQ(*h3, *h1); 323 global_handles->Destroy(h1.location()); 324 global_handles->Destroy(h3.location()); 325 326 CHECK_EQ(*h4, *h2); 327 global_handles->Destroy(h2.location()); 328 global_handles->Destroy(h4.location()); 329 } 330 331 332 static bool WeakPointerCleared = false; 333 334 static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle, 335 void* id) { 336 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true; 337 handle.Dispose(); 338 } 339 340 341 TEST(WeakGlobalHandlesScavenge) { 342 InitializeVM(); 343 GlobalHandles* global_handles = Isolate::Current()->global_handles(); 344 345 WeakPointerCleared = false; 346 347 Handle<Object> h1; 348 Handle<Object> h2; 349 350 { 351 HandleScope scope; 352 353 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk")); 354 Handle<Object> u = FACTORY->NewNumber(1.12344); 355 356 h1 = global_handles->Create(*i); 357 h2 = global_handles->Create(*u); 358 } 359 360 global_handles->MakeWeak(h2.location(), 361 reinterpret_cast<void*>(1234), 362 &TestWeakGlobalHandleCallback); 363 364 // Scavenge treats weak pointers as normal roots. 365 HEAP->PerformScavenge(); 366 367 CHECK((*h1)->IsString()); 368 CHECK((*h2)->IsHeapNumber()); 369 370 CHECK(!WeakPointerCleared); 371 CHECK(!global_handles->IsNearDeath(h2.location())); 372 CHECK(!global_handles->IsNearDeath(h1.location())); 373 374 global_handles->Destroy(h1.location()); 375 global_handles->Destroy(h2.location()); 376 } 377 378 379 TEST(WeakGlobalHandlesMark) { 380 InitializeVM(); 381 GlobalHandles* global_handles = Isolate::Current()->global_handles(); 382 383 WeakPointerCleared = false; 384 385 Handle<Object> h1; 386 Handle<Object> h2; 387 388 { 389 HandleScope scope; 390 391 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk")); 392 Handle<Object> u = FACTORY->NewNumber(1.12344); 393 394 h1 = global_handles->Create(*i); 395 h2 = global_handles->Create(*u); 396 } 397 398 HEAP->CollectGarbage(OLD_POINTER_SPACE); 399 HEAP->CollectGarbage(NEW_SPACE); 400 // Make sure the object is promoted. 401 402 global_handles->MakeWeak(h2.location(), 403 reinterpret_cast<void*>(1234), 404 &TestWeakGlobalHandleCallback); 405 CHECK(!GlobalHandles::IsNearDeath(h1.location())); 406 CHECK(!GlobalHandles::IsNearDeath(h2.location())); 407 408 HEAP->CollectGarbage(OLD_POINTER_SPACE); 409 410 CHECK((*h1)->IsString()); 411 412 CHECK(WeakPointerCleared); 413 CHECK(!GlobalHandles::IsNearDeath(h1.location())); 414 415 global_handles->Destroy(h1.location()); 416 } 417 418 TEST(DeleteWeakGlobalHandle) { 419 InitializeVM(); 420 GlobalHandles* global_handles = Isolate::Current()->global_handles(); 421 422 WeakPointerCleared = false; 423 424 Handle<Object> h; 425 426 { 427 HandleScope scope; 428 429 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk")); 430 h = global_handles->Create(*i); 431 } 432 433 global_handles->MakeWeak(h.location(), 434 reinterpret_cast<void*>(1234), 435 &TestWeakGlobalHandleCallback); 436 437 // Scanvenge does not recognize weak reference. 438 HEAP->PerformScavenge(); 439 440 CHECK(!WeakPointerCleared); 441 442 // Mark-compact treats weak reference properly. 443 HEAP->CollectGarbage(OLD_POINTER_SPACE); 444 445 CHECK(WeakPointerCleared); 446 } 447 448 static const char* not_so_random_string_table[] = { 449 "abstract", 450 "boolean", 451 "break", 452 "byte", 453 "case", 454 "catch", 455 "char", 456 "class", 457 "const", 458 "continue", 459 "debugger", 460 "default", 461 "delete", 462 "do", 463 "double", 464 "else", 465 "enum", 466 "export", 467 "extends", 468 "false", 469 "final", 470 "finally", 471 "float", 472 "for", 473 "function", 474 "goto", 475 "if", 476 "implements", 477 "import", 478 "in", 479 "instanceof", 480 "int", 481 "interface", 482 "long", 483 "native", 484 "new", 485 "null", 486 "package", 487 "private", 488 "protected", 489 "public", 490 "return", 491 "short", 492 "static", 493 "super", 494 "switch", 495 "synchronized", 496 "this", 497 "throw", 498 "throws", 499 "transient", 500 "true", 501 "try", 502 "typeof", 503 "var", 504 "void", 505 "volatile", 506 "while", 507 "with", 508 0 509 }; 510 511 512 static void CheckSymbols(const char** strings) { 513 for (const char* string = *strings; *strings != 0; string = *strings++) { 514 Object* a; 515 MaybeObject* maybe_a = HEAP->LookupAsciiSymbol(string); 516 // LookupAsciiSymbol may return a failure if a GC is needed. 517 if (!maybe_a->ToObject(&a)) continue; 518 CHECK(a->IsSymbol()); 519 Object* b; 520 MaybeObject* maybe_b = HEAP->LookupAsciiSymbol(string); 521 if (!maybe_b->ToObject(&b)) continue; 522 CHECK_EQ(b, a); 523 CHECK(String::cast(b)->IsEqualTo(CStrVector(string))); 524 } 525 } 526 527 528 TEST(SymbolTable) { 529 InitializeVM(); 530 531 CheckSymbols(not_so_random_string_table); 532 CheckSymbols(not_so_random_string_table); 533 } 534 535 536 TEST(FunctionAllocation) { 537 InitializeVM(); 538 539 v8::HandleScope sc; 540 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction"); 541 Handle<JSFunction> function = 542 FACTORY->NewFunction(name, FACTORY->undefined_value()); 543 Handle<Map> initial_map = 544 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); 545 function->set_initial_map(*initial_map); 546 547 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot"); 548 Handle<JSObject> obj = FACTORY->NewJSObject(function); 549 obj->SetProperty( 550 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked(); 551 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name)); 552 // Check that we can add properties to function objects. 553 function->SetProperty( 554 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked(); 555 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name)); 556 } 557 558 559 TEST(ObjectProperties) { 560 InitializeVM(); 561 562 v8::HandleScope sc; 563 String* object_symbol = String::cast(HEAP->Object_symbol()); 564 Object* raw_object = Isolate::Current()->context()->global()-> 565 GetProperty(object_symbol)->ToObjectChecked(); 566 JSFunction* object_function = JSFunction::cast(raw_object); 567 Handle<JSFunction> constructor(object_function); 568 Handle<JSObject> obj = FACTORY->NewJSObject(constructor); 569 Handle<String> first = FACTORY->LookupAsciiSymbol("first"); 570 Handle<String> second = FACTORY->LookupAsciiSymbol("second"); 571 572 // check for empty 573 CHECK(!obj->HasLocalProperty(*first)); 574 575 // add first 576 obj->SetProperty( 577 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); 578 CHECK(obj->HasLocalProperty(*first)); 579 580 // delete first 581 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION)); 582 CHECK(!obj->HasLocalProperty(*first)); 583 584 // add first and then second 585 obj->SetProperty( 586 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); 587 obj->SetProperty( 588 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked(); 589 CHECK(obj->HasLocalProperty(*first)); 590 CHECK(obj->HasLocalProperty(*second)); 591 592 // delete first and then second 593 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION)); 594 CHECK(obj->HasLocalProperty(*second)); 595 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION)); 596 CHECK(!obj->HasLocalProperty(*first)); 597 CHECK(!obj->HasLocalProperty(*second)); 598 599 // add first and then second 600 obj->SetProperty( 601 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); 602 obj->SetProperty( 603 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked(); 604 CHECK(obj->HasLocalProperty(*first)); 605 CHECK(obj->HasLocalProperty(*second)); 606 607 // delete second and then first 608 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION)); 609 CHECK(obj->HasLocalProperty(*first)); 610 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION)); 611 CHECK(!obj->HasLocalProperty(*first)); 612 CHECK(!obj->HasLocalProperty(*second)); 613 614 // check string and symbol match 615 static const char* string1 = "fisk"; 616 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1)); 617 obj->SetProperty( 618 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); 619 Handle<String> s1_symbol = FACTORY->LookupAsciiSymbol(string1); 620 CHECK(obj->HasLocalProperty(*s1_symbol)); 621 622 // check symbol and string match 623 static const char* string2 = "fugl"; 624 Handle<String> s2_symbol = FACTORY->LookupAsciiSymbol(string2); 625 obj->SetProperty( 626 *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); 627 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2)); 628 CHECK(obj->HasLocalProperty(*s2)); 629 } 630 631 632 TEST(JSObjectMaps) { 633 InitializeVM(); 634 635 v8::HandleScope sc; 636 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction"); 637 Handle<JSFunction> function = 638 FACTORY->NewFunction(name, FACTORY->undefined_value()); 639 Handle<Map> initial_map = 640 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize); 641 function->set_initial_map(*initial_map); 642 643 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot"); 644 Handle<JSObject> obj = FACTORY->NewJSObject(function); 645 646 // Set a propery 647 obj->SetProperty( 648 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked(); 649 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name)); 650 651 // Check the map has changed 652 CHECK(*initial_map != obj->map()); 653 } 654 655 656 TEST(JSArray) { 657 InitializeVM(); 658 659 v8::HandleScope sc; 660 Handle<String> name = FACTORY->LookupAsciiSymbol("Array"); 661 Object* raw_object = Isolate::Current()->context()->global()-> 662 GetProperty(*name)->ToObjectChecked(); 663 Handle<JSFunction> function = Handle<JSFunction>( 664 JSFunction::cast(raw_object)); 665 666 // Allocate the object. 667 Handle<JSObject> object = FACTORY->NewJSObject(function); 668 Handle<JSArray> array = Handle<JSArray>::cast(object); 669 // We just initialized the VM, no heap allocation failure yet. 670 Object* ok = array->Initialize(0)->ToObjectChecked(); 671 672 // Set array length to 0. 673 ok = array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked(); 674 CHECK_EQ(Smi::FromInt(0), array->length()); 675 CHECK(array->HasFastElements()); // Must be in fast mode. 676 677 // array[length] = name. 678 ok = array->SetElement(0, *name, kNonStrictMode)->ToObjectChecked(); 679 CHECK_EQ(Smi::FromInt(1), array->length()); 680 CHECK_EQ(array->GetElement(0), *name); 681 682 // Set array length with larger than smi value. 683 Handle<Object> length = 684 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1); 685 ok = array->SetElementsLength(*length)->ToObjectChecked(); 686 687 uint32_t int_length = 0; 688 CHECK(length->ToArrayIndex(&int_length)); 689 CHECK_EQ(*length, array->length()); 690 CHECK(array->HasDictionaryElements()); // Must be in slow mode. 691 692 // array[length] = name. 693 ok = array->SetElement(int_length, *name, kNonStrictMode)->ToObjectChecked(); 694 uint32_t new_int_length = 0; 695 CHECK(array->length()->ToArrayIndex(&new_int_length)); 696 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1); 697 CHECK_EQ(array->GetElement(int_length), *name); 698 CHECK_EQ(array->GetElement(0), *name); 699 } 700 701 702 TEST(JSObjectCopy) { 703 InitializeVM(); 704 705 v8::HandleScope sc; 706 String* object_symbol = String::cast(HEAP->Object_symbol()); 707 Object* raw_object = Isolate::Current()->context()->global()-> 708 GetProperty(object_symbol)->ToObjectChecked(); 709 JSFunction* object_function = JSFunction::cast(raw_object); 710 Handle<JSFunction> constructor(object_function); 711 Handle<JSObject> obj = FACTORY->NewJSObject(constructor); 712 Handle<String> first = FACTORY->LookupAsciiSymbol("first"); 713 Handle<String> second = FACTORY->LookupAsciiSymbol("second"); 714 715 obj->SetProperty( 716 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); 717 obj->SetProperty( 718 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked(); 719 720 Object* ok = obj->SetElement(0, *first, kNonStrictMode)->ToObjectChecked(); 721 722 ok = obj->SetElement(1, *second, kNonStrictMode)->ToObjectChecked(); 723 724 // Make the clone. 725 Handle<JSObject> clone = Copy(obj); 726 CHECK(!clone.is_identical_to(obj)); 727 728 CHECK_EQ(obj->GetElement(0), clone->GetElement(0)); 729 CHECK_EQ(obj->GetElement(1), clone->GetElement(1)); 730 731 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first)); 732 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second)); 733 734 // Flip the values. 735 clone->SetProperty( 736 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked(); 737 clone->SetProperty( 738 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked(); 739 740 ok = clone->SetElement(0, *second, kNonStrictMode)->ToObjectChecked(); 741 ok = clone->SetElement(1, *first, kNonStrictMode)->ToObjectChecked(); 742 743 CHECK_EQ(obj->GetElement(1), clone->GetElement(0)); 744 CHECK_EQ(obj->GetElement(0), clone->GetElement(1)); 745 746 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first)); 747 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second)); 748 } 749 750 751 TEST(StringAllocation) { 752 InitializeVM(); 753 754 755 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 }; 756 for (int length = 0; length < 100; length++) { 757 v8::HandleScope scope; 758 char* non_ascii = NewArray<char>(3 * length + 1); 759 char* ascii = NewArray<char>(length + 1); 760 non_ascii[3 * length] = 0; 761 ascii[length] = 0; 762 for (int i = 0; i < length; i++) { 763 ascii[i] = 'a'; 764 non_ascii[3 * i] = chars[0]; 765 non_ascii[3 * i + 1] = chars[1]; 766 non_ascii[3 * i + 2] = chars[2]; 767 } 768 Handle<String> non_ascii_sym = 769 FACTORY->LookupSymbol(Vector<const char>(non_ascii, 3 * length)); 770 CHECK_EQ(length, non_ascii_sym->length()); 771 Handle<String> ascii_sym = 772 FACTORY->LookupSymbol(Vector<const char>(ascii, length)); 773 CHECK_EQ(length, ascii_sym->length()); 774 Handle<String> non_ascii_str = 775 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length)); 776 non_ascii_str->Hash(); 777 CHECK_EQ(length, non_ascii_str->length()); 778 Handle<String> ascii_str = 779 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length)); 780 ascii_str->Hash(); 781 CHECK_EQ(length, ascii_str->length()); 782 DeleteArray(non_ascii); 783 DeleteArray(ascii); 784 } 785 } 786 787 788 static int ObjectsFoundInHeap(Handle<Object> objs[], int size) { 789 // Count the number of objects found in the heap. 790 int found_count = 0; 791 HeapIterator iterator; 792 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { 793 for (int i = 0; i < size; i++) { 794 if (*objs[i] == obj) { 795 found_count++; 796 } 797 } 798 } 799 return found_count; 800 } 801 802 803 TEST(Iteration) { 804 InitializeVM(); 805 v8::HandleScope scope; 806 807 // Array of objects to scan haep for. 808 const int objs_count = 6; 809 Handle<Object> objs[objs_count]; 810 int next_objs_index = 0; 811 812 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE 813 objs[next_objs_index++] = FACTORY->NewJSArray(10); 814 objs[next_objs_index++] = FACTORY->NewJSArray(10, TENURED); 815 816 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE 817 objs[next_objs_index++] = 818 FACTORY->NewStringFromAscii(CStrVector("abcdefghij")); 819 objs[next_objs_index++] = 820 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED); 821 822 // Allocate a large string (for large object space). 823 int large_size = HEAP->MaxObjectSizeInPagedSpace() + 1; 824 char* str = new char[large_size]; 825 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a'; 826 str[large_size - 1] = '\0'; 827 objs[next_objs_index++] = 828 FACTORY->NewStringFromAscii(CStrVector(str), TENURED); 829 delete[] str; 830 831 // Add a Map object to look for. 832 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map()); 833 834 CHECK_EQ(objs_count, next_objs_index); 835 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count)); 836 } 837 838 839 TEST(LargeObjectSpaceContains) { 840 InitializeVM(); 841 842 HEAP->CollectGarbage(NEW_SPACE); 843 844 Address current_top = HEAP->new_space()->top(); 845 Page* page = Page::FromAddress(current_top); 846 Address current_page = page->address(); 847 Address next_page = current_page + Page::kPageSize; 848 int bytes_to_page = static_cast<int>(next_page - current_top); 849 if (bytes_to_page <= FixedArray::kHeaderSize) { 850 // Alas, need to cross another page to be able to 851 // put desired value. 852 next_page += Page::kPageSize; 853 bytes_to_page = static_cast<int>(next_page - current_top); 854 } 855 CHECK(bytes_to_page > FixedArray::kHeaderSize); 856 857 intptr_t* flags_ptr = &Page::FromAddress(next_page)->flags_; 858 Address flags_addr = reinterpret_cast<Address>(flags_ptr); 859 860 int bytes_to_allocate = 861 static_cast<int>(flags_addr - current_top) + kPointerSize; 862 863 int n_elements = (bytes_to_allocate - FixedArray::kHeaderSize) / 864 kPointerSize; 865 CHECK_EQ(bytes_to_allocate, FixedArray::SizeFor(n_elements)); 866 FixedArray* array = FixedArray::cast( 867 HEAP->AllocateFixedArray(n_elements)->ToObjectChecked()); 868 869 int index = n_elements - 1; 870 CHECK_EQ(flags_ptr, 871 HeapObject::RawField(array, FixedArray::OffsetOfElementAt(index))); 872 array->set(index, Smi::FromInt(0)); 873 // This chould have turned next page into LargeObjectPage: 874 // CHECK(Page::FromAddress(next_page)->IsLargeObjectPage()); 875 876 HeapObject* addr = HeapObject::FromAddress(next_page + 2 * kPointerSize); 877 CHECK(HEAP->new_space()->Contains(addr)); 878 CHECK(!HEAP->lo_space()->Contains(addr)); 879 } 880 881 882 TEST(EmptyHandleEscapeFrom) { 883 InitializeVM(); 884 885 v8::HandleScope scope; 886 Handle<JSObject> runaway; 887 888 { 889 v8::HandleScope nested; 890 Handle<JSObject> empty; 891 runaway = empty.EscapeFrom(&nested); 892 } 893 894 CHECK(runaway.is_null()); 895 } 896 897 898 static int LenFromSize(int size) { 899 return (size - FixedArray::kHeaderSize) / kPointerSize; 900 } 901 902 903 TEST(Regression39128) { 904 // Test case for crbug.com/39128. 905 InitializeVM(); 906 907 // Increase the chance of 'bump-the-pointer' allocation in old space. 908 bool force_compaction = true; 909 HEAP->CollectAllGarbage(force_compaction); 910 911 v8::HandleScope scope; 912 913 // The plan: create JSObject which references objects in new space. 914 // Then clone this object (forcing it to go into old space) and check 915 // that region dirty marks are updated correctly. 916 917 // Step 1: prepare a map for the object. We add 1 inobject property to it. 918 Handle<JSFunction> object_ctor( 919 Isolate::Current()->global_context()->object_function()); 920 CHECK(object_ctor->has_initial_map()); 921 Handle<Map> object_map(object_ctor->initial_map()); 922 // Create a map with single inobject property. 923 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1); 924 int n_properties = my_map->inobject_properties(); 925 CHECK_GT(n_properties, 0); 926 927 int object_size = my_map->instance_size(); 928 929 // Step 2: allocate a lot of objects so to almost fill new space: we need 930 // just enough room to allocate JSObject and thus fill the newspace. 931 932 int allocation_amount = Min(FixedArray::kMaxSize, 933 HEAP->MaxObjectSizeInNewSpace()); 934 int allocation_len = LenFromSize(allocation_amount); 935 NewSpace* new_space = HEAP->new_space(); 936 Address* top_addr = new_space->allocation_top_address(); 937 Address* limit_addr = new_space->allocation_limit_address(); 938 while ((*limit_addr - *top_addr) > allocation_amount) { 939 CHECK(!HEAP->always_allocate()); 940 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked(); 941 CHECK(!array->IsFailure()); 942 CHECK(new_space->Contains(array)); 943 } 944 945 // Step 3: now allocate fixed array and JSObject to fill the whole new space. 946 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size); 947 int fixed_array_len = LenFromSize(to_fill); 948 CHECK(fixed_array_len < FixedArray::kMaxLength); 949 950 CHECK(!HEAP->always_allocate()); 951 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked(); 952 CHECK(!array->IsFailure()); 953 CHECK(new_space->Contains(array)); 954 955 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked(); 956 CHECK(new_space->Contains(object)); 957 JSObject* jsobject = JSObject::cast(object); 958 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length()); 959 CHECK_EQ(0, jsobject->properties()->length()); 960 // Create a reference to object in new space in jsobject. 961 jsobject->FastPropertyAtPut(-1, array); 962 963 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr)); 964 965 // Step 4: clone jsobject, but force always allocate first to create a clone 966 // in old pointer space. 967 Address old_pointer_space_top = HEAP->old_pointer_space()->top(); 968 AlwaysAllocateScope aa_scope; 969 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked(); 970 JSObject* clone = JSObject::cast(clone_obj); 971 if (clone->address() != old_pointer_space_top) { 972 // Alas, got allocated from free list, we cannot do checks. 973 return; 974 } 975 CHECK(HEAP->old_pointer_space()->Contains(clone->address())); 976 977 // Step 5: verify validity of region dirty marks. 978 Address clone_addr = clone->address(); 979 Page* page = Page::FromAddress(clone_addr); 980 // Check that region covering inobject property 1 is marked dirty. 981 CHECK(page->IsRegionDirty(clone_addr + (object_size - kPointerSize))); 982 } 983 984 985 TEST(TestCodeFlushing) { 986 i::FLAG_allow_natives_syntax = true; 987 // If we do not flush code this test is invalid. 988 if (!FLAG_flush_code) return; 989 InitializeVM(); 990 v8::HandleScope scope; 991 const char* source = "function foo() {" 992 " var x = 42;" 993 " var y = 42;" 994 " var z = x + y;" 995 "};" 996 "foo()"; 997 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo"); 998 999 // This compile will add the code to the compilation cache. 1000 { v8::HandleScope scope; 1001 CompileRun(source); 1002 } 1003 1004 // Check function is compiled. 1005 Object* func_value = Isolate::Current()->context()->global()-> 1006 GetProperty(*foo_name)->ToObjectChecked(); 1007 CHECK(func_value->IsJSFunction()); 1008 Handle<JSFunction> function(JSFunction::cast(func_value)); 1009 CHECK(function->shared()->is_compiled()); 1010 1011 HEAP->CollectAllGarbage(true); 1012 HEAP->CollectAllGarbage(true); 1013 1014 CHECK(function->shared()->is_compiled()); 1015 1016 HEAP->CollectAllGarbage(true); 1017 HEAP->CollectAllGarbage(true); 1018 HEAP->CollectAllGarbage(true); 1019 HEAP->CollectAllGarbage(true); 1020 HEAP->CollectAllGarbage(true); 1021 HEAP->CollectAllGarbage(true); 1022 1023 // foo should no longer be in the compilation cache 1024 CHECK(!function->shared()->is_compiled() || function->IsOptimized()); 1025 CHECK(!function->is_compiled() || function->IsOptimized()); 1026 // Call foo to get it recompiled. 1027 CompileRun("foo()"); 1028 CHECK(function->shared()->is_compiled()); 1029 CHECK(function->is_compiled()); 1030 } 1031 1032 1033 // Count the number of global contexts in the weak list of global contexts. 1034 static int CountGlobalContexts() { 1035 int count = 0; 1036 Object* object = HEAP->global_contexts_list(); 1037 while (!object->IsUndefined()) { 1038 count++; 1039 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK); 1040 } 1041 return count; 1042 } 1043 1044 1045 // Count the number of user functions in the weak list of optimized 1046 // functions attached to a global context. 1047 static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) { 1048 int count = 0; 1049 Handle<Context> icontext = v8::Utils::OpenHandle(*context); 1050 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST); 1051 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) { 1052 count++; 1053 object = JSFunction::cast(object)->next_function_link(); 1054 } 1055 return count; 1056 } 1057 1058 1059 TEST(TestInternalWeakLists) { 1060 v8::V8::Initialize(); 1061 1062 static const int kNumTestContexts = 10; 1063 1064 v8::HandleScope scope; 1065 v8::Persistent<v8::Context> ctx[kNumTestContexts]; 1066 1067 CHECK_EQ(0, CountGlobalContexts()); 1068 1069 // Create a number of global contests which gets linked together. 1070 for (int i = 0; i < kNumTestContexts; i++) { 1071 ctx[i] = v8::Context::New(); 1072 1073 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft()); 1074 1075 CHECK_EQ(i + 1, CountGlobalContexts()); 1076 1077 ctx[i]->Enter(); 1078 1079 // Create a handle scope so no function objects get stuch in the outer 1080 // handle scope 1081 v8::HandleScope scope; 1082 const char* source = "function f1() { };" 1083 "function f2() { };" 1084 "function f3() { };" 1085 "function f4() { };" 1086 "function f5() { };"; 1087 CompileRun(source); 1088 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i])); 1089 CompileRun("f1()"); 1090 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i])); 1091 CompileRun("f2()"); 1092 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i])); 1093 CompileRun("f3()"); 1094 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); 1095 CompileRun("f4()"); 1096 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); 1097 CompileRun("f5()"); 1098 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i])); 1099 1100 // Remove function f1, and 1101 CompileRun("f1=null"); 1102 1103 // Scavenge treats these references as strong. 1104 for (int j = 0; j < 10; j++) { 1105 HEAP->PerformScavenge(); 1106 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i])); 1107 } 1108 1109 // Mark compact handles the weak references. 1110 HEAP->CollectAllGarbage(true); 1111 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); 1112 1113 // Get rid of f3 and f5 in the same way. 1114 CompileRun("f3=null"); 1115 for (int j = 0; j < 10; j++) { 1116 HEAP->PerformScavenge(); 1117 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i])); 1118 } 1119 HEAP->CollectAllGarbage(true); 1120 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); 1121 CompileRun("f5=null"); 1122 for (int j = 0; j < 10; j++) { 1123 HEAP->PerformScavenge(); 1124 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i])); 1125 } 1126 HEAP->CollectAllGarbage(true); 1127 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i])); 1128 1129 ctx[i]->Exit(); 1130 } 1131 1132 // Force compilation cache cleanup. 1133 HEAP->CollectAllGarbage(true); 1134 1135 // Dispose the global contexts one by one. 1136 for (int i = 0; i < kNumTestContexts; i++) { 1137 ctx[i].Dispose(); 1138 ctx[i].Clear(); 1139 1140 // Scavenge treats these references as strong. 1141 for (int j = 0; j < 10; j++) { 1142 HEAP->PerformScavenge(); 1143 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts()); 1144 } 1145 1146 // Mark compact handles the weak references. 1147 HEAP->CollectAllGarbage(true); 1148 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts()); 1149 } 1150 1151 CHECK_EQ(0, CountGlobalContexts()); 1152 } 1153 1154 1155 // Count the number of global contexts in the weak list of global contexts 1156 // causing a GC after the specified number of elements. 1157 static int CountGlobalContextsWithGC(int n) { 1158 int count = 0; 1159 Handle<Object> object(HEAP->global_contexts_list()); 1160 while (!object->IsUndefined()) { 1161 count++; 1162 if (count == n) HEAP->CollectAllGarbage(true); 1163 object = 1164 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK)); 1165 } 1166 return count; 1167 } 1168 1169 1170 // Count the number of user functions in the weak list of optimized 1171 // functions attached to a global context causing a GC after the 1172 // specified number of elements. 1173 static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context, 1174 int n) { 1175 int count = 0; 1176 Handle<Context> icontext = v8::Utils::OpenHandle(*context); 1177 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST)); 1178 while (object->IsJSFunction() && 1179 !Handle<JSFunction>::cast(object)->IsBuiltin()) { 1180 count++; 1181 if (count == n) HEAP->CollectAllGarbage(true); 1182 object = Handle<Object>( 1183 Object::cast(JSFunction::cast(*object)->next_function_link())); 1184 } 1185 return count; 1186 } 1187 1188 1189 TEST(TestInternalWeakListsTraverseWithGC) { 1190 v8::V8::Initialize(); 1191 1192 static const int kNumTestContexts = 10; 1193 1194 v8::HandleScope scope; 1195 v8::Persistent<v8::Context> ctx[kNumTestContexts]; 1196 1197 CHECK_EQ(0, CountGlobalContexts()); 1198 1199 // Create an number of contexts and check the length of the weak list both 1200 // with and without GCs while iterating the list. 1201 for (int i = 0; i < kNumTestContexts; i++) { 1202 ctx[i] = v8::Context::New(); 1203 CHECK_EQ(i + 1, CountGlobalContexts()); 1204 CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1)); 1205 } 1206 1207 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft()); 1208 1209 // Compile a number of functions the length of the weak list of optimized 1210 // functions both with and without GCs while iterating the list. 1211 ctx[0]->Enter(); 1212 const char* source = "function f1() { };" 1213 "function f2() { };" 1214 "function f3() { };" 1215 "function f4() { };" 1216 "function f5() { };"; 1217 CompileRun(source); 1218 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0])); 1219 CompileRun("f1()"); 1220 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0])); 1221 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1)); 1222 CompileRun("f2()"); 1223 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0])); 1224 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1)); 1225 CompileRun("f3()"); 1226 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0])); 1227 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1)); 1228 CompileRun("f4()"); 1229 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0])); 1230 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2)); 1231 CompileRun("f5()"); 1232 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0])); 1233 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4)); 1234 1235 ctx[0]->Exit(); 1236 } 1237 1238 1239 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) { 1240 InitializeVM(); 1241 intptr_t size_of_objects_1 = HEAP->SizeOfObjects(); 1242 HeapIterator iterator(HeapIterator::kFilterFreeListNodes); 1243 intptr_t size_of_objects_2 = 0; 1244 for (HeapObject* obj = iterator.next(); 1245 obj != NULL; 1246 obj = iterator.next()) { 1247 size_of_objects_2 += obj->Size(); 1248 } 1249 // Delta must be within 1% of the larger result. 1250 if (size_of_objects_1 > size_of_objects_2) { 1251 intptr_t delta = size_of_objects_1 - size_of_objects_2; 1252 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " 1253 "Iterator: %" V8_PTR_PREFIX "d, " 1254 "delta: %" V8_PTR_PREFIX "d\n", 1255 size_of_objects_1, size_of_objects_2, delta); 1256 CHECK_GT(size_of_objects_1 / 100, delta); 1257 } else { 1258 intptr_t delta = size_of_objects_2 - size_of_objects_1; 1259 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, " 1260 "Iterator: %" V8_PTR_PREFIX "d, " 1261 "delta: %" V8_PTR_PREFIX "d\n", 1262 size_of_objects_1, size_of_objects_2, delta); 1263 CHECK_GT(size_of_objects_2 / 100, delta); 1264 } 1265 } 1266 1267 1268 class HeapIteratorTestHelper { 1269 public: 1270 HeapIteratorTestHelper(Object* a, Object* b) 1271 : a_(a), b_(b), a_found_(false), b_found_(false) {} 1272 bool a_found() { return a_found_; } 1273 bool b_found() { return b_found_; } 1274 void IterateHeap(HeapIterator::HeapObjectsFiltering mode) { 1275 HeapIterator iterator(mode); 1276 for (HeapObject* obj = iterator.next(); 1277 obj != NULL; 1278 obj = iterator.next()) { 1279 if (obj == a_) 1280 a_found_ = true; 1281 else if (obj == b_) 1282 b_found_ = true; 1283 } 1284 } 1285 private: 1286 Object* a_; 1287 Object* b_; 1288 bool a_found_; 1289 bool b_found_; 1290 }; 1291 1292 TEST(HeapIteratorFilterUnreachable) { 1293 InitializeVM(); 1294 v8::HandleScope scope; 1295 CompileRun("a = {}; b = {};"); 1296 v8::Handle<Object> a(ISOLATE->context()->global()->GetProperty( 1297 *FACTORY->LookupAsciiSymbol("a"))->ToObjectChecked()); 1298 v8::Handle<Object> b(ISOLATE->context()->global()->GetProperty( 1299 *FACTORY->LookupAsciiSymbol("b"))->ToObjectChecked()); 1300 CHECK_NE(*a, *b); 1301 { 1302 HeapIteratorTestHelper helper(*a, *b); 1303 helper.IterateHeap(HeapIterator::kFilterUnreachable); 1304 CHECK(helper.a_found()); 1305 CHECK(helper.b_found()); 1306 } 1307 CHECK(ISOLATE->context()->global()->DeleteProperty( 1308 *FACTORY->LookupAsciiSymbol("a"), JSObject::FORCE_DELETION)); 1309 // We ensure that GC will not happen, so our raw pointer stays valid. 1310 AssertNoAllocation no_alloc; 1311 Object* a_saved = *a; 1312 a.Clear(); 1313 // Verify that "a" object still resides in the heap... 1314 { 1315 HeapIteratorTestHelper helper(a_saved, *b); 1316 helper.IterateHeap(HeapIterator::kNoFiltering); 1317 CHECK(helper.a_found()); 1318 CHECK(helper.b_found()); 1319 } 1320 // ...but is now unreachable. 1321 { 1322 HeapIteratorTestHelper helper(a_saved, *b); 1323 helper.IterateHeap(HeapIterator::kFilterUnreachable); 1324 CHECK(!helper.a_found()); 1325 CHECK(helper.b_found()); 1326 } 1327 } 1328