blob: fb9a48e790274812bfadff16d6e726197df5855e [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);
kasperl@chromium.orge959c182009-07-27 08:59:04 +000039 CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, FixedArray::kHeaderSize);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000040 CheckMap(Heap::long_string_map(), LONG_STRING_TYPE,
kasperl@chromium.org71affb52009-05-26 05:44:31 +000041 SeqTwoByteString::kAlignedSize);
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
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000135#ifndef V8_TARGET_ARCH_X64
136 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000137 value = Heap::NumberFromInt32(Smi::kMinValue - 1);
138 CHECK(value->IsHeapNumber());
139 CHECK(value->IsNumber());
140 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000141#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000142
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000143 value = Heap::NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000144 CHECK(value->IsHeapNumber());
145 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000146 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
147 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000148
149 // nan oddball checks
150 CHECK(Heap::nan_value()->IsNumber());
151 CHECK(isnan(Heap::nan_value()->Number()));
152
153 Object* str = Heap::AllocateStringFromAscii(CStrVector("fisk hest "));
154 if (!str->IsFailure()) {
155 String* s = String::cast(str);
156 CHECK(s->IsString());
157 CHECK_EQ(10, s->length());
158 } else {
159 CHECK(false);
160 }
161
162 String* object_symbol = String::cast(Heap::Object_symbol());
163 CHECK(Top::context()->global()->HasLocalProperty(object_symbol));
164
165 // Check ToString for oddballs
166 CheckOddball(Heap::true_value(), "true");
167 CheckOddball(Heap::false_value(), "false");
168 CheckOddball(Heap::null_value(), "null");
169 CheckOddball(Heap::undefined_value(), "undefined");
170
171 // Check ToString for Smis
172 CheckSmi(0, "0");
173 CheckSmi(42, "42");
174 CheckSmi(-42, "-42");
175
176 // Check ToString for Numbers
177 CheckNumber(1.1, "1.1");
178
179 CheckFindCodeObject();
180}
181
182
183TEST(Tagging) {
184 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000185 int request = 24;
ager@chromium.org18ad94b2009-09-02 08:22:29 +0000186 CHECK_EQ(request, static_cast<int>(OBJECT_SIZE_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000187 CHECK(Smi::FromInt(42)->IsSmi());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000188 CHECK(Failure::RetryAfterGC(request, NEW_SPACE)->IsFailure());
189 CHECK_EQ(request, Failure::RetryAfterGC(request, NEW_SPACE)->requested());
190 CHECK_EQ(NEW_SPACE,
191 Failure::RetryAfterGC(request, NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000192 CHECK_EQ(OLD_POINTER_SPACE,
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000193 Failure::RetryAfterGC(request,
194 OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000195 CHECK(Failure::Exception()->IsFailure());
196 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
197 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
198}
199
200
201TEST(GarbageCollection) {
202 InitializeVM();
203
204 v8::HandleScope sc;
205 // check GC when heap is empty
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000206 int free_bytes = Heap::MaxObjectSizeInPagedSpace();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000207 CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE));
208
209 // allocate a function and keep it in global object's property
210 String* func_name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
211 SharedFunctionInfo* function_share =
212 SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(func_name));
213 JSFunction* function =
214 JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
215 function_share,
216 Heap::undefined_value()));
217 Map* initial_map =
218 Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
219 function->set_initial_map(initial_map);
220 Top::context()->global()->SetProperty(func_name, function, NONE);
221
222 // allocate an object, but it is unrooted
223 String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
224 String* prop_namex = String::cast(Heap::LookupAsciiSymbol("theSlotx"));
225 JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
226 obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
227 obj->SetProperty(prop_namex, Smi::FromInt(24), NONE);
228
229 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
230 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(prop_namex));
231
232 CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE));
233
234 // function should be alive, func_name might be invalid after GC
235 func_name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
236 CHECK(Top::context()->global()->HasLocalProperty(func_name));
237 // check function is retained
238 Object* func_value = Top::context()->global()->GetProperty(func_name);
239 CHECK(func_value->IsJSFunction());
240 // old function pointer may not be valid
241 function = JSFunction::cast(func_value);
242
243 // allocate another object, make it reachable from global
244 obj = JSObject::cast(Heap::AllocateJSObject(function));
245 String* obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
246 Top::context()->global()->SetProperty(obj_name, obj, NONE);
247 // set property
248 prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
249 obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
250
251 // after gc, it should survive
252 CHECK(Heap::CollectGarbage(free_bytes, NEW_SPACE));
253
254 obj_name = String::cast(Heap::LookupAsciiSymbol("theObject"));
255 CHECK(Top::context()->global()->HasLocalProperty(obj_name));
256 CHECK(Top::context()->global()->GetProperty(obj_name)->IsJSObject());
257 obj = JSObject::cast(Top::context()->global()->GetProperty(obj_name));
258 prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
259 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
260}
261
262
263static void VerifyStringAllocation(const char* string) {
264 String* s = String::cast(Heap::AllocateStringFromUtf8(CStrVector(string)));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000265 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000266 for (int index = 0; index < s->length(); index++) {
267 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index)); }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000268}
269
270
271TEST(String) {
272 InitializeVM();
273
274 VerifyStringAllocation("a");
275 VerifyStringAllocation("ab");
276 VerifyStringAllocation("abc");
277 VerifyStringAllocation("abcd");
278 VerifyStringAllocation("fiskerdrengen er paa havet");
279}
280
281
282TEST(LocalHandles) {
283 InitializeVM();
284
285 v8::HandleScope scope;
286 const char* name = "Kasper the spunky";
287 Handle<String> string = Factory::NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000288 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000289}
290
291
292TEST(GlobalHandles) {
293 InitializeVM();
294
295 Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
296 Object* u = Heap::AllocateHeapNumber(1.12344);
297
298 Handle<Object> h1 = GlobalHandles::Create(i);
299 Handle<Object> h2 = GlobalHandles::Create(u);
300 Handle<Object> h3 = GlobalHandles::Create(i);
301 Handle<Object> h4 = GlobalHandles::Create(u);
302
303 // after gc, it should survive
304 CHECK(Heap::CollectGarbage(0, NEW_SPACE));
305
306 CHECK((*h1)->IsString());
307 CHECK((*h2)->IsHeapNumber());
308 CHECK((*h3)->IsString());
309 CHECK((*h4)->IsHeapNumber());
310
311 CHECK_EQ(*h3, *h1);
312 GlobalHandles::Destroy(h1.location());
313 GlobalHandles::Destroy(h3.location());
314
315 CHECK_EQ(*h4, *h2);
316 GlobalHandles::Destroy(h2.location());
317 GlobalHandles::Destroy(h4.location());
318}
319
320
321static bool WeakPointerCleared = false;
322
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000323static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000324 void* id) {
325 USE(handle);
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000326 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000327}
328
329
330TEST(WeakGlobalHandlesScavenge) {
331 InitializeVM();
332
333 WeakPointerCleared = false;
334
335 Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
336 Object* u = Heap::AllocateHeapNumber(1.12344);
337
338 Handle<Object> h1 = GlobalHandles::Create(i);
339 Handle<Object> h2 = GlobalHandles::Create(u);
340
341 GlobalHandles::MakeWeak(h2.location(),
342 reinterpret_cast<void*>(1234),
343 &TestWeakGlobalHandleCallback);
344
345 // Scavenge treats weak pointers as normal roots.
346 Heap::PerformScavenge();
347
348 CHECK((*h1)->IsString());
349 CHECK((*h2)->IsHeapNumber());
350
351 CHECK(!WeakPointerCleared);
352 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
353 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
354
355 GlobalHandles::Destroy(h1.location());
356 GlobalHandles::Destroy(h2.location());
357}
358
359
360TEST(WeakGlobalHandlesMark) {
361 InitializeVM();
362
363 WeakPointerCleared = false;
364
365 Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
366 Object* u = Heap::AllocateHeapNumber(1.12344);
367
368 Handle<Object> h1 = GlobalHandles::Create(i);
369 Handle<Object> h2 = GlobalHandles::Create(u);
370
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000371 CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000372 CHECK(Heap::CollectGarbage(0, NEW_SPACE));
373 // Make sure the object is promoted.
374
375 GlobalHandles::MakeWeak(h2.location(),
376 reinterpret_cast<void*>(1234),
377 &TestWeakGlobalHandleCallback);
378 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
379 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
380
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000381 CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000382
383 CHECK((*h1)->IsString());
384
385 CHECK(WeakPointerCleared);
386 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
387 CHECK(GlobalHandles::IsNearDeath(h2.location()));
388
389 GlobalHandles::Destroy(h1.location());
390 GlobalHandles::Destroy(h2.location());
391}
392
393static void TestDeleteWeakGlobalHandleCallback(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000394 v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000395 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000396 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000397 handle.Dispose();
398}
399
400TEST(DeleteWeakGlobalHandle) {
401 InitializeVM();
402
403 WeakPointerCleared = false;
404
405 Object* i = Heap::AllocateStringFromAscii(CStrVector("fisk"));
406 Handle<Object> h = GlobalHandles::Create(i);
407
408 GlobalHandles::MakeWeak(h.location(),
409 reinterpret_cast<void*>(1234),
410 &TestDeleteWeakGlobalHandleCallback);
411
412 // Scanvenge does not recognize weak reference.
413 Heap::PerformScavenge();
414
415 CHECK(!WeakPointerCleared);
416
417 // Mark-compact treats weak reference properly.
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000418 CHECK(Heap::CollectGarbage(0, OLD_POINTER_SPACE));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000419
420 CHECK(WeakPointerCleared);
421}
422
423static const char* not_so_random_string_table[] = {
424 "abstract",
425 "boolean",
426 "break",
427 "byte",
428 "case",
429 "catch",
430 "char",
431 "class",
432 "const",
433 "continue",
434 "debugger",
435 "default",
436 "delete",
437 "do",
438 "double",
439 "else",
440 "enum",
441 "export",
442 "extends",
443 "false",
444 "final",
445 "finally",
446 "float",
447 "for",
448 "function",
449 "goto",
450 "if",
451 "implements",
452 "import",
453 "in",
454 "instanceof",
455 "int",
456 "interface",
457 "long",
458 "native",
459 "new",
460 "null",
461 "package",
462 "private",
463 "protected",
464 "public",
465 "return",
466 "short",
467 "static",
468 "super",
469 "switch",
470 "synchronized",
471 "this",
472 "throw",
473 "throws",
474 "transient",
475 "true",
476 "try",
477 "typeof",
478 "var",
479 "void",
480 "volatile",
481 "while",
482 "with",
483 0
484};
485
486
487static void CheckSymbols(const char** strings) {
488 for (const char* string = *strings; *strings != 0; string = *strings++) {
489 Object* a = Heap::LookupAsciiSymbol(string);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000490 // LookupAsciiSymbol may return a failure if a GC is needed.
491 if (a->IsFailure()) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000492 CHECK(a->IsSymbol());
493 Object* b = Heap::LookupAsciiSymbol(string);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000494 if (b->IsFailure()) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000495 CHECK_EQ(b, a);
496 CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
497 }
498}
499
500
501TEST(SymbolTable) {
502 InitializeVM();
503
504 CheckSymbols(not_so_random_string_table);
505 CheckSymbols(not_so_random_string_table);
506}
507
508
509TEST(FunctionAllocation) {
510 InitializeVM();
511
512 v8::HandleScope sc;
513 String* name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
514 SharedFunctionInfo* function_share =
515 SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(name));
516 JSFunction* function =
517 JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
518 function_share,
519 Heap::undefined_value()));
520 Map* initial_map =
521 Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
522 function->set_initial_map(initial_map);
523
524 String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
525 JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
526 obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
527 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
528 // Check that we can add properties to function objects.
529 function->SetProperty(prop_name, Smi::FromInt(24), NONE);
530 CHECK_EQ(Smi::FromInt(24), function->GetProperty(prop_name));
531}
532
533
534TEST(ObjectProperties) {
535 InitializeVM();
536
537 v8::HandleScope sc;
538 JSFunction* constructor =
539 JSFunction::cast(
540 Top::context()->global()->GetProperty(String::cast(
541 Heap::Object_symbol())));
542 JSObject* obj = JSObject::cast(Heap::AllocateJSObject(constructor));
543 String* first = String::cast(Heap::LookupAsciiSymbol("first"));
544 String* second = String::cast(Heap::LookupAsciiSymbol("second"));
545
546 // check for empty
547 CHECK(!obj->HasLocalProperty(first));
548
549 // add first
550 obj->SetProperty(first, Smi::FromInt(1), NONE);
551 CHECK(obj->HasLocalProperty(first));
552
553 // delete first
ager@chromium.orge2902be2009-06-08 12:21:35 +0000554 CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000555 CHECK(!obj->HasLocalProperty(first));
556
557 // add first and then second
558 obj->SetProperty(first, Smi::FromInt(1), NONE);
559 obj->SetProperty(second, Smi::FromInt(2), NONE);
560 CHECK(obj->HasLocalProperty(first));
561 CHECK(obj->HasLocalProperty(second));
562
563 // delete first and then second
ager@chromium.orge2902be2009-06-08 12:21:35 +0000564 CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000565 CHECK(obj->HasLocalProperty(second));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000566 CHECK(obj->DeleteProperty(second, JSObject::NORMAL_DELETION));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000567 CHECK(!obj->HasLocalProperty(first));
568 CHECK(!obj->HasLocalProperty(second));
569
570 // add first and then second
571 obj->SetProperty(first, Smi::FromInt(1), NONE);
572 obj->SetProperty(second, Smi::FromInt(2), NONE);
573 CHECK(obj->HasLocalProperty(first));
574 CHECK(obj->HasLocalProperty(second));
575
576 // delete second and then first
ager@chromium.orge2902be2009-06-08 12:21:35 +0000577 CHECK(obj->DeleteProperty(second, JSObject::NORMAL_DELETION));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000578 CHECK(obj->HasLocalProperty(first));
ager@chromium.orge2902be2009-06-08 12:21:35 +0000579 CHECK(obj->DeleteProperty(first, JSObject::NORMAL_DELETION));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000580 CHECK(!obj->HasLocalProperty(first));
581 CHECK(!obj->HasLocalProperty(second));
582
583 // check string and symbol match
584 static const char* string1 = "fisk";
585 String* s1 =
586 String::cast(Heap::AllocateStringFromAscii(CStrVector(string1)));
587 obj->SetProperty(s1, Smi::FromInt(1), NONE);
588 CHECK(obj->HasLocalProperty(String::cast(Heap::LookupAsciiSymbol(string1))));
589
590 // check symbol and string match
591 static const char* string2 = "fugl";
592 String* s2 = String::cast(Heap::LookupAsciiSymbol(string2));
593 obj->SetProperty(s2, Smi::FromInt(1), NONE);
594 CHECK(obj->HasLocalProperty(
595 String::cast(Heap::AllocateStringFromAscii(CStrVector(string2)))));
596}
597
598
599TEST(JSObjectMaps) {
600 InitializeVM();
601
602 v8::HandleScope sc;
603 String* name = String::cast(Heap::LookupAsciiSymbol("theFunction"));
604 SharedFunctionInfo* function_share =
605 SharedFunctionInfo::cast(Heap::AllocateSharedFunctionInfo(name));
606 JSFunction* function =
607 JSFunction::cast(Heap::AllocateFunction(*Top::function_map(),
608 function_share,
609 Heap::undefined_value()));
610 Map* initial_map =
611 Map::cast(Heap::AllocateMap(JS_OBJECT_TYPE, JSObject::kHeaderSize));
612 function->set_initial_map(initial_map);
613 String* prop_name = String::cast(Heap::LookupAsciiSymbol("theSlot"));
614 JSObject* obj = JSObject::cast(Heap::AllocateJSObject(function));
615
616 // Set a propery
617 obj->SetProperty(prop_name, Smi::FromInt(23), NONE);
618 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(prop_name));
619
620 // Check the map has changed
621 CHECK(initial_map != obj->map());
622}
623
624
625TEST(JSArray) {
626 InitializeVM();
627
628 v8::HandleScope sc;
629 String* name = String::cast(Heap::LookupAsciiSymbol("Array"));
630 JSFunction* function =
631 JSFunction::cast(Top::context()->global()->GetProperty(name));
632
633 // Allocate the object.
634 JSArray* array = JSArray::cast(Heap::AllocateJSObject(function));
635 array->Initialize(0);
636
637 // Set array length to 0.
638 array->SetElementsLength(Smi::FromInt(0));
639 CHECK_EQ(Smi::FromInt(0), array->length());
640 CHECK(array->HasFastElements()); // Must be in fast mode.
641
642 // array[length] = name.
643 array->SetElement(0, name);
644 CHECK_EQ(Smi::FromInt(1), array->length());
645 CHECK_EQ(array->GetElement(0), name);
646
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000647// Set array length with larger than smi value.
648 Object* length =
649 Heap::NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000650 array->SetElementsLength(length);
651
652 uint32_t int_length = 0;
653 CHECK(Array::IndexFromObject(length, &int_length));
654 CHECK_EQ(length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000655 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000656
657 // array[length] = name.
658 array->SetElement(int_length, name);
659 uint32_t new_int_length = 0;
660 CHECK(Array::IndexFromObject(array->length(), &new_int_length));
661 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
662 CHECK_EQ(array->GetElement(int_length), name);
663 CHECK_EQ(array->GetElement(0), name);
664}
665
666
667TEST(JSObjectCopy) {
668 InitializeVM();
669
670 v8::HandleScope sc;
671 String* name = String::cast(Heap::Object_symbol());
672 JSFunction* constructor =
673 JSFunction::cast(Top::context()->global()->GetProperty(name));
674 JSObject* obj = JSObject::cast(Heap::AllocateJSObject(constructor));
675 String* first = String::cast(Heap::LookupAsciiSymbol("first"));
676 String* second = String::cast(Heap::LookupAsciiSymbol("second"));
677
678 obj->SetProperty(first, Smi::FromInt(1), NONE);
679 obj->SetProperty(second, Smi::FromInt(2), NONE);
680
681 obj->SetElement(0, first);
682 obj->SetElement(1, second);
683
684 // Make the clone.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000685 JSObject* clone = JSObject::cast(Heap::CopyJSObject(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000686 CHECK(clone != obj);
687
688 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
689 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
690
691 CHECK_EQ(obj->GetProperty(first), clone->GetProperty(first));
692 CHECK_EQ(obj->GetProperty(second), clone->GetProperty(second));
693
694 // Flip the values.
695 clone->SetProperty(first, Smi::FromInt(2), NONE);
696 clone->SetProperty(second, Smi::FromInt(1), NONE);
697
698 clone->SetElement(0, second);
699 clone->SetElement(1, first);
700
701 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
702 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
703
704 CHECK_EQ(obj->GetProperty(second), clone->GetProperty(first));
705 CHECK_EQ(obj->GetProperty(first), clone->GetProperty(second));
706}
707
708
709TEST(StringAllocation) {
710 InitializeVM();
711
712
713 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
714 for (int length = 0; length < 100; length++) {
715 v8::HandleScope scope;
716 char* non_ascii = NewArray<char>(3 * length + 1);
717 char* ascii = NewArray<char>(length + 1);
718 non_ascii[3 * length] = 0;
719 ascii[length] = 0;
720 for (int i = 0; i < length; i++) {
721 ascii[i] = 'a';
722 non_ascii[3 * i] = chars[0];
723 non_ascii[3 * i + 1] = chars[1];
724 non_ascii[3 * i + 2] = chars[2];
725 }
726 Handle<String> non_ascii_sym =
727 Factory::LookupSymbol(Vector<const char>(non_ascii, 3 * length));
728 CHECK_EQ(length, non_ascii_sym->length());
729 Handle<String> ascii_sym =
730 Factory::LookupSymbol(Vector<const char>(ascii, length));
731 CHECK_EQ(length, ascii_sym->length());
732 Handle<String> non_ascii_str =
733 Factory::NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
734 non_ascii_str->Hash();
735 CHECK_EQ(length, non_ascii_str->length());
736 Handle<String> ascii_str =
737 Factory::NewStringFromUtf8(Vector<const char>(ascii, length));
738 ascii_str->Hash();
739 CHECK_EQ(length, ascii_str->length());
740 DeleteArray(non_ascii);
741 DeleteArray(ascii);
742 }
743}
744
745
746static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
747 // Count the number of objects found in the heap.
748 int found_count = 0;
749 HeapIterator iterator;
750 while (iterator.has_next()) {
751 HeapObject* obj = iterator.next();
752 CHECK(obj != NULL);
753 for (int i = 0; i < size; i++) {
754 if (*objs[i] == obj) {
755 found_count++;
756 }
757 }
758 }
759 CHECK(!iterator.has_next());
760 return found_count;
761}
762
763
764TEST(Iteration) {
765 InitializeVM();
766 v8::HandleScope scope;
767
768 // Array of objects to scan haep for.
769 const int objs_count = 6;
770 Handle<Object> objs[objs_count];
771 int next_objs_index = 0;
772
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000773 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000774 objs[next_objs_index++] = Factory::NewJSArray(10);
775 objs[next_objs_index++] = Factory::NewJSArray(10, TENURED);
776
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000777 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000778 objs[next_objs_index++] =
779 Factory::NewStringFromAscii(CStrVector("abcdefghij"));
780 objs[next_objs_index++] =
781 Factory::NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
782
783 // Allocate a large string (for large object space).
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000784 int large_size = Heap::MaxObjectSizeInPagedSpace() + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000785 char* str = new char[large_size];
786 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
787 str[large_size - 1] = '\0';
788 objs[next_objs_index++] =
789 Factory::NewStringFromAscii(CStrVector(str), TENURED);
790 delete[] str;
791
792 // Add a Map object to look for.
793 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
794
795 CHECK_EQ(objs_count, next_objs_index);
796 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
797}