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, FixedArray::kHeaderSize); 40 CheckMap(Heap::string_map(), STRING_TYPE, SeqTwoByteString::kAlignedSize); 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); 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(NULL, 0); 74 75 __ nop(); // supported on all architectures 76 77 CodeDesc desc; 78 assm.GetCode(&desc); 79 Object* code = Heap::CreateCode(desc, 80 NULL, 81 Code::ComputeFlags(Code::STUB), 82 Handle<Object>(Heap::undefined_value())); 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(desc, 94 NULL, 95 Code::ComputeFlags(Code::STUB), 96 Handle<Object>(Heap::undefined_value())); 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); 110 CHECK(value->IsHeapNumber()); 111 CHECK(value->IsNumber()); 112 CHECK_EQ(1.000123, value->Number()); 113 114 value = Heap::NumberFromDouble(1.0); 115 CHECK(value->IsSmi()); 116 CHECK(value->IsNumber()); 117 CHECK_EQ(1.0, value->Number()); 118 119 value = Heap::NumberFromInt32(1024); 120 CHECK(value->IsSmi()); 121 CHECK(value->IsNumber()); 122 CHECK_EQ(1024.0, value->Number()); 123 124 value = Heap::NumberFromInt32(Smi::kMinValue); 125 CHECK(value->IsSmi()); 126 CHECK(value->IsNumber()); 127 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value()); 128 129 value = Heap::NumberFromInt32(Smi::kMaxValue); 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); 137 CHECK(value->IsHeapNumber()); 138 CHECK(value->IsNumber()); 139 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number()); 140 #endif 141 142 value = Heap::NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1); 143 CHECK(value->IsHeapNumber()); 144 CHECK(value->IsNumber()); 145 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1), 146 value->Number()); 147 148 // nan oddball checks 149 CHECK(Heap::nan_value()->IsNumber()); 150 CHECK(isnan(Heap::nan_value()->Number())); 151 152 Object* str = Heap::AllocateStringFromAscii(CStrVector("fisk hest ")); 153 if (!str->IsFailure()) { 154 String* s = String::cast(str); 155 CHECK(s->IsString()); 156 CHECK_EQ(10, s->length()); 157 } else { 158 CHECK(false); 159 } 160 161 String* object_symbol = String::cast(Heap::Object_symbol()); 162 CHECK(Top::context()->global()->HasLocalProperty(object_symbol)); 163 164 // Check ToString for oddballs 165 CheckOddball(Heap::true_value(), "true"); 166 CheckOddball(Heap::false_value(), "false"); 167 CheckOddball(Heap::null_value(), "null"); 168 CheckOddball(Heap::undefined_value(), "undefined"); 169 170 // Check ToString for Smis 171 CheckSmi(0, "0"); 172 CheckSmi(42, "42"); 173 CheckSmi(-42, "-42"); 174 175 // Check ToString for Numbers 176 CheckNumber(1.1, "1.1"); 177 178 CheckFindCodeObject(); 179 } 180 181 182 TEST(Tagging) { 183 InitializeVM(); 184 int request = 24; 185 CHECK_EQ(request, static_cast<int>(OBJECT_SIZE_ALIGN(request))); 186 CHECK(Smi::FromInt(42)->IsSmi()); 187 CHECK(Failure::RetryAfterGC(request, NEW_SPACE)->IsFailure()); 188 CHECK_EQ(request, Failure::RetryAfterGC(request, NEW_SPACE)->requested()); 189 CHECK_EQ(NEW_SPACE, 190 Failure::RetryAfterGC(request, NEW_SPACE)->allocation_space()); 191 CHECK_EQ(OLD_POINTER_SPACE, 192 Failure::RetryAfterGC(request, 193 OLD_POINTER_SPACE)->allocation_space()); 194 CHECK(Failure::Exception()->IsFailure()); 195 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi()); 196 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi()); 197 } 198 199 200 TEST(GarbageCollection) { 201 InitializeVM(); 202 203 v8::HandleScope sc; 204 // check GC when heap is empty 205 int free_bytes = Heap::MaxObjectSizeInPagedSpace(); 206 CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE)); 207 208 // allocate a function and keep it in global object's property 209 String* func_name = String::cast(Heap::LookupAsciiSymbol("theFunction")); 210 SharedFunctionInfo* function_share = 211 SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(func_name)); 212 JSFunction* function = 213 JSFunction::cast(Heap::AllocateFunction(*Top::function_map(), 214 function_share, 215 Heap::undefined_value())); 216 Map* initial_map = 217 Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize)); 218 function->set_initial_map(initial_map); 219 Top::context()->global()->SetProperty(func_name, function, NONE); 220 221 // allocate an object, but it is unrooted 222 String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot")); 223 String* prop_namex = String::cast(Heap::LookupAsciiSymbol("theSlotx")); 224 JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function)); 225 obj->SetProperty(prop_name, Smi::FromInt(23), NONE); 226 obj->SetProperty(prop_namex, Smi::FromInt(24), NONE); 227 228 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name)); 229 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(prop_namex)); 230 231 CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE)); 232 233 // function should be alive, func_name might be invalid after GC 234 func_name = String::cast(Heap::LookupAsciiSymbol("theFunction")); 235 CHECK(Top::context()->global()->HasLocalProperty(func_name)); 236 // check function is retained 237 Object* func_value = Top::context()->global()->GetProperty(func_name); 238 CHECK(func_value->IsJSFunction()); 239 // old function pointer may not be valid 240 function = JSFunction::cast(func_value); 241 242 // allocate another object, make it reachable from global 243 obj = JSObject::cast(Heap::AllocateJSObject(function)); 244 String* obj_name = String::cast(Heap::LookupAsciiSymbol("theObject")); 245 Top::context()->global()->SetProperty(obj_name, obj, NONE); 246 // set property 247 prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot")); 248 obj->SetProperty(prop_name, Smi::FromInt(23), NONE); 249 250 // after gc, it should survive 251 CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE)); 252 253 obj_name = String::cast(Heap::LookupAsciiSymbol("theObject")); 254 CHECK(Top::context()->global()->HasLocalProperty(obj_name)); 255 CHECK(Top::context()->global()->GetProperty(obj_name)->IsJSObject()); 256 obj = JSObject::cast(Top::context()->global()->GetProperty(obj_name)); 257 prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot")); 258 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name)); 259 } 260 261 262 static void VerifyStringAllocation(const char* string) { 263 String* s = String::cast(Heap::AllocateStringFromUtf8(CStrVector(string))); 264 CHECK_EQ(StrLength(string), s->length()); 265 for (int index = 0; index < s->length(); index++) { 266 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index)); } 267 } 268 269 270 TEST(String) { 271 InitializeVM(); 272 273 VerifyStringAllocation("a"); 274 VerifyStringAllocation("ab"); 275 VerifyStringAllocation("abc"); 276 VerifyStringAllocation("abcd"); 277 VerifyStringAllocation("fiskerdrengen er paa havet"); 278 } 279 280 281 TEST(LocalHandles) { 282 InitializeVM(); 283 284 v8::HandleScope scope; 285 const char* name = "Kasper the spunky"; 286 Handle<String> string = Factory::NewStringFromAscii(CStrVector(name)); 287 CHECK_EQ(StrLength(name), string->length()); 288 } 289 290 291 TEST(GlobalHandles) { 292 InitializeVM(); 293 294 Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk")); 295 Object* u = Heap::AllocateHeapNumber(1.12344); 296 297 Handle<Object> h1 = GlobalHandles::Create(i); 298 Handle<Object> h2 = GlobalHandles::Create(u); 299 Handle<Object> h3 = GlobalHandles::Create(i); 300 Handle<Object> h4 = GlobalHandles::Create(u); 301 302 // after gc, it should survive 303 CHECK(Heap::CollectGarbage(0, NEW_SPACE)); 304 305 CHECK((*h1)->IsString()); 306 CHECK((*h2)->IsHeapNumber()); 307 CHECK((*h3)->IsString()); 308 CHECK((*h4)->IsHeapNumber()); 309 310 CHECK_EQ(*h3, *h1); 311 GlobalHandles::Destroy(h1.location()); 312 GlobalHandles::Destroy(h3.location()); 313 314 CHECK_EQ(*h4, *h2); 315 GlobalHandles::Destroy(h2.location()); 316 GlobalHandles::Destroy(h4.location()); 317 } 318 319 320 static bool WeakPointerCleared = false; 321 322 static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle, 323 void* id) { 324 USE(handle); 325 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true; 326 } 327 328 329 TEST(WeakGlobalHandlesScavenge) { 330 InitializeVM(); 331 332 WeakPointerCleared = false; 333 334 Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk")); 335 Object* u = Heap::AllocateHeapNumber(1.12344); 336 337 Handle<Object> h1 = GlobalHandles::Create(i); 338 Handle<Object> h2 = GlobalHandles::Create(u); 339 340 GlobalHandles::MakeWeak(h2.location(), 341 reinterpret_cast<void*>(1234), 342 &TestWeakGlobalHandleCallback); 343 344 // Scavenge treats weak pointers as normal roots. 345 Heap::PerformScavenge(); 346 347 CHECK((*h1)->IsString()); 348 CHECK((*h2)->IsHeapNumber()); 349 350 CHECK(!WeakPointerCleared); 351 CHECK(!GlobalHandles::IsNearDeath(h2.location())); 352 CHECK(!GlobalHandles::IsNearDeath(h1.location())); 353 354 GlobalHandles::Destroy(h1.location()); 355 GlobalHandles::Destroy(h2.location()); 356 } 357 358 359 TEST(WeakGlobalHandlesMark) { 360 InitializeVM(); 361 362 WeakPointerCleared = false; 363 364 Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk")); 365 Object* u = Heap::AllocateHeapNumber(1.12344); 366 367 Handle<Object> h1 = GlobalHandles::Create(i); 368 Handle<Object> h2 = GlobalHandles::Create(u); 369 370 CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE)); 371 CHECK(Heap::CollectGarbage(0, NEW_SPACE)); 372 // Make sure the object is promoted. 373 374 GlobalHandles::MakeWeak(h2.location(), 375 reinterpret_cast<void*>(1234), 376 &TestWeakGlobalHandleCallback); 377 CHECK(!GlobalHandles::IsNearDeath(h1.location())); 378 CHECK(!GlobalHandles::IsNearDeath(h2.location())); 379 380 CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE)); 381 382 CHECK((*h1)->IsString()); 383 384 CHECK(WeakPointerCleared); 385 CHECK(!GlobalHandles::IsNearDeath(h1.location())); 386 CHECK(GlobalHandles::IsNearDeath(h2.location())); 387 388 GlobalHandles::Destroy(h1.location()); 389 GlobalHandles::Destroy(h2.location()); 390 } 391 392 static void TestDeleteWeakGlobalHandleCallback( 393 v8::Persistent<v8::Value> handle, 394 void* id) { 395 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true; 396 handle.Dispose(); 397 } 398 399 TEST(DeleteWeakGlobalHandle) { 400 InitializeVM(); 401 402 WeakPointerCleared = false; 403 404 Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk")); 405 Handle<Object> h = GlobalHandles::Create(i); 406 407 GlobalHandles::MakeWeak(h.location(), 408 reinterpret_cast<void*>(1234), 409 &TestDeleteWeakGlobalHandleCallback); 410 411 // Scanvenge does not recognize weak reference. 412 Heap::PerformScavenge(); 413 414 CHECK(!WeakPointerCleared); 415 416 // Mark-compact treats weak reference properly. 417 CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE)); 418 419 CHECK(WeakPointerCleared); 420 } 421 422 static const char* not_so_random_string_table[] = { 423 "abstract", 424 "boolean", 425 "break", 426 "byte", 427 "case", 428 "catch", 429 "char", 430 "class", 431 "const", 432 "continue", 433 "debugger", 434 "default", 435 "delete", 436 "do", 437 "double", 438 "else", 439 "enum", 440 "export", 441 "extends", 442 "false", 443 "final", 444 "finally", 445 "float", 446 "for", 447 "function", 448 "goto", 449 "if", 450 "implements", 451 "import", 452 "in", 453 "instanceof", 454 "int", 455 "interface", 456 "long", 457 "native", 458 "new", 459 "null", 460 "package", 461 "private", 462 "protected", 463 "public", 464 "return", 465 "short", 466 "static", 467 "super", 468 "switch", 469 "synchronized", 470 "this", 471 "throw", 472 "throws", 473 "transient", 474 "true", 475 "try", 476 "typeof", 477 "var", 478 "void", 479 "volatile", 480 "while", 481 "with", 482 0 483 }; 484 485 486 static void CheckSymbols(const char** strings) { 487 for (const char* string = *strings; *strings != 0; string = *strings++) { 488 Object* a = Heap::LookupAsciiSymbol(string); 489 // LookupAsciiSymbol may return a failure if a GC is needed. 490 if (a->IsFailure()) continue; 491 CHECK(a->IsSymbol()); 492 Object* b = Heap::LookupAsciiSymbol(string); 493 if (b->IsFailure()) continue; 494 CHECK_EQ(b, a); 495 CHECK(String::cast(b)->IsEqualTo(CStrVector(string))); 496 } 497 } 498 499 500 TEST(SymbolTable) { 501 InitializeVM(); 502 503 CheckSymbols(not_so_random_string_table); 504 CheckSymbols(not_so_random_string_table); 505 } 506 507 508 TEST(FunctionAllocation) { 509 InitializeVM(); 510 511 v8::HandleScope sc; 512 String* name = String::cast(Heap::LookupAsciiSymbol("theFunction")); 513 SharedFunctionInfo* function_share = 514 SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(name)); 515 JSFunction* function = 516 JSFunction::cast(Heap::AllocateFunction(*Top::function_map(), 517 function_share, 518 Heap::undefined_value())); 519 Map* initial_map = 520 Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize)); 521 function->set_initial_map(initial_map); 522 523 String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot")); 524 JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function)); 525 obj->SetProperty(prop_name, Smi::FromInt(23), NONE); 526 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name)); 527 // Check that we can add properties to function objects. 528 function->SetProperty(prop_name, Smi::FromInt(24), NONE); 529 CHECK_EQ(Smi::FromInt(24), function->GetProperty(prop_name)); 530 } 531 532 533 TEST(ObjectProperties) { 534 InitializeVM(); 535 536 v8::HandleScope sc; 537 JSFunction* constructor = 538 JSFunction::cast( 539 Top::context()->global()->GetProperty(String::cast( 540 Heap::Object_symbol()))); 541 JSObject* obj = JSObject::cast(Heap::AllocateJSObject(constructor)); 542 String* first = String::cast(Heap::LookupAsciiSymbol("first")); 543 String* second = String::cast(Heap::LookupAsciiSymbol("second")); 544 545 // check for empty 546 CHECK(!obj->HasLocalProperty(first)); 547 548 // add first 549 obj->SetProperty(first, Smi::FromInt(1), NONE); 550 CHECK(obj->HasLocalProperty(first)); 551 552 // delete first 553 CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION)); 554 CHECK(!obj->HasLocalProperty(first)); 555 556 // add first and then second 557 obj->SetProperty(first, Smi::FromInt(1), NONE); 558 obj->SetProperty(second, Smi::FromInt(2), NONE); 559 CHECK(obj->HasLocalProperty(first)); 560 CHECK(obj->HasLocalProperty(second)); 561 562 // delete first and then second 563 CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION)); 564 CHECK(obj->HasLocalProperty(second)); 565 CHECK(obj->DeleteProperty(second, JSObject::NORMAL_DELETION)); 566 CHECK(!obj->HasLocalProperty(first)); 567 CHECK(!obj->HasLocalProperty(second)); 568 569 // add first and then second 570 obj->SetProperty(first, Smi::FromInt(1), NONE); 571 obj->SetProperty(second, Smi::FromInt(2), NONE); 572 CHECK(obj->HasLocalProperty(first)); 573 CHECK(obj->HasLocalProperty(second)); 574 575 // delete second and then first 576 CHECK(obj->DeleteProperty(second, JSObject::NORMAL_DELETION)); 577 CHECK(obj->HasLocalProperty(first)); 578 CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION)); 579 CHECK(!obj->HasLocalProperty(first)); 580 CHECK(!obj->HasLocalProperty(second)); 581 582 // check string and symbol match 583 static const char* string1 = "fisk"; 584 String* s1 = 585 String::cast(Heap::AllocateStringFromAscii(CStrVector(string1))); 586 obj->SetProperty(s1, Smi::FromInt(1), NONE); 587 CHECK(obj->HasLocalProperty(String::cast(Heap::LookupAsciiSymbol(string1)))); 588 589 // check symbol and string match 590 static const char* string2 = "fugl"; 591 String* s2 = String::cast(Heap::LookupAsciiSymbol(string2)); 592 obj->SetProperty(s2, Smi::FromInt(1), NONE); 593 CHECK(obj->HasLocalProperty( 594 String::cast(Heap::AllocateStringFromAscii(CStrVector(string2))))); 595 } 596 597 598 TEST(JSObjectMaps) { 599 InitializeVM(); 600 601 v8::HandleScope sc; 602 String* name = String::cast(Heap::LookupAsciiSymbol("theFunction")); 603 SharedFunctionInfo* function_share = 604 SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(name)); 605 JSFunction* function = 606 JSFunction::cast(Heap::AllocateFunction(*Top::function_map(), 607 function_share, 608 Heap::undefined_value())); 609 Map* initial_map = 610 Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize)); 611 function->set_initial_map(initial_map); 612 String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot")); 613 JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function)); 614 615 // Set a propery 616 obj->SetProperty(prop_name, Smi::FromInt(23), NONE); 617 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name)); 618 619 // Check the map has changed 620 CHECK(initial_map != obj->map()); 621 } 622 623 624 TEST(JSArray) { 625 InitializeVM(); 626 627 v8::HandleScope sc; 628 String* name = String::cast(Heap::LookupAsciiSymbol("Array")); 629 JSFunction* function = 630 JSFunction::cast(Top::context()->global()->GetProperty(name)); 631 632 // Allocate the object. 633 JSArray* array = JSArray::cast(Heap::AllocateJSObject(function)); 634 array->Initialize(0); 635 636 // Set array length to 0. 637 array->SetElementsLength(Smi::FromInt(0)); 638 CHECK_EQ(Smi::FromInt(0), array->length()); 639 CHECK(array->HasFastElements()); // Must be in fast mode. 640 641 // array[length] = name. 642 array->SetElement(0, name); 643 CHECK_EQ(Smi::FromInt(1), array->length()); 644 CHECK_EQ(array->GetElement(0), name); 645 646 // Set array length with larger than smi value. 647 Object* length = 648 Heap::NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1); 649 array->SetElementsLength(length); 650 651 uint32_t int_length = 0; 652 CHECK(Array::IndexFromObject(length, &int_length)); 653 CHECK_EQ(length, array->length()); 654 CHECK(array->HasDictionaryElements()); // Must be in slow mode. 655 656 // array[length] = name. 657 array->SetElement(int_length, name); 658 uint32_t new_int_length = 0; 659 CHECK(Array::IndexFromObject(array->length(), &new_int_length)); 660 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1); 661 CHECK_EQ(array->GetElement(int_length), name); 662 CHECK_EQ(array->GetElement(0), name); 663 } 664 665 666 TEST(JSObjectCopy) { 667 InitializeVM(); 668 669 v8::HandleScope sc; 670 String* name = String::cast(Heap::Object_symbol()); 671 JSFunction* constructor = 672 JSFunction::cast(Top::context()->global()->GetProperty(name)); 673 JSObject* obj = JSObject::cast(Heap::AllocateJSObject(constructor)); 674 String* first = String::cast(Heap::LookupAsciiSymbol("first")); 675 String* second = String::cast(Heap::LookupAsciiSymbol("second")); 676 677 obj->SetProperty(first, Smi::FromInt(1), NONE); 678 obj->SetProperty(second, Smi::FromInt(2), NONE); 679 680 obj->SetElement(0, first); 681 obj->SetElement(1, second); 682 683 // Make the clone. 684 JSObject* clone = JSObject::cast(Heap::CopyJSObject(obj)); 685 CHECK(clone != obj); 686 687 CHECK_EQ(obj->GetElement(0), clone->GetElement(0)); 688 CHECK_EQ(obj->GetElement(1), clone->GetElement(1)); 689 690 CHECK_EQ(obj->GetProperty(first), clone->GetProperty(first)); 691 CHECK_EQ(obj->GetProperty(second), clone->GetProperty(second)); 692 693 // Flip the values. 694 clone->SetProperty(first, Smi::FromInt(2), NONE); 695 clone->SetProperty(second, Smi::FromInt(1), NONE); 696 697 clone->SetElement(0, second); 698 clone->SetElement(1, first); 699 700 CHECK_EQ(obj->GetElement(1), clone->GetElement(0)); 701 CHECK_EQ(obj->GetElement(0), clone->GetElement(1)); 702 703 CHECK_EQ(obj->GetProperty(second), clone->GetProperty(first)); 704 CHECK_EQ(obj->GetProperty(first), clone->GetProperty(second)); 705 } 706 707 708 TEST(StringAllocation) { 709 InitializeVM(); 710 711 712 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 }; 713 for (int length = 0; length < 100; length++) { 714 v8::HandleScope scope; 715 char* non_ascii = NewArray<char>(3 * length + 1); 716 char* ascii = NewArray<char>(length + 1); 717 non_ascii[3 * length] = 0; 718 ascii[length] = 0; 719 for (int i = 0; i < length; i++) { 720 ascii[i] = 'a'; 721 non_ascii[3 * i] = chars[0]; 722 non_ascii[3 * i + 1] = chars[1]; 723 non_ascii[3 * i + 2] = chars[2]; 724 } 725 Handle<String> non_ascii_sym = 726 Factory::LookupSymbol(Vector<const char>(non_ascii, 3 * length)); 727 CHECK_EQ(length, non_ascii_sym->length()); 728 Handle<String> ascii_sym = 729 Factory::LookupSymbol(Vector<const char>(ascii, length)); 730 CHECK_EQ(length, ascii_sym->length()); 731 Handle<String> non_ascii_str = 732 Factory::NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length)); 733 non_ascii_str->Hash(); 734 CHECK_EQ(length, non_ascii_str->length()); 735 Handle<String> ascii_str = 736 Factory::NewStringFromUtf8(Vector<const char>(ascii, length)); 737 ascii_str->Hash(); 738 CHECK_EQ(length, ascii_str->length()); 739 DeleteArray(non_ascii); 740 DeleteArray(ascii); 741 } 742 } 743 744 745 static int ObjectsFoundInHeap(Handle<Object> objs[], int size) { 746 // Count the number of objects found in the heap. 747 int found_count = 0; 748 HeapIterator iterator; 749 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) { 750 for (int i = 0; i < size; i++) { 751 if (*objs[i] == obj) { 752 found_count++; 753 } 754 } 755 } 756 return found_count; 757 } 758 759 760 TEST(Iteration) { 761 InitializeVM(); 762 v8::HandleScope scope; 763 764 // Array of objects to scan haep for. 765 const int objs_count = 6; 766 Handle<Object> objs[objs_count]; 767 int next_objs_index = 0; 768 769 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE 770 objs[next_objs_index++] = Factory::NewJSArray(10); 771 objs[next_objs_index++] = Factory::NewJSArray(10, TENURED); 772 773 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE 774 objs[next_objs_index++] = 775 Factory::NewStringFromAscii(CStrVector("abcdefghij")); 776 objs[next_objs_index++] = 777 Factory::NewStringFromAscii(CStrVector("abcdefghij"), TENURED); 778 779 // Allocate a large string (for large object space). 780 int large_size = Heap::MaxObjectSizeInPagedSpace() + 1; 781 char* str = new char[large_size]; 782 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a'; 783 str[large_size - 1] = '\0'; 784 objs[next_objs_index++] = 785 Factory::NewStringFromAscii(CStrVector(str), TENURED); 786 delete[] str; 787 788 // Add a Map object to look for. 789 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map()); 790 791 CHECK_EQ(objs_count, next_objs_index); 792 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count)); 793 } 794