blob: 94d05555ec556276834a381ad68786266f433e77 [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) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000061 Object* obj = Heap::NumberFromDouble(value)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000062 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);
lrn@chromium.org303ada72010-10-27 09:33:13 +000079 Object* code = Heap::CreateCode(
80 desc,
81 Code::ComputeFlags(Code::STUB),
82 Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
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
lrn@chromium.org303ada72010-10-27 09:33:13 +000093 Object* copy = Heap::CreateCode(
94 desc,
95 Code::ComputeFlags(Code::STUB),
96 Handle<Object>(Heap::undefined_value()))->ToObjectChecked();
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;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000109 Object* value = Heap::NumberFromDouble(1.000123)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000110 CHECK(value->IsHeapNumber());
111 CHECK(value->IsNumber());
112 CHECK_EQ(1.000123, value->Number());
113
lrn@chromium.org303ada72010-10-27 09:33:13 +0000114 value = Heap::NumberFromDouble(1.0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000115 CHECK(value->IsSmi());
116 CHECK(value->IsNumber());
117 CHECK_EQ(1.0, value->Number());
118
lrn@chromium.org303ada72010-10-27 09:33:13 +0000119 value = Heap::NumberFromInt32(1024)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000120 CHECK(value->IsSmi());
121 CHECK(value->IsNumber());
122 CHECK_EQ(1024.0, value->Number());
123
lrn@chromium.org303ada72010-10-27 09:33:13 +0000124 value = Heap::NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000125 CHECK(value->IsSmi());
126 CHECK(value->IsNumber());
127 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
128
lrn@chromium.org303ada72010-10-27 09:33:13 +0000129 value = Heap::NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000130 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.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 value = Heap::NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000137 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
lrn@chromium.org303ada72010-10-27 09:33:13 +0000142 MaybeObject* maybe_value =
143 Heap::NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
144 value = maybe_value->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000145 CHECK(value->IsHeapNumber());
146 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000147 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
148 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000149
150 // nan oddball checks
151 CHECK(Heap::nan_value()->IsNumber());
152 CHECK(isnan(Heap::nan_value()->Number()));
153
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000154 Handle<String> s = Factory::NewStringFromAscii(CStrVector("fisk hest "));
155 CHECK(s->IsString());
156 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000157
158 String* object_symbol = String::cast(Heap::Object_symbol());
159 CHECK(Top::context()->global()->HasLocalProperty(object_symbol));
160
161 // Check ToString for oddballs
162 CheckOddball(Heap::true_value(), "true");
163 CheckOddball(Heap::false_value(), "false");
164 CheckOddball(Heap::null_value(), "null");
165 CheckOddball(Heap::undefined_value(), "undefined");
166
167 // Check ToString for Smis
168 CheckSmi(0, "0");
169 CheckSmi(42, "42");
170 CheckSmi(-42, "-42");
171
172 // Check ToString for Numbers
173 CheckNumber(1.1, "1.1");
174
175 CheckFindCodeObject();
176}
177
178
179TEST(Tagging) {
180 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000181 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000182 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000183 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000184 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000185 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000186 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000187 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000188 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000189 CHECK(Failure::Exception()->IsFailure());
190 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
191 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
192}
193
194
195TEST(GarbageCollection) {
196 InitializeVM();
197
198 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000199 // Check GC.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000200 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000201
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000202 Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
203 Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
204 Handle<String> prop_namex = Factory::LookupAsciiSymbol("theSlotx");
205 Handle<String> obj_name = Factory::LookupAsciiSymbol("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000206
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000207 {
208 v8::HandleScope inner_scope;
209 // Allocate a function and keep it in global object's property.
210 Handle<JSFunction> function =
211 Factory::NewFunction(name, Factory::undefined_value());
212 Handle<Map> initial_map =
213 Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
214 function->set_initial_map(*initial_map);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000215 Top::context()->global()->SetProperty(*name,
216 *function,
217 NONE)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000218 // Allocate an object. Unrooted after leaving the scope.
219 Handle<JSObject> obj = Factory::NewJSObject(function);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000220 obj->SetProperty(*prop_name, Smi::FromInt(23), NONE)->ToObjectChecked();
221 obj->SetProperty(*prop_namex, Smi::FromInt(24), NONE)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000222
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000223 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
224 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
225 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000226
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000227 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000228
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000229 // Function should be alive.
230 CHECK(Top::context()->global()->HasLocalProperty(*name));
231 // Check function is retained.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000232 Object* func_value =
233 Top::context()->global()->GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000234 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000235 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000236
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000237 {
238 HandleScope inner_scope;
239 // Allocate another object, make it reachable from global.
240 Handle<JSObject> obj = Factory::NewJSObject(function);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000241 Top::context()->global()->SetProperty(*obj_name,
242 *obj,
243 NONE)->ToObjectChecked();
244 obj->SetProperty(*prop_name, Smi::FromInt(23), NONE)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000245 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000246
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000247 // After gc, it should survive.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000248 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000249
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000250 CHECK(Top::context()->global()->HasLocalProperty(*obj_name));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000251 CHECK(Top::context()->global()->GetProperty(*obj_name)->ToObjectChecked()->
252 IsJSObject());
253 Object* obj =
254 Top::context()->global()->GetProperty(*obj_name)->ToObjectChecked();
255 JSObject* js_obj = JSObject::cast(obj);
256 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000257}
258
259
260static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000261 v8::HandleScope scope;
262 Handle<String> s = Factory::NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000263 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000264 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000265 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
266 }
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
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000294 Handle<Object> h1;
295 Handle<Object> h2;
296 Handle<Object> h3;
297 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000298
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000299 {
300 HandleScope scope;
301
302 Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
303 Handle<Object> u = Factory::NewNumber(1.12344);
304
305 h1 = GlobalHandles::Create(*i);
306 h2 = GlobalHandles::Create(*u);
307 h3 = GlobalHandles::Create(*i);
308 h4 = GlobalHandles::Create(*u);
309 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000310
311 // after gc, it should survive
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000312 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000313
314 CHECK((*h1)->IsString());
315 CHECK((*h2)->IsHeapNumber());
316 CHECK((*h3)->IsString());
317 CHECK((*h4)->IsHeapNumber());
318
319 CHECK_EQ(*h3, *h1);
320 GlobalHandles::Destroy(h1.location());
321 GlobalHandles::Destroy(h3.location());
322
323 CHECK_EQ(*h4, *h2);
324 GlobalHandles::Destroy(h2.location());
325 GlobalHandles::Destroy(h4.location());
326}
327
328
329static bool WeakPointerCleared = false;
330
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000331static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000332 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000333 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000334 handle.Dispose();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000335}
336
337
338TEST(WeakGlobalHandlesScavenge) {
339 InitializeVM();
340
341 WeakPointerCleared = false;
342
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000343 Handle<Object> h1;
344 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000345
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000346 {
347 HandleScope scope;
348
349 Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
350 Handle<Object> u = Factory::NewNumber(1.12344);
351
352 h1 = GlobalHandles::Create(*i);
353 h2 = GlobalHandles::Create(*u);
354 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000355
356 GlobalHandles::MakeWeak(h2.location(),
357 reinterpret_cast<void*>(1234),
358 &TestWeakGlobalHandleCallback);
359
360 // Scavenge treats weak pointers as normal roots.
361 Heap::PerformScavenge();
362
363 CHECK((*h1)->IsString());
364 CHECK((*h2)->IsHeapNumber());
365
366 CHECK(!WeakPointerCleared);
367 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
368 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
369
370 GlobalHandles::Destroy(h1.location());
371 GlobalHandles::Destroy(h2.location());
372}
373
374
375TEST(WeakGlobalHandlesMark) {
376 InitializeVM();
377
378 WeakPointerCleared = false;
379
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000380 Handle<Object> h1;
381 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000382
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000383 {
384 HandleScope scope;
385
386 Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
387 Handle<Object> u = Factory::NewNumber(1.12344);
388
389 h1 = GlobalHandles::Create(*i);
390 h2 = GlobalHandles::Create(*u);
391 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000392
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000393 Heap::CollectGarbage(OLD_POINTER_SPACE);
394 Heap::CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000395 // Make sure the object is promoted.
396
397 GlobalHandles::MakeWeak(h2.location(),
398 reinterpret_cast<void*>(1234),
399 &TestWeakGlobalHandleCallback);
400 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
401 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
402
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000403 Heap::CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000404
405 CHECK((*h1)->IsString());
406
407 CHECK(WeakPointerCleared);
408 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000409
410 GlobalHandles::Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000411}
412
413TEST(DeleteWeakGlobalHandle) {
414 InitializeVM();
415
416 WeakPointerCleared = false;
417
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000418 Handle<Object> h;
419
420 {
421 HandleScope scope;
422
423 Handle<Object> i = Factory::NewStringFromAscii(CStrVector("fisk"));
424 h = GlobalHandles::Create(*i);
425 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000426
427 GlobalHandles::MakeWeak(h.location(),
428 reinterpret_cast<void*>(1234),
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000429 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000430
431 // Scanvenge does not recognize weak reference.
432 Heap::PerformScavenge();
433
434 CHECK(!WeakPointerCleared);
435
436 // Mark-compact treats weak reference properly.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000437 Heap::CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000438
439 CHECK(WeakPointerCleared);
440}
441
442static const char* not_so_random_string_table[] = {
443 "abstract",
444 "boolean",
445 "break",
446 "byte",
447 "case",
448 "catch",
449 "char",
450 "class",
451 "const",
452 "continue",
453 "debugger",
454 "default",
455 "delete",
456 "do",
457 "double",
458 "else",
459 "enum",
460 "export",
461 "extends",
462 "false",
463 "final",
464 "finally",
465 "float",
466 "for",
467 "function",
468 "goto",
469 "if",
470 "implements",
471 "import",
472 "in",
473 "instanceof",
474 "int",
475 "interface",
476 "long",
477 "native",
478 "new",
479 "null",
480 "package",
481 "private",
482 "protected",
483 "public",
484 "return",
485 "short",
486 "static",
487 "super",
488 "switch",
489 "synchronized",
490 "this",
491 "throw",
492 "throws",
493 "transient",
494 "true",
495 "try",
496 "typeof",
497 "var",
498 "void",
499 "volatile",
500 "while",
501 "with",
502 0
503};
504
505
506static void CheckSymbols(const char** strings) {
507 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000508 Object* a;
509 MaybeObject* maybe_a = Heap::LookupAsciiSymbol(string);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000510 // LookupAsciiSymbol may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000511 if (!maybe_a->ToObject(&a)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000512 CHECK(a->IsSymbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000513 Object* b;
514 MaybeObject* maybe_b = Heap::LookupAsciiSymbol(string);
515 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000516 CHECK_EQ(b, a);
517 CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
518 }
519}
520
521
522TEST(SymbolTable) {
523 InitializeVM();
524
525 CheckSymbols(not_so_random_string_table);
526 CheckSymbols(not_so_random_string_table);
527}
528
529
530TEST(FunctionAllocation) {
531 InitializeVM();
532
533 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000534 Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
535 Handle<JSFunction> function =
536 Factory::NewFunction(name, Factory::undefined_value());
537 Handle<Map> initial_map =
538 Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
539 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000540
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000541 Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
542 Handle<JSObject> obj = Factory::NewJSObject(function);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000543 obj->SetProperty(*prop_name, Smi::FromInt(23), NONE)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000544 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000545 // Check that we can add properties to function objects.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000546 function->SetProperty(*prop_name,
547 Smi::FromInt(24),
548 NONE)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000549 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000550}
551
552
553TEST(ObjectProperties) {
554 InitializeVM();
555
556 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000557 String* object_symbol = String::cast(Heap::Object_symbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000558 Object* raw_object =
559 Top::context()->global()->GetProperty(object_symbol)->ToObjectChecked();
560 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000561 Handle<JSFunction> constructor(object_function);
562 Handle<JSObject> obj = Factory::NewJSObject(constructor);
563 Handle<String> first = Factory::LookupAsciiSymbol("first");
564 Handle<String> second = Factory::LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000565
566 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000567 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000568
569 // add first
lrn@chromium.org303ada72010-10-27 09:33:13 +0000570 obj->SetProperty(*first, Smi::FromInt(1), NONE)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000571 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000572
573 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000574 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
575 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000576
577 // add first and then second
lrn@chromium.org303ada72010-10-27 09:33:13 +0000578 obj->SetProperty(*first, Smi::FromInt(1), NONE)->ToObjectChecked();
579 obj->SetProperty(*second, Smi::FromInt(2), NONE)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000580 CHECK(obj->HasLocalProperty(*first));
581 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000582
583 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000584 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
585 CHECK(obj->HasLocalProperty(*second));
586 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
587 CHECK(!obj->HasLocalProperty(*first));
588 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000589
590 // add first and then second
lrn@chromium.org303ada72010-10-27 09:33:13 +0000591 obj->SetProperty(*first, Smi::FromInt(1), NONE)->ToObjectChecked();
592 obj->SetProperty(*second, Smi::FromInt(2), NONE)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000593 CHECK(obj->HasLocalProperty(*first));
594 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000595
596 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000597 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
598 CHECK(obj->HasLocalProperty(*first));
599 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
600 CHECK(!obj->HasLocalProperty(*first));
601 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000602
603 // check string and symbol match
604 static const char* string1 = "fisk";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000605 Handle<String> s1 = Factory::NewStringFromAscii(CStrVector(string1));
lrn@chromium.org303ada72010-10-27 09:33:13 +0000606 obj->SetProperty(*s1, Smi::FromInt(1), NONE)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000607 Handle<String> s1_symbol = Factory::LookupAsciiSymbol(string1);
608 CHECK(obj->HasLocalProperty(*s1_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000609
610 // check symbol and string match
611 static const char* string2 = "fugl";
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000612 Handle<String> s2_symbol = Factory::LookupAsciiSymbol(string2);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000613 obj->SetProperty(*s2_symbol, Smi::FromInt(1), NONE)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000614 Handle<String> s2 = Factory::NewStringFromAscii(CStrVector(string2));
615 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000616}
617
618
619TEST(JSObjectMaps) {
620 InitializeVM();
621
622 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000623 Handle<String> name = Factory::LookupAsciiSymbol("theFunction");
624 Handle<JSFunction> function =
625 Factory::NewFunction(name, Factory::undefined_value());
626 Handle<Map> initial_map =
627 Factory::NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
628 function->set_initial_map(*initial_map);
629
630 Handle<String> prop_name = Factory::LookupAsciiSymbol("theSlot");
631 Handle<JSObject> obj = Factory::NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000632
633 // Set a propery
lrn@chromium.org303ada72010-10-27 09:33:13 +0000634 obj->SetProperty(*prop_name, Smi::FromInt(23), NONE)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000635 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000636
637 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000638 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000639}
640
641
642TEST(JSArray) {
643 InitializeVM();
644
645 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000646 Handle<String> name = Factory::LookupAsciiSymbol("Array");
lrn@chromium.org303ada72010-10-27 09:33:13 +0000647 Object* raw_object =
648 Top::context()->global()->GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000649 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000650 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000651
652 // Allocate the object.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000653 Handle<JSObject> object = Factory::NewJSObject(function);
654 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000655 // We just initialized the VM, no heap allocation failure yet.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000656 Object* ok = array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000657
658 // Set array length to 0.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000659 ok = array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000660 CHECK_EQ(Smi::FromInt(0), array->length());
661 CHECK(array->HasFastElements()); // Must be in fast mode.
662
663 // array[length] = name.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000664 ok = array->SetElement(0, *name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000665 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000666 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000667
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000668 // Set array length with larger than smi value.
669 Handle<Object> length =
670 Factory::NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000671 ok = array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000672
673 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000674 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000675 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000676 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000677
678 // array[length] = name.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000679 ok = array->SetElement(int_length, *name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000680 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000681 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000682 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000683 CHECK_EQ(array->GetElement(int_length), *name);
684 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000685}
686
687
688TEST(JSObjectCopy) {
689 InitializeVM();
690
691 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000692 String* object_symbol = String::cast(Heap::Object_symbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000693 Object* raw_object =
694 Top::context()->global()->GetProperty(object_symbol)->ToObjectChecked();
695 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000696 Handle<JSFunction> constructor(object_function);
697 Handle<JSObject> obj = Factory::NewJSObject(constructor);
698 Handle<String> first = Factory::LookupAsciiSymbol("first");
699 Handle<String> second = Factory::LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000700
lrn@chromium.org303ada72010-10-27 09:33:13 +0000701 obj->SetProperty(*first, Smi::FromInt(1), NONE)->ToObjectChecked();
702 obj->SetProperty(*second, Smi::FromInt(2), NONE)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000703
lrn@chromium.org303ada72010-10-27 09:33:13 +0000704 Object* ok = obj->SetElement(0, *first)->ToObjectChecked();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000705
lrn@chromium.org303ada72010-10-27 09:33:13 +0000706 ok = obj->SetElement(1, *second)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000707
708 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000709 Handle<JSObject> clone = Copy(obj);
710 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000711
712 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
713 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
714
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000715 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
716 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000717
718 // Flip the values.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000719 clone->SetProperty(*first, Smi::FromInt(2), NONE)->ToObjectChecked();
720 clone->SetProperty(*second, Smi::FromInt(1), NONE)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000721
lrn@chromium.org303ada72010-10-27 09:33:13 +0000722 ok = clone->SetElement(0, *second)->ToObjectChecked();
723 ok = clone->SetElement(1, *first)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000724
725 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
726 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
727
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000728 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
729 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000730}
731
732
733TEST(StringAllocation) {
734 InitializeVM();
735
736
737 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
738 for (int length = 0; length < 100; length++) {
739 v8::HandleScope scope;
740 char* non_ascii = NewArray<char>(3 * length + 1);
741 char* ascii = NewArray<char>(length + 1);
742 non_ascii[3 * length] = 0;
743 ascii[length] = 0;
744 for (int i = 0; i < length; i++) {
745 ascii[i] = 'a';
746 non_ascii[3 * i] = chars[0];
747 non_ascii[3 * i + 1] = chars[1];
748 non_ascii[3 * i + 2] = chars[2];
749 }
750 Handle<String> non_ascii_sym =
751 Factory::LookupSymbol(Vector<const char>(non_ascii, 3 * length));
752 CHECK_EQ(length, non_ascii_sym->length());
753 Handle<String> ascii_sym =
754 Factory::LookupSymbol(Vector<const char>(ascii, length));
755 CHECK_EQ(length, ascii_sym->length());
756 Handle<String> non_ascii_str =
757 Factory::NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
758 non_ascii_str->Hash();
759 CHECK_EQ(length, non_ascii_str->length());
760 Handle<String> ascii_str =
761 Factory::NewStringFromUtf8(Vector<const char>(ascii, length));
762 ascii_str->Hash();
763 CHECK_EQ(length, ascii_str->length());
764 DeleteArray(non_ascii);
765 DeleteArray(ascii);
766 }
767}
768
769
770static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
771 // Count the number of objects found in the heap.
772 int found_count = 0;
773 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000774 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000775 for (int i = 0; i < size; i++) {
776 if (*objs[i] == obj) {
777 found_count++;
778 }
779 }
780 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000781 return found_count;
782}
783
784
785TEST(Iteration) {
786 InitializeVM();
787 v8::HandleScope scope;
788
789 // Array of objects to scan haep for.
790 const int objs_count = 6;
791 Handle<Object> objs[objs_count];
792 int next_objs_index = 0;
793
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000794 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000795 objs[next_objs_index++] = Factory::NewJSArray(10);
796 objs[next_objs_index++] = Factory::NewJSArray(10, TENURED);
797
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000798 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000799 objs[next_objs_index++] =
800 Factory::NewStringFromAscii(CStrVector("abcdefghij"));
801 objs[next_objs_index++] =
802 Factory::NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
803
804 // Allocate a large string (for large object space).
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000805 int large_size = Heap::MaxObjectSizeInPagedSpace() + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000806 char* str = new char[large_size];
807 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
808 str[large_size - 1] = '\0';
809 objs[next_objs_index++] =
810 Factory::NewStringFromAscii(CStrVector(str), TENURED);
811 delete[] str;
812
813 // Add a Map object to look for.
814 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
815
816 CHECK_EQ(objs_count, next_objs_index);
817 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
818}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000819
820
821TEST(LargeObjectSpaceContains) {
822 InitializeVM();
823
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000824 Heap::CollectGarbage(NEW_SPACE);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000825
826 Address current_top = Heap::new_space()->top();
827 Page* page = Page::FromAddress(current_top);
828 Address current_page = page->address();
829 Address next_page = current_page + Page::kPageSize;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000830 int bytes_to_page = static_cast<int>(next_page - current_top);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000831 if (bytes_to_page <= FixedArray::kHeaderSize) {
832 // Alas, need to cross another page to be able to
833 // put desired value.
834 next_page += Page::kPageSize;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000835 bytes_to_page = static_cast<int>(next_page - current_top);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000836 }
837 CHECK(bytes_to_page > FixedArray::kHeaderSize);
838
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000839 intptr_t* flags_ptr = &Page::FromAddress(next_page)->flags_;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000840 Address flags_addr = reinterpret_cast<Address>(flags_ptr);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000841
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000842 int bytes_to_allocate =
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000843 static_cast<int>(flags_addr - current_top) + kPointerSize;
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000844
845 int n_elements = (bytes_to_allocate - FixedArray::kHeaderSize) /
846 kPointerSize;
847 CHECK_EQ(bytes_to_allocate, FixedArray::SizeFor(n_elements));
848 FixedArray* array = FixedArray::cast(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000849 Heap::AllocateFixedArray(n_elements)->ToObjectChecked());
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000850
851 int index = n_elements - 1;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000852 CHECK_EQ(flags_ptr,
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000853 HeapObject::RawField(array, FixedArray::OffsetOfElementAt(index)));
854 array->set(index, Smi::FromInt(0));
855 // This chould have turned next page into LargeObjectPage:
856 // CHECK(Page::FromAddress(next_page)->IsLargeObjectPage());
857
858 HeapObject* addr = HeapObject::FromAddress(next_page + 2 * kPointerSize);
859 CHECK(Heap::new_space()->Contains(addr));
860 CHECK(!Heap::lo_space()->Contains(addr));
861}
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000862
863
864TEST(EmptyHandleEscapeFrom) {
865 InitializeVM();
866
867 v8::HandleScope scope;
868 Handle<JSObject> runaway;
869
870 {
871 v8::HandleScope nested;
872 Handle<JSObject> empty;
873 runaway = empty.EscapeFrom(&nested);
874 }
875
876 CHECK(runaway.is_null());
877}
878
879
880static int LenFromSize(int size) {
881 return (size - FixedArray::kHeaderSize) / kPointerSize;
882}
883
884
885TEST(Regression39128) {
886 // Test case for crbug.com/39128.
887 InitializeVM();
888
889 // Increase the chance of 'bump-the-pointer' allocation in old space.
890 bool force_compaction = true;
891 Heap::CollectAllGarbage(force_compaction);
892
893 v8::HandleScope scope;
894
895 // The plan: create JSObject which references objects in new space.
896 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000897 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000898
899 // Step 1: prepare a map for the object. We add 1 inobject property to it.
900 Handle<JSFunction> object_ctor(Top::global_context()->object_function());
901 CHECK(object_ctor->has_initial_map());
902 Handle<Map> object_map(object_ctor->initial_map());
903 // Create a map with single inobject property.
904 Handle<Map> my_map = Factory::CopyMap(object_map, 1);
905 int n_properties = my_map->inobject_properties();
906 CHECK_GT(n_properties, 0);
907
908 int object_size = my_map->instance_size();
909
910 // Step 2: allocate a lot of objects so to almost fill new space: we need
911 // just enough room to allocate JSObject and thus fill the newspace.
912
913 int allocation_amount = Min(FixedArray::kMaxSize,
914 Heap::MaxObjectSizeInNewSpace());
915 int allocation_len = LenFromSize(allocation_amount);
916 NewSpace* new_space = Heap::new_space();
917 Address* top_addr = new_space->allocation_top_address();
918 Address* limit_addr = new_space->allocation_limit_address();
919 while ((*limit_addr - *top_addr) > allocation_amount) {
920 CHECK(!Heap::always_allocate());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000921 Object* array =
922 Heap::AllocateFixedArray(allocation_len)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000923 CHECK(new_space->Contains(array));
924 }
925
926 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000927 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000928 int fixed_array_len = LenFromSize(to_fill);
929 CHECK(fixed_array_len < FixedArray::kMaxLength);
930
931 CHECK(!Heap::always_allocate());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000932 Object* array =
933 Heap::AllocateFixedArray(fixed_array_len)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000934 CHECK(new_space->Contains(array));
935
lrn@chromium.org303ada72010-10-27 09:33:13 +0000936 Object* object = Heap::AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000937 CHECK(new_space->Contains(object));
938 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000939 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000940 CHECK_EQ(0, jsobject->properties()->length());
941 // Create a reference to object in new space in jsobject.
942 jsobject->FastPropertyAtPut(-1, array);
943
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000944 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000945
946 // Step 4: clone jsobject, but force always allocate first to create a clone
947 // in old pointer space.
948 Address old_pointer_space_top = Heap::old_pointer_space()->top();
949 AlwaysAllocateScope aa_scope;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000950 Object* clone_obj = Heap::CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000951 JSObject* clone = JSObject::cast(clone_obj);
952 if (clone->address() != old_pointer_space_top) {
953 // Alas, got allocated from free list, we cannot do checks.
954 return;
955 }
956 CHECK(Heap::old_pointer_space()->Contains(clone->address()));
957
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000958 // Step 5: verify validity of region dirty marks.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000959 Address clone_addr = clone->address();
960 Page* page = Page::FromAddress(clone_addr);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000961 // Check that region covering inobject property 1 is marked dirty.
962 CHECK(page->IsRegionDirty(clone_addr + (object_size - kPointerSize)));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000963}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000964
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000965
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000966TEST(TestCodeFlushing) {
967 i::FLAG_allow_natives_syntax = true;
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000968 // If we do not flush code this test is invalid.
969 if (!FLAG_flush_code) return;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000970 InitializeVM();
971 v8::HandleScope scope;
972 const char* source = "function foo() {"
973 " var x = 42;"
974 " var y = 42;"
975 " var z = x + y;"
976 "};"
977 "foo()";
978 Handle<String> foo_name = Factory::LookupAsciiSymbol("foo");
979
980 // This compile will add the code to the compilation cache.
981 CompileRun(source);
982
983 // Check function is compiled.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000984 Object* func_value =
985 Top::context()->global()->GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000986 CHECK(func_value->IsJSFunction());
987 Handle<JSFunction> function(JSFunction::cast(func_value));
988 CHECK(function->shared()->is_compiled());
989
990 Heap::CollectAllGarbage(true);
991 Heap::CollectAllGarbage(true);
992
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000993 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000994
995 Heap::CollectAllGarbage(true);
996 Heap::CollectAllGarbage(true);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000997 Heap::CollectAllGarbage(true);
998 Heap::CollectAllGarbage(true);
999 Heap::CollectAllGarbage(true);
1000 Heap::CollectAllGarbage(true);
1001
1002 // foo should no longer be in the compilation cache
1003 CHECK(!function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001004 CHECK(!function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001005 // Call foo to get it recompiled.
1006 CompileRun("foo()");
1007 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001008 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001009}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001010
1011
1012// Count the number of global contexts in the weak list of global contexts.
1013static int CountGlobalContexts() {
1014 int count = 0;
1015 Object* object = Heap::global_contexts_list();
1016 while (!object->IsUndefined()) {
1017 count++;
1018 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1019 }
1020 return count;
1021}
1022
1023
1024TEST(TestInternalWeakLists) {
1025 static const int kNumTestContexts = 10;
1026
1027 v8::HandleScope scope;
1028 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1029
1030 CHECK_EQ(0, CountGlobalContexts());
1031
1032 // Create a number of global contests which gets linked together.
1033 for (int i = 0; i < kNumTestContexts; i++) {
1034 ctx[i] = v8::Context::New();
1035 CHECK_EQ(i + 1, CountGlobalContexts());
1036
1037 ctx[i]->Enter();
1038 ctx[i]->Exit();
1039 }
1040
1041 // Force compilation cache cleanup.
1042 Heap::CollectAllGarbage(true);
1043
1044 // Dispose the global contexts one by one.
1045 for (int i = 0; i < kNumTestContexts; i++) {
1046 ctx[i].Dispose();
1047 ctx[i].Clear();
1048
1049 // Scavenge treats these references as strong.
1050 for (int j = 0; j < 10; j++) {
1051 Heap::PerformScavenge();
1052 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts());
1053 }
1054
1055 // Mark compact handles the weak references.
1056 Heap::CollectAllGarbage(true);
1057 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts());
1058 }
1059
1060 CHECK_EQ(0, CountGlobalContexts());
1061}
1062
1063
1064// Count the number of global contexts in the weak list of global contexts
1065// causing a GC after the specified number of elements.
1066static int CountGlobalContextsWithGC(int n) {
1067 int count = 0;
1068 Handle<Object> object(Heap::global_contexts_list());
1069 while (!object->IsUndefined()) {
1070 count++;
1071 if (count == n) Heap::CollectAllGarbage(true);
1072 object =
1073 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1074 }
1075 return count;
1076}
1077
1078
1079TEST(TestInternalWeakListsTraverseWithGC) {
1080 static const int kNumTestContexts = 10;
1081
1082 v8::HandleScope scope;
1083 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1084
1085 CHECK_EQ(0, CountGlobalContexts());
1086
1087 // Create an number of contexts and check the length of the weak list both
1088 // with and without GCs while iterating the list.
1089 for (int i = 0; i < kNumTestContexts; i++) {
1090 ctx[i] = v8::Context::New();
1091 CHECK_EQ(i + 1, CountGlobalContexts());
1092 CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1));
1093
1094 ctx[i]->Enter();
1095 ctx[i]->Exit();
1096 }
1097}