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