blob: 126ac21adac5acd376825032d9039f9803a1ef2a [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);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +000039 CheckMap(Heap::fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
40 CheckMap(Heap::string_map(), STRING_TYPE, kVariableSizeSentinel);
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,
kasperl@chromium.org061ef742009-02-27 12:16:20 +000080 Code::ComputeFlags(Code::STUB),
81 Handle<Object>(Heap::undefined_value()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000082 CHECK(code->IsCode());
83
84 HeapObject* obj = HeapObject::cast(code);
85 Address obj_addr = obj->address();
86
87 for (int i = 0; i < obj->Size(); i += kPointerSize) {
88 Object* found = Heap::FindCodeObject(obj_addr + i);
89 CHECK_EQ(code, found);
90 }
91
kasperl@chromium.org061ef742009-02-27 12:16:20 +000092 Object* copy = Heap::CreateCode(desc,
kasperl@chromium.org061ef742009-02-27 12:16:20 +000093 Code::ComputeFlags(Code::STUB),
94 Handle<Object>(Heap::undefined_value()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000095 CHECK(copy->IsCode());
96 HeapObject* obj_copy = HeapObject::cast(copy);
97 Object* not_right = Heap::FindCodeObject(obj_copy->address() +
98 obj_copy->Size() / 2);
99 CHECK(not_right != code);
100}
101
102
103TEST(HeapObjects) {
104 InitializeVM();
105
106 v8::HandleScope sc;
107 Object* value = Heap::NumberFromDouble(1.000123);
108 CHECK(value->IsHeapNumber());
109 CHECK(value->IsNumber());
110 CHECK_EQ(1.000123, value->Number());
111
112 value = Heap::NumberFromDouble(1.0);
113 CHECK(value->IsSmi());
114 CHECK(value->IsNumber());
115 CHECK_EQ(1.0, value->Number());
116
117 value = Heap::NumberFromInt32(1024);
118 CHECK(value->IsSmi());
119 CHECK(value->IsNumber());
120 CHECK_EQ(1024.0, value->Number());
121
122 value = Heap::NumberFromInt32(Smi::kMinValue);
123 CHECK(value->IsSmi());
124 CHECK(value->IsNumber());
125 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
126
127 value = Heap::NumberFromInt32(Smi::kMaxValue);
128 CHECK(value->IsSmi());
129 CHECK(value->IsNumber());
130 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
131
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000132#ifndef V8_TARGET_ARCH_X64
133 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000134 value = Heap::NumberFromInt32(Smi::kMinValue - 1);
135 CHECK(value->IsHeapNumber());
136 CHECK(value->IsNumber());
137 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000138#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000139
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000140 value = Heap::NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000141 CHECK(value->IsHeapNumber());
142 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000143 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
144 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000145
146 // nan oddball checks
147 CHECK(Heap::nan_value()->IsNumber());
148 CHECK(isnan(Heap::nan_value()->Number()));
149
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000150 Handle<String> s = Factory::NewStringFromAscii(CStrVector("fisk hest "));
151 CHECK(s->IsString());
152 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000153
154 String* object_symbol = String::cast(Heap::Object_symbol());
155 CHECK(Top::context()->global()->HasLocalProperty(object_symbol));
156
157 // Check ToString for oddballs
158 CheckOddball(Heap::true_value(), "true");
159 CheckOddball(Heap::false_value(), "false");
160 CheckOddball(Heap::null_value(), "null");
161 CheckOddball(Heap::undefined_value(), "undefined");
162
163 // Check ToString for Smis
164 CheckSmi(0, "0");
165 CheckSmi(42, "42");
166 CheckSmi(-42, "-42");
167
168 // Check ToString for Numbers
169 CheckNumber(1.1, "1.1");
170
171 CheckFindCodeObject();
172}
173
174
175TEST(Tagging) {
176 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000177 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000178 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000179 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000180 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000181 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000182 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000183 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000184 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000185 CHECK(Failure::Exception()->IsFailure());
186 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
187 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
188}
189
190
191TEST(GarbageCollection) {
192 InitializeVM();
193
194 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000195 // Check GC.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000196 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000197
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000198 Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
199 Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
200 Handle<String> prop_namex = Factory::LookupAsciiSymbol("theSlotx");
201 Handle<String> obj_name = Factory::LookupAsciiSymbol("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000202
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000203 {
204 v8::HandleScope inner_scope;
205 // Allocate a function and keep it in global object's property.
206 Handle<JSFunction> function =
207 Factory::NewFunction(name, Factory::undefined_value());
208 Handle<Map> initial_map =
209 Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
210 function->set_initial_map(*initial_map);
211 Top::context()->global()->SetProperty(*name, *function, NONE);
212 // Allocate an object. Unrooted after leaving the scope.
213 Handle<JSObject> obj = Factory::NewJSObject(function);
214 obj->SetProperty(*prop_name, Smi::FromInt(23), NONE);
215 obj->SetProperty(*prop_namex, Smi::FromInt(24), NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000216
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000217 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
218 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
219 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000220
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000221 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000222
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000223 // Function should be alive.
224 CHECK(Top::context()->global()->HasLocalProperty(*name));
225 // Check function is retained.
226 Object* func_value = Top::context()->global()->GetProperty(*name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000227 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000228 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000229
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000230 {
231 HandleScope inner_scope;
232 // Allocate another object, make it reachable from global.
233 Handle<JSObject> obj = Factory::NewJSObject(function);
234 Top::context()->global()->SetProperty(*obj_name, *obj, NONE);
235 obj->SetProperty(*prop_name, Smi::FromInt(23), NONE);
236 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000237
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000238 // After gc, it should survive.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000239 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000240
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000241 CHECK(Top::context()->global()->HasLocalProperty(*obj_name));
242 CHECK(Top::context()->global()->GetProperty(*obj_name)->IsJSObject());
243 JSObject* obj =
244 JSObject::cast(Top::context()->global()->GetProperty(*obj_name));
245 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000246}
247
248
249static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000250 v8::HandleScope scope;
251 Handle<String> s = Factory::NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000252 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000253 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000254 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
255 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000256}
257
258
259TEST(String) {
260 InitializeVM();
261
262 VerifyStringAllocation("a");
263 VerifyStringAllocation("ab");
264 VerifyStringAllocation("abc");
265 VerifyStringAllocation("abcd");
266 VerifyStringAllocation("fiskerdrengen er paa havet");
267}
268
269
270TEST(LocalHandles) {
271 InitializeVM();
272
273 v8::HandleScope scope;
274 const char* name = "Kasper the spunky";
275 Handle<String> string = Factory::NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000276 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000277}
278
279
280TEST(GlobalHandles) {
281 InitializeVM();
282
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000283 Handle<Object> h1;
284 Handle<Object> h2;
285 Handle<Object> h3;
286 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000287
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000288 {
289 HandleScope scope;
290
291 Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
292 Handle<Object> u = Factory::NewNumber(1.12344);
293
294 h1 = GlobalHandles::Create(*i);
295 h2 = GlobalHandles::Create(*u);
296 h3 = GlobalHandles::Create(*i);
297 h4 = GlobalHandles::Create(*u);
298 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000299
300 // after gc, it should survive
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000301 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000302
303 CHECK((*h1)->IsString());
304 CHECK((*h2)->IsHeapNumber());
305 CHECK((*h3)->IsString());
306 CHECK((*h4)->IsHeapNumber());
307
308 CHECK_EQ(*h3, *h1);
309 GlobalHandles::Destroy(h1.location());
310 GlobalHandles::Destroy(h3.location());
311
312 CHECK_EQ(*h4, *h2);
313 GlobalHandles::Destroy(h2.location());
314 GlobalHandles::Destroy(h4.location());
315}
316
317
318static bool WeakPointerCleared = false;
319
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000320static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000321 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000322 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000323 handle.Dispose();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000324}
325
326
327TEST(WeakGlobalHandlesScavenge) {
328 InitializeVM();
329
330 WeakPointerCleared = false;
331
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000332 Handle<Object> h1;
333 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000334
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000335 {
336 HandleScope scope;
337
338 Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
339 Handle<Object> u = Factory::NewNumber(1.12344);
340
341 h1 = GlobalHandles::Create(*i);
342 h2 = GlobalHandles::Create(*u);
343 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000344
345 GlobalHandles::MakeWeak(h2.location(),
346 reinterpret_cast<void*>(1234),
347 &TestWeakGlobalHandleCallback);
348
349 // Scavenge treats weak pointers as normal roots.
350 Heap::PerformScavenge();
351
352 CHECK((*h1)->IsString());
353 CHECK((*h2)->IsHeapNumber());
354
355 CHECK(!WeakPointerCleared);
356 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
357 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
358
359 GlobalHandles::Destroy(h1.location());
360 GlobalHandles::Destroy(h2.location());
361}
362
363
364TEST(WeakGlobalHandlesMark) {
365 InitializeVM();
366
367 WeakPointerCleared = false;
368
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000369 Handle<Object> h1;
370 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000371
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000372 {
373 HandleScope scope;
374
375 Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
376 Handle<Object> u = Factory::NewNumber(1.12344);
377
378 h1 = GlobalHandles::Create(*i);
379 h2 = GlobalHandles::Create(*u);
380 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000381
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000382 Heap::CollectGarbage(OLD_POINTER_SPACE);
383 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000384 // Make sure the object is promoted.
385
386 GlobalHandles::MakeWeak(h2.location(),
387 reinterpret_cast<void*>(1234),
388 &TestWeakGlobalHandleCallback);
389 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
390 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
391
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000392 Heap::CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000393
394 CHECK((*h1)->IsString());
395
396 CHECK(WeakPointerCleared);
397 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000398
399 GlobalHandles::Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000400}
401
402TEST(DeleteWeakGlobalHandle) {
403 InitializeVM();
404
405 WeakPointerCleared = false;
406
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000407 Handle<Object> h;
408
409 {
410 HandleScope scope;
411
412 Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
413 h = GlobalHandles::Create(*i);
414 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000415
416 GlobalHandles::MakeWeak(h.location(),
417 reinterpret_cast<void*>(1234),
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000418 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000419
420 // Scanvenge does not recognize weak reference.
421 Heap::PerformScavenge();
422
423 CHECK(!WeakPointerCleared);
424
425 // Mark-compact treats weak reference properly.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000426 Heap::CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000427
428 CHECK(WeakPointerCleared);
429}
430
431static const char* not_so_random_string_table[] = {
432 "abstract",
433 "boolean",
434 "break",
435 "byte",
436 "case",
437 "catch",
438 "char",
439 "class",
440 "const",
441 "continue",
442 "debugger",
443 "default",
444 "delete",
445 "do",
446 "double",
447 "else",
448 "enum",
449 "export",
450 "extends",
451 "false",
452 "final",
453 "finally",
454 "float",
455 "for",
456 "function",
457 "goto",
458 "if",
459 "implements",
460 "import",
461 "in",
462 "instanceof",
463 "int",
464 "interface",
465 "long",
466 "native",
467 "new",
468 "null",
469 "package",
470 "private",
471 "protected",
472 "public",
473 "return",
474 "short",
475 "static",
476 "super",
477 "switch",
478 "synchronized",
479 "this",
480 "throw",
481 "throws",
482 "transient",
483 "true",
484 "try",
485 "typeof",
486 "var",
487 "void",
488 "volatile",
489 "while",
490 "with",
491 0
492};
493
494
495static void CheckSymbols(const char** strings) {
496 for (const char* string = *strings; *strings != 0; string = *strings++) {
497 Object* a = Heap::LookupAsciiSymbol(string);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000498 // LookupAsciiSymbol may return a failure if a GC is needed.
499 if (a->IsFailure()) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000500 CHECK(a->IsSymbol());
501 Object* b = Heap::LookupAsciiSymbol(string);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000502 if (b->IsFailure()) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000503 CHECK_EQ(b, a);
504 CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
505 }
506}
507
508
509TEST(SymbolTable) {
510 InitializeVM();
511
512 CheckSymbols(not_so_random_string_table);
513 CheckSymbols(not_so_random_string_table);
514}
515
516
517TEST(FunctionAllocation) {
518 InitializeVM();
519
520 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000521 Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
522 Handle<JSFunction> function =
523 Factory::NewFunction(name, Factory::undefined_value());
524 Handle<Map> initial_map =
525 Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
526 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000527
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000528 Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
529 Handle<JSObject> obj = Factory::NewJSObject(function);
530 obj->SetProperty(*prop_name, Smi::FromInt(23), NONE);
531 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000532 // Check that we can add properties to function objects.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000533 function->SetProperty(*prop_name, Smi::FromInt(24), NONE);
534 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000535}
536
537
538TEST(ObjectProperties) {
539 InitializeVM();
540
541 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000542 String* object_symbol = String::cast(Heap::Object_symbol());
543 JSFunction* object_function =
544 JSFunction::cast(Top::context()->global()->GetProperty(object_symbol));
545 Handle<JSFunction> constructor(object_function);
546 Handle<JSObject> obj = Factory::NewJSObject(constructor);
547 Handle<String> first = Factory::LookupAsciiSymbol("first");
548 Handle<String> second = Factory::LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000549
550 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000551 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000552
553 // add first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000554 obj->SetProperty(*first, Smi::FromInt(1), NONE);
555 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000556
557 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000558 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
559 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000560
561 // add first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000562 obj->SetProperty(*first, Smi::FromInt(1), NONE);
563 obj->SetProperty(*second, Smi::FromInt(2), NONE);
564 CHECK(obj->HasLocalProperty(*first));
565 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000566
567 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000568 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
569 CHECK(obj->HasLocalProperty(*second));
570 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
571 CHECK(!obj->HasLocalProperty(*first));
572 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000573
574 // add first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000575 obj->SetProperty(*first, Smi::FromInt(1), NONE);
576 obj->SetProperty(*second, Smi::FromInt(2), NONE);
577 CHECK(obj->HasLocalProperty(*first));
578 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000579
580 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000581 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
582 CHECK(obj->HasLocalProperty(*first));
583 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
584 CHECK(!obj->HasLocalProperty(*first));
585 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000586
587 // check string and symbol match
588 static const char* string1 = "fisk";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000589 Handle<String> s1 = Factory::NewStringFromAscii(CStrVector(string1));
590 obj->SetProperty(*s1, Smi::FromInt(1), NONE);
591 Handle<String> s1_symbol = Factory::LookupAsciiSymbol(string1);
592 CHECK(obj->HasLocalProperty(*s1_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000593
594 // check symbol and string match
595 static const char* string2 = "fugl";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000596 Handle<String> s2_symbol = Factory::LookupAsciiSymbol(string2);
597 obj->SetProperty(*s2_symbol, Smi::FromInt(1), NONE);
598 Handle<String> s2 = Factory::NewStringFromAscii(CStrVector(string2));
599 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000600}
601
602
603TEST(JSObjectMaps) {
604 InitializeVM();
605
606 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000607 Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
608 Handle<JSFunction> function =
609 Factory::NewFunction(name, Factory::undefined_value());
610 Handle<Map> initial_map =
611 Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
612 function->set_initial_map(*initial_map);
613
614 Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
615 Handle<JSObject> obj = Factory::NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000616
617 // Set a propery
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000618 obj->SetProperty(*prop_name, Smi::FromInt(23), NONE);
619 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000620
621 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000622 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000623}
624
625
626TEST(JSArray) {
627 InitializeVM();
628
629 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000630 Handle<String> name = Factory::LookupAsciiSymbol("Array");
631 Handle<JSFunction> function = Handle<JSFunction>(
632 JSFunction::cast(Top::context()->global()->GetProperty(*name)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000633
634 // Allocate the object.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000635 Handle<JSObject> object = Factory::NewJSObject(function);
636 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000637 Object* ok = array->Initialize(0);
638 // We just initialized the VM, no heap allocation failure yet.
639 CHECK(!ok->IsFailure());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000640
641 // Set array length to 0.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000642 ok = array->SetElementsLength(Smi::FromInt(0));
643 CHECK(!ok->IsFailure());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000644 CHECK_EQ(Smi::FromInt(0), array->length());
645 CHECK(array->HasFastElements()); // Must be in fast mode.
646
647 // array[length] = name.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000648 ok = array->SetElement(0, *name);
649 CHECK(!ok->IsFailure());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000650 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000651 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000652
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000653 // Set array length with larger than smi value.
654 Handle<Object> length =
655 Factory::NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000656 ok = array->SetElementsLength(*length);
657 CHECK(!ok->IsFailure());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000658
659 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000660 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000661 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000662 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000663
664 // array[length] = name.
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000665 ok = array->SetElement(int_length, *name);
666 CHECK(!ok->IsFailure());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000667 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000668 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000669 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000670 CHECK_EQ(array->GetElement(int_length), *name);
671 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000672}
673
674
675TEST(JSObjectCopy) {
676 InitializeVM();
677
678 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000679 String* object_symbol = String::cast(Heap::Object_symbol());
680 JSFunction* object_function =
681 JSFunction::cast(Top::context()->global()->GetProperty(object_symbol));
682 Handle<JSFunction> constructor(object_function);
683 Handle<JSObject> obj = Factory::NewJSObject(constructor);
684 Handle<String> first = Factory::LookupAsciiSymbol("first");
685 Handle<String> second = Factory::LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000686
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000687 obj->SetProperty(*first, Smi::FromInt(1), NONE);
688 obj->SetProperty(*second, Smi::FromInt(2), NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000689
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000690 Object* ok = obj->SetElement(0, *first);
691 CHECK(!ok->IsFailure());
692
693 ok = obj->SetElement(1, *second);
694 CHECK(!ok->IsFailure());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000695
696 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000697 Handle<JSObject> clone = Copy(obj);
698 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000699
700 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
701 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
702
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000703 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
704 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000705
706 // Flip the values.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000707 clone->SetProperty(*first, Smi::FromInt(2), NONE);
708 clone->SetProperty(*second, Smi::FromInt(1), NONE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000709
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000710 ok = clone->SetElement(0, *second);
711 CHECK(!ok->IsFailure());
712 ok = clone->SetElement(1, *first);
713 CHECK(!ok->IsFailure());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000714
715 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
716 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
717
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000718 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
719 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000720}
721
722
723TEST(StringAllocation) {
724 InitializeVM();
725
726
727 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
728 for (int length = 0; length < 100; length++) {
729 v8::HandleScope scope;
730 char* non_ascii = NewArray<char>(3 * length + 1);
731 char* ascii = NewArray<char>(length + 1);
732 non_ascii[3 * length] = 0;
733 ascii[length] = 0;
734 for (int i = 0; i < length; i++) {
735 ascii[i] = 'a';
736 non_ascii[3 * i] = chars[0];
737 non_ascii[3 * i + 1] = chars[1];
738 non_ascii[3 * i + 2] = chars[2];
739 }
740 Handle<String> non_ascii_sym =
741 Factory::LookupSymbol(Vector<const char>(non_ascii, 3 * length));
742 CHECK_EQ(length, non_ascii_sym->length());
743 Handle<String> ascii_sym =
744 Factory::LookupSymbol(Vector<const char>(ascii, length));
745 CHECK_EQ(length, ascii_sym->length());
746 Handle<String> non_ascii_str =
747 Factory::NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
748 non_ascii_str->Hash();
749 CHECK_EQ(length, non_ascii_str->length());
750 Handle<String> ascii_str =
751 Factory::NewStringFromUtf8(Vector<const char>(ascii, length));
752 ascii_str->Hash();
753 CHECK_EQ(length, ascii_str->length());
754 DeleteArray(non_ascii);
755 DeleteArray(ascii);
756 }
757}
758
759
760static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
761 // Count the number of objects found in the heap.
762 int found_count = 0;
763 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000764 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000765 for (int i = 0; i < size; i++) {
766 if (*objs[i] == obj) {
767 found_count++;
768 }
769 }
770 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000771 return found_count;
772}
773
774
775TEST(Iteration) {
776 InitializeVM();
777 v8::HandleScope scope;
778
779 // Array of objects to scan haep for.
780 const int objs_count = 6;
781 Handle<Object> objs[objs_count];
782 int next_objs_index = 0;
783
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000784 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000785 objs[next_objs_index++] = Factory::NewJSArray(10);
786 objs[next_objs_index++] = Factory::NewJSArray(10, TENURED);
787
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000788 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000789 objs[next_objs_index++] =
790 Factory::NewStringFromAscii(CStrVector("abcdefghij"));
791 objs[next_objs_index++] =
792 Factory::NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
793
794 // Allocate a large string (for large object space).
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000795 int large_size = Heap::MaxObjectSizeInPagedSpace() + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000796 char* str = new char[large_size];
797 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
798 str[large_size - 1] = '\0';
799 objs[next_objs_index++] =
800 Factory::NewStringFromAscii(CStrVector(str), TENURED);
801 delete[] str;
802
803 // Add a Map object to look for.
804 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
805
806 CHECK_EQ(objs_count, next_objs_index);
807 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
808}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000809
810
811TEST(LargeObjectSpaceContains) {
812 InitializeVM();
813
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000814 Heap::CollectGarbage(NEW_SPACE);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000815
816 Address current_top = Heap::new_space()->top();
817 Page* page = Page::FromAddress(current_top);
818 Address current_page = page->address();
819 Address next_page = current_page + Page::kPageSize;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000820 int bytes_to_page = static_cast<int>(next_page - current_top);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000821 if (bytes_to_page <= FixedArray::kHeaderSize) {
822 // Alas, need to cross another page to be able to
823 // put desired value.
824 next_page += Page::kPageSize;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000825 bytes_to_page = static_cast<int>(next_page - current_top);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000826 }
827 CHECK(bytes_to_page > FixedArray::kHeaderSize);
828
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000829 intptr_t* flags_ptr = &Page::FromAddress(next_page)->flags_;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000830 Address flags_addr = reinterpret_cast<Address>(flags_ptr);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000831
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000832 int bytes_to_allocate =
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000833 static_cast<int>(flags_addr - current_top) + kPointerSize;
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000834
835 int n_elements = (bytes_to_allocate - FixedArray::kHeaderSize) /
836 kPointerSize;
837 CHECK_EQ(bytes_to_allocate, FixedArray::SizeFor(n_elements));
838 FixedArray* array = FixedArray::cast(
839 Heap::AllocateFixedArray(n_elements));
840
841 int index = n_elements - 1;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000842 CHECK_EQ(flags_ptr,
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000843 HeapObject::RawField(array, FixedArray::OffsetOfElementAt(index)));
844 array->set(index, Smi::FromInt(0));
845 // This chould have turned next page into LargeObjectPage:
846 // CHECK(Page::FromAddress(next_page)->IsLargeObjectPage());
847
848 HeapObject* addr = HeapObject::FromAddress(next_page + 2 * kPointerSize);
849 CHECK(Heap::new_space()->Contains(addr));
850 CHECK(!Heap::lo_space()->Contains(addr));
851}
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000852
853
854TEST(EmptyHandleEscapeFrom) {
855 InitializeVM();
856
857 v8::HandleScope scope;
858 Handle<JSObject> runaway;
859
860 {
861 v8::HandleScope nested;
862 Handle<JSObject> empty;
863 runaway = empty.EscapeFrom(&nested);
864 }
865
866 CHECK(runaway.is_null());
867}
868
869
870static int LenFromSize(int size) {
871 return (size - FixedArray::kHeaderSize) / kPointerSize;
872}
873
874
875TEST(Regression39128) {
876 // Test case for crbug.com/39128.
877 InitializeVM();
878
879 // Increase the chance of 'bump-the-pointer' allocation in old space.
880 bool force_compaction = true;
881 Heap::CollectAllGarbage(force_compaction);
882
883 v8::HandleScope scope;
884
885 // The plan: create JSObject which references objects in new space.
886 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000887 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000888
889 // Step 1: prepare a map for the object. We add 1 inobject property to it.
890 Handle<JSFunction> object_ctor(Top::global_context()->object_function());
891 CHECK(object_ctor->has_initial_map());
892 Handle<Map> object_map(object_ctor->initial_map());
893 // Create a map with single inobject property.
894 Handle<Map> my_map = Factory::CopyMap(object_map, 1);
895 int n_properties = my_map->inobject_properties();
896 CHECK_GT(n_properties, 0);
897
898 int object_size = my_map->instance_size();
899
900 // Step 2: allocate a lot of objects so to almost fill new space: we need
901 // just enough room to allocate JSObject and thus fill the newspace.
902
903 int allocation_amount = Min(FixedArray::kMaxSize,
904 Heap::MaxObjectSizeInNewSpace());
905 int allocation_len = LenFromSize(allocation_amount);
906 NewSpace* new_space = Heap::new_space();
907 Address* top_addr = new_space->allocation_top_address();
908 Address* limit_addr = new_space->allocation_limit_address();
909 while ((*limit_addr - *top_addr) > allocation_amount) {
910 CHECK(!Heap::always_allocate());
911 Object* array = Heap::AllocateFixedArray(allocation_len);
912 CHECK(!array->IsFailure());
913 CHECK(new_space->Contains(array));
914 }
915
916 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000917 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000918 int fixed_array_len = LenFromSize(to_fill);
919 CHECK(fixed_array_len < FixedArray::kMaxLength);
920
921 CHECK(!Heap::always_allocate());
922 Object* array = Heap::AllocateFixedArray(fixed_array_len);
923 CHECK(!array->IsFailure());
924 CHECK(new_space->Contains(array));
925
926 Object* object = Heap::AllocateJSObjectFromMap(*my_map);
927 CHECK(!object->IsFailure());
928 CHECK(new_space->Contains(object));
929 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000930 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000931 CHECK_EQ(0, jsobject->properties()->length());
932 // Create a reference to object in new space in jsobject.
933 jsobject->FastPropertyAtPut(-1, array);
934
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000935 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000936
937 // Step 4: clone jsobject, but force always allocate first to create a clone
938 // in old pointer space.
939 Address old_pointer_space_top = Heap::old_pointer_space()->top();
940 AlwaysAllocateScope aa_scope;
941 Object* clone_obj = Heap::CopyJSObject(jsobject);
942 CHECK(!object->IsFailure());
943 JSObject* clone = JSObject::cast(clone_obj);
944 if (clone->address() != old_pointer_space_top) {
945 // Alas, got allocated from free list, we cannot do checks.
946 return;
947 }
948 CHECK(Heap::old_pointer_space()->Contains(clone->address()));
949
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000950 // Step 5: verify validity of region dirty marks.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000951 Address clone_addr = clone->address();
952 Page* page = Page::FromAddress(clone_addr);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000953 // Check that region covering inobject property 1 is marked dirty.
954 CHECK(page->IsRegionDirty(clone_addr + (object_size - kPointerSize)));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000955}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000956
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000957
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000958TEST(TestCodeFlushing) {
959 i::FLAG_allow_natives_syntax = true;
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000960 // If we do not flush code this test is invalid.
961 if (!FLAG_flush_code) return;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000962 InitializeVM();
963 v8::HandleScope scope;
964 const char* source = "function foo() {"
965 " var x = 42;"
966 " var y = 42;"
967 " var z = x + y;"
968 "};"
969 "foo()";
970 Handle<String> foo_name = Factory::LookupAsciiSymbol("foo");
971
972 // This compile will add the code to the compilation cache.
973 CompileRun(source);
974
975 // Check function is compiled.
976 Object* func_value = Top::context()->global()->GetProperty(*foo_name);
977 CHECK(func_value->IsJSFunction());
978 Handle<JSFunction> function(JSFunction::cast(func_value));
979 CHECK(function->shared()->is_compiled());
980
981 Heap::CollectAllGarbage(true);
982 Heap::CollectAllGarbage(true);
983
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000984 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000985
986 Heap::CollectAllGarbage(true);
987 Heap::CollectAllGarbage(true);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000988 Heap::CollectAllGarbage(true);
989 Heap::CollectAllGarbage(true);
990 Heap::CollectAllGarbage(true);
991 Heap::CollectAllGarbage(true);
992
993 // foo should no longer be in the compilation cache
994 CHECK(!function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000995 CHECK(!function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000996 // Call foo to get it recompiled.
997 CompileRun("foo()");
998 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000999 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001000}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001001
1002
1003// Count the number of global contexts in the weak list of global contexts.
1004static int CountGlobalContexts() {
1005 int count = 0;
1006 Object* object = Heap::global_contexts_list();
1007 while (!object->IsUndefined()) {
1008 count++;
1009 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1010 }
1011 return count;
1012}
1013
1014
1015TEST(TestInternalWeakLists) {
1016 static const int kNumTestContexts = 10;
1017
1018 v8::HandleScope scope;
1019 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1020
1021 CHECK_EQ(0, CountGlobalContexts());
1022
1023 // Create a number of global contests which gets linked together.
1024 for (int i = 0; i < kNumTestContexts; i++) {
1025 ctx[i] = v8::Context::New();
1026 CHECK_EQ(i + 1, CountGlobalContexts());
1027
1028 ctx[i]->Enter();
1029 ctx[i]->Exit();
1030 }
1031
1032 // Force compilation cache cleanup.
1033 Heap::CollectAllGarbage(true);
1034
1035 // Dispose the global contexts one by one.
1036 for (int i = 0; i < kNumTestContexts; i++) {
1037 ctx[i].Dispose();
1038 ctx[i].Clear();
1039
1040 // Scavenge treats these references as strong.
1041 for (int j = 0; j < 10; j++) {
1042 Heap::PerformScavenge();
1043 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts());
1044 }
1045
1046 // Mark compact handles the weak references.
1047 Heap::CollectAllGarbage(true);
1048 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts());
1049 }
1050
1051 CHECK_EQ(0, CountGlobalContexts());
1052}
1053
1054
1055// Count the number of global contexts in the weak list of global contexts
1056// causing a GC after the specified number of elements.
1057static int CountGlobalContextsWithGC(int n) {
1058 int count = 0;
1059 Handle<Object> object(Heap::global_contexts_list());
1060 while (!object->IsUndefined()) {
1061 count++;
1062 if (count == n) Heap::CollectAllGarbage(true);
1063 object =
1064 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1065 }
1066 return count;
1067}
1068
1069
1070TEST(TestInternalWeakListsTraverseWithGC) {
1071 static const int kNumTestContexts = 10;
1072
1073 v8::HandleScope scope;
1074 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1075
1076 CHECK_EQ(0, CountGlobalContexts());
1077
1078 // Create an number of contexts and check the length of the weak list both
1079 // with and without GCs while iterating the list.
1080 for (int i = 0; i < kNumTestContexts; i++) {
1081 ctx[i] = v8::Context::New();
1082 CHECK_EQ(i + 1, CountGlobalContexts());
1083 CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1));
1084
1085 ctx[i]->Enter();
1086 ctx[i]->Exit();
1087 }
1088}