blob: ff7e2e7322bef0117f095bc836278160e7bd7b9a [file] [log] [blame]
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001// Copyright 2012 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
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000027 CHECK(HEAP->Contains(map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000028#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000029 CHECK_EQ(HEAP->meta_map(), map->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000030 CHECK_EQ(type, map->instance_type());
31 CHECK_EQ(instance_size, map->instance_size());
32}
33
34
35TEST(HeapMaps) {
36 InitializeVM();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000037 CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
38 CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
39 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) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +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
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000073 Assembler assm(Isolate::Current(), NULL, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000074
75 __ nop(); // supported on all architectures
76
77 CodeDesc desc;
78 assm.GetCode(&desc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000079 Object* code = HEAP->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +000080 desc,
81 Code::ComputeFlags(Code::STUB),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000082 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) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000089 Object* found = HEAP->FindCodeObject(obj_addr + i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000090 CHECK_EQ(code, found);
91 }
92
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000093 Object* copy = HEAP->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +000094 desc,
95 Code::ComputeFlags(Code::STUB),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000096 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);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000099 Object* not_right = HEAP->FindCodeObject(obj_copy->address() +
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000100 obj_copy->Size() / 2);
101 CHECK(not_right != code);
102}
103
104
105TEST(HeapObjects) {
106 InitializeVM();
107
108 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +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
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +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
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +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
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +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
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +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.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +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 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 HEAP->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 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
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000151 CHECK(HEAP->nan_value()->IsNumber());
152 CHECK(isnan(HEAP->nan_value()->Number()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000153
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000154 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000155 CHECK(s->IsString());
156 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000157
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000158 String* object_symbol = String::cast(HEAP->Object_symbol());
159 CHECK(
160 Isolate::Current()->context()->global()->HasLocalProperty(object_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000161
162 // Check ToString for oddballs
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000163 CheckOddball(HEAP->true_value(), "true");
164 CheckOddball(HEAP->false_value(), "false");
165 CheckOddball(HEAP->null_value(), "null");
166 CheckOddball(HEAP->undefined_value(), "undefined");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000167
168 // Check ToString for Smis
169 CheckSmi(0, "0");
170 CheckSmi(42, "42");
171 CheckSmi(-42, "-42");
172
173 // Check ToString for Numbers
174 CheckNumber(1.1, "1.1");
175
176 CheckFindCodeObject();
177}
178
179
180TEST(Tagging) {
181 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000182 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000183 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000184 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000185 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000186 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000187 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000188 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000189 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000190 CHECK(Failure::Exception()->IsFailure());
191 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
192 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
193}
194
195
196TEST(GarbageCollection) {
197 InitializeVM();
198
199 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000200 // Check GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000201 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000203 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
204 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
205 Handle<String> prop_namex = FACTORY->LookupAsciiSymbol("theSlotx");
206 Handle<String> obj_name = FACTORY->LookupAsciiSymbol("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000207
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000208 {
209 v8::HandleScope inner_scope;
210 // Allocate a function and keep it in global object's property.
211 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000212 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000213 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000214 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000215 function->set_initial_map(*initial_map);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000216 Isolate::Current()->context()->global()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000217 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000218 // Allocate an object. Unrooted after leaving the scope.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000219 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000220 obj->SetProperty(
221 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
222 obj->SetProperty(
223 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000224
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000225 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
226 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
227 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000230
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000231 // Function should be alive.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000232 CHECK(Isolate::Current()->context()->global()->HasLocalProperty(*name));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000233 // Check function is retained.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000234 Object* func_value = Isolate::Current()->context()->global()->
235 GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000236 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000237 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000238
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000239 {
240 HandleScope inner_scope;
241 // Allocate another object, make it reachable from global.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000242 Handle<JSObject> obj = FACTORY->NewJSObject(function);
243 Isolate::Current()->context()->global()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000244 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
245 obj->SetProperty(
246 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000247 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000248
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000249 // After gc, it should survive.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000250 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000251
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000252 CHECK(Isolate::Current()->context()->global()->HasLocalProperty(*obj_name));
253 CHECK(Isolate::Current()->context()->global()->
254 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
255 Object* obj = Isolate::Current()->context()->global()->
256 GetProperty(*obj_name)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000257 JSObject* js_obj = JSObject::cast(obj);
258 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000259}
260
261
262static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000263 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000264 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000265 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000266 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000267 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
268 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000269}
270
271
272TEST(String) {
273 InitializeVM();
274
275 VerifyStringAllocation("a");
276 VerifyStringAllocation("ab");
277 VerifyStringAllocation("abc");
278 VerifyStringAllocation("abcd");
279 VerifyStringAllocation("fiskerdrengen er paa havet");
280}
281
282
283TEST(LocalHandles) {
284 InitializeVM();
285
286 v8::HandleScope scope;
287 const char* name = "Kasper the spunky";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000288 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000289 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000290}
291
292
293TEST(GlobalHandles) {
294 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000295 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000296
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000297 Handle<Object> h1;
298 Handle<Object> h2;
299 Handle<Object> h3;
300 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000301
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000302 {
303 HandleScope scope;
304
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000305 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
306 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000307
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000308 h1 = global_handles->Create(*i);
309 h2 = global_handles->Create(*u);
310 h3 = global_handles->Create(*i);
311 h4 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000312 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000313
314 // after gc, it should survive
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000316
317 CHECK((*h1)->IsString());
318 CHECK((*h2)->IsHeapNumber());
319 CHECK((*h3)->IsString());
320 CHECK((*h4)->IsHeapNumber());
321
322 CHECK_EQ(*h3, *h1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000323 global_handles->Destroy(h1.location());
324 global_handles->Destroy(h3.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000325
326 CHECK_EQ(*h4, *h2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000327 global_handles->Destroy(h2.location());
328 global_handles->Destroy(h4.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000329}
330
331
332static bool WeakPointerCleared = false;
333
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000334static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000335 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000336 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000337 handle.Dispose();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000338}
339
340
341TEST(WeakGlobalHandlesScavenge) {
342 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000343 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000344
345 WeakPointerCleared = false;
346
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000347 Handle<Object> h1;
348 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000349
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000350 {
351 HandleScope scope;
352
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000353 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
354 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000356 h1 = global_handles->Create(*i);
357 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000358 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 global_handles->MakeWeak(h2.location(),
361 reinterpret_cast<void*>(1234),
362 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000363
364 // Scavenge treats weak pointers as normal roots.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000365 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000366
367 CHECK((*h1)->IsString());
368 CHECK((*h2)->IsHeapNumber());
369
370 CHECK(!WeakPointerCleared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000371 CHECK(!global_handles->IsNearDeath(h2.location()));
372 CHECK(!global_handles->IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000373
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000374 global_handles->Destroy(h1.location());
375 global_handles->Destroy(h2.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000376}
377
378
379TEST(WeakGlobalHandlesMark) {
380 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000381 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000382
383 WeakPointerCleared = false;
384
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000385 Handle<Object> h1;
386 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000387
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000388 {
389 HandleScope scope;
390
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000391 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
392 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000393
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000394 h1 = global_handles->Create(*i);
395 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000396 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000397
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000398 HEAP->CollectGarbage(OLD_POINTER_SPACE);
399 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000400 // Make sure the object is promoted.
401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000402 global_handles->MakeWeak(h2.location(),
403 reinterpret_cast<void*>(1234),
404 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000405 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
406 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000408 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000409
410 CHECK((*h1)->IsString());
411
412 CHECK(WeakPointerCleared);
413 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 global_handles->Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000416}
417
418TEST(DeleteWeakGlobalHandle) {
419 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000420 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000421
422 WeakPointerCleared = false;
423
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000424 Handle<Object> h;
425
426 {
427 HandleScope scope;
428
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000429 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
430 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000431 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433 global_handles->MakeWeak(h.location(),
434 reinterpret_cast<void*>(1234),
435 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000436
437 // Scanvenge does not recognize weak reference.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000438 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000439
440 CHECK(!WeakPointerCleared);
441
442 // Mark-compact treats weak reference properly.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000443 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000444
445 CHECK(WeakPointerCleared);
446}
447
448static const char* not_so_random_string_table[] = {
449 "abstract",
450 "boolean",
451 "break",
452 "byte",
453 "case",
454 "catch",
455 "char",
456 "class",
457 "const",
458 "continue",
459 "debugger",
460 "default",
461 "delete",
462 "do",
463 "double",
464 "else",
465 "enum",
466 "export",
467 "extends",
468 "false",
469 "final",
470 "finally",
471 "float",
472 "for",
473 "function",
474 "goto",
475 "if",
476 "implements",
477 "import",
478 "in",
479 "instanceof",
480 "int",
481 "interface",
482 "long",
483 "native",
484 "new",
485 "null",
486 "package",
487 "private",
488 "protected",
489 "public",
490 "return",
491 "short",
492 "static",
493 "super",
494 "switch",
495 "synchronized",
496 "this",
497 "throw",
498 "throws",
499 "transient",
500 "true",
501 "try",
502 "typeof",
503 "var",
504 "void",
505 "volatile",
506 "while",
507 "with",
508 0
509};
510
511
512static void CheckSymbols(const char** strings) {
513 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000514 Object* a;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000515 MaybeObject* maybe_a = HEAP->LookupAsciiSymbol(string);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000516 // LookupAsciiSymbol may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000517 if (!maybe_a->ToObject(&a)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000518 CHECK(a->IsSymbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000519 Object* b;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000520 MaybeObject* maybe_b = HEAP->LookupAsciiSymbol(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000521 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000522 CHECK_EQ(b, a);
523 CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
524 }
525}
526
527
528TEST(SymbolTable) {
529 InitializeVM();
530
531 CheckSymbols(not_so_random_string_table);
532 CheckSymbols(not_so_random_string_table);
533}
534
535
536TEST(FunctionAllocation) {
537 InitializeVM();
538
539 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000541 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000542 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000543 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000545 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000546
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000547 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
548 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000549 obj->SetProperty(
550 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000551 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000552 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000553 function->SetProperty(
554 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000555 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000556}
557
558
559TEST(ObjectProperties) {
560 InitializeVM();
561
562 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 String* object_symbol = String::cast(HEAP->Object_symbol());
564 Object* raw_object = Isolate::Current()->context()->global()->
565 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000566 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000567 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
569 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
570 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000571
572 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000573 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000574
575 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000576 obj->SetProperty(
577 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000578 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000579
580 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000581 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
582 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000583
584 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000585 obj->SetProperty(
586 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
587 obj->SetProperty(
588 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000589 CHECK(obj->HasLocalProperty(*first));
590 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000591
592 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000593 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
594 CHECK(obj->HasLocalProperty(*second));
595 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
596 CHECK(!obj->HasLocalProperty(*first));
597 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000598
599 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000600 obj->SetProperty(
601 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
602 obj->SetProperty(
603 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000604 CHECK(obj->HasLocalProperty(*first));
605 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000606
607 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000608 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
609 CHECK(obj->HasLocalProperty(*first));
610 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
611 CHECK(!obj->HasLocalProperty(*first));
612 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000613
614 // check string and symbol match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000615 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000616 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000617 obj->SetProperty(
618 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 Handle<String> s1_symbol = FACTORY->LookupAsciiSymbol(string1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000620 CHECK(obj->HasLocalProperty(*s1_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000621
622 // check symbol and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000623 const char* string2 = "fugl";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000624 Handle<String> s2_symbol = FACTORY->LookupAsciiSymbol(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000625 obj->SetProperty(
626 *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000628 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000629}
630
631
632TEST(JSObjectMaps) {
633 InitializeVM();
634
635 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000636 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000637 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000639 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000641 function->set_initial_map(*initial_map);
642
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000643 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
644 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000645
646 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000647 obj->SetProperty(
648 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000649 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000650
651 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000652 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000653}
654
655
656TEST(JSArray) {
657 InitializeVM();
658
659 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 Handle<String> name = FACTORY->LookupAsciiSymbol("Array");
661 Object* raw_object = Isolate::Current()->context()->global()->
662 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000663 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000664 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000665
666 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000667 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000668 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000669 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000670 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000671
672 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000673 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000674 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000675 // Must be in fast mode.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000676 CHECK(array->HasFastSmiOrObjectElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000677
678 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000679 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000680 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000681 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000682
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000683 // Set array length with larger than smi value.
684 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000685 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000686 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000687
688 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000689 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000690 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000691 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000692
693 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000694 array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000695 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000696 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000697 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000698 CHECK_EQ(array->GetElement(int_length), *name);
699 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000700}
701
702
703TEST(JSObjectCopy) {
704 InitializeVM();
705
706 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000707 String* object_symbol = String::cast(HEAP->Object_symbol());
708 Object* raw_object = Isolate::Current()->context()->global()->
709 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000710 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000711 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000712 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
713 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
714 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000715
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000716 obj->SetProperty(
717 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
718 obj->SetProperty(
719 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000720
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000721 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
722 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000723
724 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000725 Handle<JSObject> clone = Copy(obj);
726 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000727
728 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
729 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
730
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000731 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
732 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000733
734 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000735 clone->SetProperty(
736 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
737 clone->SetProperty(
738 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000739
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000740 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
741 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000742
743 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
744 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
745
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000746 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
747 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000748}
749
750
751TEST(StringAllocation) {
752 InitializeVM();
753
754
755 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
756 for (int length = 0; length < 100; length++) {
757 v8::HandleScope scope;
758 char* non_ascii = NewArray<char>(3 * length + 1);
759 char* ascii = NewArray<char>(length + 1);
760 non_ascii[3 * length] = 0;
761 ascii[length] = 0;
762 for (int i = 0; i < length; i++) {
763 ascii[i] = 'a';
764 non_ascii[3 * i] = chars[0];
765 non_ascii[3 * i + 1] = chars[1];
766 non_ascii[3 * i + 2] = chars[2];
767 }
768 Handle<String> non_ascii_sym =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000769 FACTORY->LookupSymbol(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000770 CHECK_EQ(length, non_ascii_sym->length());
771 Handle<String> ascii_sym =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000772 FACTORY->LookupSymbol(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000773 CHECK_EQ(length, ascii_sym->length());
774 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000775 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000776 non_ascii_str->Hash();
777 CHECK_EQ(length, non_ascii_str->length());
778 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000779 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000780 ascii_str->Hash();
781 CHECK_EQ(length, ascii_str->length());
782 DeleteArray(non_ascii);
783 DeleteArray(ascii);
784 }
785}
786
787
788static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
789 // Count the number of objects found in the heap.
790 int found_count = 0;
791 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000792 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000793 for (int i = 0; i < size; i++) {
794 if (*objs[i] == obj) {
795 found_count++;
796 }
797 }
798 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000799 return found_count;
800}
801
802
803TEST(Iteration) {
804 InitializeVM();
805 v8::HandleScope scope;
806
807 // Array of objects to scan haep for.
808 const int objs_count = 6;
809 Handle<Object> objs[objs_count];
810 int next_objs_index = 0;
811
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000812 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000813 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000814 objs[next_objs_index++] = FACTORY->NewJSArray(10,
815 FAST_HOLEY_ELEMENTS,
816 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000817
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000818 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000819 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000820 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000821 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000822 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000823
824 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000825 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000826 char* str = new char[large_size];
827 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
828 str[large_size - 1] = '\0';
829 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000830 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000831 delete[] str;
832
833 // Add a Map object to look for.
834 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
835
836 CHECK_EQ(objs_count, next_objs_index);
837 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
838}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000839
840
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000841TEST(EmptyHandleEscapeFrom) {
842 InitializeVM();
843
844 v8::HandleScope scope;
845 Handle<JSObject> runaway;
846
847 {
848 v8::HandleScope nested;
849 Handle<JSObject> empty;
850 runaway = empty.EscapeFrom(&nested);
851 }
852
853 CHECK(runaway.is_null());
854}
855
856
857static int LenFromSize(int size) {
858 return (size - FixedArray::kHeaderSize) / kPointerSize;
859}
860
861
862TEST(Regression39128) {
863 // Test case for crbug.com/39128.
864 InitializeVM();
865
866 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000867 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000868
869 v8::HandleScope scope;
870
871 // The plan: create JSObject which references objects in new space.
872 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000873 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000874
875 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000876 Handle<JSFunction> object_ctor(
877 Isolate::Current()->global_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000878 CHECK(object_ctor->has_initial_map());
879 Handle<Map> object_map(object_ctor->initial_map());
880 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000881 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000882 int n_properties = my_map->inobject_properties();
883 CHECK_GT(n_properties, 0);
884
885 int object_size = my_map->instance_size();
886
887 // Step 2: allocate a lot of objects so to almost fill new space: we need
888 // just enough room to allocate JSObject and thus fill the newspace.
889
890 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000891 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000892 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000893 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000894 Address* top_addr = new_space->allocation_top_address();
895 Address* limit_addr = new_space->allocation_limit_address();
896 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000897 CHECK(!HEAP->always_allocate());
898 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
899 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000900 CHECK(new_space->Contains(array));
901 }
902
903 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000904 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000905 int fixed_array_len = LenFromSize(to_fill);
906 CHECK(fixed_array_len < FixedArray::kMaxLength);
907
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000908 CHECK(!HEAP->always_allocate());
909 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
910 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000911 CHECK(new_space->Contains(array));
912
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000913 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000914 CHECK(new_space->Contains(object));
915 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000916 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000917 CHECK_EQ(0, jsobject->properties()->length());
918 // Create a reference to object in new space in jsobject.
919 jsobject->FastPropertyAtPut(-1, array);
920
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000921 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000922
923 // Step 4: clone jsobject, but force always allocate first to create a clone
924 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000926 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000927 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000928 JSObject* clone = JSObject::cast(clone_obj);
929 if (clone->address() != old_pointer_space_top) {
930 // Alas, got allocated from free list, we cannot do checks.
931 return;
932 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000933 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000934}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000935
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000936
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000937TEST(TestCodeFlushing) {
938 i::FLAG_allow_natives_syntax = true;
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000939 // If we do not flush code this test is invalid.
940 if (!FLAG_flush_code) return;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000941 InitializeVM();
942 v8::HandleScope scope;
943 const char* source = "function foo() {"
944 " var x = 42;"
945 " var y = 42;"
946 " var z = x + y;"
947 "};"
948 "foo()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000949 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000950
951 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000952 { v8::HandleScope scope;
953 CompileRun(source);
954 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000955
956 // Check function is compiled.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000957 Object* func_value = Isolate::Current()->context()->global()->
958 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000959 CHECK(func_value->IsJSFunction());
960 Handle<JSFunction> function(JSFunction::cast(func_value));
961 CHECK(function->shared()->is_compiled());
962
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000963 // TODO(1609) Currently incremental marker does not support code flushing.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000964 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
965 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000966
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000967 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000968
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000969 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
970 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
971 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
972 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
973 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
974 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000975
976 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000977 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
978 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000979 // Call foo to get it recompiled.
980 CompileRun("foo()");
981 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000982 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000983}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000984
985
986// Count the number of global contexts in the weak list of global contexts.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000987int CountGlobalContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000988 int count = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000989 Object* object = HEAP->global_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000990 while (!object->IsUndefined()) {
991 count++;
992 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
993 }
994 return count;
995}
996
997
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000998// Count the number of user functions in the weak list of optimized
999// functions attached to a global context.
1000static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1001 int count = 0;
1002 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1003 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1004 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1005 count++;
1006 object = JSFunction::cast(object)->next_function_link();
1007 }
1008 return count;
1009}
1010
1011
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001012TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001013 v8::V8::Initialize();
1014
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001015 static const int kNumTestContexts = 10;
1016
1017 v8::HandleScope scope;
1018 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1019
1020 CHECK_EQ(0, CountGlobalContexts());
1021
1022 // Create a number of global contests which gets linked together.
1023 for (int i = 0; i < kNumTestContexts; i++) {
1024 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001025
1026 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1027
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001028 CHECK_EQ(i + 1, CountGlobalContexts());
1029
1030 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001031
1032 // Create a handle scope so no function objects get stuch in the outer
1033 // handle scope
1034 v8::HandleScope scope;
1035 const char* source = "function f1() { };"
1036 "function f2() { };"
1037 "function f3() { };"
1038 "function f4() { };"
1039 "function f5() { };";
1040 CompileRun(source);
1041 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1042 CompileRun("f1()");
1043 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1044 CompileRun("f2()");
1045 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1046 CompileRun("f3()");
1047 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1048 CompileRun("f4()");
1049 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1050 CompileRun("f5()");
1051 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1052
1053 // Remove function f1, and
1054 CompileRun("f1=null");
1055
1056 // Scavenge treats these references as strong.
1057 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001058 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001059 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1060 }
1061
1062 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001063 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001064 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1065
1066 // Get rid of f3 and f5 in the same way.
1067 CompileRun("f3=null");
1068 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001069 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001070 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1071 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001072 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001073 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1074 CompileRun("f5=null");
1075 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001077 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1078 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001079 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001080 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1081
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001082 ctx[i]->Exit();
1083 }
1084
1085 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001086 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001087
1088 // Dispose the global contexts one by one.
1089 for (int i = 0; i < kNumTestContexts; i++) {
1090 ctx[i].Dispose();
1091 ctx[i].Clear();
1092
1093 // Scavenge treats these references as strong.
1094 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001095 HEAP->PerformScavenge();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001096 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts());
1097 }
1098
1099 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001100 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001101 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts());
1102 }
1103
1104 CHECK_EQ(0, CountGlobalContexts());
1105}
1106
1107
1108// Count the number of global contexts in the weak list of global contexts
1109// causing a GC after the specified number of elements.
1110static int CountGlobalContextsWithGC(int n) {
1111 int count = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001112 Handle<Object> object(HEAP->global_contexts_list());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001113 while (!object->IsUndefined()) {
1114 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001115 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001116 object =
1117 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1118 }
1119 return count;
1120}
1121
1122
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001123// Count the number of user functions in the weak list of optimized
1124// functions attached to a global context causing a GC after the
1125// specified number of elements.
1126static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1127 int n) {
1128 int count = 0;
1129 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1130 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1131 while (object->IsJSFunction() &&
1132 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1133 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001134 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001135 object = Handle<Object>(
1136 Object::cast(JSFunction::cast(*object)->next_function_link()));
1137 }
1138 return count;
1139}
1140
1141
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001142TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001143 v8::V8::Initialize();
1144
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001145 static const int kNumTestContexts = 10;
1146
1147 v8::HandleScope scope;
1148 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1149
1150 CHECK_EQ(0, CountGlobalContexts());
1151
1152 // Create an number of contexts and check the length of the weak list both
1153 // with and without GCs while iterating the list.
1154 for (int i = 0; i < kNumTestContexts; i++) {
1155 ctx[i] = v8::Context::New();
1156 CHECK_EQ(i + 1, CountGlobalContexts());
1157 CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001158 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001159
1160 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1161
1162 // Compile a number of functions the length of the weak list of optimized
1163 // functions both with and without GCs while iterating the list.
1164 ctx[0]->Enter();
1165 const char* source = "function f1() { };"
1166 "function f2() { };"
1167 "function f3() { };"
1168 "function f4() { };"
1169 "function f5() { };";
1170 CompileRun(source);
1171 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1172 CompileRun("f1()");
1173 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1174 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1175 CompileRun("f2()");
1176 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1177 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1178 CompileRun("f3()");
1179 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1180 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1181 CompileRun("f4()");
1182 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1183 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1184 CompileRun("f5()");
1185 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1186 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1187
1188 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001189}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001190
1191
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001192TEST(TestSizeOfObjects) {
1193 v8::V8::Initialize();
1194
1195 // Get initial heap size after several full GCs, which will stabilize
1196 // the heap size and return with sweeping finished completely.
1197 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1198 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1199 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1200 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001201 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001202 CHECK(HEAP->old_pointer_space()->IsSweepingComplete());
1203 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1204
1205 {
1206 // Allocate objects on several different old-space pages so that
1207 // lazy sweeping kicks in for subsequent GC runs.
1208 AlwaysAllocateScope always_allocate;
1209 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1210 for (int i = 1; i <= 100; i++) {
1211 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1212 CHECK_EQ(initial_size + i * filler_size,
1213 static_cast<int>(HEAP->SizeOfObjects()));
1214 }
1215 }
1216
1217 // The heap size should go back to initial size after a full GC, even
1218 // though sweeping didn't finish yet.
1219 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001220
1221 // Normally sweeping would not be complete here, but no guarantees.
1222
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001223 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1224
1225 // Advancing the sweeper step-wise should not change the heap size.
1226 while (!HEAP->old_pointer_space()->IsSweepingComplete()) {
1227 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1228 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1229 }
1230}
1231
1232
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001233TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1234 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001235 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001236 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001237 HeapIterator iterator;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001238 intptr_t size_of_objects_2 = 0;
1239 for (HeapObject* obj = iterator.next();
1240 obj != NULL;
1241 obj = iterator.next()) {
1242 size_of_objects_2 += obj->Size();
1243 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001244 // Delta must be within 5% of the larger result.
1245 // TODO(gc): Tighten this up by distinguishing between byte
1246 // arrays that are real and those that merely mark free space
1247 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001248 if (size_of_objects_1 > size_of_objects_2) {
1249 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1250 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1251 "Iterator: %" V8_PTR_PREFIX "d, "
1252 "delta: %" V8_PTR_PREFIX "d\n",
1253 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001254 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001255 } else {
1256 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1257 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1258 "Iterator: %" V8_PTR_PREFIX "d, "
1259 "delta: %" V8_PTR_PREFIX "d\n",
1260 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001261 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001262 }
1263}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001264
1265
danno@chromium.orgc612e022011-11-10 11:38:15 +00001266static void FillUpNewSpace(NewSpace* new_space) {
1267 // Fill up new space to the point that it is completely full. Make sure
1268 // that the scavenger does not undo the filling.
1269 v8::HandleScope scope;
1270 AlwaysAllocateScope always_allocate;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001271 LinearAllocationScope allocate_linearly;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001272 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001273 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001274 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001275 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001276 }
1277}
1278
1279
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001280TEST(GrowAndShrinkNewSpace) {
1281 InitializeVM();
1282 NewSpace* new_space = HEAP->new_space();
1283
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001284 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
1285 // The max size cannot exceed the reserved size, since semispaces must be
1286 // always within the reserved space. We can't test new space growing and
1287 // shrinking if the reserved size is the same as the minimum (initial) size.
1288 return;
1289 }
1290
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001291 // Explicitly growing should double the space capacity.
1292 intptr_t old_capacity, new_capacity;
1293 old_capacity = new_space->Capacity();
1294 new_space->Grow();
1295 new_capacity = new_space->Capacity();
1296 CHECK(2 * old_capacity == new_capacity);
1297
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001298 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001299 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 new_capacity = new_space->Capacity();
1301 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001302
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001303 // Explicitly shrinking should not affect space capacity.
1304 old_capacity = new_space->Capacity();
1305 new_space->Shrink();
1306 new_capacity = new_space->Capacity();
1307 CHECK(old_capacity == new_capacity);
1308
1309 // Let the scavenger empty the new space.
1310 HEAP->CollectGarbage(NEW_SPACE);
1311 CHECK_LE(new_space->Size(), old_capacity);
1312
1313 // Explicitly shrinking should halve the space capacity.
1314 old_capacity = new_space->Capacity();
1315 new_space->Shrink();
1316 new_capacity = new_space->Capacity();
1317 CHECK(old_capacity == 2 * new_capacity);
1318
1319 // Consecutive shrinking should not affect space capacity.
1320 old_capacity = new_space->Capacity();
1321 new_space->Shrink();
1322 new_space->Shrink();
1323 new_space->Shrink();
1324 new_capacity = new_space->Capacity();
1325 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001326}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001327
1328
1329TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1330 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001331
1332 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
1333 // The max size cannot exceed the reserved size, since semispaces must be
1334 // always within the reserved space. We can't test new space growing and
1335 // shrinking if the reserved size is the same as the minimum (initial) size.
1336 return;
1337 }
1338
danno@chromium.orgc612e022011-11-10 11:38:15 +00001339 v8::HandleScope scope;
1340 NewSpace* new_space = HEAP->new_space();
1341 intptr_t old_capacity, new_capacity;
1342 old_capacity = new_space->Capacity();
1343 new_space->Grow();
1344 new_capacity = new_space->Capacity();
1345 CHECK(2 * old_capacity == new_capacity);
1346 FillUpNewSpace(new_space);
1347 HEAP->CollectAllAvailableGarbage();
1348 new_capacity = new_space->Capacity();
1349 CHECK(old_capacity == new_capacity);
1350}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001351
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001352
1353static int NumberOfGlobalObjects() {
1354 int count = 0;
1355 HeapIterator iterator;
1356 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1357 if (obj->IsGlobalObject()) count++;
1358 }
1359 return count;
1360}
1361
1362
1363// Test that we don't embed maps from foreign contexts into
1364// optimized code.
1365TEST(LeakGlobalContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001366 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001367 v8::HandleScope outer_scope;
1368 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1369 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1370 ctx1->Enter();
1371
1372 HEAP->CollectAllAvailableGarbage();
1373 CHECK_EQ(4, NumberOfGlobalObjects());
1374
1375 {
1376 v8::HandleScope inner_scope;
1377 CompileRun("var v = {x: 42}");
1378 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1379 ctx2->Enter();
1380 ctx2->Global()->Set(v8_str("o"), v);
1381 v8::Local<v8::Value> res = CompileRun(
1382 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001383 "for (var i = 0; i < 10; ++i) f();"
1384 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001385 "f();");
1386 CHECK_EQ(42, res->Int32Value());
1387 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1388 ctx2->Exit();
1389 ctx1->Exit();
1390 ctx1.Dispose();
1391 }
1392 HEAP->CollectAllAvailableGarbage();
1393 CHECK_EQ(2, NumberOfGlobalObjects());
1394 ctx2.Dispose();
1395 HEAP->CollectAllAvailableGarbage();
1396 CHECK_EQ(0, NumberOfGlobalObjects());
1397}
1398
1399
1400// Test that we don't embed functions from foreign contexts into
1401// optimized code.
1402TEST(LeakGlobalContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001403 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001404 v8::HandleScope outer_scope;
1405 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1406 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1407 ctx1->Enter();
1408
1409 HEAP->CollectAllAvailableGarbage();
1410 CHECK_EQ(4, NumberOfGlobalObjects());
1411
1412 {
1413 v8::HandleScope inner_scope;
1414 CompileRun("var v = function() { return 42; }");
1415 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1416 ctx2->Enter();
1417 ctx2->Global()->Set(v8_str("o"), v);
1418 v8::Local<v8::Value> res = CompileRun(
1419 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001420 "for (var i = 0; i < 10; ++i) f(o);"
1421 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001422 "f(o);");
1423 CHECK_EQ(42, res->Int32Value());
1424 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1425 ctx2->Exit();
1426 ctx1->Exit();
1427 ctx1.Dispose();
1428 }
1429 HEAP->CollectAllAvailableGarbage();
1430 CHECK_EQ(2, NumberOfGlobalObjects());
1431 ctx2.Dispose();
1432 HEAP->CollectAllAvailableGarbage();
1433 CHECK_EQ(0, NumberOfGlobalObjects());
1434}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001435
1436
1437TEST(LeakGlobalContextViaMapKeyed) {
1438 i::FLAG_allow_natives_syntax = true;
1439 v8::HandleScope outer_scope;
1440 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1441 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1442 ctx1->Enter();
1443
1444 HEAP->CollectAllAvailableGarbage();
1445 CHECK_EQ(4, NumberOfGlobalObjects());
1446
1447 {
1448 v8::HandleScope inner_scope;
1449 CompileRun("var v = [42, 43]");
1450 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1451 ctx2->Enter();
1452 ctx2->Global()->Set(v8_str("o"), v);
1453 v8::Local<v8::Value> res = CompileRun(
1454 "function f() { return o[0]; }"
1455 "for (var i = 0; i < 10; ++i) f();"
1456 "%OptimizeFunctionOnNextCall(f);"
1457 "f();");
1458 CHECK_EQ(42, res->Int32Value());
1459 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1460 ctx2->Exit();
1461 ctx1->Exit();
1462 ctx1.Dispose();
1463 }
1464 HEAP->CollectAllAvailableGarbage();
1465 CHECK_EQ(2, NumberOfGlobalObjects());
1466 ctx2.Dispose();
1467 HEAP->CollectAllAvailableGarbage();
1468 CHECK_EQ(0, NumberOfGlobalObjects());
1469}
1470
1471
1472TEST(LeakGlobalContextViaMapProto) {
1473 i::FLAG_allow_natives_syntax = true;
1474 v8::HandleScope outer_scope;
1475 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1476 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1477 ctx1->Enter();
1478
1479 HEAP->CollectAllAvailableGarbage();
1480 CHECK_EQ(4, NumberOfGlobalObjects());
1481
1482 {
1483 v8::HandleScope inner_scope;
1484 CompileRun("var v = { y: 42}");
1485 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1486 ctx2->Enter();
1487 ctx2->Global()->Set(v8_str("o"), v);
1488 v8::Local<v8::Value> res = CompileRun(
1489 "function f() {"
1490 " var p = {x: 42};"
1491 " p.__proto__ = o;"
1492 " return p.x;"
1493 "}"
1494 "for (var i = 0; i < 10; ++i) f();"
1495 "%OptimizeFunctionOnNextCall(f);"
1496 "f();");
1497 CHECK_EQ(42, res->Int32Value());
1498 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1499 ctx2->Exit();
1500 ctx1->Exit();
1501 ctx1.Dispose();
1502 }
1503 HEAP->CollectAllAvailableGarbage();
1504 CHECK_EQ(2, NumberOfGlobalObjects());
1505 ctx2.Dispose();
1506 HEAP->CollectAllAvailableGarbage();
1507 CHECK_EQ(0, NumberOfGlobalObjects());
1508}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001509
1510
1511TEST(InstanceOfStubWriteBarrier) {
1512 i::FLAG_allow_natives_syntax = true;
1513#ifdef DEBUG
1514 i::FLAG_verify_heap = true;
1515#endif
1516 InitializeVM();
1517 if (!i::V8::UseCrankshaft()) return;
1518 v8::HandleScope outer_scope;
1519
1520 {
1521 v8::HandleScope scope;
1522 CompileRun(
1523 "function foo () { }"
1524 "function mkbar () { return new (new Function(\"\")) (); }"
1525 "function f (x) { return (x instanceof foo); }"
1526 "function g () { f(mkbar()); }"
1527 "f(new foo()); f(new foo());"
1528 "%OptimizeFunctionOnNextCall(f);"
1529 "f(new foo()); g();");
1530 }
1531
1532 IncrementalMarking* marking = HEAP->incremental_marking();
1533 marking->Abort();
1534 marking->Start();
1535
1536 Handle<JSFunction> f =
1537 v8::Utils::OpenHandle(
1538 *v8::Handle<v8::Function>::Cast(
1539 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1540
1541 CHECK(f->IsOptimized());
1542
1543 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1544 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001545 // Discard any pending GC requests otherwise we will get GC when we enter
1546 // code below.
1547 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001548 }
1549
1550 CHECK(marking->IsMarking());
1551
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001552 {
1553 v8::HandleScope scope;
1554 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1555 v8::Handle<v8::Function> g =
1556 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1557 g->Call(global, 0, NULL);
1558 }
1559
1560 HEAP->incremental_marking()->set_should_hurry(true);
1561 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1562}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001563
1564
1565TEST(PrototypeTransitionClearing) {
1566 InitializeVM();
1567 v8::HandleScope scope;
1568
1569 CompileRun(
1570 "var base = {};"
1571 "var live = [];"
1572 "for (var i = 0; i < 10; i++) {"
1573 " var object = {};"
1574 " var prototype = {};"
1575 " object.__proto__ = prototype;"
1576 " if (i >= 3) live.push(object, prototype);"
1577 "}");
1578
1579 Handle<JSObject> baseObject =
1580 v8::Utils::OpenHandle(
1581 *v8::Handle<v8::Object>::Cast(
1582 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1583
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001584 // Verify that only dead prototype transitions are cleared.
1585 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001586 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001587 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001588 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001589
1590 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001591 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001592 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001593 int j = Map::kProtoTransitionHeaderSize +
1594 i * Map::kProtoTransitionElementsPerEntry;
1595 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001596 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1597 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001598 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001599
1600 // Make sure next prototype is placed on an old-space evacuation candidate.
1601 Handle<JSObject> prototype;
1602 PagedSpace* space = HEAP->old_pointer_space();
1603 do {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001604 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001605 } while (space->FirstPage() == space->LastPage() ||
1606 !space->LastPage()->Contains(prototype->address()));
1607
1608 // Add a prototype on an evacuation candidate and verify that transition
1609 // clearing correctly records slots in prototype transition array.
1610 i::FLAG_always_compact = true;
1611 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001612 CHECK(!space->LastPage()->Contains(
1613 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001614 CHECK(space->LastPage()->Contains(prototype->address()));
1615 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1616 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1617 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1618 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001619}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001620
1621
1622TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1623 i::FLAG_allow_natives_syntax = true;
1624#ifdef DEBUG
1625 i::FLAG_verify_heap = true;
1626#endif
1627 InitializeVM();
1628 if (!i::V8::UseCrankshaft()) return;
1629 v8::HandleScope outer_scope;
1630
1631 {
1632 v8::HandleScope scope;
1633 CompileRun(
1634 "function f () {"
1635 " var s = 0;"
1636 " for (var i = 0; i < 100; i++) s += i;"
1637 " return s;"
1638 "}"
1639 "f(); f();"
1640 "%OptimizeFunctionOnNextCall(f);"
1641 "f();");
1642 }
1643 Handle<JSFunction> f =
1644 v8::Utils::OpenHandle(
1645 *v8::Handle<v8::Function>::Cast(
1646 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1647 CHECK(f->IsOptimized());
1648
1649 IncrementalMarking* marking = HEAP->incremental_marking();
1650 marking->Abort();
1651 marking->Start();
1652
1653 // The following two calls will increment HEAP->global_ic_age().
1654 const int kLongIdlePauseInMs = 1000;
1655 v8::V8::ContextDisposedNotification();
1656 v8::V8::IdleNotification(kLongIdlePauseInMs);
1657
1658 while (!marking->IsStopped() && !marking->IsComplete()) {
1659 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1660 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001661 if (!marking->IsStopped() || marking->should_hurry()) {
1662 // We don't normally finish a GC via Step(), we normally finish by
1663 // setting the stack guard and then do the final steps in the stack
1664 // guard interrupt. But here we didn't ask for that, and there is no
1665 // JS code running to trigger the interrupt, so we explicitly finalize
1666 // here.
1667 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1668 "Test finalizing incremental mark-sweep");
1669 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001670
1671 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1672 CHECK_EQ(0, f->shared()->opt_count());
1673 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1674}
1675
1676
1677TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1678 i::FLAG_allow_natives_syntax = true;
1679#ifdef DEBUG
1680 i::FLAG_verify_heap = true;
1681#endif
1682 InitializeVM();
1683 if (!i::V8::UseCrankshaft()) return;
1684 v8::HandleScope outer_scope;
1685
1686 {
1687 v8::HandleScope scope;
1688 CompileRun(
1689 "function f () {"
1690 " var s = 0;"
1691 " for (var i = 0; i < 100; i++) s += i;"
1692 " return s;"
1693 "}"
1694 "f(); f();"
1695 "%OptimizeFunctionOnNextCall(f);"
1696 "f();");
1697 }
1698 Handle<JSFunction> f =
1699 v8::Utils::OpenHandle(
1700 *v8::Handle<v8::Function>::Cast(
1701 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1702 CHECK(f->IsOptimized());
1703
1704 HEAP->incremental_marking()->Abort();
1705
1706 // The following two calls will increment HEAP->global_ic_age().
1707 // Since incremental marking is off, IdleNotification will do full GC.
1708 const int kLongIdlePauseInMs = 1000;
1709 v8::V8::ContextDisposedNotification();
1710 v8::V8::IdleNotification(kLongIdlePauseInMs);
1711
1712 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1713 CHECK_EQ(0, f->shared()->opt_count());
1714 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1715}
1716
1717
1718// Test that HAllocateObject will always return an object in new-space.
1719TEST(OptimizedAllocationAlwaysInNewSpace) {
1720 i::FLAG_allow_natives_syntax = true;
1721 InitializeVM();
1722 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
1723 v8::HandleScope scope;
1724
1725 FillUpNewSpace(HEAP->new_space());
1726 AlwaysAllocateScope always_allocate;
1727 v8::Local<v8::Value> res = CompileRun(
1728 "function c(x) {"
1729 " this.x = x;"
1730 " for (var i = 0; i < 32; i++) {"
1731 " this['x' + i] = x;"
1732 " }"
1733 "}"
1734 "function f(x) { return new c(x); };"
1735 "f(1); f(2); f(3);"
1736 "%OptimizeFunctionOnNextCall(f);"
1737 "f(4);");
1738 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
1739
1740 Handle<JSObject> o =
1741 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
1742
1743 CHECK(HEAP->InNewSpace(*o));
1744}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001745
1746
1747static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001748 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001749}
1750
1751
1752// Test that map transitions are cleared and maps are collected with
1753// incremental marking as well.
1754TEST(Regress1465) {
1755 i::FLAG_allow_natives_syntax = true;
1756 i::FLAG_trace_incremental_marking = true;
1757 InitializeVM();
1758 v8::HandleScope scope;
1759
1760 #define TRANSITION_COUNT 256
1761 for (int i = 0; i < TRANSITION_COUNT; i++) {
1762 EmbeddedVector<char, 64> buffer;
1763 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
1764 CompileRun(buffer.start());
1765 }
1766 CompileRun("var root = new Object;");
1767 Handle<JSObject> root =
1768 v8::Utils::OpenHandle(
1769 *v8::Handle<v8::Object>::Cast(
1770 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
1771
1772 // Count number of live transitions before marking.
1773 int transitions_before = CountMapTransitions(root->map());
1774 CompileRun("%DebugPrint(root);");
1775 CHECK_EQ(TRANSITION_COUNT, transitions_before);
1776
1777 // Go through all incremental marking steps in one swoop.
1778 IncrementalMarking* marking = HEAP->incremental_marking();
1779 CHECK(marking->IsStopped());
1780 marking->Start();
1781 CHECK(marking->IsMarking());
1782 while (!marking->IsComplete()) {
1783 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1784 }
1785 CHECK(marking->IsComplete());
1786 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1787 CHECK(marking->IsStopped());
1788
1789 // Count number of live transitions after marking. Note that one transition
1790 // is left, because 'o' still holds an instance of one transition target.
1791 int transitions_after = CountMapTransitions(root->map());
1792 CompileRun("%DebugPrint(root);");
1793 CHECK_EQ(1, transitions_after);
1794}
verwaest@chromium.org37141392012-05-31 13:27:02 +00001795
1796
1797TEST(Regress2143a) {
1798 i::FLAG_collect_maps = true;
1799 i::FLAG_incremental_marking = true;
1800 InitializeVM();
1801 v8::HandleScope scope;
1802
1803 // Prepare a map transition from the root object together with a yet
1804 // untransitioned root object.
1805 CompileRun("var root = new Object;"
1806 "root.foo = 0;"
1807 "root = new Object;");
1808
1809 // Go through all incremental marking steps in one swoop.
1810 IncrementalMarking* marking = HEAP->incremental_marking();
1811 CHECK(marking->IsStopped());
1812 marking->Start();
1813 CHECK(marking->IsMarking());
1814 while (!marking->IsComplete()) {
1815 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1816 }
1817 CHECK(marking->IsComplete());
1818
1819 // Compile a StoreIC that performs the prepared map transition. This
1820 // will restart incremental marking and should make sure the root is
1821 // marked grey again.
1822 CompileRun("function f(o) {"
1823 " o.foo = 0;"
1824 "}"
1825 "f(new Object);"
1826 "f(root);");
1827
1828 // This bug only triggers with aggressive IC clearing.
1829 HEAP->AgeInlineCaches();
1830
1831 // Explicitly request GC to perform final marking step and sweeping.
1832 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1833 CHECK(marking->IsStopped());
1834
1835 Handle<JSObject> root =
1836 v8::Utils::OpenHandle(
1837 *v8::Handle<v8::Object>::Cast(
1838 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
1839
1840 // The root object should be in a sane state.
1841 CHECK(root->IsJSObject());
1842 CHECK(root->map()->IsMap());
1843}
1844
1845
1846TEST(Regress2143b) {
1847 i::FLAG_collect_maps = true;
1848 i::FLAG_incremental_marking = true;
1849 i::FLAG_allow_natives_syntax = true;
1850 InitializeVM();
1851 v8::HandleScope scope;
1852
1853 // Prepare a map transition from the root object together with a yet
1854 // untransitioned root object.
1855 CompileRun("var root = new Object;"
1856 "root.foo = 0;"
1857 "root = new Object;");
1858
1859 // Go through all incremental marking steps in one swoop.
1860 IncrementalMarking* marking = HEAP->incremental_marking();
1861 CHECK(marking->IsStopped());
1862 marking->Start();
1863 CHECK(marking->IsMarking());
1864 while (!marking->IsComplete()) {
1865 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1866 }
1867 CHECK(marking->IsComplete());
1868
1869 // Compile an optimized LStoreNamedField that performs the prepared
1870 // map transition. This will restart incremental marking and should
1871 // make sure the root is marked grey again.
1872 CompileRun("function f(o) {"
1873 " o.foo = 0;"
1874 "}"
1875 "f(new Object);"
1876 "f(new Object);"
1877 "%OptimizeFunctionOnNextCall(f);"
1878 "f(root);"
1879 "%DeoptimizeFunction(f);");
1880
1881 // This bug only triggers with aggressive IC clearing.
1882 HEAP->AgeInlineCaches();
1883
1884 // Explicitly request GC to perform final marking step and sweeping.
1885 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1886 CHECK(marking->IsStopped());
1887
1888 Handle<JSObject> root =
1889 v8::Utils::OpenHandle(
1890 *v8::Handle<v8::Object>::Cast(
1891 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
1892
1893 // The root object should be in a sane state.
1894 CHECK(root->IsJSObject());
1895 CHECK(root->map()->IsMap());
1896}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001897
1898
1899// Implemented in the test-alloc.cc test suite.
1900void SimulateFullSpace(PagedSpace* space);
1901
1902
1903TEST(ReleaseOverReservedPages) {
1904 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001905 // The optimizer can allocate stuff, messing up the test.
1906 i::FLAG_crankshaft = false;
1907 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001908 InitializeVM();
1909 v8::HandleScope scope;
1910 static const int number_of_test_pages = 20;
1911
1912 // Prepare many pages with low live-bytes count.
1913 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
1914 CHECK_EQ(1, old_pointer_space->CountTotalPages());
1915 for (int i = 0; i < number_of_test_pages; i++) {
1916 AlwaysAllocateScope always_allocate;
1917 SimulateFullSpace(old_pointer_space);
1918 FACTORY->NewFixedArray(1, TENURED);
1919 }
1920 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
1921
1922 // Triggering one GC will cause a lot of garbage to be discovered but
1923 // even spread across all allocated pages.
1924 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
1925 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
1926
1927 // Triggering subsequent GCs should cause at least half of the pages
1928 // to be released to the OS after at most two cycles.
1929 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
1930 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
1931 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
1932 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
1933
1934 // Triggering a last-resort GC should cause all pages to be released
1935 // to the OS so that other processes can seize the memory.
1936 HEAP->CollectAllAvailableGarbage("triggered really hard");
1937 CHECK_EQ(1, old_pointer_space->CountTotalPages());
1938}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001939
1940
1941TEST(Regress2237) {
1942 InitializeVM();
1943 v8::HandleScope scope;
1944 Handle<String> slice(HEAP->empty_string());
1945
1946 {
1947 // Generate a parent that lives in new-space.
1948 v8::HandleScope inner_scope;
1949 const char* c = "This text is long enough to trigger sliced strings.";
1950 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
1951 CHECK(s->IsSeqAsciiString());
1952 CHECK(HEAP->InNewSpace(*s));
1953
1954 // Generate a sliced string that is based on the above parent and
1955 // lives in old-space.
1956 FillUpNewSpace(HEAP->new_space());
1957 AlwaysAllocateScope always_allocate;
1958 Handle<String> t;
1959 // TODO(mstarzinger): Unfortunately FillUpNewSpace() still leaves
1960 // some slack, so we need to allocate a few sliced strings.
1961 for (int i = 0; i < 16; i++) {
1962 t = FACTORY->NewProperSubString(s, 5, 35);
1963 }
1964 CHECK(t->IsSlicedString());
1965 CHECK(!HEAP->InNewSpace(*t));
1966 *slice.location() = *t.location();
1967 }
1968
1969 CHECK(SlicedString::cast(*slice)->parent()->IsSeqAsciiString());
1970 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1971 CHECK(SlicedString::cast(*slice)->parent()->IsSeqAsciiString());
1972}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00001973
1974
1975#ifdef OBJECT_PRINT
1976TEST(PrintSharedFunctionInfo) {
1977 InitializeVM();
1978 v8::HandleScope scope;
1979 const char* source = "f = function() { return 987654321; }\n"
1980 "g = function() { return 123456789; }\n";
1981 CompileRun(source);
1982 Handle<JSFunction> g =
1983 v8::Utils::OpenHandle(
1984 *v8::Handle<v8::Function>::Cast(
1985 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
1986
1987 AssertNoAllocation no_alloc;
1988 g->shared()->PrintLn();
1989}
1990#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001991
1992
1993TEST(Regress2211) {
1994 InitializeVM();
1995 v8::HandleScope scope;
1996
1997 v8::Handle<v8::String> value = v8_str("val string");
1998 Smi* hash = Smi::FromInt(321);
1999 Heap* heap = Isolate::Current()->heap();
2000
2001 for (int i = 0; i < 2; i++) {
2002 // Store identity hash first and common hidden property second.
2003 v8::Handle<v8::Object> obj = v8::Object::New();
2004 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2005 CHECK(internal_obj->HasFastProperties());
2006
2007 // In the first iteration, set hidden value first and identity hash second.
2008 // In the second iteration, reverse the order.
2009 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2010 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2011 ALLOW_CREATION);
2012 CHECK(!maybe_obj->IsFailure());
2013 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2014
2015 // Check values.
2016 CHECK_EQ(hash,
2017 internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
2018 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2019
2020 // Check size.
2021 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2022 ObjectHashTable* hashtable = ObjectHashTable::cast(
2023 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2024 // HashTable header (5) and 4 initial entries (8).
2025 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2026 }
2027}