blob: aa5fe59bd991b9dc7f9016fa5bfcde49f803d03f [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;
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000514 MaybeObject *maybe_b = Heap::LookupAsciiSymbol(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000515 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.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000981 { v8::HandleScope scope;
982 CompileRun(source);
983 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000984
985 // Check function is compiled.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000986 Object* func_value =
987 Top::context()->global()->GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000988 CHECK(func_value->IsJSFunction());
989 Handle<JSFunction> function(JSFunction::cast(func_value));
990 CHECK(function->shared()->is_compiled());
991
992 Heap::CollectAllGarbage(true);
993 Heap::CollectAllGarbage(true);
994
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000995 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000996
997 Heap::CollectAllGarbage(true);
998 Heap::CollectAllGarbage(true);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000999 Heap::CollectAllGarbage(true);
1000 Heap::CollectAllGarbage(true);
1001 Heap::CollectAllGarbage(true);
1002 Heap::CollectAllGarbage(true);
1003
1004 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001005 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1006 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001007 // Call foo to get it recompiled.
1008 CompileRun("foo()");
1009 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001010 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001011}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001012
1013
1014// Count the number of global contexts in the weak list of global contexts.
1015static int CountGlobalContexts() {
1016 int count = 0;
1017 Object* object = Heap::global_contexts_list();
1018 while (!object->IsUndefined()) {
1019 count++;
1020 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1021 }
1022 return count;
1023}
1024
1025
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001026// Count the number of user functions in the weak list of optimized
1027// functions attached to a global context.
1028static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1029 int count = 0;
1030 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1031 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1032 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1033 count++;
1034 object = JSFunction::cast(object)->next_function_link();
1035 }
1036 return count;
1037}
1038
1039
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001040TEST(TestInternalWeakLists) {
1041 static const int kNumTestContexts = 10;
1042
1043 v8::HandleScope scope;
1044 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1045
1046 CHECK_EQ(0, CountGlobalContexts());
1047
1048 // Create a number of global contests which gets linked together.
1049 for (int i = 0; i < kNumTestContexts; i++) {
1050 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001051
1052 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1053
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001054 CHECK_EQ(i + 1, CountGlobalContexts());
1055
1056 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001057
1058 // Create a handle scope so no function objects get stuch in the outer
1059 // handle scope
1060 v8::HandleScope scope;
1061 const char* source = "function f1() { };"
1062 "function f2() { };"
1063 "function f3() { };"
1064 "function f4() { };"
1065 "function f5() { };";
1066 CompileRun(source);
1067 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1068 CompileRun("f1()");
1069 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1070 CompileRun("f2()");
1071 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1072 CompileRun("f3()");
1073 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1074 CompileRun("f4()");
1075 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1076 CompileRun("f5()");
1077 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1078
1079 // Remove function f1, and
1080 CompileRun("f1=null");
1081
1082 // Scavenge treats these references as strong.
1083 for (int j = 0; j < 10; j++) {
1084 Heap::PerformScavenge();
1085 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1086 }
1087
1088 // Mark compact handles the weak references.
1089 Heap::CollectAllGarbage(true);
1090 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1091
1092 // Get rid of f3 and f5 in the same way.
1093 CompileRun("f3=null");
1094 for (int j = 0; j < 10; j++) {
1095 Heap::PerformScavenge();
1096 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1097 }
1098 Heap::CollectAllGarbage(true);
1099 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1100 CompileRun("f5=null");
1101 for (int j = 0; j < 10; j++) {
1102 Heap::PerformScavenge();
1103 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1104 }
1105 Heap::CollectAllGarbage(true);
1106 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1107
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001108 ctx[i]->Exit();
1109 }
1110
1111 // Force compilation cache cleanup.
1112 Heap::CollectAllGarbage(true);
1113
1114 // Dispose the global contexts one by one.
1115 for (int i = 0; i < kNumTestContexts; i++) {
1116 ctx[i].Dispose();
1117 ctx[i].Clear();
1118
1119 // Scavenge treats these references as strong.
1120 for (int j = 0; j < 10; j++) {
1121 Heap::PerformScavenge();
1122 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts());
1123 }
1124
1125 // Mark compact handles the weak references.
1126 Heap::CollectAllGarbage(true);
1127 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts());
1128 }
1129
1130 CHECK_EQ(0, CountGlobalContexts());
1131}
1132
1133
1134// Count the number of global contexts in the weak list of global contexts
1135// causing a GC after the specified number of elements.
1136static int CountGlobalContextsWithGC(int n) {
1137 int count = 0;
1138 Handle<Object> object(Heap::global_contexts_list());
1139 while (!object->IsUndefined()) {
1140 count++;
1141 if (count == n) Heap::CollectAllGarbage(true);
1142 object =
1143 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1144 }
1145 return count;
1146}
1147
1148
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001149// Count the number of user functions in the weak list of optimized
1150// functions attached to a global context causing a GC after the
1151// specified number of elements.
1152static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1153 int n) {
1154 int count = 0;
1155 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1156 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1157 while (object->IsJSFunction() &&
1158 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1159 count++;
1160 if (count == n) Heap::CollectAllGarbage(true);
1161 object = Handle<Object>(
1162 Object::cast(JSFunction::cast(*object)->next_function_link()));
1163 }
1164 return count;
1165}
1166
1167
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001168TEST(TestInternalWeakListsTraverseWithGC) {
1169 static const int kNumTestContexts = 10;
1170
1171 v8::HandleScope scope;
1172 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1173
1174 CHECK_EQ(0, CountGlobalContexts());
1175
1176 // Create an number of contexts and check the length of the weak list both
1177 // with and without GCs while iterating the list.
1178 for (int i = 0; i < kNumTestContexts; i++) {
1179 ctx[i] = v8::Context::New();
1180 CHECK_EQ(i + 1, CountGlobalContexts());
1181 CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001182 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001183
1184 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1185
1186 // Compile a number of functions the length of the weak list of optimized
1187 // functions both with and without GCs while iterating the list.
1188 ctx[0]->Enter();
1189 const char* source = "function f1() { };"
1190 "function f2() { };"
1191 "function f3() { };"
1192 "function f4() { };"
1193 "function f5() { };";
1194 CompileRun(source);
1195 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1196 CompileRun("f1()");
1197 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1198 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1199 CompileRun("f2()");
1200 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1201 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1202 CompileRun("f3()");
1203 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1204 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1205 CompileRun("f4()");
1206 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1207 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1208 CompileRun("f5()");
1209 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1210 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1211
1212 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001213}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001214
1215
1216TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1217 InitializeVM();
1218 intptr_t size_of_objects_1 = Heap::SizeOfObjects();
1219 HeapIterator iterator(HeapIterator::kPreciseFiltering);
1220 intptr_t size_of_objects_2 = 0;
1221 for (HeapObject* obj = iterator.next();
1222 obj != NULL;
1223 obj = iterator.next()) {
1224 size_of_objects_2 += obj->Size();
1225 }
1226 // Delta must be within 1% of the larger result.
1227 if (size_of_objects_1 > size_of_objects_2) {
1228 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1229 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1230 "Iterator: %" V8_PTR_PREFIX "d, "
1231 "delta: %" V8_PTR_PREFIX "d\n",
1232 size_of_objects_1, size_of_objects_2, delta);
1233 CHECK_GT(size_of_objects_1 / 100, delta);
1234 } else {
1235 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1236 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1237 "Iterator: %" V8_PTR_PREFIX "d, "
1238 "delta: %" V8_PTR_PREFIX "d\n",
1239 size_of_objects_1, size_of_objects_2, delta);
1240 CHECK_GT(size_of_objects_2 / 100, delta);
1241 }
1242}