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