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