blob: 648d7ebe1734611ce3651f7a6d3d7cea88f8f836 [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
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007#include "compilation-cache.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008#include "execution.h"
9#include "factory.h"
10#include "macro-assembler.h"
11#include "global-handles.h"
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000012#include "stub-cache.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000013#include "cctest.h"
14
15using namespace v8::internal;
16
17static v8::Persistent<v8::Context> env;
18
19static void InitializeVM() {
20 if (env.IsEmpty()) env = v8::Context::New();
21 v8::HandleScope scope;
22 env->Enter();
23}
24
25
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000026// Go through all incremental marking steps in one swoop.
27static void SimulateIncrementalMarking() {
28 IncrementalMarking* marking = HEAP->incremental_marking();
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000029 CHECK(marking->IsMarking() || marking->IsStopped());
30 if (marking->IsStopped()) {
31 marking->Start();
32 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000033 CHECK(marking->IsMarking());
34 while (!marking->IsComplete()) {
35 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
36 }
37 CHECK(marking->IsComplete());
38}
39
40
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000041static void CheckMap(Map* map, int type, int instance_size) {
42 CHECK(map->IsHeapObject());
43#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000044 CHECK(HEAP->Contains(map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000045#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000046 CHECK_EQ(HEAP->meta_map(), map->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000047 CHECK_EQ(type, map->instance_type());
48 CHECK_EQ(instance_size, map->instance_size());
49}
50
51
52TEST(HeapMaps) {
53 InitializeVM();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000054 CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
55 CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
56 CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
57 CheckMap(HEAP->string_map(), STRING_TYPE, kVariableSizeSentinel);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000058}
59
60
61static void CheckOddball(Object* obj, const char* string) {
62 CHECK(obj->IsOddball());
63 bool exc;
64 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000065 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000066}
67
68
69static void CheckSmi(int value, const char* string) {
70 bool exc;
71 Object* print_string =
72 *Execution::ToString(Handle<Object>(Smi::FromInt(value)), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000073 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000074}
75
76
77static void CheckNumber(double value, const char* string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000078 Object* obj = HEAP->NumberFromDouble(value)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000079 CHECK(obj->IsNumber());
80 bool exc;
81 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000082 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000083}
84
85
86static void CheckFindCodeObject() {
87 // Test FindCodeObject
88#define __ assm.
89
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000090 Assembler assm(Isolate::Current(), NULL, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000091
92 __ nop(); // supported on all architectures
93
94 CodeDesc desc;
95 assm.GetCode(&desc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000096 Object* code = HEAP->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +000097 desc,
98 Code::ComputeFlags(Code::STUB),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000099 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000100 CHECK(code->IsCode());
101
102 HeapObject* obj = HeapObject::cast(code);
103 Address obj_addr = obj->address();
104
105 for (int i = 0; i < obj->Size(); i += kPointerSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000106 Object* found = HEAP->FindCodeObject(obj_addr + i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000107 CHECK_EQ(code, found);
108 }
109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000110 Object* copy = HEAP->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000111 desc,
112 Code::ComputeFlags(Code::STUB),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000114 CHECK(copy->IsCode());
115 HeapObject* obj_copy = HeapObject::cast(copy);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000116 Object* not_right = HEAP->FindCodeObject(obj_copy->address() +
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000117 obj_copy->Size() / 2);
118 CHECK(not_right != code);
119}
120
121
122TEST(HeapObjects) {
123 InitializeVM();
124
125 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 Object* value = HEAP->NumberFromDouble(1.000123)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000127 CHECK(value->IsHeapNumber());
128 CHECK(value->IsNumber());
129 CHECK_EQ(1.000123, value->Number());
130
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000131 value = HEAP->NumberFromDouble(1.0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000132 CHECK(value->IsSmi());
133 CHECK(value->IsNumber());
134 CHECK_EQ(1.0, value->Number());
135
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000136 value = HEAP->NumberFromInt32(1024)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000137 CHECK(value->IsSmi());
138 CHECK(value->IsNumber());
139 CHECK_EQ(1024.0, value->Number());
140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000141 value = HEAP->NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000142 CHECK(value->IsSmi());
143 CHECK(value->IsNumber());
144 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 value = HEAP->NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000147 CHECK(value->IsSmi());
148 CHECK(value->IsNumber());
149 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
150
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000151#ifndef V8_TARGET_ARCH_X64
152 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000153 value = HEAP->NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000154 CHECK(value->IsHeapNumber());
155 CHECK(value->IsNumber());
156 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000157#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000158
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 MaybeObject* maybe_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 HEAP->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 value = maybe_value->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000162 CHECK(value->IsHeapNumber());
163 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000164 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
165 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000166
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000167 maybe_value = HEAP->NumberFromUint32(static_cast<uint32_t>(1) << 31);
168 value = maybe_value->ToObjectChecked();
169 CHECK(value->IsHeapNumber());
170 CHECK(value->IsNumber());
171 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(1) << 31),
172 value->Number());
173
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000174 // nan oddball checks
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000175 CHECK(HEAP->nan_value()->IsNumber());
176 CHECK(isnan(HEAP->nan_value()->Number()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000177
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000178 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000179 CHECK(s->IsString());
180 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000181
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000182 String* object_symbol = String::cast(HEAP->Object_symbol());
183 CHECK(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000184 Isolate::Current()->context()->global_object()->HasLocalProperty(
185 object_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000186
187 // Check ToString for oddballs
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000188 CheckOddball(HEAP->true_value(), "true");
189 CheckOddball(HEAP->false_value(), "false");
190 CheckOddball(HEAP->null_value(), "null");
191 CheckOddball(HEAP->undefined_value(), "undefined");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000192
193 // Check ToString for Smis
194 CheckSmi(0, "0");
195 CheckSmi(42, "42");
196 CheckSmi(-42, "-42");
197
198 // Check ToString for Numbers
199 CheckNumber(1.1, "1.1");
200
201 CheckFindCodeObject();
202}
203
204
205TEST(Tagging) {
206 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000207 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000208 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000209 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000210 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000211 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000212 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000213 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000214 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000215 CHECK(Failure::Exception()->IsFailure());
216 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
217 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
218}
219
220
221TEST(GarbageCollection) {
222 InitializeVM();
223
224 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000225 // Check GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000226 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000227
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000228 Handle<String> name = FACTORY->LookupUtf8Symbol("theFunction");
229 Handle<String> prop_name = FACTORY->LookupUtf8Symbol("theSlot");
230 Handle<String> prop_namex = FACTORY->LookupUtf8Symbol("theSlotx");
231 Handle<String> obj_name = FACTORY->LookupUtf8Symbol("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000232
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000233 {
234 v8::HandleScope inner_scope;
235 // Allocate a function and keep it in global object's property.
236 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000238 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000239 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000240 function->set_initial_map(*initial_map);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000241 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000242 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000243 // Allocate an object. Unrooted after leaving the scope.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000244 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000245 obj->SetProperty(
246 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
247 obj->SetProperty(
248 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000249
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000250 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
251 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
252 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000253
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000254 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000255
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000256 // Function should be alive.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000257 CHECK(Isolate::Current()->context()->global_object()->
258 HasLocalProperty(*name));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000259 // Check function is retained.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000260 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000261 GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000262 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000263 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000264
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000265 {
266 HandleScope inner_scope;
267 // Allocate another object, make it reachable from global.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000268 Handle<JSObject> obj = FACTORY->NewJSObject(function);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000269 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000270 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
271 obj->SetProperty(
272 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000273 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000274
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000275 // After gc, it should survive.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000276 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000277
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000278 CHECK(Isolate::Current()->context()->global_object()->
279 HasLocalProperty(*obj_name));
280 CHECK(Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000281 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000282 Object* obj = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000283 GetProperty(*obj_name)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000284 JSObject* js_obj = JSObject::cast(obj);
285 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000286}
287
288
289static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000290 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000291 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000292 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000293 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000294 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
295 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000296}
297
298
299TEST(String) {
300 InitializeVM();
301
302 VerifyStringAllocation("a");
303 VerifyStringAllocation("ab");
304 VerifyStringAllocation("abc");
305 VerifyStringAllocation("abcd");
306 VerifyStringAllocation("fiskerdrengen er paa havet");
307}
308
309
310TEST(LocalHandles) {
311 InitializeVM();
312
313 v8::HandleScope scope;
314 const char* name = "Kasper the spunky";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000316 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000317}
318
319
320TEST(GlobalHandles) {
321 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000322 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000323
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000324 Handle<Object> h1;
325 Handle<Object> h2;
326 Handle<Object> h3;
327 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000328
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000329 {
330 HandleScope scope;
331
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000332 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
333 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000334
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000335 h1 = global_handles->Create(*i);
336 h2 = global_handles->Create(*u);
337 h3 = global_handles->Create(*i);
338 h4 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000339 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000340
341 // after gc, it should survive
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000342 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000343
344 CHECK((*h1)->IsString());
345 CHECK((*h2)->IsHeapNumber());
346 CHECK((*h3)->IsString());
347 CHECK((*h4)->IsHeapNumber());
348
349 CHECK_EQ(*h3, *h1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000350 global_handles->Destroy(h1.location());
351 global_handles->Destroy(h3.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000352
353 CHECK_EQ(*h4, *h2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000354 global_handles->Destroy(h2.location());
355 global_handles->Destroy(h4.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000356}
357
358
359static bool WeakPointerCleared = false;
360
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000361static void TestWeakGlobalHandleCallback(v8::Isolate* isolate,
362 v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000363 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000364 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000365 handle.Dispose(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000366}
367
368
369TEST(WeakGlobalHandlesScavenge) {
370 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000371 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000372
373 WeakPointerCleared = false;
374
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000375 Handle<Object> h1;
376 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000377
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000378 {
379 HandleScope scope;
380
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000381 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
382 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000383
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000384 h1 = global_handles->Create(*i);
385 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000386 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000387
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000388 global_handles->MakeWeak(h2.location(),
389 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000390 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000391 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000392
393 // Scavenge treats weak pointers as normal roots.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000394 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000395
396 CHECK((*h1)->IsString());
397 CHECK((*h2)->IsHeapNumber());
398
399 CHECK(!WeakPointerCleared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000400 CHECK(!global_handles->IsNearDeath(h2.location()));
401 CHECK(!global_handles->IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000402
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000403 global_handles->Destroy(h1.location());
404 global_handles->Destroy(h2.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000405}
406
407
408TEST(WeakGlobalHandlesMark) {
409 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000410 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000411
412 WeakPointerCleared = false;
413
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000414 Handle<Object> h1;
415 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000416
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000417 {
418 HandleScope scope;
419
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000420 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
421 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000422
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000423 h1 = global_handles->Create(*i);
424 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000425 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000426
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000427 // Make sure the objects are promoted.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000428 HEAP->CollectGarbage(OLD_POINTER_SPACE);
429 HEAP->CollectGarbage(NEW_SPACE);
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000430 CHECK(!HEAP->InNewSpace(*h1) && !HEAP->InNewSpace(*h2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000431
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000432 global_handles->MakeWeak(h2.location(),
433 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000434 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000436 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
437 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
438
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000439 // Incremental marking potentially marked handles before they turned weak.
440 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000441
442 CHECK((*h1)->IsString());
443
444 CHECK(WeakPointerCleared);
445 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000446
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 global_handles->Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000448}
449
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000450
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000451TEST(DeleteWeakGlobalHandle) {
452 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000453 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000454
455 WeakPointerCleared = false;
456
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000457 Handle<Object> h;
458
459 {
460 HandleScope scope;
461
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
463 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000464 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000465
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 global_handles->MakeWeak(h.location(),
467 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000468 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000469 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000470
471 // Scanvenge does not recognize weak reference.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000472 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000473
474 CHECK(!WeakPointerCleared);
475
476 // Mark-compact treats weak reference properly.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000477 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000478
479 CHECK(WeakPointerCleared);
480}
481
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000482
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000483static const char* not_so_random_string_table[] = {
484 "abstract",
485 "boolean",
486 "break",
487 "byte",
488 "case",
489 "catch",
490 "char",
491 "class",
492 "const",
493 "continue",
494 "debugger",
495 "default",
496 "delete",
497 "do",
498 "double",
499 "else",
500 "enum",
501 "export",
502 "extends",
503 "false",
504 "final",
505 "finally",
506 "float",
507 "for",
508 "function",
509 "goto",
510 "if",
511 "implements",
512 "import",
513 "in",
514 "instanceof",
515 "int",
516 "interface",
517 "long",
518 "native",
519 "new",
520 "null",
521 "package",
522 "private",
523 "protected",
524 "public",
525 "return",
526 "short",
527 "static",
528 "super",
529 "switch",
530 "synchronized",
531 "this",
532 "throw",
533 "throws",
534 "transient",
535 "true",
536 "try",
537 "typeof",
538 "var",
539 "void",
540 "volatile",
541 "while",
542 "with",
543 0
544};
545
546
547static void CheckSymbols(const char** strings) {
548 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000549 Object* a;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000550 MaybeObject* maybe_a = HEAP->LookupUtf8Symbol(string);
551 // LookupUtf8Symbol may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000552 if (!maybe_a->ToObject(&a)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000553 CHECK(a->IsSymbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000554 Object* b;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000555 MaybeObject* maybe_b = HEAP->LookupUtf8Symbol(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000556 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000557 CHECK_EQ(b, a);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000558 CHECK(String::cast(b)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000559 }
560}
561
562
563TEST(SymbolTable) {
564 InitializeVM();
565
566 CheckSymbols(not_so_random_string_table);
567 CheckSymbols(not_so_random_string_table);
568}
569
570
571TEST(FunctionAllocation) {
572 InitializeVM();
573
574 v8::HandleScope sc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000575 Handle<String> name = FACTORY->LookupUtf8Symbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000576 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000577 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000578 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000580 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000581
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000582 Handle<String> prop_name = FACTORY->LookupUtf8Symbol("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000584 obj->SetProperty(
585 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000586 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000587 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000588 function->SetProperty(
589 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000590 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000591}
592
593
594TEST(ObjectProperties) {
595 InitializeVM();
596
597 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000599 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000601 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000602 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000603 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000604 Handle<String> first = FACTORY->LookupUtf8Symbol("first");
605 Handle<String> second = FACTORY->LookupUtf8Symbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000606
607 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000608 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000609
610 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000611 obj->SetProperty(
612 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000613 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000614
615 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000616 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
617 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000618
619 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000620 obj->SetProperty(
621 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
622 obj->SetProperty(
623 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000624 CHECK(obj->HasLocalProperty(*first));
625 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000626
627 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000628 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
629 CHECK(obj->HasLocalProperty(*second));
630 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
631 CHECK(!obj->HasLocalProperty(*first));
632 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000633
634 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000635 obj->SetProperty(
636 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
637 obj->SetProperty(
638 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000639 CHECK(obj->HasLocalProperty(*first));
640 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000641
642 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000643 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
644 CHECK(obj->HasLocalProperty(*first));
645 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
646 CHECK(!obj->HasLocalProperty(*first));
647 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000648
649 // check string and symbol match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000650 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000651 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000652 obj->SetProperty(
653 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000654 Handle<String> s1_symbol = FACTORY->LookupUtf8Symbol(string1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000655 CHECK(obj->HasLocalProperty(*s1_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000656
657 // check symbol and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000658 const char* string2 = "fugl";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000659 Handle<String> s2_symbol = FACTORY->LookupUtf8Symbol(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000660 obj->SetProperty(
661 *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000662 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000663 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000664}
665
666
667TEST(JSObjectMaps) {
668 InitializeVM();
669
670 v8::HandleScope sc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000671 Handle<String> name = FACTORY->LookupUtf8Symbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000672 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000673 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000674 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000675 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000676 function->set_initial_map(*initial_map);
677
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000678 Handle<String> prop_name = FACTORY->LookupUtf8Symbol("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000679 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000680
681 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000682 obj->SetProperty(
683 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000684 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000685
686 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000687 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000688}
689
690
691TEST(JSArray) {
692 InitializeVM();
693
694 v8::HandleScope sc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000695 Handle<String> name = FACTORY->LookupUtf8Symbol("Array");
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000696 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000697 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000698 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000699 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000700
701 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000702 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000703 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000704 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000705 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000706
707 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000708 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000709 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000710 // Must be in fast mode.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000711 CHECK(array->HasFastSmiOrObjectElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000712
713 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000714 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000715 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000716 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000717
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000718 // Set array length with larger than smi value.
719 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000720 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000721 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000722
723 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000724 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000725 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000726 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000727
728 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000729 array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000730 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000731 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000732 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000733 CHECK_EQ(array->GetElement(int_length), *name);
734 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000735}
736
737
738TEST(JSObjectCopy) {
739 InitializeVM();
740
741 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000742 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000743 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000744 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000745 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000746 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000747 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000748 Handle<String> first = FACTORY->LookupUtf8Symbol("first");
749 Handle<String> second = FACTORY->LookupUtf8Symbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000750
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000751 obj->SetProperty(
752 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
753 obj->SetProperty(
754 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000755
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000756 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
757 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000758
759 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000760 Handle<JSObject> clone = Copy(obj);
761 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000762
763 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
764 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
765
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000766 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
767 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000768
769 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000770 clone->SetProperty(
771 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
772 clone->SetProperty(
773 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000774
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000775 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
776 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000777
778 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
779 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
780
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000781 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
782 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000783}
784
785
786TEST(StringAllocation) {
787 InitializeVM();
788
789
790 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
791 for (int length = 0; length < 100; length++) {
792 v8::HandleScope scope;
793 char* non_ascii = NewArray<char>(3 * length + 1);
794 char* ascii = NewArray<char>(length + 1);
795 non_ascii[3 * length] = 0;
796 ascii[length] = 0;
797 for (int i = 0; i < length; i++) {
798 ascii[i] = 'a';
799 non_ascii[3 * i] = chars[0];
800 non_ascii[3 * i + 1] = chars[1];
801 non_ascii[3 * i + 2] = chars[2];
802 }
803 Handle<String> non_ascii_sym =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000804 FACTORY->LookupUtf8Symbol(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000805 CHECK_EQ(length, non_ascii_sym->length());
806 Handle<String> ascii_sym =
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000807 FACTORY->LookupOneByteSymbol(OneByteVector(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000808 CHECK_EQ(length, ascii_sym->length());
809 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000810 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000811 non_ascii_str->Hash();
812 CHECK_EQ(length, non_ascii_str->length());
813 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000814 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000815 ascii_str->Hash();
816 CHECK_EQ(length, ascii_str->length());
817 DeleteArray(non_ascii);
818 DeleteArray(ascii);
819 }
820}
821
822
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000823static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000824 // Count the number of objects found in the heap.
825 int found_count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000826 HeapIterator iterator(heap);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000827 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000828 for (int i = 0; i < size; i++) {
829 if (*objs[i] == obj) {
830 found_count++;
831 }
832 }
833 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000834 return found_count;
835}
836
837
838TEST(Iteration) {
839 InitializeVM();
840 v8::HandleScope scope;
841
842 // Array of objects to scan haep for.
843 const int objs_count = 6;
844 Handle<Object> objs[objs_count];
845 int next_objs_index = 0;
846
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000847 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000848 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000849 objs[next_objs_index++] = FACTORY->NewJSArray(10,
850 FAST_HOLEY_ELEMENTS,
851 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000852
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000853 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000854 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000855 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000856 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000857 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000858
859 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000860 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000861 char* str = new char[large_size];
862 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
863 str[large_size - 1] = '\0';
864 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000865 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000866 delete[] str;
867
868 // Add a Map object to look for.
869 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
870
871 CHECK_EQ(objs_count, next_objs_index);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000872 CHECK_EQ(objs_count, ObjectsFoundInHeap(HEAP, objs, objs_count));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000873}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000874
875
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000876TEST(EmptyHandleEscapeFrom) {
877 InitializeVM();
878
879 v8::HandleScope scope;
880 Handle<JSObject> runaway;
881
882 {
883 v8::HandleScope nested;
884 Handle<JSObject> empty;
885 runaway = empty.EscapeFrom(&nested);
886 }
887
888 CHECK(runaway.is_null());
889}
890
891
892static int LenFromSize(int size) {
893 return (size - FixedArray::kHeaderSize) / kPointerSize;
894}
895
896
897TEST(Regression39128) {
898 // Test case for crbug.com/39128.
899 InitializeVM();
900
901 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000902 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000903
904 v8::HandleScope scope;
905
906 // The plan: create JSObject which references objects in new space.
907 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000908 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000909
910 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000911 Handle<JSFunction> object_ctor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000912 Isolate::Current()->native_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000913 CHECK(object_ctor->has_initial_map());
914 Handle<Map> object_map(object_ctor->initial_map());
915 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000916 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000917 int n_properties = my_map->inobject_properties();
918 CHECK_GT(n_properties, 0);
919
920 int object_size = my_map->instance_size();
921
922 // Step 2: allocate a lot of objects so to almost fill new space: we need
923 // just enough room to allocate JSObject and thus fill the newspace.
924
925 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000926 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000927 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000929 Address* top_addr = new_space->allocation_top_address();
930 Address* limit_addr = new_space->allocation_limit_address();
931 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 CHECK(!HEAP->always_allocate());
933 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
934 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000935 CHECK(new_space->Contains(array));
936 }
937
938 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000939 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000940 int fixed_array_len = LenFromSize(to_fill);
941 CHECK(fixed_array_len < FixedArray::kMaxLength);
942
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000943 CHECK(!HEAP->always_allocate());
944 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
945 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000946 CHECK(new_space->Contains(array));
947
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000948 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000949 CHECK(new_space->Contains(object));
950 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000951 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000952 CHECK_EQ(0, jsobject->properties()->length());
953 // Create a reference to object in new space in jsobject.
954 jsobject->FastPropertyAtPut(-1, array);
955
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000956 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000957
958 // Step 4: clone jsobject, but force always allocate first to create a clone
959 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000960 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000961 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000962 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000963 JSObject* clone = JSObject::cast(clone_obj);
964 if (clone->address() != old_pointer_space_top) {
965 // Alas, got allocated from free list, we cannot do checks.
966 return;
967 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000969}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000970
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000971
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000972TEST(TestCodeFlushing) {
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000973 // If we do not flush code this test is invalid.
974 if (!FLAG_flush_code) return;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000975 i::FLAG_allow_natives_syntax = true;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000976 InitializeVM();
977 v8::HandleScope scope;
978 const char* source = "function foo() {"
979 " var x = 42;"
980 " var y = 42;"
981 " var z = x + y;"
982 "};"
983 "foo()";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000984 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000985
986 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000987 { v8::HandleScope scope;
988 CompileRun(source);
989 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000990
991 // Check function is compiled.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000992 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000993 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000994 CHECK(func_value->IsJSFunction());
995 Handle<JSFunction> function(JSFunction::cast(func_value));
996 CHECK(function->shared()->is_compiled());
997
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000998 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000999 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1000 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001001 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001002
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001003 // Simulate several GCs that use full marking.
1004 const int kAgingThreshold = 6;
1005 for (int i = 0; i < kAgingThreshold; i++) {
1006 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1007 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001008
1009 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001010 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1011 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001012 // Call foo to get it recompiled.
1013 CompileRun("foo()");
1014 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001015 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001016}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001017
1018
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001019TEST(TestCodeFlushingIncremental) {
1020 // If we do not flush code this test is invalid.
1021 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1022 i::FLAG_allow_natives_syntax = true;
1023 InitializeVM();
1024 v8::HandleScope scope;
1025 const char* source = "function foo() {"
1026 " var x = 42;"
1027 " var y = 42;"
1028 " var z = x + y;"
1029 "};"
1030 "foo()";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001031 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001032
1033 // This compile will add the code to the compilation cache.
1034 { v8::HandleScope scope;
1035 CompileRun(source);
1036 }
1037
1038 // Check function is compiled.
1039 Object* func_value = Isolate::Current()->context()->global_object()->
1040 GetProperty(*foo_name)->ToObjectChecked();
1041 CHECK(func_value->IsJSFunction());
1042 Handle<JSFunction> function(JSFunction::cast(func_value));
1043 CHECK(function->shared()->is_compiled());
1044
1045 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001046 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1047 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001048 CHECK(function->shared()->is_compiled());
1049
1050 // Simulate several GCs that use incremental marking.
1051 const int kAgingThreshold = 6;
1052 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001053 SimulateIncrementalMarking();
1054 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1055 }
1056 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1057 CHECK(!function->is_compiled() || function->IsOptimized());
1058
1059 // This compile will compile the function again.
1060 { v8::HandleScope scope;
1061 CompileRun("foo();");
1062 }
1063
1064 // Simulate several GCs that use incremental marking but make sure
1065 // the loop breaks once the function is enqueued as a candidate.
1066 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001067 SimulateIncrementalMarking();
1068 if (!function->next_function_link()->IsUndefined()) break;
1069 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1070 }
1071
1072 // Force optimization while incremental marking is active and while
1073 // the function is enqueued as a candidate.
1074 { v8::HandleScope scope;
1075 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1076 }
1077
1078 // Simulate one final GC to make sure the candidate queue is sane.
1079 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1080 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1081 CHECK(function->is_compiled() || !function->IsOptimized());
1082}
1083
1084
1085TEST(TestCodeFlushingIncrementalScavenge) {
1086 // If we do not flush code this test is invalid.
1087 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1088 i::FLAG_allow_natives_syntax = true;
1089 InitializeVM();
1090 v8::HandleScope scope;
1091 const char* source = "var foo = function() {"
1092 " var x = 42;"
1093 " var y = 42;"
1094 " var z = x + y;"
1095 "};"
1096 "foo();"
1097 "var bar = function() {"
1098 " var x = 23;"
1099 "};"
1100 "bar();";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001101 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
1102 Handle<String> bar_name = FACTORY->LookupUtf8Symbol("bar");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001103
1104 // Perfrom one initial GC to enable code flushing.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001105 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001106
1107 // This compile will add the code to the compilation cache.
1108 { v8::HandleScope scope;
1109 CompileRun(source);
1110 }
1111
1112 // Check functions are compiled.
1113 Object* func_value = Isolate::Current()->context()->global_object()->
1114 GetProperty(*foo_name)->ToObjectChecked();
1115 CHECK(func_value->IsJSFunction());
1116 Handle<JSFunction> function(JSFunction::cast(func_value));
1117 CHECK(function->shared()->is_compiled());
1118 Object* func_value2 = Isolate::Current()->context()->global_object()->
1119 GetProperty(*bar_name)->ToObjectChecked();
1120 CHECK(func_value2->IsJSFunction());
1121 Handle<JSFunction> function2(JSFunction::cast(func_value2));
1122 CHECK(function2->shared()->is_compiled());
1123
1124 // Clear references to functions so that one of them can die.
1125 { v8::HandleScope scope;
1126 CompileRun("foo = 0; bar = 0;");
1127 }
1128
1129 // Bump the code age so that flushing is triggered while the function
1130 // object is still located in new-space.
1131 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001132 for (int i = 0; i < kAgingThreshold; i++) {
1133 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1134 function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1135 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001136
1137 // Simulate incremental marking so that the functions are enqueued as
1138 // code flushing candidates. Then kill one of the functions. Finally
1139 // perform a scavenge while incremental marking is still running.
1140 SimulateIncrementalMarking();
1141 *function2.location() = NULL;
1142 HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking");
1143
1144 // Simulate one final GC to make sure the candidate queue is sane.
1145 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1146 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1147 CHECK(!function->is_compiled() || function->IsOptimized());
1148}
1149
1150
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001151TEST(TestCodeFlushingIncrementalAbort) {
1152 // If we do not flush code this test is invalid.
1153 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1154 i::FLAG_allow_natives_syntax = true;
1155 InitializeVM();
1156 v8::HandleScope scope;
1157 const char* source = "function foo() {"
1158 " var x = 42;"
1159 " var y = 42;"
1160 " var z = x + y;"
1161 "};"
1162 "foo()";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001163 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001164
1165 // This compile will add the code to the compilation cache.
1166 { v8::HandleScope scope;
1167 CompileRun(source);
1168 }
1169
1170 // Check function is compiled.
1171 Object* func_value = Isolate::Current()->context()->global_object()->
1172 GetProperty(*foo_name)->ToObjectChecked();
1173 CHECK(func_value->IsJSFunction());
1174 Handle<JSFunction> function(JSFunction::cast(func_value));
1175 CHECK(function->shared()->is_compiled());
1176
1177 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001178 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1179 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001180 CHECK(function->shared()->is_compiled());
1181
1182 // Bump the code age so that flushing is triggered.
1183 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001184 for (int i = 0; i < kAgingThreshold; i++) {
1185 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1186 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001187
1188 // Simulate incremental marking so that the function is enqueued as
1189 // code flushing candidate.
1190 SimulateIncrementalMarking();
1191
1192 // Enable the debugger and add a breakpoint while incremental marking
1193 // is running so that incremental marking aborts and code flushing is
1194 // disabled.
1195 int position = 0;
1196 Handle<Object> breakpoint_object(Smi::FromInt(0));
1197 ISOLATE->debug()->SetBreakPoint(function, breakpoint_object, &position);
1198 ISOLATE->debug()->ClearAllBreakPoints();
1199
1200 // Force optimization now that code flushing is disabled.
1201 { v8::HandleScope scope;
1202 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1203 }
1204
1205 // Simulate one final GC to make sure the candidate queue is sane.
1206 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1207 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1208 CHECK(function->is_compiled() || !function->IsOptimized());
1209}
1210
1211
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001212// Count the number of native contexts in the weak list of native contexts.
1213int CountNativeContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001214 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001215 Object* object = HEAP->native_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001216 while (!object->IsUndefined()) {
1217 count++;
1218 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1219 }
1220 return count;
1221}
1222
1223
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001224// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001225// functions attached to a native context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001226static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1227 int count = 0;
1228 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1229 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1230 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1231 count++;
1232 object = JSFunction::cast(object)->next_function_link();
1233 }
1234 return count;
1235}
1236
1237
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001238TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001239 v8::V8::Initialize();
1240
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001241 // Some flags turn Scavenge collections into Mark-sweep collections
1242 // and hence are incompatible with this test case.
1243 if (FLAG_gc_global || FLAG_stress_compaction) return;
1244
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001245 static const int kNumTestContexts = 10;
1246
1247 v8::HandleScope scope;
1248 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1249
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001250 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001251
1252 // Create a number of global contests which gets linked together.
1253 for (int i = 0; i < kNumTestContexts; i++) {
1254 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001255
1256 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1257
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001258 CHECK_EQ(i + 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001259
1260 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001261
1262 // Create a handle scope so no function objects get stuch in the outer
1263 // handle scope
1264 v8::HandleScope scope;
1265 const char* source = "function f1() { };"
1266 "function f2() { };"
1267 "function f3() { };"
1268 "function f4() { };"
1269 "function f5() { };";
1270 CompileRun(source);
1271 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1272 CompileRun("f1()");
1273 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1274 CompileRun("f2()");
1275 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1276 CompileRun("f3()");
1277 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1278 CompileRun("f4()");
1279 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1280 CompileRun("f5()");
1281 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1282
1283 // Remove function f1, and
1284 CompileRun("f1=null");
1285
1286 // Scavenge treats these references as strong.
1287 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001288 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001289 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1290 }
1291
1292 // Mark compact handles the weak references.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001293 ISOLATE->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001294 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001295 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1296
1297 // Get rid of f3 and f5 in the same way.
1298 CompileRun("f3=null");
1299 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001300 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001301 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1302 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001303 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001304 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1305 CompileRun("f5=null");
1306 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001307 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001308 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1309 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001310 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001311 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1312
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001313 ctx[i]->Exit();
1314 }
1315
1316 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001317 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001318
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001319 // Dispose the native contexts one by one.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001320 for (int i = 0; i < kNumTestContexts; i++) {
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001321 ctx[i].Dispose(ctx[i]->GetIsolate());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001322 ctx[i].Clear();
1323
1324 // Scavenge treats these references as strong.
1325 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 HEAP->PerformScavenge();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001327 CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001328 }
1329
1330 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001331 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001332 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001333 }
1334
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001335 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001336}
1337
1338
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001339// Count the number of native contexts in the weak list of native contexts
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001340// causing a GC after the specified number of elements.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001341static int CountNativeContextsWithGC(int n) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001342 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001343 Handle<Object> object(HEAP->native_contexts_list());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001344 while (!object->IsUndefined()) {
1345 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001346 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001347 object =
1348 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1349 }
1350 return count;
1351}
1352
1353
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001354// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001355// functions attached to a native context causing a GC after the
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001356// specified number of elements.
1357static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1358 int n) {
1359 int count = 0;
1360 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1361 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1362 while (object->IsJSFunction() &&
1363 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1364 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001365 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001366 object = Handle<Object>(
1367 Object::cast(JSFunction::cast(*object)->next_function_link()));
1368 }
1369 return count;
1370}
1371
1372
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001373TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001374 v8::V8::Initialize();
1375
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001376 static const int kNumTestContexts = 10;
1377
1378 v8::HandleScope scope;
1379 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1380
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001381 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001382
1383 // Create an number of contexts and check the length of the weak list both
1384 // with and without GCs while iterating the list.
1385 for (int i = 0; i < kNumTestContexts; i++) {
1386 ctx[i] = v8::Context::New();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001387 CHECK_EQ(i + 1, CountNativeContexts());
1388 CHECK_EQ(i + 1, CountNativeContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001389 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001390
1391 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1392
1393 // Compile a number of functions the length of the weak list of optimized
1394 // functions both with and without GCs while iterating the list.
1395 ctx[0]->Enter();
1396 const char* source = "function f1() { };"
1397 "function f2() { };"
1398 "function f3() { };"
1399 "function f4() { };"
1400 "function f5() { };";
1401 CompileRun(source);
1402 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1403 CompileRun("f1()");
1404 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1405 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1406 CompileRun("f2()");
1407 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1408 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1409 CompileRun("f3()");
1410 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1411 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1412 CompileRun("f4()");
1413 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1414 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1415 CompileRun("f5()");
1416 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1417 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1418
1419 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001420}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001421
1422
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001423TEST(TestSizeOfObjects) {
1424 v8::V8::Initialize();
1425
1426 // Get initial heap size after several full GCs, which will stabilize
1427 // the heap size and return with sweeping finished completely.
1428 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1429 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1430 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1431 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001432 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001433 CHECK(HEAP->old_pointer_space()->IsLazySweepingComplete());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001434 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1435
1436 {
1437 // Allocate objects on several different old-space pages so that
1438 // lazy sweeping kicks in for subsequent GC runs.
1439 AlwaysAllocateScope always_allocate;
1440 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1441 for (int i = 1; i <= 100; i++) {
1442 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1443 CHECK_EQ(initial_size + i * filler_size,
1444 static_cast<int>(HEAP->SizeOfObjects()));
1445 }
1446 }
1447
1448 // The heap size should go back to initial size after a full GC, even
1449 // though sweeping didn't finish yet.
1450 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001451
1452 // Normally sweeping would not be complete here, but no guarantees.
1453
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001454 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1455
1456 // Advancing the sweeper step-wise should not change the heap size.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001457 while (!HEAP->old_pointer_space()->IsLazySweepingComplete()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001458 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1459 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1460 }
1461}
1462
1463
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001464TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1465 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001466 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001467 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001468 HeapIterator iterator(HEAP);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001469 intptr_t size_of_objects_2 = 0;
1470 for (HeapObject* obj = iterator.next();
1471 obj != NULL;
1472 obj = iterator.next()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001473 if (!obj->IsFreeSpace()) {
1474 size_of_objects_2 += obj->Size();
1475 }
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001476 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001477 // Delta must be within 5% of the larger result.
1478 // TODO(gc): Tighten this up by distinguishing between byte
1479 // arrays that are real and those that merely mark free space
1480 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001481 if (size_of_objects_1 > size_of_objects_2) {
1482 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1483 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1484 "Iterator: %" V8_PTR_PREFIX "d, "
1485 "delta: %" V8_PTR_PREFIX "d\n",
1486 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001487 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001488 } else {
1489 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1490 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1491 "Iterator: %" V8_PTR_PREFIX "d, "
1492 "delta: %" V8_PTR_PREFIX "d\n",
1493 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001494 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001495 }
1496}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001497
1498
danno@chromium.orgc612e022011-11-10 11:38:15 +00001499static void FillUpNewSpace(NewSpace* new_space) {
1500 // Fill up new space to the point that it is completely full. Make sure
1501 // that the scavenger does not undo the filling.
1502 v8::HandleScope scope;
1503 AlwaysAllocateScope always_allocate;
1504 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001505 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001506 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001507 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001508 }
1509}
1510
1511
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001512TEST(GrowAndShrinkNewSpace) {
1513 InitializeVM();
1514 NewSpace* new_space = HEAP->new_space();
1515
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001516 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1517 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001518 // The max size cannot exceed the reserved size, since semispaces must be
1519 // always within the reserved space. We can't test new space growing and
1520 // shrinking if the reserved size is the same as the minimum (initial) size.
1521 return;
1522 }
1523
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001524 // Explicitly growing should double the space capacity.
1525 intptr_t old_capacity, new_capacity;
1526 old_capacity = new_space->Capacity();
1527 new_space->Grow();
1528 new_capacity = new_space->Capacity();
1529 CHECK(2 * old_capacity == new_capacity);
1530
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001531 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001532 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001533 new_capacity = new_space->Capacity();
1534 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001535
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001536 // Explicitly shrinking should not affect space capacity.
1537 old_capacity = new_space->Capacity();
1538 new_space->Shrink();
1539 new_capacity = new_space->Capacity();
1540 CHECK(old_capacity == new_capacity);
1541
1542 // Let the scavenger empty the new space.
1543 HEAP->CollectGarbage(NEW_SPACE);
1544 CHECK_LE(new_space->Size(), old_capacity);
1545
1546 // Explicitly shrinking should halve the space capacity.
1547 old_capacity = new_space->Capacity();
1548 new_space->Shrink();
1549 new_capacity = new_space->Capacity();
1550 CHECK(old_capacity == 2 * new_capacity);
1551
1552 // Consecutive shrinking should not affect space capacity.
1553 old_capacity = new_space->Capacity();
1554 new_space->Shrink();
1555 new_space->Shrink();
1556 new_space->Shrink();
1557 new_capacity = new_space->Capacity();
1558 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001559}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001560
1561
1562TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1563 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001564
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001565 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1566 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001567 // The max size cannot exceed the reserved size, since semispaces must be
1568 // always within the reserved space. We can't test new space growing and
1569 // shrinking if the reserved size is the same as the minimum (initial) size.
1570 return;
1571 }
1572
danno@chromium.orgc612e022011-11-10 11:38:15 +00001573 v8::HandleScope scope;
1574 NewSpace* new_space = HEAP->new_space();
1575 intptr_t old_capacity, new_capacity;
1576 old_capacity = new_space->Capacity();
1577 new_space->Grow();
1578 new_capacity = new_space->Capacity();
1579 CHECK(2 * old_capacity == new_capacity);
1580 FillUpNewSpace(new_space);
1581 HEAP->CollectAllAvailableGarbage();
1582 new_capacity = new_space->Capacity();
1583 CHECK(old_capacity == new_capacity);
1584}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001585
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001586
1587static int NumberOfGlobalObjects() {
1588 int count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001589 HeapIterator iterator(HEAP);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001590 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1591 if (obj->IsGlobalObject()) count++;
1592 }
1593 return count;
1594}
1595
1596
1597// Test that we don't embed maps from foreign contexts into
1598// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001599TEST(LeakNativeContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001600 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001601 v8::HandleScope outer_scope;
1602 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1603 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1604 ctx1->Enter();
1605
1606 HEAP->CollectAllAvailableGarbage();
1607 CHECK_EQ(4, NumberOfGlobalObjects());
1608
1609 {
1610 v8::HandleScope inner_scope;
1611 CompileRun("var v = {x: 42}");
1612 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1613 ctx2->Enter();
1614 ctx2->Global()->Set(v8_str("o"), v);
1615 v8::Local<v8::Value> res = CompileRun(
1616 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001617 "for (var i = 0; i < 10; ++i) f();"
1618 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001619 "f();");
1620 CHECK_EQ(42, res->Int32Value());
1621 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1622 ctx2->Exit();
1623 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001624 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001625 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001626 }
1627 HEAP->CollectAllAvailableGarbage();
1628 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001629 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001630 HEAP->CollectAllAvailableGarbage();
1631 CHECK_EQ(0, NumberOfGlobalObjects());
1632}
1633
1634
1635// Test that we don't embed functions from foreign contexts into
1636// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001637TEST(LeakNativeContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001638 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001639 v8::HandleScope outer_scope;
1640 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1641 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1642 ctx1->Enter();
1643
1644 HEAP->CollectAllAvailableGarbage();
1645 CHECK_EQ(4, NumberOfGlobalObjects());
1646
1647 {
1648 v8::HandleScope inner_scope;
1649 CompileRun("var v = function() { return 42; }");
1650 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1651 ctx2->Enter();
1652 ctx2->Global()->Set(v8_str("o"), v);
1653 v8::Local<v8::Value> res = CompileRun(
1654 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001655 "for (var i = 0; i < 10; ++i) f(o);"
1656 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001657 "f(o);");
1658 CHECK_EQ(42, res->Int32Value());
1659 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1660 ctx2->Exit();
1661 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001662 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001663 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001664 }
1665 HEAP->CollectAllAvailableGarbage();
1666 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001667 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001668 HEAP->CollectAllAvailableGarbage();
1669 CHECK_EQ(0, NumberOfGlobalObjects());
1670}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001671
1672
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001673TEST(LeakNativeContextViaMapKeyed) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001674 i::FLAG_allow_natives_syntax = true;
1675 v8::HandleScope outer_scope;
1676 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1677 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1678 ctx1->Enter();
1679
1680 HEAP->CollectAllAvailableGarbage();
1681 CHECK_EQ(4, NumberOfGlobalObjects());
1682
1683 {
1684 v8::HandleScope inner_scope;
1685 CompileRun("var v = [42, 43]");
1686 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1687 ctx2->Enter();
1688 ctx2->Global()->Set(v8_str("o"), v);
1689 v8::Local<v8::Value> res = CompileRun(
1690 "function f() { return o[0]; }"
1691 "for (var i = 0; i < 10; ++i) f();"
1692 "%OptimizeFunctionOnNextCall(f);"
1693 "f();");
1694 CHECK_EQ(42, res->Int32Value());
1695 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1696 ctx2->Exit();
1697 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001698 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001699 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001700 }
1701 HEAP->CollectAllAvailableGarbage();
1702 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001703 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001704 HEAP->CollectAllAvailableGarbage();
1705 CHECK_EQ(0, NumberOfGlobalObjects());
1706}
1707
1708
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001709TEST(LeakNativeContextViaMapProto) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001710 i::FLAG_allow_natives_syntax = true;
1711 v8::HandleScope outer_scope;
1712 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1713 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1714 ctx1->Enter();
1715
1716 HEAP->CollectAllAvailableGarbage();
1717 CHECK_EQ(4, NumberOfGlobalObjects());
1718
1719 {
1720 v8::HandleScope inner_scope;
1721 CompileRun("var v = { y: 42}");
1722 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1723 ctx2->Enter();
1724 ctx2->Global()->Set(v8_str("o"), v);
1725 v8::Local<v8::Value> res = CompileRun(
1726 "function f() {"
1727 " var p = {x: 42};"
1728 " p.__proto__ = o;"
1729 " return p.x;"
1730 "}"
1731 "for (var i = 0; i < 10; ++i) f();"
1732 "%OptimizeFunctionOnNextCall(f);"
1733 "f();");
1734 CHECK_EQ(42, res->Int32Value());
1735 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1736 ctx2->Exit();
1737 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001738 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001739 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001740 }
1741 HEAP->CollectAllAvailableGarbage();
1742 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001743 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001744 HEAP->CollectAllAvailableGarbage();
1745 CHECK_EQ(0, NumberOfGlobalObjects());
1746}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001747
1748
1749TEST(InstanceOfStubWriteBarrier) {
1750 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001751#ifdef VERIFY_HEAP
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001752 i::FLAG_verify_heap = true;
1753#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001754
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001755 InitializeVM();
1756 if (!i::V8::UseCrankshaft()) return;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001757 if (i::FLAG_force_marking_deque_overflows) return;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001758 v8::HandleScope outer_scope;
1759
1760 {
1761 v8::HandleScope scope;
1762 CompileRun(
1763 "function foo () { }"
1764 "function mkbar () { return new (new Function(\"\")) (); }"
1765 "function f (x) { return (x instanceof foo); }"
1766 "function g () { f(mkbar()); }"
1767 "f(new foo()); f(new foo());"
1768 "%OptimizeFunctionOnNextCall(f);"
1769 "f(new foo()); g();");
1770 }
1771
1772 IncrementalMarking* marking = HEAP->incremental_marking();
1773 marking->Abort();
1774 marking->Start();
1775
1776 Handle<JSFunction> f =
1777 v8::Utils::OpenHandle(
1778 *v8::Handle<v8::Function>::Cast(
1779 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1780
1781 CHECK(f->IsOptimized());
1782
1783 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1784 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001785 // Discard any pending GC requests otherwise we will get GC when we enter
1786 // code below.
1787 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001788 }
1789
1790 CHECK(marking->IsMarking());
1791
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001792 {
1793 v8::HandleScope scope;
1794 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1795 v8::Handle<v8::Function> g =
1796 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1797 g->Call(global, 0, NULL);
1798 }
1799
1800 HEAP->incremental_marking()->set_should_hurry(true);
1801 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1802}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001803
1804
1805TEST(PrototypeTransitionClearing) {
1806 InitializeVM();
1807 v8::HandleScope scope;
1808
1809 CompileRun(
1810 "var base = {};"
1811 "var live = [];"
1812 "for (var i = 0; i < 10; i++) {"
1813 " var object = {};"
1814 " var prototype = {};"
1815 " object.__proto__ = prototype;"
1816 " if (i >= 3) live.push(object, prototype);"
1817 "}");
1818
1819 Handle<JSObject> baseObject =
1820 v8::Utils::OpenHandle(
1821 *v8::Handle<v8::Object>::Cast(
1822 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1823
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001824 // Verify that only dead prototype transitions are cleared.
1825 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001826 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001827 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001828 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001829
1830 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001831 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001832 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001833 int j = Map::kProtoTransitionHeaderSize +
1834 i * Map::kProtoTransitionElementsPerEntry;
1835 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001836 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1837 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001838 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001839
1840 // Make sure next prototype is placed on an old-space evacuation candidate.
1841 Handle<JSObject> prototype;
1842 PagedSpace* space = HEAP->old_pointer_space();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001843 {
1844 AlwaysAllocateScope always_allocate;
1845 SimulateFullSpace(space);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001846 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001847 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001848
1849 // Add a prototype on an evacuation candidate and verify that transition
1850 // clearing correctly records slots in prototype transition array.
1851 i::FLAG_always_compact = true;
1852 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001853 CHECK(!space->LastPage()->Contains(
1854 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001855 CHECK(space->LastPage()->Contains(prototype->address()));
1856 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1857 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1858 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1859 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001860}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001861
1862
1863TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1864 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001865#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001866 i::FLAG_verify_heap = true;
1867#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001868
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001869 InitializeVM();
1870 if (!i::V8::UseCrankshaft()) return;
1871 v8::HandleScope outer_scope;
1872
1873 {
1874 v8::HandleScope scope;
1875 CompileRun(
1876 "function f () {"
1877 " var s = 0;"
1878 " for (var i = 0; i < 100; i++) s += i;"
1879 " return s;"
1880 "}"
1881 "f(); f();"
1882 "%OptimizeFunctionOnNextCall(f);"
1883 "f();");
1884 }
1885 Handle<JSFunction> f =
1886 v8::Utils::OpenHandle(
1887 *v8::Handle<v8::Function>::Cast(
1888 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1889 CHECK(f->IsOptimized());
1890
1891 IncrementalMarking* marking = HEAP->incremental_marking();
1892 marking->Abort();
1893 marking->Start();
1894
1895 // The following two calls will increment HEAP->global_ic_age().
1896 const int kLongIdlePauseInMs = 1000;
1897 v8::V8::ContextDisposedNotification();
1898 v8::V8::IdleNotification(kLongIdlePauseInMs);
1899
1900 while (!marking->IsStopped() && !marking->IsComplete()) {
1901 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1902 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001903 if (!marking->IsStopped() || marking->should_hurry()) {
1904 // We don't normally finish a GC via Step(), we normally finish by
1905 // setting the stack guard and then do the final steps in the stack
1906 // guard interrupt. But here we didn't ask for that, and there is no
1907 // JS code running to trigger the interrupt, so we explicitly finalize
1908 // here.
1909 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1910 "Test finalizing incremental mark-sweep");
1911 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001912
1913 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1914 CHECK_EQ(0, f->shared()->opt_count());
1915 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1916}
1917
1918
1919TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1920 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001921#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001922 i::FLAG_verify_heap = true;
1923#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001924
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001925 InitializeVM();
1926 if (!i::V8::UseCrankshaft()) return;
1927 v8::HandleScope outer_scope;
1928
1929 {
1930 v8::HandleScope scope;
1931 CompileRun(
1932 "function f () {"
1933 " var s = 0;"
1934 " for (var i = 0; i < 100; i++) s += i;"
1935 " return s;"
1936 "}"
1937 "f(); f();"
1938 "%OptimizeFunctionOnNextCall(f);"
1939 "f();");
1940 }
1941 Handle<JSFunction> f =
1942 v8::Utils::OpenHandle(
1943 *v8::Handle<v8::Function>::Cast(
1944 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1945 CHECK(f->IsOptimized());
1946
1947 HEAP->incremental_marking()->Abort();
1948
1949 // The following two calls will increment HEAP->global_ic_age().
1950 // Since incremental marking is off, IdleNotification will do full GC.
1951 const int kLongIdlePauseInMs = 1000;
1952 v8::V8::ContextDisposedNotification();
1953 v8::V8::IdleNotification(kLongIdlePauseInMs);
1954
1955 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1956 CHECK_EQ(0, f->shared()->opt_count());
1957 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1958}
1959
1960
1961// Test that HAllocateObject will always return an object in new-space.
1962TEST(OptimizedAllocationAlwaysInNewSpace) {
1963 i::FLAG_allow_natives_syntax = true;
1964 InitializeVM();
1965 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001966 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001967 v8::HandleScope scope;
1968
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001969 SimulateFullSpace(HEAP->new_space());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001970 AlwaysAllocateScope always_allocate;
1971 v8::Local<v8::Value> res = CompileRun(
1972 "function c(x) {"
1973 " this.x = x;"
1974 " for (var i = 0; i < 32; i++) {"
1975 " this['x' + i] = x;"
1976 " }"
1977 "}"
1978 "function f(x) { return new c(x); };"
1979 "f(1); f(2); f(3);"
1980 "%OptimizeFunctionOnNextCall(f);"
1981 "f(4);");
1982 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
1983
1984 Handle<JSObject> o =
1985 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
1986
1987 CHECK(HEAP->InNewSpace(*o));
1988}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001989
1990
1991static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001992 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001993}
1994
1995
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001996// Test that map transitions are cleared and maps are collected with
1997// incremental marking as well.
1998TEST(Regress1465) {
1999 i::FLAG_allow_natives_syntax = true;
2000 i::FLAG_trace_incremental_marking = true;
2001 InitializeVM();
2002 v8::HandleScope scope;
2003 static const int transitions_count = 256;
2004
2005 {
2006 AlwaysAllocateScope always_allocate;
2007 for (int i = 0; i < transitions_count; i++) {
2008 EmbeddedVector<char, 64> buffer;
2009 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
2010 CompileRun(buffer.start());
2011 }
2012 CompileRun("var root = new Object;");
2013 }
2014
2015 Handle<JSObject> root =
2016 v8::Utils::OpenHandle(
2017 *v8::Handle<v8::Object>::Cast(
2018 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2019
2020 // Count number of live transitions before marking.
2021 int transitions_before = CountMapTransitions(root->map());
2022 CompileRun("%DebugPrint(root);");
2023 CHECK_EQ(transitions_count, transitions_before);
2024
2025 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002026 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002027
2028 // Count number of live transitions after marking. Note that one transition
2029 // is left, because 'o' still holds an instance of one transition target.
2030 int transitions_after = CountMapTransitions(root->map());
2031 CompileRun("%DebugPrint(root);");
2032 CHECK_EQ(1, transitions_after);
2033}
verwaest@chromium.org37141392012-05-31 13:27:02 +00002034
2035
2036TEST(Regress2143a) {
2037 i::FLAG_collect_maps = true;
2038 i::FLAG_incremental_marking = true;
2039 InitializeVM();
2040 v8::HandleScope scope;
2041
2042 // Prepare a map transition from the root object together with a yet
2043 // untransitioned root object.
2044 CompileRun("var root = new Object;"
2045 "root.foo = 0;"
2046 "root = new Object;");
2047
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002048 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002049
2050 // Compile a StoreIC that performs the prepared map transition. This
2051 // will restart incremental marking and should make sure the root is
2052 // marked grey again.
2053 CompileRun("function f(o) {"
2054 " o.foo = 0;"
2055 "}"
2056 "f(new Object);"
2057 "f(root);");
2058
2059 // This bug only triggers with aggressive IC clearing.
2060 HEAP->AgeInlineCaches();
2061
2062 // Explicitly request GC to perform final marking step and sweeping.
2063 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002064
2065 Handle<JSObject> root =
2066 v8::Utils::OpenHandle(
2067 *v8::Handle<v8::Object>::Cast(
2068 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2069
2070 // The root object should be in a sane state.
2071 CHECK(root->IsJSObject());
2072 CHECK(root->map()->IsMap());
2073}
2074
2075
2076TEST(Regress2143b) {
2077 i::FLAG_collect_maps = true;
2078 i::FLAG_incremental_marking = true;
2079 i::FLAG_allow_natives_syntax = true;
2080 InitializeVM();
2081 v8::HandleScope scope;
2082
2083 // Prepare a map transition from the root object together with a yet
2084 // untransitioned root object.
2085 CompileRun("var root = new Object;"
2086 "root.foo = 0;"
2087 "root = new Object;");
2088
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002089 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002090
2091 // Compile an optimized LStoreNamedField that performs the prepared
2092 // map transition. This will restart incremental marking and should
2093 // make sure the root is marked grey again.
2094 CompileRun("function f(o) {"
2095 " o.foo = 0;"
2096 "}"
2097 "f(new Object);"
2098 "f(new Object);"
2099 "%OptimizeFunctionOnNextCall(f);"
2100 "f(root);"
2101 "%DeoptimizeFunction(f);");
2102
2103 // This bug only triggers with aggressive IC clearing.
2104 HEAP->AgeInlineCaches();
2105
2106 // Explicitly request GC to perform final marking step and sweeping.
2107 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002108
2109 Handle<JSObject> root =
2110 v8::Utils::OpenHandle(
2111 *v8::Handle<v8::Object>::Cast(
2112 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2113
2114 // The root object should be in a sane state.
2115 CHECK(root->IsJSObject());
2116 CHECK(root->map()->IsMap());
2117}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002118
2119
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002120TEST(ReleaseOverReservedPages) {
2121 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002122 // The optimizer can allocate stuff, messing up the test.
2123 i::FLAG_crankshaft = false;
2124 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002125 InitializeVM();
2126 v8::HandleScope scope;
2127 static const int number_of_test_pages = 20;
2128
2129 // Prepare many pages with low live-bytes count.
2130 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
2131 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2132 for (int i = 0; i < number_of_test_pages; i++) {
2133 AlwaysAllocateScope always_allocate;
2134 SimulateFullSpace(old_pointer_space);
2135 FACTORY->NewFixedArray(1, TENURED);
2136 }
2137 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2138
2139 // Triggering one GC will cause a lot of garbage to be discovered but
2140 // even spread across all allocated pages.
2141 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002142 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002143
2144 // Triggering subsequent GCs should cause at least half of the pages
2145 // to be released to the OS after at most two cycles.
2146 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
2147 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2148 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
2149 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
2150
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002151 // Triggering a last-resort GC should cause all pages to be released to the
2152 // OS so that other processes can seize the memory. If we get a failure here
2153 // where there are 2 pages left instead of 1, then we should increase the
2154 // size of the first page a little in SizeOfFirstPage in spaces.cc. The
2155 // first page should be small in order to reduce memory used when the VM
2156 // boots, but if the 20 small arrays don't fit on the first page then that's
2157 // an indication that it is too small.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002158 HEAP->CollectAllAvailableGarbage("triggered really hard");
2159 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2160}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002161
2162
2163TEST(Regress2237) {
2164 InitializeVM();
2165 v8::HandleScope scope;
2166 Handle<String> slice(HEAP->empty_string());
2167
2168 {
2169 // Generate a parent that lives in new-space.
2170 v8::HandleScope inner_scope;
2171 const char* c = "This text is long enough to trigger sliced strings.";
2172 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002173 CHECK(s->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002174 CHECK(HEAP->InNewSpace(*s));
2175
2176 // Generate a sliced string that is based on the above parent and
2177 // lives in old-space.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002178 SimulateFullSpace(HEAP->new_space());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002179 AlwaysAllocateScope always_allocate;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002180 Handle<String> t = FACTORY->NewProperSubString(s, 5, 35);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002181 CHECK(t->IsSlicedString());
2182 CHECK(!HEAP->InNewSpace(*t));
2183 *slice.location() = *t.location();
2184 }
2185
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002186 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002187 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002188 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002189}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002190
2191
2192#ifdef OBJECT_PRINT
2193TEST(PrintSharedFunctionInfo) {
2194 InitializeVM();
2195 v8::HandleScope scope;
2196 const char* source = "f = function() { return 987654321; }\n"
2197 "g = function() { return 123456789; }\n";
2198 CompileRun(source);
2199 Handle<JSFunction> g =
2200 v8::Utils::OpenHandle(
2201 *v8::Handle<v8::Function>::Cast(
2202 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2203
2204 AssertNoAllocation no_alloc;
2205 g->shared()->PrintLn();
2206}
2207#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002208
2209
2210TEST(Regress2211) {
2211 InitializeVM();
2212 v8::HandleScope scope;
2213
2214 v8::Handle<v8::String> value = v8_str("val string");
2215 Smi* hash = Smi::FromInt(321);
2216 Heap* heap = Isolate::Current()->heap();
2217
2218 for (int i = 0; i < 2; i++) {
2219 // Store identity hash first and common hidden property second.
2220 v8::Handle<v8::Object> obj = v8::Object::New();
2221 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2222 CHECK(internal_obj->HasFastProperties());
2223
2224 // In the first iteration, set hidden value first and identity hash second.
2225 // In the second iteration, reverse the order.
2226 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2227 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2228 ALLOW_CREATION);
2229 CHECK(!maybe_obj->IsFailure());
2230 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2231
2232 // Check values.
2233 CHECK_EQ(hash,
2234 internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
2235 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2236
2237 // Check size.
2238 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2239 ObjectHashTable* hashtable = ObjectHashTable::cast(
2240 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2241 // HashTable header (5) and 4 initial entries (8).
2242 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2243 }
2244}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002245
2246
2247TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2248 if (i::FLAG_always_opt) return;
2249 InitializeVM();
2250 v8::HandleScope scope;
2251 v8::Local<v8::Value> fun1, fun2;
2252
2253 {
2254 LocalContext env;
2255 CompileRun("function fun() {};");
2256 fun1 = env->Global()->Get(v8_str("fun"));
2257 }
2258
2259 {
2260 LocalContext env;
2261 CompileRun("function fun() {};");
2262 fun2 = env->Global()->Get(v8_str("fun"));
2263 }
2264
2265 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002266 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002267 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2268 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2269 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2270 Handle<JSFunction> f =
2271 v8::Utils::OpenHandle(
2272 *v8::Handle<v8::Function>::Cast(
2273 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2274 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2275 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2276
2277 CHECK_EQ(2, cells->CellCount());
2278 CHECK(cells->Cell(0)->value()->IsJSFunction());
2279 CHECK(cells->Cell(1)->value()->IsJSFunction());
2280
2281 SimulateIncrementalMarking();
2282 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2283
2284 CHECK_EQ(2, cells->CellCount());
2285 CHECK(cells->Cell(0)->value()->IsTheHole());
2286 CHECK(cells->Cell(1)->value()->IsTheHole());
2287}
2288
2289
2290static Code* FindFirstIC(Code* code, Code::Kind kind) {
2291 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2292 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2293 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2294 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2295 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2296 RelocInfo* info = it.rinfo();
2297 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2298 if (target->is_inline_cache_stub() && target->kind() == kind) {
2299 return target;
2300 }
2301 }
2302 return NULL;
2303}
2304
2305
2306TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2307 if (i::FLAG_always_opt) return;
2308 InitializeVM();
2309 v8::HandleScope scope;
2310
2311 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002312 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002313 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2314 "function f(o) { return o.x; } f(obj); f(obj);");
2315 Handle<JSFunction> f =
2316 v8::Utils::OpenHandle(
2317 *v8::Handle<v8::Function>::Cast(
2318 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2319
2320 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2321 CHECK(ic_before->ic_state() == MONOMORPHIC);
2322
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002323 SimulateIncrementalMarking();
2324 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2325
2326 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2327 CHECK(ic_after->ic_state() == MONOMORPHIC);
2328}
2329
2330
2331TEST(IncrementalMarkingClearsMonomorhpicIC) {
2332 if (i::FLAG_always_opt) return;
2333 InitializeVM();
2334 v8::HandleScope scope;
2335 v8::Local<v8::Value> obj1;
2336
2337 {
2338 LocalContext env;
2339 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2340 obj1 = env->Global()->Get(v8_str("obj"));
2341 }
2342
2343 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002344 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002345 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2346 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2347 Handle<JSFunction> f =
2348 v8::Utils::OpenHandle(
2349 *v8::Handle<v8::Function>::Cast(
2350 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2351
2352 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2353 CHECK(ic_before->ic_state() == MONOMORPHIC);
2354
2355 // Fire context dispose notification.
2356 v8::V8::ContextDisposedNotification();
2357 SimulateIncrementalMarking();
2358 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2359
2360 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2361 CHECK(ic_after->ic_state() == UNINITIALIZED);
2362}
2363
2364
2365TEST(IncrementalMarkingClearsPolymorhpicIC) {
2366 if (i::FLAG_always_opt) return;
2367 InitializeVM();
2368 v8::HandleScope scope;
2369 v8::Local<v8::Value> obj1, obj2;
2370
2371 {
2372 LocalContext env;
2373 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2374 obj1 = env->Global()->Get(v8_str("obj"));
2375 }
2376
2377 {
2378 LocalContext env;
2379 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2380 obj2 = env->Global()->Get(v8_str("obj"));
2381 }
2382
2383 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002384 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002385 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2386 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2387 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2388 Handle<JSFunction> f =
2389 v8::Utils::OpenHandle(
2390 *v8::Handle<v8::Function>::Cast(
2391 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2392
2393 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2394 CHECK(ic_before->ic_state() == MEGAMORPHIC);
2395
2396 // Fire context dispose notification.
2397 v8::V8::ContextDisposedNotification();
2398 SimulateIncrementalMarking();
2399 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2400
2401 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2402 CHECK(ic_after->ic_state() == UNINITIALIZED);
2403}
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002404
2405
2406class SourceResource: public v8::String::ExternalAsciiStringResource {
2407 public:
2408 explicit SourceResource(const char* data)
2409 : data_(data), length_(strlen(data)) { }
2410
2411 virtual void Dispose() {
2412 i::DeleteArray(data_);
2413 data_ = NULL;
2414 }
2415
2416 const char* data() const { return data_; }
2417
2418 size_t length() const { return length_; }
2419
2420 bool IsDisposed() { return data_ == NULL; }
2421
2422 private:
2423 const char* data_;
2424 size_t length_;
2425};
2426
2427
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002428void ReleaseStackTraceDataTest(const char* source) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002429 // Test that the data retained by the Error.stack accessor is released
2430 // after the first time the accessor is fired. We use external string
2431 // to check whether the data is being released since the external string
2432 // resource's callback is fired when the external string is GC'ed.
2433 InitializeVM();
2434 v8::HandleScope scope;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002435 SourceResource* resource = new SourceResource(i::StrDup(source));
2436 {
2437 v8::HandleScope scope;
2438 v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
2439 v8::Script::Compile(source_string)->Run();
2440 CHECK(!resource->IsDisposed());
2441 }
2442 HEAP->CollectAllAvailableGarbage();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002443
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002444 // External source has been released.
2445 CHECK(resource->IsDisposed());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002446 delete resource;
2447}
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002448
2449
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002450TEST(ReleaseStackTraceData) {
2451 static const char* source1 = "var error = null; "
2452 /* Normal Error */ "try { "
2453 " throw new Error(); "
2454 "} catch (e) { "
2455 " error = e; "
2456 "} ";
2457 static const char* source2 = "var error = null; "
2458 /* Stack overflow */ "try { "
2459 " (function f() { f(); })(); "
2460 "} catch (e) { "
2461 " error = e; "
2462 "} ";
2463 ReleaseStackTraceDataTest(source1);
2464 ReleaseStackTraceDataTest(source2);
2465}
2466
2467
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002468TEST(Regression144230) {
2469 InitializeVM();
2470 v8::HandleScope scope;
2471
2472 // First make sure that the uninitialized CallIC stub is on a single page
2473 // that will later be selected as an evacuation candidate.
2474 {
2475 v8::HandleScope inner_scope;
2476 AlwaysAllocateScope always_allocate;
2477 SimulateFullSpace(HEAP->code_space());
2478 ISOLATE->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET);
2479 }
2480
2481 // Second compile a CallIC and execute it once so that it gets patched to
2482 // the pre-monomorphic stub. These code objects are on yet another page.
2483 {
2484 v8::HandleScope inner_scope;
2485 AlwaysAllocateScope always_allocate;
2486 SimulateFullSpace(HEAP->code_space());
2487 CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};"
2488 "function call() { o.f(1,2,3,4,5,6,7,8,9); };"
2489 "call();");
2490 }
2491
2492 // Third we fill up the last page of the code space so that it does not get
2493 // chosen as an evacuation candidate.
2494 {
2495 v8::HandleScope inner_scope;
2496 AlwaysAllocateScope always_allocate;
2497 CompileRun("for (var i = 0; i < 2000; i++) {"
2498 " eval('function f' + i + '() { return ' + i +'; };' +"
2499 " 'f' + i + '();');"
2500 "}");
2501 }
2502 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2503
2504 // Fourth is the tricky part. Make sure the code containing the CallIC is
2505 // visited first without clearing the IC. The shared function info is then
2506 // visited later, causing the CallIC to be cleared.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002507 Handle<String> name = FACTORY->LookupUtf8Symbol("call");
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002508 Handle<GlobalObject> global(ISOLATE->context()->global_object());
2509 MaybeObject* maybe_call = global->GetProperty(*name);
2510 JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
2511 USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode));
2512 ISOLATE->compilation_cache()->Clear();
2513 call->shared()->set_ic_age(HEAP->global_ic_age() + 1);
2514 Handle<Object> call_code(call->code());
2515 Handle<Object> call_function(call);
2516
2517 // Now we are ready to mess up the heap.
2518 HEAP->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
2519
2520 // Either heap verification caught the problem already or we go kaboom once
2521 // the CallIC is executed the next time.
2522 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode));
2523 CompileRun("call();");
2524}
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002525
2526
2527TEST(Regress159140) {
2528 i::FLAG_allow_natives_syntax = true;
2529 i::FLAG_flush_code_incrementally = true;
2530 InitializeVM();
2531 v8::HandleScope scope;
2532
2533 // Perform one initial GC to enable code flushing.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002534 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002535
2536 // Prepare several closures that are all eligible for code flushing
2537 // because all reachable ones are not optimized. Make sure that the
2538 // optimized code object is directly reachable through a handle so
2539 // that it is marked black during incremental marking.
2540 Handle<Code> code;
2541 {
2542 HandleScope inner_scope;
2543 CompileRun("function h(x) {}"
2544 "function mkClosure() {"
2545 " return function(x) { return x + 1; };"
2546 "}"
2547 "var f = mkClosure();"
2548 "var g = mkClosure();"
2549 "f(1); f(2);"
2550 "g(1); g(2);"
2551 "h(1); h(2);"
2552 "%OptimizeFunctionOnNextCall(f); f(3);"
2553 "%OptimizeFunctionOnNextCall(h); h(3);");
2554
2555 Handle<JSFunction> f =
2556 v8::Utils::OpenHandle(
2557 *v8::Handle<v8::Function>::Cast(
2558 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2559 CHECK(f->is_compiled());
2560 CompileRun("f = null;");
2561
2562 Handle<JSFunction> g =
2563 v8::Utils::OpenHandle(
2564 *v8::Handle<v8::Function>::Cast(
2565 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2566 CHECK(g->is_compiled());
2567 const int kAgingThreshold = 6;
2568 for (int i = 0; i < kAgingThreshold; i++) {
2569 g->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2570 }
2571
2572 code = inner_scope.CloseAndEscape(Handle<Code>(f->code()));
2573 }
2574
2575 // Simulate incremental marking so that the functions are enqueued as
2576 // code flushing candidates. Then optimize one function. Finally
2577 // finish the GC to complete code flushing.
2578 SimulateIncrementalMarking();
2579 CompileRun("%OptimizeFunctionOnNextCall(g); g(3);");
2580 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2581
2582 // Unoptimized code is missing and the deoptimizer will go ballistic.
2583 CompileRun("g('bozo');");
2584}
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002585
2586
2587TEST(Regress165495) {
2588 i::FLAG_allow_natives_syntax = true;
2589 i::FLAG_flush_code_incrementally = true;
2590 InitializeVM();
2591 v8::HandleScope scope;
2592
2593 // Perform one initial GC to enable code flushing.
2594 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
2595
2596 // Prepare an optimized closure that the optimized code map will get
2597 // populated. Then age the unoptimized code to trigger code flushing
2598 // but make sure the optimized code is unreachable.
2599 {
2600 HandleScope inner_scope;
2601 CompileRun("function mkClosure() {"
2602 " return function(x) { return x + 1; };"
2603 "}"
2604 "var f = mkClosure();"
2605 "f(1); f(2);"
2606 "%OptimizeFunctionOnNextCall(f); f(3);");
2607
2608 Handle<JSFunction> f =
2609 v8::Utils::OpenHandle(
2610 *v8::Handle<v8::Function>::Cast(
2611 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2612 CHECK(f->is_compiled());
2613 const int kAgingThreshold = 6;
2614 for (int i = 0; i < kAgingThreshold; i++) {
2615 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2616 }
2617
2618 CompileRun("f = null;");
2619 }
2620
2621 // Simulate incremental marking so that unoptimized code is flushed
2622 // even though it still is cached in the optimized code map.
2623 SimulateIncrementalMarking();
2624 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2625
2626 // Make a new closure that will get code installed from the code map.
2627 // Unoptimized code is missing and the deoptimizer will go ballistic.
2628 CompileRun("var g = mkClosure(); g('bozo');");
2629}
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002630
2631
2632TEST(Regress169209) {
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002633 i::FLAG_stress_compaction = false;
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002634 i::FLAG_allow_natives_syntax = true;
2635 i::FLAG_flush_code_incrementally = true;
2636 InitializeVM();
2637 v8::HandleScope scope;
2638
2639 // Perform one initial GC to enable code flushing.
2640 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
2641
2642 // Prepare a shared function info eligible for code flushing for which
2643 // the unoptimized code will be replaced during optimization.
2644 Handle<SharedFunctionInfo> shared1;
2645 {
2646 HandleScope inner_scope;
2647 CompileRun("function f() { return 'foobar'; }"
2648 "function g(x) { if (x) f(); }"
2649 "f();"
2650 "g(false);"
2651 "g(false);");
2652
2653 Handle<JSFunction> f =
2654 v8::Utils::OpenHandle(
2655 *v8::Handle<v8::Function>::Cast(
2656 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2657 CHECK(f->is_compiled());
2658 const int kAgingThreshold = 6;
2659 for (int i = 0; i < kAgingThreshold; i++) {
2660 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2661 }
2662
2663 shared1 = inner_scope.CloseAndEscape(handle(f->shared(), ISOLATE));
2664 }
2665
2666 // Prepare a shared function info eligible for code flushing that will
2667 // represent the dangling tail of the candidate list.
2668 Handle<SharedFunctionInfo> shared2;
2669 {
2670 HandleScope inner_scope;
2671 CompileRun("function flushMe() { return 0; }"
2672 "flushMe(1);");
2673
2674 Handle<JSFunction> f =
2675 v8::Utils::OpenHandle(
2676 *v8::Handle<v8::Function>::Cast(
2677 v8::Context::GetCurrent()->Global()->Get(v8_str("flushMe"))));
2678 CHECK(f->is_compiled());
2679 const int kAgingThreshold = 6;
2680 for (int i = 0; i < kAgingThreshold; i++) {
2681 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2682 }
2683
2684 shared2 = inner_scope.CloseAndEscape(handle(f->shared(), ISOLATE));
2685 }
2686
2687 // Simulate incremental marking and collect code flushing candidates.
2688 SimulateIncrementalMarking();
2689 CHECK(shared1->code()->gc_metadata() != NULL);
2690
2691 // Optimize function and make sure the unoptimized code is replaced.
2692#ifdef DEBUG
2693 FLAG_stop_at = "f";
2694#endif
2695 CompileRun("%OptimizeFunctionOnNextCall(g);"
2696 "g(false);");
2697
2698 // Finish garbage collection cycle.
2699 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2700 CHECK(shared1->code()->gc_metadata() == NULL);
2701}
yangguo@chromium.org28381b42013-01-21 14:39:38 +00002702
2703
2704// Helper function that simulates a fill new-space in the heap.
2705static inline void AllocateAllButNBytes(v8::internal::NewSpace* space,
2706 int extra_bytes) {
2707 int space_remaining = static_cast<int>(
2708 *space->allocation_limit_address() - *space->allocation_top_address());
2709 CHECK(space_remaining >= extra_bytes);
2710 int new_linear_size = space_remaining - extra_bytes;
2711 v8::internal::MaybeObject* maybe = space->AllocateRaw(new_linear_size);
2712 v8::internal::FreeListNode* node = v8::internal::FreeListNode::cast(maybe);
2713 node->set_size(space->heap(), new_linear_size);
2714}
2715
2716
2717TEST(Regress169928) {
2718 i::FLAG_allow_natives_syntax = true;
2719 i::FLAG_crankshaft = false;
2720 InitializeVM();
2721 v8::HandleScope scope;
2722
2723 // Some flags turn Scavenge collections into Mark-sweep collections
2724 // and hence are incompatible with this test case.
2725 if (FLAG_gc_global || FLAG_stress_compaction) return;
2726
2727 // Prepare the environment
2728 CompileRun("function fastliteralcase(literal, value) {"
2729 " literal[0] = value;"
2730 " return literal;"
2731 "}"
2732 "function get_standard_literal() {"
2733 " var literal = [1, 2, 3];"
2734 " return literal;"
2735 "}"
2736 "obj = fastliteralcase(get_standard_literal(), 1);"
2737 "obj = fastliteralcase(get_standard_literal(), 1.5);"
2738 "obj = fastliteralcase(get_standard_literal(), 2);");
2739
2740 // prepare the heap
2741 v8::Local<v8::String> mote_code_string =
2742 v8_str("fastliteralcase(mote, 2.5);");
2743
2744 v8::Local<v8::String> array_name = v8_str("mote");
2745 v8::Context::GetCurrent()->Global()->Set(array_name, v8::Int32::New(0));
2746
2747 // First make sure we flip spaces
2748 HEAP->CollectGarbage(NEW_SPACE);
2749
2750 // Allocate the object.
2751 Handle<FixedArray> array_data = FACTORY->NewFixedArray(2, NOT_TENURED);
2752 array_data->set(0, Smi::FromInt(1));
2753 array_data->set(1, Smi::FromInt(2));
2754
2755 AllocateAllButNBytes(HEAP->new_space(),
2756 JSArray::kSize + AllocationSiteInfo::kSize +
2757 kPointerSize);
2758
2759 Handle<JSArray> array = FACTORY->NewJSArrayWithElements(array_data,
2760 FAST_SMI_ELEMENTS,
2761 NOT_TENURED);
2762
2763 CHECK_EQ(Smi::FromInt(2), array->length());
2764 CHECK(array->HasFastSmiOrObjectElements());
2765
2766 // We need filler the size of AllocationSiteInfo object, plus an extra
2767 // fill pointer value.
2768 MaybeObject* maybe_object = HEAP->AllocateRaw(
2769 AllocationSiteInfo::kSize + kPointerSize, NEW_SPACE, OLD_POINTER_SPACE);
2770 Object* obj = NULL;
2771 CHECK(maybe_object->ToObject(&obj));
2772 Address addr_obj = reinterpret_cast<Address>(
2773 reinterpret_cast<byte*>(obj - kHeapObjectTag));
2774 HEAP->CreateFillerObjectAt(addr_obj,
2775 AllocationSiteInfo::kSize + kPointerSize);
2776
2777 // Give the array a name, making sure not to allocate strings.
2778 v8::Handle<v8::Object> array_obj = v8::Utils::ToLocal(array);
2779 v8::Context::GetCurrent()->Global()->Set(array_name, array_obj);
2780
2781 // This should crash with a protection violation if we are running a build
2782 // with the bug.
2783 AlwaysAllocateScope aa_scope;
2784 v8::Script::Compile(mote_code_string)->Run();
2785}
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002786
2787
2788TEST(Regress168801) {
2789 i::FLAG_always_compact = true;
2790 i::FLAG_cache_optimized_code = false;
2791 i::FLAG_allow_natives_syntax = true;
2792 i::FLAG_flush_code_incrementally = true;
2793 InitializeVM();
2794 v8::HandleScope scope;
2795
2796 // Perform one initial GC to enable code flushing.
2797 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
2798
2799 // Ensure the code ends up on an evacuation candidate.
2800 SimulateFullSpace(HEAP->code_space());
2801
2802 // Prepare an unoptimized function that is eligible for code flushing.
2803 Handle<JSFunction> function;
2804 {
2805 HandleScope inner_scope;
2806 CompileRun("function mkClosure() {"
2807 " return function(x) { return x + 1; };"
2808 "}"
2809 "var f = mkClosure();"
2810 "f(1); f(2);");
2811
2812 Handle<JSFunction> f =
2813 v8::Utils::OpenHandle(
2814 *v8::Handle<v8::Function>::Cast(
2815 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2816 CHECK(f->is_compiled());
2817 const int kAgingThreshold = 6;
2818 for (int i = 0; i < kAgingThreshold; i++) {
2819 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2820 }
2821
2822 function = inner_scope.CloseAndEscape(handle(*f, ISOLATE));
2823 }
2824
2825 // Simulate incremental marking so that unoptimized function is enqueued as a
2826 // candidate for code flushing. The shared function info however will not be
2827 // explicitly enqueued.
2828 SimulateIncrementalMarking();
2829
2830 // Now optimize the function so that it is taken off the candidate list.
2831 {
2832 HandleScope inner_scope;
2833 CompileRun("%OptimizeFunctionOnNextCall(f); f(3);");
2834 }
2835
2836 // This cycle will bust the heap and subsequent cycles will go ballistic.
2837 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2838 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2839}
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002840
2841
2842TEST(Regress173458) {
2843 i::FLAG_always_compact = true;
2844 i::FLAG_cache_optimized_code = false;
2845 i::FLAG_allow_natives_syntax = true;
2846 i::FLAG_flush_code_incrementally = true;
2847 InitializeVM();
2848 v8::HandleScope scope;
2849
2850 // Perform one initial GC to enable code flushing.
2851 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
2852
2853 // Ensure the code ends up on an evacuation candidate.
2854 SimulateFullSpace(HEAP->code_space());
2855
2856 // Prepare an unoptimized function that is eligible for code flushing.
2857 Handle<JSFunction> function;
2858 {
2859 HandleScope inner_scope;
2860 CompileRun("function mkClosure() {"
2861 " return function(x) { return x + 1; };"
2862 "}"
2863 "var f = mkClosure();"
2864 "f(1); f(2);");
2865
2866 Handle<JSFunction> f =
2867 v8::Utils::OpenHandle(
2868 *v8::Handle<v8::Function>::Cast(
2869 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2870 CHECK(f->is_compiled());
2871 const int kAgingThreshold = 6;
2872 for (int i = 0; i < kAgingThreshold; i++) {
2873 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2874 }
2875
2876 function = inner_scope.CloseAndEscape(handle(*f, ISOLATE));
2877 }
2878
2879 // Simulate incremental marking so that unoptimized function is enqueued as a
2880 // candidate for code flushing. The shared function info however will not be
2881 // explicitly enqueued.
2882 SimulateIncrementalMarking();
2883
2884 // Now enable the debugger which in turn will disable code flushing.
2885 CHECK(ISOLATE->debug()->Load());
2886
2887 // This cycle will bust the heap and subsequent cycles will go ballistic.
2888 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2889 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2890}