Home | History | Annotate | Download | only in cctest
      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