blob: 0248030fc8f269c2dfc25e56579e521086a41a5c [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
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000418
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000419TEST(DeleteWeakGlobalHandle) {
420 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000421 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000422
423 WeakPointerCleared = false;
424
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000425 Handle<Object> h;
426
427 {
428 HandleScope scope;
429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000430 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
431 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000432 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000433
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000434 global_handles->MakeWeak(h.location(),
435 reinterpret_cast<void*>(1234),
436 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000437
438 // Scanvenge does not recognize weak reference.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000439 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000440
441 CHECK(!WeakPointerCleared);
442
443 // Mark-compact treats weak reference properly.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000444 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000445
446 CHECK(WeakPointerCleared);
447}
448
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000449
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000450static const char* not_so_random_string_table[] = {
451 "abstract",
452 "boolean",
453 "break",
454 "byte",
455 "case",
456 "catch",
457 "char",
458 "class",
459 "const",
460 "continue",
461 "debugger",
462 "default",
463 "delete",
464 "do",
465 "double",
466 "else",
467 "enum",
468 "export",
469 "extends",
470 "false",
471 "final",
472 "finally",
473 "float",
474 "for",
475 "function",
476 "goto",
477 "if",
478 "implements",
479 "import",
480 "in",
481 "instanceof",
482 "int",
483 "interface",
484 "long",
485 "native",
486 "new",
487 "null",
488 "package",
489 "private",
490 "protected",
491 "public",
492 "return",
493 "short",
494 "static",
495 "super",
496 "switch",
497 "synchronized",
498 "this",
499 "throw",
500 "throws",
501 "transient",
502 "true",
503 "try",
504 "typeof",
505 "var",
506 "void",
507 "volatile",
508 "while",
509 "with",
510 0
511};
512
513
514static void CheckSymbols(const char** strings) {
515 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000516 Object* a;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000517 MaybeObject* maybe_a = HEAP->LookupAsciiSymbol(string);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000518 // LookupAsciiSymbol may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000519 if (!maybe_a->ToObject(&a)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000520 CHECK(a->IsSymbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000521 Object* b;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000522 MaybeObject* maybe_b = HEAP->LookupAsciiSymbol(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000523 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000524 CHECK_EQ(b, a);
525 CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
526 }
527}
528
529
530TEST(SymbolTable) {
531 InitializeVM();
532
533 CheckSymbols(not_so_random_string_table);
534 CheckSymbols(not_so_random_string_table);
535}
536
537
538TEST(FunctionAllocation) {
539 InitializeVM();
540
541 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000542 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000543 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000545 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000547 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000548
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
550 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000551 obj->SetProperty(
552 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000553 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000554 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000555 function->SetProperty(
556 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000557 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000558}
559
560
561TEST(ObjectProperties) {
562 InitializeVM();
563
564 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 String* object_symbol = String::cast(HEAP->Object_symbol());
566 Object* raw_object = Isolate::Current()->context()->global()->
567 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000568 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000569 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000570 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
571 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
572 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000573
574 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000575 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000576
577 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000578 obj->SetProperty(
579 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000580 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000581
582 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000583 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
584 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000585
586 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000587 obj->SetProperty(
588 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
589 obj->SetProperty(
590 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000591 CHECK(obj->HasLocalProperty(*first));
592 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000593
594 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000595 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
596 CHECK(obj->HasLocalProperty(*second));
597 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
598 CHECK(!obj->HasLocalProperty(*first));
599 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000600
601 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000602 obj->SetProperty(
603 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
604 obj->SetProperty(
605 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000606 CHECK(obj->HasLocalProperty(*first));
607 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000608
609 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000610 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
611 CHECK(obj->HasLocalProperty(*first));
612 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
613 CHECK(!obj->HasLocalProperty(*first));
614 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000615
616 // check string and symbol match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000617 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000619 obj->SetProperty(
620 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000621 Handle<String> s1_symbol = FACTORY->LookupAsciiSymbol(string1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000622 CHECK(obj->HasLocalProperty(*s1_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000623
624 // check symbol and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000625 const char* string2 = "fugl";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 Handle<String> s2_symbol = FACTORY->LookupAsciiSymbol(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000627 obj->SetProperty(
628 *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000629 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000630 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000631}
632
633
634TEST(JSObjectMaps) {
635 InitializeVM();
636
637 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000639 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000641 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000642 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000643 function->set_initial_map(*initial_map);
644
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000645 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
646 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000647
648 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000649 obj->SetProperty(
650 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000651 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000652
653 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000654 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000655}
656
657
658TEST(JSArray) {
659 InitializeVM();
660
661 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000662 Handle<String> name = FACTORY->LookupAsciiSymbol("Array");
663 Object* raw_object = Isolate::Current()->context()->global()->
664 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000665 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000666 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000667
668 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000669 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000670 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000671 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000672 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000673
674 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000675 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000676 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000677 // Must be in fast mode.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000678 CHECK(array->HasFastSmiOrObjectElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000679
680 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000681 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000682 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000683 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000684
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000685 // Set array length with larger than smi value.
686 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000687 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000688 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000689
690 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000691 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000692 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000693 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000694
695 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000696 array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000697 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000698 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000699 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000700 CHECK_EQ(array->GetElement(int_length), *name);
701 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000702}
703
704
705TEST(JSObjectCopy) {
706 InitializeVM();
707
708 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000709 String* object_symbol = String::cast(HEAP->Object_symbol());
710 Object* raw_object = Isolate::Current()->context()->global()->
711 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000712 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000713 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000714 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
715 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
716 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000717
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000718 obj->SetProperty(
719 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
720 obj->SetProperty(
721 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000722
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000723 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
724 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000725
726 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000727 Handle<JSObject> clone = Copy(obj);
728 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000729
730 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
731 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
732
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000733 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
734 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000735
736 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000737 clone->SetProperty(
738 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
739 clone->SetProperty(
740 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000741
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000742 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
743 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000744
745 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
746 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
747
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000748 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
749 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000750}
751
752
753TEST(StringAllocation) {
754 InitializeVM();
755
756
757 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
758 for (int length = 0; length < 100; length++) {
759 v8::HandleScope scope;
760 char* non_ascii = NewArray<char>(3 * length + 1);
761 char* ascii = NewArray<char>(length + 1);
762 non_ascii[3 * length] = 0;
763 ascii[length] = 0;
764 for (int i = 0; i < length; i++) {
765 ascii[i] = 'a';
766 non_ascii[3 * i] = chars[0];
767 non_ascii[3 * i + 1] = chars[1];
768 non_ascii[3 * i + 2] = chars[2];
769 }
770 Handle<String> non_ascii_sym =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000771 FACTORY->LookupSymbol(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000772 CHECK_EQ(length, non_ascii_sym->length());
773 Handle<String> ascii_sym =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000774 FACTORY->LookupSymbol(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000775 CHECK_EQ(length, ascii_sym->length());
776 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000777 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000778 non_ascii_str->Hash();
779 CHECK_EQ(length, non_ascii_str->length());
780 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000781 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000782 ascii_str->Hash();
783 CHECK_EQ(length, ascii_str->length());
784 DeleteArray(non_ascii);
785 DeleteArray(ascii);
786 }
787}
788
789
790static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
791 // Count the number of objects found in the heap.
792 int found_count = 0;
793 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000794 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000795 for (int i = 0; i < size; i++) {
796 if (*objs[i] == obj) {
797 found_count++;
798 }
799 }
800 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000801 return found_count;
802}
803
804
805TEST(Iteration) {
806 InitializeVM();
807 v8::HandleScope scope;
808
809 // Array of objects to scan haep for.
810 const int objs_count = 6;
811 Handle<Object> objs[objs_count];
812 int next_objs_index = 0;
813
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000814 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000815 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000816 objs[next_objs_index++] = FACTORY->NewJSArray(10,
817 FAST_HOLEY_ELEMENTS,
818 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000819
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000820 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
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"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000823 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000824 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000825
826 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000827 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000828 char* str = new char[large_size];
829 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
830 str[large_size - 1] = '\0';
831 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000832 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000833 delete[] str;
834
835 // Add a Map object to look for.
836 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
837
838 CHECK_EQ(objs_count, next_objs_index);
839 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
840}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000841
842
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000843TEST(EmptyHandleEscapeFrom) {
844 InitializeVM();
845
846 v8::HandleScope scope;
847 Handle<JSObject> runaway;
848
849 {
850 v8::HandleScope nested;
851 Handle<JSObject> empty;
852 runaway = empty.EscapeFrom(&nested);
853 }
854
855 CHECK(runaway.is_null());
856}
857
858
859static int LenFromSize(int size) {
860 return (size - FixedArray::kHeaderSize) / kPointerSize;
861}
862
863
864TEST(Regression39128) {
865 // Test case for crbug.com/39128.
866 InitializeVM();
867
868 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000869 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000870
871 v8::HandleScope scope;
872
873 // The plan: create JSObject which references objects in new space.
874 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000875 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000876
877 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000878 Handle<JSFunction> object_ctor(
879 Isolate::Current()->global_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000880 CHECK(object_ctor->has_initial_map());
881 Handle<Map> object_map(object_ctor->initial_map());
882 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000884 int n_properties = my_map->inobject_properties();
885 CHECK_GT(n_properties, 0);
886
887 int object_size = my_map->instance_size();
888
889 // Step 2: allocate a lot of objects so to almost fill new space: we need
890 // just enough room to allocate JSObject and thus fill the newspace.
891
892 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000893 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000894 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000896 Address* top_addr = new_space->allocation_top_address();
897 Address* limit_addr = new_space->allocation_limit_address();
898 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000899 CHECK(!HEAP->always_allocate());
900 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
901 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000902 CHECK(new_space->Contains(array));
903 }
904
905 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000906 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000907 int fixed_array_len = LenFromSize(to_fill);
908 CHECK(fixed_array_len < FixedArray::kMaxLength);
909
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000910 CHECK(!HEAP->always_allocate());
911 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
912 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000913 CHECK(new_space->Contains(array));
914
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000915 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000916 CHECK(new_space->Contains(object));
917 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000918 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000919 CHECK_EQ(0, jsobject->properties()->length());
920 // Create a reference to object in new space in jsobject.
921 jsobject->FastPropertyAtPut(-1, array);
922
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000923 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000924
925 // Step 4: clone jsobject, but force always allocate first to create a clone
926 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000927 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000928 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000929 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000930 JSObject* clone = JSObject::cast(clone_obj);
931 if (clone->address() != old_pointer_space_top) {
932 // Alas, got allocated from free list, we cannot do checks.
933 return;
934 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000935 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000936}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000937
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000938
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000939TEST(TestCodeFlushing) {
940 i::FLAG_allow_natives_syntax = true;
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000941 // If we do not flush code this test is invalid.
942 if (!FLAG_flush_code) return;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000943 InitializeVM();
944 v8::HandleScope scope;
945 const char* source = "function foo() {"
946 " var x = 42;"
947 " var y = 42;"
948 " var z = x + y;"
949 "};"
950 "foo()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000951 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000952
953 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000954 { v8::HandleScope scope;
955 CompileRun(source);
956 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000957
958 // Check function is compiled.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000959 Object* func_value = Isolate::Current()->context()->global()->
960 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000961 CHECK(func_value->IsJSFunction());
962 Handle<JSFunction> function(JSFunction::cast(func_value));
963 CHECK(function->shared()->is_compiled());
964
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000965 // TODO(1609) Currently incremental marker does not support code flushing.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000966 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
967 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000968
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000969 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000970
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000971 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
972 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
973 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
974 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
975 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
976 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000977
978 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000979 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
980 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000981 // Call foo to get it recompiled.
982 CompileRun("foo()");
983 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000984 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000985}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000986
987
988// Count the number of global contexts in the weak list of global contexts.
jkummerow@chromium.org28583c92012-07-16 11:31:55 +0000989int CountGlobalContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000990 int count = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000991 Object* object = HEAP->global_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000992 while (!object->IsUndefined()) {
993 count++;
994 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
995 }
996 return count;
997}
998
999
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001000// Count the number of user functions in the weak list of optimized
1001// functions attached to a global context.
1002static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1003 int count = 0;
1004 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1005 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1006 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1007 count++;
1008 object = JSFunction::cast(object)->next_function_link();
1009 }
1010 return count;
1011}
1012
1013
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001014TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001015 v8::V8::Initialize();
1016
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001017 static const int kNumTestContexts = 10;
1018
1019 v8::HandleScope scope;
1020 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1021
1022 CHECK_EQ(0, CountGlobalContexts());
1023
1024 // Create a number of global contests which gets linked together.
1025 for (int i = 0; i < kNumTestContexts; i++) {
1026 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001027
1028 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1029
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001030 CHECK_EQ(i + 1, CountGlobalContexts());
1031
1032 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001033
1034 // Create a handle scope so no function objects get stuch in the outer
1035 // handle scope
1036 v8::HandleScope scope;
1037 const char* source = "function f1() { };"
1038 "function f2() { };"
1039 "function f3() { };"
1040 "function f4() { };"
1041 "function f5() { };";
1042 CompileRun(source);
1043 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1044 CompileRun("f1()");
1045 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1046 CompileRun("f2()");
1047 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1048 CompileRun("f3()");
1049 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1050 CompileRun("f4()");
1051 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1052 CompileRun("f5()");
1053 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1054
1055 // Remove function f1, and
1056 CompileRun("f1=null");
1057
1058 // Scavenge treats these references as strong.
1059 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001061 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1062 }
1063
1064 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001065 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001066 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1067
1068 // Get rid of f3 and f5 in the same way.
1069 CompileRun("f3=null");
1070 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001071 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001072 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1073 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001074 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001075 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1076 CompileRun("f5=null");
1077 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001078 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001079 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1080 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001081 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001082 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1083
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001084 ctx[i]->Exit();
1085 }
1086
1087 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001088 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001089
1090 // Dispose the global contexts one by one.
1091 for (int i = 0; i < kNumTestContexts; i++) {
1092 ctx[i].Dispose();
1093 ctx[i].Clear();
1094
1095 // Scavenge treats these references as strong.
1096 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001097 HEAP->PerformScavenge();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001098 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts());
1099 }
1100
1101 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001102 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001103 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts());
1104 }
1105
1106 CHECK_EQ(0, CountGlobalContexts());
1107}
1108
1109
1110// Count the number of global contexts in the weak list of global contexts
1111// causing a GC after the specified number of elements.
1112static int CountGlobalContextsWithGC(int n) {
1113 int count = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001114 Handle<Object> object(HEAP->global_contexts_list());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001115 while (!object->IsUndefined()) {
1116 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001117 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001118 object =
1119 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1120 }
1121 return count;
1122}
1123
1124
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001125// Count the number of user functions in the weak list of optimized
1126// functions attached to a global context causing a GC after the
1127// specified number of elements.
1128static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1129 int n) {
1130 int count = 0;
1131 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1132 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1133 while (object->IsJSFunction() &&
1134 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1135 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001136 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001137 object = Handle<Object>(
1138 Object::cast(JSFunction::cast(*object)->next_function_link()));
1139 }
1140 return count;
1141}
1142
1143
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001144TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001145 v8::V8::Initialize();
1146
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001147 static const int kNumTestContexts = 10;
1148
1149 v8::HandleScope scope;
1150 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1151
1152 CHECK_EQ(0, CountGlobalContexts());
1153
1154 // Create an number of contexts and check the length of the weak list both
1155 // with and without GCs while iterating the list.
1156 for (int i = 0; i < kNumTestContexts; i++) {
1157 ctx[i] = v8::Context::New();
1158 CHECK_EQ(i + 1, CountGlobalContexts());
1159 CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001160 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001161
1162 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1163
1164 // Compile a number of functions the length of the weak list of optimized
1165 // functions both with and without GCs while iterating the list.
1166 ctx[0]->Enter();
1167 const char* source = "function f1() { };"
1168 "function f2() { };"
1169 "function f3() { };"
1170 "function f4() { };"
1171 "function f5() { };";
1172 CompileRun(source);
1173 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1174 CompileRun("f1()");
1175 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1176 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1177 CompileRun("f2()");
1178 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1179 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1180 CompileRun("f3()");
1181 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1182 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1183 CompileRun("f4()");
1184 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1185 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1186 CompileRun("f5()");
1187 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1188 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1189
1190 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001191}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001192
1193
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001194TEST(TestSizeOfObjects) {
1195 v8::V8::Initialize();
1196
1197 // Get initial heap size after several full GCs, which will stabilize
1198 // the heap size and return with sweeping finished completely.
1199 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1200 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1201 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1202 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001203 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001204 CHECK(HEAP->old_pointer_space()->IsSweepingComplete());
1205 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1206
1207 {
1208 // Allocate objects on several different old-space pages so that
1209 // lazy sweeping kicks in for subsequent GC runs.
1210 AlwaysAllocateScope always_allocate;
1211 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1212 for (int i = 1; i <= 100; i++) {
1213 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1214 CHECK_EQ(initial_size + i * filler_size,
1215 static_cast<int>(HEAP->SizeOfObjects()));
1216 }
1217 }
1218
1219 // The heap size should go back to initial size after a full GC, even
1220 // though sweeping didn't finish yet.
1221 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001222
1223 // Normally sweeping would not be complete here, but no guarantees.
1224
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001225 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1226
1227 // Advancing the sweeper step-wise should not change the heap size.
1228 while (!HEAP->old_pointer_space()->IsSweepingComplete()) {
1229 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1230 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1231 }
1232}
1233
1234
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001235TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1236 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001237 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001238 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001239 HeapIterator iterator;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001240 intptr_t size_of_objects_2 = 0;
1241 for (HeapObject* obj = iterator.next();
1242 obj != NULL;
1243 obj = iterator.next()) {
1244 size_of_objects_2 += obj->Size();
1245 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001246 // Delta must be within 5% of the larger result.
1247 // TODO(gc): Tighten this up by distinguishing between byte
1248 // arrays that are real and those that merely mark free space
1249 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001250 if (size_of_objects_1 > size_of_objects_2) {
1251 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1252 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1253 "Iterator: %" V8_PTR_PREFIX "d, "
1254 "delta: %" V8_PTR_PREFIX "d\n",
1255 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001256 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001257 } else {
1258 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1259 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1260 "Iterator: %" V8_PTR_PREFIX "d, "
1261 "delta: %" V8_PTR_PREFIX "d\n",
1262 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001263 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001264 }
1265}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001266
1267
danno@chromium.orgc612e022011-11-10 11:38:15 +00001268static void FillUpNewSpace(NewSpace* new_space) {
1269 // Fill up new space to the point that it is completely full. Make sure
1270 // that the scavenger does not undo the filling.
1271 v8::HandleScope scope;
1272 AlwaysAllocateScope always_allocate;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001273 LinearAllocationScope allocate_linearly;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001274 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001275 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001276 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001277 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001278 }
1279}
1280
1281
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001282TEST(GrowAndShrinkNewSpace) {
1283 InitializeVM();
1284 NewSpace* new_space = HEAP->new_space();
1285
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001286 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1287 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001288 // The max size cannot exceed the reserved size, since semispaces must be
1289 // always within the reserved space. We can't test new space growing and
1290 // shrinking if the reserved size is the same as the minimum (initial) size.
1291 return;
1292 }
1293
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001294 // Explicitly growing should double the space capacity.
1295 intptr_t old_capacity, new_capacity;
1296 old_capacity = new_space->Capacity();
1297 new_space->Grow();
1298 new_capacity = new_space->Capacity();
1299 CHECK(2 * old_capacity == new_capacity);
1300
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001301 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001302 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001303 new_capacity = new_space->Capacity();
1304 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001305
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001306 // Explicitly shrinking should not affect space capacity.
1307 old_capacity = new_space->Capacity();
1308 new_space->Shrink();
1309 new_capacity = new_space->Capacity();
1310 CHECK(old_capacity == new_capacity);
1311
1312 // Let the scavenger empty the new space.
1313 HEAP->CollectGarbage(NEW_SPACE);
1314 CHECK_LE(new_space->Size(), old_capacity);
1315
1316 // Explicitly shrinking should halve the space capacity.
1317 old_capacity = new_space->Capacity();
1318 new_space->Shrink();
1319 new_capacity = new_space->Capacity();
1320 CHECK(old_capacity == 2 * new_capacity);
1321
1322 // Consecutive shrinking should not affect space capacity.
1323 old_capacity = new_space->Capacity();
1324 new_space->Shrink();
1325 new_space->Shrink();
1326 new_space->Shrink();
1327 new_capacity = new_space->Capacity();
1328 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001329}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001330
1331
1332TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1333 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001334
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001335 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1336 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001337 // The max size cannot exceed the reserved size, since semispaces must be
1338 // always within the reserved space. We can't test new space growing and
1339 // shrinking if the reserved size is the same as the minimum (initial) size.
1340 return;
1341 }
1342
danno@chromium.orgc612e022011-11-10 11:38:15 +00001343 v8::HandleScope scope;
1344 NewSpace* new_space = HEAP->new_space();
1345 intptr_t old_capacity, new_capacity;
1346 old_capacity = new_space->Capacity();
1347 new_space->Grow();
1348 new_capacity = new_space->Capacity();
1349 CHECK(2 * old_capacity == new_capacity);
1350 FillUpNewSpace(new_space);
1351 HEAP->CollectAllAvailableGarbage();
1352 new_capacity = new_space->Capacity();
1353 CHECK(old_capacity == new_capacity);
1354}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001355
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001356
1357static int NumberOfGlobalObjects() {
1358 int count = 0;
1359 HeapIterator iterator;
1360 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1361 if (obj->IsGlobalObject()) count++;
1362 }
1363 return count;
1364}
1365
1366
1367// Test that we don't embed maps from foreign contexts into
1368// optimized code.
1369TEST(LeakGlobalContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001370 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001371 v8::HandleScope outer_scope;
1372 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1373 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1374 ctx1->Enter();
1375
1376 HEAP->CollectAllAvailableGarbage();
1377 CHECK_EQ(4, NumberOfGlobalObjects());
1378
1379 {
1380 v8::HandleScope inner_scope;
1381 CompileRun("var v = {x: 42}");
1382 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1383 ctx2->Enter();
1384 ctx2->Global()->Set(v8_str("o"), v);
1385 v8::Local<v8::Value> res = CompileRun(
1386 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001387 "for (var i = 0; i < 10; ++i) f();"
1388 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001389 "f();");
1390 CHECK_EQ(42, res->Int32Value());
1391 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1392 ctx2->Exit();
1393 ctx1->Exit();
1394 ctx1.Dispose();
1395 }
1396 HEAP->CollectAllAvailableGarbage();
1397 CHECK_EQ(2, NumberOfGlobalObjects());
1398 ctx2.Dispose();
1399 HEAP->CollectAllAvailableGarbage();
1400 CHECK_EQ(0, NumberOfGlobalObjects());
1401}
1402
1403
1404// Test that we don't embed functions from foreign contexts into
1405// optimized code.
1406TEST(LeakGlobalContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001407 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001408 v8::HandleScope outer_scope;
1409 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1410 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1411 ctx1->Enter();
1412
1413 HEAP->CollectAllAvailableGarbage();
1414 CHECK_EQ(4, NumberOfGlobalObjects());
1415
1416 {
1417 v8::HandleScope inner_scope;
1418 CompileRun("var v = function() { return 42; }");
1419 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1420 ctx2->Enter();
1421 ctx2->Global()->Set(v8_str("o"), v);
1422 v8::Local<v8::Value> res = CompileRun(
1423 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001424 "for (var i = 0; i < 10; ++i) f(o);"
1425 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001426 "f(o);");
1427 CHECK_EQ(42, res->Int32Value());
1428 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1429 ctx2->Exit();
1430 ctx1->Exit();
1431 ctx1.Dispose();
1432 }
1433 HEAP->CollectAllAvailableGarbage();
1434 CHECK_EQ(2, NumberOfGlobalObjects());
1435 ctx2.Dispose();
1436 HEAP->CollectAllAvailableGarbage();
1437 CHECK_EQ(0, NumberOfGlobalObjects());
1438}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001439
1440
1441TEST(LeakGlobalContextViaMapKeyed) {
1442 i::FLAG_allow_natives_syntax = true;
1443 v8::HandleScope outer_scope;
1444 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1445 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1446 ctx1->Enter();
1447
1448 HEAP->CollectAllAvailableGarbage();
1449 CHECK_EQ(4, NumberOfGlobalObjects());
1450
1451 {
1452 v8::HandleScope inner_scope;
1453 CompileRun("var v = [42, 43]");
1454 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1455 ctx2->Enter();
1456 ctx2->Global()->Set(v8_str("o"), v);
1457 v8::Local<v8::Value> res = CompileRun(
1458 "function f() { return o[0]; }"
1459 "for (var i = 0; i < 10; ++i) f();"
1460 "%OptimizeFunctionOnNextCall(f);"
1461 "f();");
1462 CHECK_EQ(42, res->Int32Value());
1463 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1464 ctx2->Exit();
1465 ctx1->Exit();
1466 ctx1.Dispose();
1467 }
1468 HEAP->CollectAllAvailableGarbage();
1469 CHECK_EQ(2, NumberOfGlobalObjects());
1470 ctx2.Dispose();
1471 HEAP->CollectAllAvailableGarbage();
1472 CHECK_EQ(0, NumberOfGlobalObjects());
1473}
1474
1475
1476TEST(LeakGlobalContextViaMapProto) {
1477 i::FLAG_allow_natives_syntax = true;
1478 v8::HandleScope outer_scope;
1479 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1480 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1481 ctx1->Enter();
1482
1483 HEAP->CollectAllAvailableGarbage();
1484 CHECK_EQ(4, NumberOfGlobalObjects());
1485
1486 {
1487 v8::HandleScope inner_scope;
1488 CompileRun("var v = { y: 42}");
1489 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1490 ctx2->Enter();
1491 ctx2->Global()->Set(v8_str("o"), v);
1492 v8::Local<v8::Value> res = CompileRun(
1493 "function f() {"
1494 " var p = {x: 42};"
1495 " p.__proto__ = o;"
1496 " return p.x;"
1497 "}"
1498 "for (var i = 0; i < 10; ++i) f();"
1499 "%OptimizeFunctionOnNextCall(f);"
1500 "f();");
1501 CHECK_EQ(42, res->Int32Value());
1502 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1503 ctx2->Exit();
1504 ctx1->Exit();
1505 ctx1.Dispose();
1506 }
1507 HEAP->CollectAllAvailableGarbage();
1508 CHECK_EQ(2, NumberOfGlobalObjects());
1509 ctx2.Dispose();
1510 HEAP->CollectAllAvailableGarbage();
1511 CHECK_EQ(0, NumberOfGlobalObjects());
1512}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001513
1514
1515TEST(InstanceOfStubWriteBarrier) {
1516 i::FLAG_allow_natives_syntax = true;
1517#ifdef DEBUG
1518 i::FLAG_verify_heap = true;
1519#endif
1520 InitializeVM();
1521 if (!i::V8::UseCrankshaft()) return;
1522 v8::HandleScope outer_scope;
1523
1524 {
1525 v8::HandleScope scope;
1526 CompileRun(
1527 "function foo () { }"
1528 "function mkbar () { return new (new Function(\"\")) (); }"
1529 "function f (x) { return (x instanceof foo); }"
1530 "function g () { f(mkbar()); }"
1531 "f(new foo()); f(new foo());"
1532 "%OptimizeFunctionOnNextCall(f);"
1533 "f(new foo()); g();");
1534 }
1535
1536 IncrementalMarking* marking = HEAP->incremental_marking();
1537 marking->Abort();
1538 marking->Start();
1539
1540 Handle<JSFunction> f =
1541 v8::Utils::OpenHandle(
1542 *v8::Handle<v8::Function>::Cast(
1543 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1544
1545 CHECK(f->IsOptimized());
1546
1547 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1548 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001549 // Discard any pending GC requests otherwise we will get GC when we enter
1550 // code below.
1551 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001552 }
1553
1554 CHECK(marking->IsMarking());
1555
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001556 {
1557 v8::HandleScope scope;
1558 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1559 v8::Handle<v8::Function> g =
1560 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1561 g->Call(global, 0, NULL);
1562 }
1563
1564 HEAP->incremental_marking()->set_should_hurry(true);
1565 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1566}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001567
1568
1569TEST(PrototypeTransitionClearing) {
1570 InitializeVM();
1571 v8::HandleScope scope;
1572
1573 CompileRun(
1574 "var base = {};"
1575 "var live = [];"
1576 "for (var i = 0; i < 10; i++) {"
1577 " var object = {};"
1578 " var prototype = {};"
1579 " object.__proto__ = prototype;"
1580 " if (i >= 3) live.push(object, prototype);"
1581 "}");
1582
1583 Handle<JSObject> baseObject =
1584 v8::Utils::OpenHandle(
1585 *v8::Handle<v8::Object>::Cast(
1586 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1587
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001588 // Verify that only dead prototype transitions are cleared.
1589 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001590 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001591 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001592 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001593
1594 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001595 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001596 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001597 int j = Map::kProtoTransitionHeaderSize +
1598 i * Map::kProtoTransitionElementsPerEntry;
1599 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001600 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1601 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001602 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001603
1604 // Make sure next prototype is placed on an old-space evacuation candidate.
1605 Handle<JSObject> prototype;
1606 PagedSpace* space = HEAP->old_pointer_space();
1607 do {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001608 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001609 } while (space->FirstPage() == space->LastPage() ||
1610 !space->LastPage()->Contains(prototype->address()));
1611
1612 // Add a prototype on an evacuation candidate and verify that transition
1613 // clearing correctly records slots in prototype transition array.
1614 i::FLAG_always_compact = true;
1615 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001616 CHECK(!space->LastPage()->Contains(
1617 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001618 CHECK(space->LastPage()->Contains(prototype->address()));
1619 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1620 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1621 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1622 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001623}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001624
1625
1626TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1627 i::FLAG_allow_natives_syntax = true;
1628#ifdef DEBUG
1629 i::FLAG_verify_heap = true;
1630#endif
1631 InitializeVM();
1632 if (!i::V8::UseCrankshaft()) return;
1633 v8::HandleScope outer_scope;
1634
1635 {
1636 v8::HandleScope scope;
1637 CompileRun(
1638 "function f () {"
1639 " var s = 0;"
1640 " for (var i = 0; i < 100; i++) s += i;"
1641 " return s;"
1642 "}"
1643 "f(); f();"
1644 "%OptimizeFunctionOnNextCall(f);"
1645 "f();");
1646 }
1647 Handle<JSFunction> f =
1648 v8::Utils::OpenHandle(
1649 *v8::Handle<v8::Function>::Cast(
1650 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1651 CHECK(f->IsOptimized());
1652
1653 IncrementalMarking* marking = HEAP->incremental_marking();
1654 marking->Abort();
1655 marking->Start();
1656
1657 // The following two calls will increment HEAP->global_ic_age().
1658 const int kLongIdlePauseInMs = 1000;
1659 v8::V8::ContextDisposedNotification();
1660 v8::V8::IdleNotification(kLongIdlePauseInMs);
1661
1662 while (!marking->IsStopped() && !marking->IsComplete()) {
1663 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1664 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001665 if (!marking->IsStopped() || marking->should_hurry()) {
1666 // We don't normally finish a GC via Step(), we normally finish by
1667 // setting the stack guard and then do the final steps in the stack
1668 // guard interrupt. But here we didn't ask for that, and there is no
1669 // JS code running to trigger the interrupt, so we explicitly finalize
1670 // here.
1671 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1672 "Test finalizing incremental mark-sweep");
1673 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001674
1675 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1676 CHECK_EQ(0, f->shared()->opt_count());
1677 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1678}
1679
1680
1681TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1682 i::FLAG_allow_natives_syntax = true;
1683#ifdef DEBUG
1684 i::FLAG_verify_heap = true;
1685#endif
1686 InitializeVM();
1687 if (!i::V8::UseCrankshaft()) return;
1688 v8::HandleScope outer_scope;
1689
1690 {
1691 v8::HandleScope scope;
1692 CompileRun(
1693 "function f () {"
1694 " var s = 0;"
1695 " for (var i = 0; i < 100; i++) s += i;"
1696 " return s;"
1697 "}"
1698 "f(); f();"
1699 "%OptimizeFunctionOnNextCall(f);"
1700 "f();");
1701 }
1702 Handle<JSFunction> f =
1703 v8::Utils::OpenHandle(
1704 *v8::Handle<v8::Function>::Cast(
1705 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1706 CHECK(f->IsOptimized());
1707
1708 HEAP->incremental_marking()->Abort();
1709
1710 // The following two calls will increment HEAP->global_ic_age().
1711 // Since incremental marking is off, IdleNotification will do full GC.
1712 const int kLongIdlePauseInMs = 1000;
1713 v8::V8::ContextDisposedNotification();
1714 v8::V8::IdleNotification(kLongIdlePauseInMs);
1715
1716 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1717 CHECK_EQ(0, f->shared()->opt_count());
1718 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1719}
1720
1721
1722// Test that HAllocateObject will always return an object in new-space.
1723TEST(OptimizedAllocationAlwaysInNewSpace) {
1724 i::FLAG_allow_natives_syntax = true;
1725 InitializeVM();
1726 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
1727 v8::HandleScope scope;
1728
1729 FillUpNewSpace(HEAP->new_space());
1730 AlwaysAllocateScope always_allocate;
1731 v8::Local<v8::Value> res = CompileRun(
1732 "function c(x) {"
1733 " this.x = x;"
1734 " for (var i = 0; i < 32; i++) {"
1735 " this['x' + i] = x;"
1736 " }"
1737 "}"
1738 "function f(x) { return new c(x); };"
1739 "f(1); f(2); f(3);"
1740 "%OptimizeFunctionOnNextCall(f);"
1741 "f(4);");
1742 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
1743
1744 Handle<JSObject> o =
1745 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
1746
1747 CHECK(HEAP->InNewSpace(*o));
1748}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001749
1750
1751static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001752 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001753}
1754
1755
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001756// Go through all incremental marking steps in one swoop.
1757static void SimulateIncrementalMarking() {
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001758 IncrementalMarking* marking = HEAP->incremental_marking();
1759 CHECK(marking->IsStopped());
1760 marking->Start();
1761 CHECK(marking->IsMarking());
1762 while (!marking->IsComplete()) {
1763 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1764 }
1765 CHECK(marking->IsComplete());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001766}
1767
1768
1769// Test that map transitions are cleared and maps are collected with
1770// incremental marking as well.
1771TEST(Regress1465) {
1772 i::FLAG_allow_natives_syntax = true;
1773 i::FLAG_trace_incremental_marking = true;
1774 InitializeVM();
1775 v8::HandleScope scope;
1776 static const int transitions_count = 256;
1777
1778 {
1779 AlwaysAllocateScope always_allocate;
1780 for (int i = 0; i < transitions_count; i++) {
1781 EmbeddedVector<char, 64> buffer;
1782 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
1783 CompileRun(buffer.start());
1784 }
1785 CompileRun("var root = new Object;");
1786 }
1787
1788 Handle<JSObject> root =
1789 v8::Utils::OpenHandle(
1790 *v8::Handle<v8::Object>::Cast(
1791 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
1792
1793 // Count number of live transitions before marking.
1794 int transitions_before = CountMapTransitions(root->map());
1795 CompileRun("%DebugPrint(root);");
1796 CHECK_EQ(transitions_count, transitions_before);
1797
1798 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001799 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001800
1801 // Count number of live transitions after marking. Note that one transition
1802 // is left, because 'o' still holds an instance of one transition target.
1803 int transitions_after = CountMapTransitions(root->map());
1804 CompileRun("%DebugPrint(root);");
1805 CHECK_EQ(1, transitions_after);
1806}
verwaest@chromium.org37141392012-05-31 13:27:02 +00001807
1808
1809TEST(Regress2143a) {
1810 i::FLAG_collect_maps = true;
1811 i::FLAG_incremental_marking = true;
1812 InitializeVM();
1813 v8::HandleScope scope;
1814
1815 // Prepare a map transition from the root object together with a yet
1816 // untransitioned root object.
1817 CompileRun("var root = new Object;"
1818 "root.foo = 0;"
1819 "root = new Object;");
1820
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001821 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00001822
1823 // Compile a StoreIC that performs the prepared map transition. This
1824 // will restart incremental marking and should make sure the root is
1825 // marked grey again.
1826 CompileRun("function f(o) {"
1827 " o.foo = 0;"
1828 "}"
1829 "f(new Object);"
1830 "f(root);");
1831
1832 // This bug only triggers with aggressive IC clearing.
1833 HEAP->AgeInlineCaches();
1834
1835 // Explicitly request GC to perform final marking step and sweeping.
1836 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00001837
1838 Handle<JSObject> root =
1839 v8::Utils::OpenHandle(
1840 *v8::Handle<v8::Object>::Cast(
1841 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
1842
1843 // The root object should be in a sane state.
1844 CHECK(root->IsJSObject());
1845 CHECK(root->map()->IsMap());
1846}
1847
1848
1849TEST(Regress2143b) {
1850 i::FLAG_collect_maps = true;
1851 i::FLAG_incremental_marking = true;
1852 i::FLAG_allow_natives_syntax = true;
1853 InitializeVM();
1854 v8::HandleScope scope;
1855
1856 // Prepare a map transition from the root object together with a yet
1857 // untransitioned root object.
1858 CompileRun("var root = new Object;"
1859 "root.foo = 0;"
1860 "root = new Object;");
1861
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001862 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00001863
1864 // Compile an optimized LStoreNamedField that performs the prepared
1865 // map transition. This will restart incremental marking and should
1866 // make sure the root is marked grey again.
1867 CompileRun("function f(o) {"
1868 " o.foo = 0;"
1869 "}"
1870 "f(new Object);"
1871 "f(new Object);"
1872 "%OptimizeFunctionOnNextCall(f);"
1873 "f(root);"
1874 "%DeoptimizeFunction(f);");
1875
1876 // This bug only triggers with aggressive IC clearing.
1877 HEAP->AgeInlineCaches();
1878
1879 // Explicitly request GC to perform final marking step and sweeping.
1880 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00001881
1882 Handle<JSObject> root =
1883 v8::Utils::OpenHandle(
1884 *v8::Handle<v8::Object>::Cast(
1885 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
1886
1887 // The root object should be in a sane state.
1888 CHECK(root->IsJSObject());
1889 CHECK(root->map()->IsMap());
1890}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001891
1892
1893// Implemented in the test-alloc.cc test suite.
1894void SimulateFullSpace(PagedSpace* space);
1895
1896
1897TEST(ReleaseOverReservedPages) {
1898 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001899 // The optimizer can allocate stuff, messing up the test.
1900 i::FLAG_crankshaft = false;
1901 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001902 InitializeVM();
1903 v8::HandleScope scope;
1904 static const int number_of_test_pages = 20;
1905
1906 // Prepare many pages with low live-bytes count.
1907 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
1908 CHECK_EQ(1, old_pointer_space->CountTotalPages());
1909 for (int i = 0; i < number_of_test_pages; i++) {
1910 AlwaysAllocateScope always_allocate;
1911 SimulateFullSpace(old_pointer_space);
1912 FACTORY->NewFixedArray(1, TENURED);
1913 }
1914 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
1915
1916 // Triggering one GC will cause a lot of garbage to be discovered but
1917 // even spread across all allocated pages.
1918 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
1919 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
1920
1921 // Triggering subsequent GCs should cause at least half of the pages
1922 // to be released to the OS after at most two cycles.
1923 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
1924 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
1925 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
1926 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
1927
1928 // Triggering a last-resort GC should cause all pages to be released
1929 // to the OS so that other processes can seize the memory.
1930 HEAP->CollectAllAvailableGarbage("triggered really hard");
1931 CHECK_EQ(1, old_pointer_space->CountTotalPages());
1932}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001933
1934
1935TEST(Regress2237) {
1936 InitializeVM();
1937 v8::HandleScope scope;
1938 Handle<String> slice(HEAP->empty_string());
1939
1940 {
1941 // Generate a parent that lives in new-space.
1942 v8::HandleScope inner_scope;
1943 const char* c = "This text is long enough to trigger sliced strings.";
1944 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
1945 CHECK(s->IsSeqAsciiString());
1946 CHECK(HEAP->InNewSpace(*s));
1947
1948 // Generate a sliced string that is based on the above parent and
1949 // lives in old-space.
1950 FillUpNewSpace(HEAP->new_space());
1951 AlwaysAllocateScope always_allocate;
1952 Handle<String> t;
1953 // TODO(mstarzinger): Unfortunately FillUpNewSpace() still leaves
1954 // some slack, so we need to allocate a few sliced strings.
1955 for (int i = 0; i < 16; i++) {
1956 t = FACTORY->NewProperSubString(s, 5, 35);
1957 }
1958 CHECK(t->IsSlicedString());
1959 CHECK(!HEAP->InNewSpace(*t));
1960 *slice.location() = *t.location();
1961 }
1962
1963 CHECK(SlicedString::cast(*slice)->parent()->IsSeqAsciiString());
1964 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1965 CHECK(SlicedString::cast(*slice)->parent()->IsSeqAsciiString());
1966}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00001967
1968
1969#ifdef OBJECT_PRINT
1970TEST(PrintSharedFunctionInfo) {
1971 InitializeVM();
1972 v8::HandleScope scope;
1973 const char* source = "f = function() { return 987654321; }\n"
1974 "g = function() { return 123456789; }\n";
1975 CompileRun(source);
1976 Handle<JSFunction> g =
1977 v8::Utils::OpenHandle(
1978 *v8::Handle<v8::Function>::Cast(
1979 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
1980
1981 AssertNoAllocation no_alloc;
1982 g->shared()->PrintLn();
1983}
1984#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001985
1986
1987TEST(Regress2211) {
1988 InitializeVM();
1989 v8::HandleScope scope;
1990
1991 v8::Handle<v8::String> value = v8_str("val string");
1992 Smi* hash = Smi::FromInt(321);
1993 Heap* heap = Isolate::Current()->heap();
1994
1995 for (int i = 0; i < 2; i++) {
1996 // Store identity hash first and common hidden property second.
1997 v8::Handle<v8::Object> obj = v8::Object::New();
1998 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
1999 CHECK(internal_obj->HasFastProperties());
2000
2001 // In the first iteration, set hidden value first and identity hash second.
2002 // In the second iteration, reverse the order.
2003 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2004 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2005 ALLOW_CREATION);
2006 CHECK(!maybe_obj->IsFailure());
2007 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2008
2009 // Check values.
2010 CHECK_EQ(hash,
2011 internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
2012 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2013
2014 // Check size.
2015 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2016 ObjectHashTable* hashtable = ObjectHashTable::cast(
2017 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2018 // HashTable header (5) and 4 initial entries (8).
2019 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2020 }
2021}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002022
2023
2024TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2025 if (i::FLAG_always_opt) return;
2026 InitializeVM();
2027 v8::HandleScope scope;
2028 v8::Local<v8::Value> fun1, fun2;
2029
2030 {
2031 LocalContext env;
2032 CompileRun("function fun() {};");
2033 fun1 = env->Global()->Get(v8_str("fun"));
2034 }
2035
2036 {
2037 LocalContext env;
2038 CompileRun("function fun() {};");
2039 fun2 = env->Global()->Get(v8_str("fun"));
2040 }
2041
2042 // Prepare function f that contains type feedback for closures
2043 // originating from two different global contexts.
2044 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2045 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2046 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2047 Handle<JSFunction> f =
2048 v8::Utils::OpenHandle(
2049 *v8::Handle<v8::Function>::Cast(
2050 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2051 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2052 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2053
2054 CHECK_EQ(2, cells->CellCount());
2055 CHECK(cells->Cell(0)->value()->IsJSFunction());
2056 CHECK(cells->Cell(1)->value()->IsJSFunction());
2057
2058 SimulateIncrementalMarking();
2059 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2060
2061 CHECK_EQ(2, cells->CellCount());
2062 CHECK(cells->Cell(0)->value()->IsTheHole());
2063 CHECK(cells->Cell(1)->value()->IsTheHole());
2064}
2065
2066
2067static Code* FindFirstIC(Code* code, Code::Kind kind) {
2068 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2069 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2070 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2071 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2072 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2073 RelocInfo* info = it.rinfo();
2074 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2075 if (target->is_inline_cache_stub() && target->kind() == kind) {
2076 return target;
2077 }
2078 }
2079 return NULL;
2080}
2081
2082
2083TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2084 if (i::FLAG_always_opt) return;
2085 InitializeVM();
2086 v8::HandleScope scope;
2087
2088 // Prepare function f that contains a monomorphic IC for object
2089 // originating from the same global context.
2090 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2091 "function f(o) { return o.x; } f(obj); f(obj);");
2092 Handle<JSFunction> f =
2093 v8::Utils::OpenHandle(
2094 *v8::Handle<v8::Function>::Cast(
2095 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2096
2097 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2098 CHECK(ic_before->ic_state() == MONOMORPHIC);
2099
2100 // Fire context dispose notification.
2101 v8::V8::ContextDisposedNotification();
2102 SimulateIncrementalMarking();
2103 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2104
2105 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2106 CHECK(ic_after->ic_state() == MONOMORPHIC);
2107}
2108
2109
2110TEST(IncrementalMarkingClearsMonomorhpicIC) {
2111 if (i::FLAG_always_opt) return;
2112 InitializeVM();
2113 v8::HandleScope scope;
2114 v8::Local<v8::Value> obj1;
2115
2116 {
2117 LocalContext env;
2118 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2119 obj1 = env->Global()->Get(v8_str("obj"));
2120 }
2121
2122 // Prepare function f that contains a monomorphic IC for object
2123 // originating from a different global context.
2124 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2125 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2126 Handle<JSFunction> f =
2127 v8::Utils::OpenHandle(
2128 *v8::Handle<v8::Function>::Cast(
2129 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2130
2131 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2132 CHECK(ic_before->ic_state() == MONOMORPHIC);
2133
2134 // Fire context dispose notification.
2135 v8::V8::ContextDisposedNotification();
2136 SimulateIncrementalMarking();
2137 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2138
2139 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2140 CHECK(ic_after->ic_state() == UNINITIALIZED);
2141}
2142
2143
2144TEST(IncrementalMarkingClearsPolymorhpicIC) {
2145 if (i::FLAG_always_opt) return;
2146 InitializeVM();
2147 v8::HandleScope scope;
2148 v8::Local<v8::Value> obj1, obj2;
2149
2150 {
2151 LocalContext env;
2152 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2153 obj1 = env->Global()->Get(v8_str("obj"));
2154 }
2155
2156 {
2157 LocalContext env;
2158 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2159 obj2 = env->Global()->Get(v8_str("obj"));
2160 }
2161
2162 // Prepare function f that contains a polymorphic IC for objects
2163 // originating from two different global contexts.
2164 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2165 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2166 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2167 Handle<JSFunction> f =
2168 v8::Utils::OpenHandle(
2169 *v8::Handle<v8::Function>::Cast(
2170 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2171
2172 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2173 CHECK(ic_before->ic_state() == MEGAMORPHIC);
2174
2175 // Fire context dispose notification.
2176 v8::V8::ContextDisposedNotification();
2177 SimulateIncrementalMarking();
2178 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2179
2180 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2181 CHECK(ic_after->ic_state() == UNINITIALIZED);
2182}