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