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