blob: 58ff4606b8c3f92769c53b014f21a88ef5a936d1 [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
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000361static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000362 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000363 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000364 handle.Dispose();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000365}
366
367
368TEST(WeakGlobalHandlesScavenge) {
369 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000370 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000371
372 WeakPointerCleared = false;
373
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000374 Handle<Object> h1;
375 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000376
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000377 {
378 HandleScope scope;
379
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000380 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
381 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000382
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000383 h1 = global_handles->Create(*i);
384 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000385 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000386
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000387 global_handles->MakeWeak(h2.location(),
388 reinterpret_cast<void*>(1234),
389 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000390
391 // Scavenge treats weak pointers as normal roots.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000392 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000393
394 CHECK((*h1)->IsString());
395 CHECK((*h2)->IsHeapNumber());
396
397 CHECK(!WeakPointerCleared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000398 CHECK(!global_handles->IsNearDeath(h2.location()));
399 CHECK(!global_handles->IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000400
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000401 global_handles->Destroy(h1.location());
402 global_handles->Destroy(h2.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000403}
404
405
406TEST(WeakGlobalHandlesMark) {
407 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000408 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000409
410 WeakPointerCleared = false;
411
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000412 Handle<Object> h1;
413 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000414
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000415 {
416 HandleScope scope;
417
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
419 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000420
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000421 h1 = global_handles->Create(*i);
422 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000423 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000424
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000425 // Make sure the objects are promoted.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000426 HEAP->CollectGarbage(OLD_POINTER_SPACE);
427 HEAP->CollectGarbage(NEW_SPACE);
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000428 CHECK(!HEAP->InNewSpace(*h1) && !HEAP->InNewSpace(*h2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000429
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000430 global_handles->MakeWeak(h2.location(),
431 reinterpret_cast<void*>(1234),
432 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000433 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
434 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
435
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000436 // Incremental marking potentially marked handles before they turned weak.
437 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000438
439 CHECK((*h1)->IsString());
440
441 CHECK(WeakPointerCleared);
442 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000443
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000444 global_handles->Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000445}
446
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000447
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000448TEST(DeleteWeakGlobalHandle) {
449 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000450 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000451
452 WeakPointerCleared = false;
453
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000454 Handle<Object> h;
455
456 {
457 HandleScope scope;
458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000459 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
460 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000461 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000462
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000463 global_handles->MakeWeak(h.location(),
464 reinterpret_cast<void*>(1234),
465 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000466
467 // Scanvenge does not recognize weak reference.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000468 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000469
470 CHECK(!WeakPointerCleared);
471
472 // Mark-compact treats weak reference properly.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000473 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000474
475 CHECK(WeakPointerCleared);
476}
477
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000478
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000479static const char* not_so_random_string_table[] = {
480 "abstract",
481 "boolean",
482 "break",
483 "byte",
484 "case",
485 "catch",
486 "char",
487 "class",
488 "const",
489 "continue",
490 "debugger",
491 "default",
492 "delete",
493 "do",
494 "double",
495 "else",
496 "enum",
497 "export",
498 "extends",
499 "false",
500 "final",
501 "finally",
502 "float",
503 "for",
504 "function",
505 "goto",
506 "if",
507 "implements",
508 "import",
509 "in",
510 "instanceof",
511 "int",
512 "interface",
513 "long",
514 "native",
515 "new",
516 "null",
517 "package",
518 "private",
519 "protected",
520 "public",
521 "return",
522 "short",
523 "static",
524 "super",
525 "switch",
526 "synchronized",
527 "this",
528 "throw",
529 "throws",
530 "transient",
531 "true",
532 "try",
533 "typeof",
534 "var",
535 "void",
536 "volatile",
537 "while",
538 "with",
539 0
540};
541
542
543static void CheckSymbols(const char** strings) {
544 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000545 Object* a;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000546 MaybeObject* maybe_a = HEAP->LookupUtf8Symbol(string);
547 // LookupUtf8Symbol may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000548 if (!maybe_a->ToObject(&a)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000549 CHECK(a->IsSymbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000550 Object* b;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000551 MaybeObject* maybe_b = HEAP->LookupUtf8Symbol(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000552 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000553 CHECK_EQ(b, a);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000554 CHECK(String::cast(b)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000555 }
556}
557
558
559TEST(SymbolTable) {
560 InitializeVM();
561
562 CheckSymbols(not_so_random_string_table);
563 CheckSymbols(not_so_random_string_table);
564}
565
566
567TEST(FunctionAllocation) {
568 InitializeVM();
569
570 v8::HandleScope sc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000571 Handle<String> name = FACTORY->LookupUtf8Symbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000572 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000573 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000574 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000575 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000576 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000577
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000578 Handle<String> prop_name = FACTORY->LookupUtf8Symbol("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000579 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000580 obj->SetProperty(
581 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000582 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000583 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000584 function->SetProperty(
585 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000586 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000587}
588
589
590TEST(ObjectProperties) {
591 InitializeVM();
592
593 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000594 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000595 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000596 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000597 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000598 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000599 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000600 Handle<String> first = FACTORY->LookupUtf8Symbol("first");
601 Handle<String> second = FACTORY->LookupUtf8Symbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000602
603 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000604 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000605
606 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000607 obj->SetProperty(
608 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000609 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000610
611 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000612 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
613 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000614
615 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000616 obj->SetProperty(
617 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
618 obj->SetProperty(
619 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000620 CHECK(obj->HasLocalProperty(*first));
621 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000622
623 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000624 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
625 CHECK(obj->HasLocalProperty(*second));
626 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
627 CHECK(!obj->HasLocalProperty(*first));
628 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000629
630 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000631 obj->SetProperty(
632 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
633 obj->SetProperty(
634 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000635 CHECK(obj->HasLocalProperty(*first));
636 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000637
638 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000639 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
640 CHECK(obj->HasLocalProperty(*first));
641 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
642 CHECK(!obj->HasLocalProperty(*first));
643 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000644
645 // check string and symbol match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000646 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000648 obj->SetProperty(
649 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000650 Handle<String> s1_symbol = FACTORY->LookupUtf8Symbol(string1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000651 CHECK(obj->HasLocalProperty(*s1_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000652
653 // check symbol and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000654 const char* string2 = "fugl";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000655 Handle<String> s2_symbol = FACTORY->LookupUtf8Symbol(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000656 obj->SetProperty(
657 *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000658 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000659 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000660}
661
662
663TEST(JSObjectMaps) {
664 InitializeVM();
665
666 v8::HandleScope sc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000667 Handle<String> name = FACTORY->LookupUtf8Symbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000668 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000669 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000670 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000671 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000672 function->set_initial_map(*initial_map);
673
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000674 Handle<String> prop_name = FACTORY->LookupUtf8Symbol("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000675 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000676
677 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000678 obj->SetProperty(
679 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000680 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000681
682 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000683 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000684}
685
686
687TEST(JSArray) {
688 InitializeVM();
689
690 v8::HandleScope sc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000691 Handle<String> name = FACTORY->LookupUtf8Symbol("Array");
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000692 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000693 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000694 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000695 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000696
697 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000698 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000699 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000700 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000701 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000702
703 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000704 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000705 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000706 // Must be in fast mode.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000707 CHECK(array->HasFastSmiOrObjectElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000708
709 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000710 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000711 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000712 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000713
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000714 // Set array length with larger than smi value.
715 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000716 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000717 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000718
719 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000720 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000721 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000722 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000723
724 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000725 array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000726 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000727 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000728 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000729 CHECK_EQ(array->GetElement(int_length), *name);
730 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000731}
732
733
734TEST(JSObjectCopy) {
735 InitializeVM();
736
737 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000738 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000739 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000740 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000741 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000742 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000743 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000744 Handle<String> first = FACTORY->LookupUtf8Symbol("first");
745 Handle<String> second = FACTORY->LookupUtf8Symbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000746
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000747 obj->SetProperty(
748 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
749 obj->SetProperty(
750 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000751
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000752 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
753 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000754
755 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000756 Handle<JSObject> clone = Copy(obj);
757 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000758
759 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
760 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
761
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000762 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
763 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000764
765 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000766 clone->SetProperty(
767 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
768 clone->SetProperty(
769 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000770
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000771 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
772 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000773
774 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
775 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
776
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000777 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
778 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000779}
780
781
782TEST(StringAllocation) {
783 InitializeVM();
784
785
786 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
787 for (int length = 0; length < 100; length++) {
788 v8::HandleScope scope;
789 char* non_ascii = NewArray<char>(3 * length + 1);
790 char* ascii = NewArray<char>(length + 1);
791 non_ascii[3 * length] = 0;
792 ascii[length] = 0;
793 for (int i = 0; i < length; i++) {
794 ascii[i] = 'a';
795 non_ascii[3 * i] = chars[0];
796 non_ascii[3 * i + 1] = chars[1];
797 non_ascii[3 * i + 2] = chars[2];
798 }
799 Handle<String> non_ascii_sym =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000800 FACTORY->LookupUtf8Symbol(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000801 CHECK_EQ(length, non_ascii_sym->length());
802 Handle<String> ascii_sym =
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000803 FACTORY->LookupOneByteSymbol(OneByteVector(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000804 CHECK_EQ(length, ascii_sym->length());
805 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000806 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000807 non_ascii_str->Hash();
808 CHECK_EQ(length, non_ascii_str->length());
809 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000810 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000811 ascii_str->Hash();
812 CHECK_EQ(length, ascii_str->length());
813 DeleteArray(non_ascii);
814 DeleteArray(ascii);
815 }
816}
817
818
819static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
820 // Count the number of objects found in the heap.
821 int found_count = 0;
822 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000823 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000824 for (int i = 0; i < size; i++) {
825 if (*objs[i] == obj) {
826 found_count++;
827 }
828 }
829 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000830 return found_count;
831}
832
833
834TEST(Iteration) {
835 InitializeVM();
836 v8::HandleScope scope;
837
838 // Array of objects to scan haep for.
839 const int objs_count = 6;
840 Handle<Object> objs[objs_count];
841 int next_objs_index = 0;
842
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000843 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000845 objs[next_objs_index++] = FACTORY->NewJSArray(10,
846 FAST_HOLEY_ELEMENTS,
847 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000848
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000849 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000850 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000851 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000852 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000853 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000854
855 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000856 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000857 char* str = new char[large_size];
858 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
859 str[large_size - 1] = '\0';
860 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000861 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000862 delete[] str;
863
864 // Add a Map object to look for.
865 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
866
867 CHECK_EQ(objs_count, next_objs_index);
868 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
869}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000870
871
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000872TEST(EmptyHandleEscapeFrom) {
873 InitializeVM();
874
875 v8::HandleScope scope;
876 Handle<JSObject> runaway;
877
878 {
879 v8::HandleScope nested;
880 Handle<JSObject> empty;
881 runaway = empty.EscapeFrom(&nested);
882 }
883
884 CHECK(runaway.is_null());
885}
886
887
888static int LenFromSize(int size) {
889 return (size - FixedArray::kHeaderSize) / kPointerSize;
890}
891
892
893TEST(Regression39128) {
894 // Test case for crbug.com/39128.
895 InitializeVM();
896
897 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000898 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000899
900 v8::HandleScope scope;
901
902 // The plan: create JSObject which references objects in new space.
903 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000904 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000905
906 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000907 Handle<JSFunction> object_ctor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000908 Isolate::Current()->native_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000909 CHECK(object_ctor->has_initial_map());
910 Handle<Map> object_map(object_ctor->initial_map());
911 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000912 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000913 int n_properties = my_map->inobject_properties();
914 CHECK_GT(n_properties, 0);
915
916 int object_size = my_map->instance_size();
917
918 // Step 2: allocate a lot of objects so to almost fill new space: we need
919 // just enough room to allocate JSObject and thus fill the newspace.
920
921 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000922 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000923 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000924 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000925 Address* top_addr = new_space->allocation_top_address();
926 Address* limit_addr = new_space->allocation_limit_address();
927 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 CHECK(!HEAP->always_allocate());
929 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
930 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000931 CHECK(new_space->Contains(array));
932 }
933
934 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000935 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000936 int fixed_array_len = LenFromSize(to_fill);
937 CHECK(fixed_array_len < FixedArray::kMaxLength);
938
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000939 CHECK(!HEAP->always_allocate());
940 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
941 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000942 CHECK(new_space->Contains(array));
943
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000944 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000945 CHECK(new_space->Contains(object));
946 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000947 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000948 CHECK_EQ(0, jsobject->properties()->length());
949 // Create a reference to object in new space in jsobject.
950 jsobject->FastPropertyAtPut(-1, array);
951
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000952 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000953
954 // Step 4: clone jsobject, but force always allocate first to create a clone
955 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000956 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000957 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000959 JSObject* clone = JSObject::cast(clone_obj);
960 if (clone->address() != old_pointer_space_top) {
961 // Alas, got allocated from free list, we cannot do checks.
962 return;
963 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000964 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000965}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000966
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000967
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000968TEST(TestCodeFlushing) {
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000969 // If we do not flush code this test is invalid.
970 if (!FLAG_flush_code) return;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000971 i::FLAG_allow_natives_syntax = true;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000972 InitializeVM();
973 v8::HandleScope scope;
974 const char* source = "function foo() {"
975 " var x = 42;"
976 " var y = 42;"
977 " var z = x + y;"
978 "};"
979 "foo()";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000980 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000981
982 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000983 { v8::HandleScope scope;
984 CompileRun(source);
985 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000986
987 // Check function is compiled.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000988 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000989 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000990 CHECK(func_value->IsJSFunction());
991 Handle<JSFunction> function(JSFunction::cast(func_value));
992 CHECK(function->shared()->is_compiled());
993
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000994 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000995 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
996 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000997 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000998
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000999 // Simulate several GCs that use full marking.
1000 const int kAgingThreshold = 6;
1001 for (int i = 0; i < kAgingThreshold; i++) {
1002 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1003 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001004
1005 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001006 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1007 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001008 // Call foo to get it recompiled.
1009 CompileRun("foo()");
1010 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001011 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001012}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001013
1014
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001015TEST(TestCodeFlushingIncremental) {
1016 // If we do not flush code this test is invalid.
1017 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1018 i::FLAG_allow_natives_syntax = true;
1019 InitializeVM();
1020 v8::HandleScope scope;
1021 const char* source = "function foo() {"
1022 " var x = 42;"
1023 " var y = 42;"
1024 " var z = x + y;"
1025 "};"
1026 "foo()";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001027 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001028
1029 // This compile will add the code to the compilation cache.
1030 { v8::HandleScope scope;
1031 CompileRun(source);
1032 }
1033
1034 // Check function is compiled.
1035 Object* func_value = Isolate::Current()->context()->global_object()->
1036 GetProperty(*foo_name)->ToObjectChecked();
1037 CHECK(func_value->IsJSFunction());
1038 Handle<JSFunction> function(JSFunction::cast(func_value));
1039 CHECK(function->shared()->is_compiled());
1040
1041 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001042 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1043 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001044 CHECK(function->shared()->is_compiled());
1045
1046 // Simulate several GCs that use incremental marking.
1047 const int kAgingThreshold = 6;
1048 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001049 SimulateIncrementalMarking();
1050 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1051 }
1052 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1053 CHECK(!function->is_compiled() || function->IsOptimized());
1054
1055 // This compile will compile the function again.
1056 { v8::HandleScope scope;
1057 CompileRun("foo();");
1058 }
1059
1060 // Simulate several GCs that use incremental marking but make sure
1061 // the loop breaks once the function is enqueued as a candidate.
1062 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001063 SimulateIncrementalMarking();
1064 if (!function->next_function_link()->IsUndefined()) break;
1065 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1066 }
1067
1068 // Force optimization while incremental marking is active and while
1069 // the function is enqueued as a candidate.
1070 { v8::HandleScope scope;
1071 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1072 }
1073
1074 // Simulate one final GC to make sure the candidate queue is sane.
1075 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1076 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1077 CHECK(function->is_compiled() || !function->IsOptimized());
1078}
1079
1080
1081TEST(TestCodeFlushingIncrementalScavenge) {
1082 // If we do not flush code this test is invalid.
1083 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1084 i::FLAG_allow_natives_syntax = true;
1085 InitializeVM();
1086 v8::HandleScope scope;
1087 const char* source = "var foo = function() {"
1088 " var x = 42;"
1089 " var y = 42;"
1090 " var z = x + y;"
1091 "};"
1092 "foo();"
1093 "var bar = function() {"
1094 " var x = 23;"
1095 "};"
1096 "bar();";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001097 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
1098 Handle<String> bar_name = FACTORY->LookupUtf8Symbol("bar");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001099
1100 // Perfrom one initial GC to enable code flushing.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001101 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001102
1103 // This compile will add the code to the compilation cache.
1104 { v8::HandleScope scope;
1105 CompileRun(source);
1106 }
1107
1108 // Check functions are compiled.
1109 Object* func_value = Isolate::Current()->context()->global_object()->
1110 GetProperty(*foo_name)->ToObjectChecked();
1111 CHECK(func_value->IsJSFunction());
1112 Handle<JSFunction> function(JSFunction::cast(func_value));
1113 CHECK(function->shared()->is_compiled());
1114 Object* func_value2 = Isolate::Current()->context()->global_object()->
1115 GetProperty(*bar_name)->ToObjectChecked();
1116 CHECK(func_value2->IsJSFunction());
1117 Handle<JSFunction> function2(JSFunction::cast(func_value2));
1118 CHECK(function2->shared()->is_compiled());
1119
1120 // Clear references to functions so that one of them can die.
1121 { v8::HandleScope scope;
1122 CompileRun("foo = 0; bar = 0;");
1123 }
1124
1125 // Bump the code age so that flushing is triggered while the function
1126 // object is still located in new-space.
1127 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001128 for (int i = 0; i < kAgingThreshold; i++) {
1129 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1130 function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1131 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001132
1133 // Simulate incremental marking so that the functions are enqueued as
1134 // code flushing candidates. Then kill one of the functions. Finally
1135 // perform a scavenge while incremental marking is still running.
1136 SimulateIncrementalMarking();
1137 *function2.location() = NULL;
1138 HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking");
1139
1140 // Simulate one final GC to make sure the candidate queue is sane.
1141 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1142 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1143 CHECK(!function->is_compiled() || function->IsOptimized());
1144}
1145
1146
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001147TEST(TestCodeFlushingIncrementalAbort) {
1148 // If we do not flush code this test is invalid.
1149 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1150 i::FLAG_allow_natives_syntax = true;
1151 InitializeVM();
1152 v8::HandleScope scope;
1153 const char* source = "function foo() {"
1154 " var x = 42;"
1155 " var y = 42;"
1156 " var z = x + y;"
1157 "};"
1158 "foo()";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001159 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001160
1161 // This compile will add the code to the compilation cache.
1162 { v8::HandleScope scope;
1163 CompileRun(source);
1164 }
1165
1166 // Check function is compiled.
1167 Object* func_value = Isolate::Current()->context()->global_object()->
1168 GetProperty(*foo_name)->ToObjectChecked();
1169 CHECK(func_value->IsJSFunction());
1170 Handle<JSFunction> function(JSFunction::cast(func_value));
1171 CHECK(function->shared()->is_compiled());
1172
1173 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001174 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1175 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001176 CHECK(function->shared()->is_compiled());
1177
1178 // Bump the code age so that flushing is triggered.
1179 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001180 for (int i = 0; i < kAgingThreshold; i++) {
1181 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1182 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001183
1184 // Simulate incremental marking so that the function is enqueued as
1185 // code flushing candidate.
1186 SimulateIncrementalMarking();
1187
1188 // Enable the debugger and add a breakpoint while incremental marking
1189 // is running so that incremental marking aborts and code flushing is
1190 // disabled.
1191 int position = 0;
1192 Handle<Object> breakpoint_object(Smi::FromInt(0));
1193 ISOLATE->debug()->SetBreakPoint(function, breakpoint_object, &position);
1194 ISOLATE->debug()->ClearAllBreakPoints();
1195
1196 // Force optimization now that code flushing is disabled.
1197 { v8::HandleScope scope;
1198 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1199 }
1200
1201 // Simulate one final GC to make sure the candidate queue is sane.
1202 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1203 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1204 CHECK(function->is_compiled() || !function->IsOptimized());
1205}
1206
1207
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001208// Count the number of native contexts in the weak list of native contexts.
1209int CountNativeContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001210 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001211 Object* object = HEAP->native_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001212 while (!object->IsUndefined()) {
1213 count++;
1214 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1215 }
1216 return count;
1217}
1218
1219
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001220// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001221// functions attached to a native context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001222static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1223 int count = 0;
1224 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1225 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1226 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1227 count++;
1228 object = JSFunction::cast(object)->next_function_link();
1229 }
1230 return count;
1231}
1232
1233
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001234TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001235 v8::V8::Initialize();
1236
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001237 // Some flags turn Scavenge collections into Mark-sweep collections
1238 // and hence are incompatible with this test case.
1239 if (FLAG_gc_global || FLAG_stress_compaction) return;
1240
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001241 static const int kNumTestContexts = 10;
1242
1243 v8::HandleScope scope;
1244 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1245
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001246 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001247
1248 // Create a number of global contests which gets linked together.
1249 for (int i = 0; i < kNumTestContexts; i++) {
1250 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001251
1252 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1253
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001254 CHECK_EQ(i + 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001255
1256 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001257
1258 // Create a handle scope so no function objects get stuch in the outer
1259 // handle scope
1260 v8::HandleScope scope;
1261 const char* source = "function f1() { };"
1262 "function f2() { };"
1263 "function f3() { };"
1264 "function f4() { };"
1265 "function f5() { };";
1266 CompileRun(source);
1267 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1268 CompileRun("f1()");
1269 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1270 CompileRun("f2()");
1271 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1272 CompileRun("f3()");
1273 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1274 CompileRun("f4()");
1275 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1276 CompileRun("f5()");
1277 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1278
1279 // Remove function f1, and
1280 CompileRun("f1=null");
1281
1282 // Scavenge treats these references as strong.
1283 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001284 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001285 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1286 }
1287
1288 // Mark compact handles the weak references.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001289 ISOLATE->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001290 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001291 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1292
1293 // Get rid of f3 and f5 in the same way.
1294 CompileRun("f3=null");
1295 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001296 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001297 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1298 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001299 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001300 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1301 CompileRun("f5=null");
1302 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001303 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001304 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1305 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001306 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001307 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1308
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001309 ctx[i]->Exit();
1310 }
1311
1312 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001313 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001314
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001315 // Dispose the native contexts one by one.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001316 for (int i = 0; i < kNumTestContexts; i++) {
1317 ctx[i].Dispose();
1318 ctx[i].Clear();
1319
1320 // Scavenge treats these references as strong.
1321 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001322 HEAP->PerformScavenge();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001323 CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001324 }
1325
1326 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001327 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001328 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001329 }
1330
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001331 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001332}
1333
1334
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001335// Count the number of native contexts in the weak list of native contexts
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001336// causing a GC after the specified number of elements.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001337static int CountNativeContextsWithGC(int n) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001338 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001339 Handle<Object> object(HEAP->native_contexts_list());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001340 while (!object->IsUndefined()) {
1341 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001342 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001343 object =
1344 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1345 }
1346 return count;
1347}
1348
1349
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001350// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001351// functions attached to a native context causing a GC after the
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001352// specified number of elements.
1353static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1354 int n) {
1355 int count = 0;
1356 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1357 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1358 while (object->IsJSFunction() &&
1359 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1360 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001361 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001362 object = Handle<Object>(
1363 Object::cast(JSFunction::cast(*object)->next_function_link()));
1364 }
1365 return count;
1366}
1367
1368
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001369TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001370 v8::V8::Initialize();
1371
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001372 static const int kNumTestContexts = 10;
1373
1374 v8::HandleScope scope;
1375 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1376
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001377 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001378
1379 // Create an number of contexts and check the length of the weak list both
1380 // with and without GCs while iterating the list.
1381 for (int i = 0; i < kNumTestContexts; i++) {
1382 ctx[i] = v8::Context::New();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001383 CHECK_EQ(i + 1, CountNativeContexts());
1384 CHECK_EQ(i + 1, CountNativeContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001385 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001386
1387 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1388
1389 // Compile a number of functions the length of the weak list of optimized
1390 // functions both with and without GCs while iterating the list.
1391 ctx[0]->Enter();
1392 const char* source = "function f1() { };"
1393 "function f2() { };"
1394 "function f3() { };"
1395 "function f4() { };"
1396 "function f5() { };";
1397 CompileRun(source);
1398 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1399 CompileRun("f1()");
1400 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1401 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1402 CompileRun("f2()");
1403 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1404 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1405 CompileRun("f3()");
1406 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1407 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1408 CompileRun("f4()");
1409 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1410 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1411 CompileRun("f5()");
1412 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1413 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1414
1415 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001416}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001417
1418
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001419TEST(TestSizeOfObjects) {
1420 v8::V8::Initialize();
1421
1422 // Get initial heap size after several full GCs, which will stabilize
1423 // the heap size and return with sweeping finished completely.
1424 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1425 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1426 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1427 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001428 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001429 CHECK(HEAP->old_pointer_space()->IsSweepingComplete());
1430 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1431
1432 {
1433 // Allocate objects on several different old-space pages so that
1434 // lazy sweeping kicks in for subsequent GC runs.
1435 AlwaysAllocateScope always_allocate;
1436 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1437 for (int i = 1; i <= 100; i++) {
1438 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1439 CHECK_EQ(initial_size + i * filler_size,
1440 static_cast<int>(HEAP->SizeOfObjects()));
1441 }
1442 }
1443
1444 // The heap size should go back to initial size after a full GC, even
1445 // though sweeping didn't finish yet.
1446 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001447
1448 // Normally sweeping would not be complete here, but no guarantees.
1449
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001450 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1451
1452 // Advancing the sweeper step-wise should not change the heap size.
1453 while (!HEAP->old_pointer_space()->IsSweepingComplete()) {
1454 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1455 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1456 }
1457}
1458
1459
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001460TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1461 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001462 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001463 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001464 HeapIterator iterator;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001465 intptr_t size_of_objects_2 = 0;
1466 for (HeapObject* obj = iterator.next();
1467 obj != NULL;
1468 obj = iterator.next()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001469 if (!obj->IsFreeSpace()) {
1470 size_of_objects_2 += obj->Size();
1471 }
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001472 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001473 // Delta must be within 5% of the larger result.
1474 // TODO(gc): Tighten this up by distinguishing between byte
1475 // arrays that are real and those that merely mark free space
1476 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001477 if (size_of_objects_1 > size_of_objects_2) {
1478 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1479 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1480 "Iterator: %" V8_PTR_PREFIX "d, "
1481 "delta: %" V8_PTR_PREFIX "d\n",
1482 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001483 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001484 } else {
1485 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1486 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1487 "Iterator: %" V8_PTR_PREFIX "d, "
1488 "delta: %" V8_PTR_PREFIX "d\n",
1489 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001490 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001491 }
1492}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001493
1494
danno@chromium.orgc612e022011-11-10 11:38:15 +00001495static void FillUpNewSpace(NewSpace* new_space) {
1496 // Fill up new space to the point that it is completely full. Make sure
1497 // that the scavenger does not undo the filling.
1498 v8::HandleScope scope;
1499 AlwaysAllocateScope always_allocate;
1500 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001501 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001502 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001503 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001504 }
1505}
1506
1507
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001508TEST(GrowAndShrinkNewSpace) {
1509 InitializeVM();
1510 NewSpace* new_space = HEAP->new_space();
1511
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001512 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1513 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001514 // The max size cannot exceed the reserved size, since semispaces must be
1515 // always within the reserved space. We can't test new space growing and
1516 // shrinking if the reserved size is the same as the minimum (initial) size.
1517 return;
1518 }
1519
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001520 // Explicitly growing should double the space capacity.
1521 intptr_t old_capacity, new_capacity;
1522 old_capacity = new_space->Capacity();
1523 new_space->Grow();
1524 new_capacity = new_space->Capacity();
1525 CHECK(2 * old_capacity == new_capacity);
1526
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001527 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001528 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001529 new_capacity = new_space->Capacity();
1530 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001531
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001532 // Explicitly shrinking should not affect space capacity.
1533 old_capacity = new_space->Capacity();
1534 new_space->Shrink();
1535 new_capacity = new_space->Capacity();
1536 CHECK(old_capacity == new_capacity);
1537
1538 // Let the scavenger empty the new space.
1539 HEAP->CollectGarbage(NEW_SPACE);
1540 CHECK_LE(new_space->Size(), old_capacity);
1541
1542 // Explicitly shrinking should halve the space capacity.
1543 old_capacity = new_space->Capacity();
1544 new_space->Shrink();
1545 new_capacity = new_space->Capacity();
1546 CHECK(old_capacity == 2 * new_capacity);
1547
1548 // Consecutive shrinking should not affect space capacity.
1549 old_capacity = new_space->Capacity();
1550 new_space->Shrink();
1551 new_space->Shrink();
1552 new_space->Shrink();
1553 new_capacity = new_space->Capacity();
1554 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001555}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001556
1557
1558TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1559 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001560
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001561 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1562 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001563 // The max size cannot exceed the reserved size, since semispaces must be
1564 // always within the reserved space. We can't test new space growing and
1565 // shrinking if the reserved size is the same as the minimum (initial) size.
1566 return;
1567 }
1568
danno@chromium.orgc612e022011-11-10 11:38:15 +00001569 v8::HandleScope scope;
1570 NewSpace* new_space = HEAP->new_space();
1571 intptr_t old_capacity, new_capacity;
1572 old_capacity = new_space->Capacity();
1573 new_space->Grow();
1574 new_capacity = new_space->Capacity();
1575 CHECK(2 * old_capacity == new_capacity);
1576 FillUpNewSpace(new_space);
1577 HEAP->CollectAllAvailableGarbage();
1578 new_capacity = new_space->Capacity();
1579 CHECK(old_capacity == new_capacity);
1580}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001581
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001582
1583static int NumberOfGlobalObjects() {
1584 int count = 0;
1585 HeapIterator iterator;
1586 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1587 if (obj->IsGlobalObject()) count++;
1588 }
1589 return count;
1590}
1591
1592
1593// Test that we don't embed maps from foreign contexts into
1594// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001595TEST(LeakNativeContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001596 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001597 v8::HandleScope outer_scope;
1598 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1599 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1600 ctx1->Enter();
1601
1602 HEAP->CollectAllAvailableGarbage();
1603 CHECK_EQ(4, NumberOfGlobalObjects());
1604
1605 {
1606 v8::HandleScope inner_scope;
1607 CompileRun("var v = {x: 42}");
1608 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1609 ctx2->Enter();
1610 ctx2->Global()->Set(v8_str("o"), v);
1611 v8::Local<v8::Value> res = CompileRun(
1612 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001613 "for (var i = 0; i < 10; ++i) f();"
1614 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001615 "f();");
1616 CHECK_EQ(42, res->Int32Value());
1617 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1618 ctx2->Exit();
1619 ctx1->Exit();
1620 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001621 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001622 }
1623 HEAP->CollectAllAvailableGarbage();
1624 CHECK_EQ(2, NumberOfGlobalObjects());
1625 ctx2.Dispose();
1626 HEAP->CollectAllAvailableGarbage();
1627 CHECK_EQ(0, NumberOfGlobalObjects());
1628}
1629
1630
1631// Test that we don't embed functions from foreign contexts into
1632// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001633TEST(LeakNativeContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001634 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001635 v8::HandleScope outer_scope;
1636 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1637 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1638 ctx1->Enter();
1639
1640 HEAP->CollectAllAvailableGarbage();
1641 CHECK_EQ(4, NumberOfGlobalObjects());
1642
1643 {
1644 v8::HandleScope inner_scope;
1645 CompileRun("var v = function() { return 42; }");
1646 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1647 ctx2->Enter();
1648 ctx2->Global()->Set(v8_str("o"), v);
1649 v8::Local<v8::Value> res = CompileRun(
1650 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001651 "for (var i = 0; i < 10; ++i) f(o);"
1652 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001653 "f(o);");
1654 CHECK_EQ(42, res->Int32Value());
1655 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1656 ctx2->Exit();
1657 ctx1->Exit();
1658 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001659 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001660 }
1661 HEAP->CollectAllAvailableGarbage();
1662 CHECK_EQ(2, NumberOfGlobalObjects());
1663 ctx2.Dispose();
1664 HEAP->CollectAllAvailableGarbage();
1665 CHECK_EQ(0, NumberOfGlobalObjects());
1666}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001667
1668
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001669TEST(LeakNativeContextViaMapKeyed) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001670 i::FLAG_allow_natives_syntax = true;
1671 v8::HandleScope outer_scope;
1672 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1673 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1674 ctx1->Enter();
1675
1676 HEAP->CollectAllAvailableGarbage();
1677 CHECK_EQ(4, NumberOfGlobalObjects());
1678
1679 {
1680 v8::HandleScope inner_scope;
1681 CompileRun("var v = [42, 43]");
1682 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1683 ctx2->Enter();
1684 ctx2->Global()->Set(v8_str("o"), v);
1685 v8::Local<v8::Value> res = CompileRun(
1686 "function f() { return o[0]; }"
1687 "for (var i = 0; i < 10; ++i) f();"
1688 "%OptimizeFunctionOnNextCall(f);"
1689 "f();");
1690 CHECK_EQ(42, res->Int32Value());
1691 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1692 ctx2->Exit();
1693 ctx1->Exit();
1694 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001695 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001696 }
1697 HEAP->CollectAllAvailableGarbage();
1698 CHECK_EQ(2, NumberOfGlobalObjects());
1699 ctx2.Dispose();
1700 HEAP->CollectAllAvailableGarbage();
1701 CHECK_EQ(0, NumberOfGlobalObjects());
1702}
1703
1704
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001705TEST(LeakNativeContextViaMapProto) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001706 i::FLAG_allow_natives_syntax = true;
1707 v8::HandleScope outer_scope;
1708 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1709 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1710 ctx1->Enter();
1711
1712 HEAP->CollectAllAvailableGarbage();
1713 CHECK_EQ(4, NumberOfGlobalObjects());
1714
1715 {
1716 v8::HandleScope inner_scope;
1717 CompileRun("var v = { y: 42}");
1718 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1719 ctx2->Enter();
1720 ctx2->Global()->Set(v8_str("o"), v);
1721 v8::Local<v8::Value> res = CompileRun(
1722 "function f() {"
1723 " var p = {x: 42};"
1724 " p.__proto__ = o;"
1725 " return p.x;"
1726 "}"
1727 "for (var i = 0; i < 10; ++i) f();"
1728 "%OptimizeFunctionOnNextCall(f);"
1729 "f();");
1730 CHECK_EQ(42, res->Int32Value());
1731 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1732 ctx2->Exit();
1733 ctx1->Exit();
1734 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001735 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001736 }
1737 HEAP->CollectAllAvailableGarbage();
1738 CHECK_EQ(2, NumberOfGlobalObjects());
1739 ctx2.Dispose();
1740 HEAP->CollectAllAvailableGarbage();
1741 CHECK_EQ(0, NumberOfGlobalObjects());
1742}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001743
1744
1745TEST(InstanceOfStubWriteBarrier) {
1746 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001747#ifdef VERIFY_HEAP
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001748 i::FLAG_verify_heap = true;
1749#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001750
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001751 InitializeVM();
1752 if (!i::V8::UseCrankshaft()) return;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001753 if (i::FLAG_force_marking_deque_overflows) return;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001754 v8::HandleScope outer_scope;
1755
1756 {
1757 v8::HandleScope scope;
1758 CompileRun(
1759 "function foo () { }"
1760 "function mkbar () { return new (new Function(\"\")) (); }"
1761 "function f (x) { return (x instanceof foo); }"
1762 "function g () { f(mkbar()); }"
1763 "f(new foo()); f(new foo());"
1764 "%OptimizeFunctionOnNextCall(f);"
1765 "f(new foo()); g();");
1766 }
1767
1768 IncrementalMarking* marking = HEAP->incremental_marking();
1769 marking->Abort();
1770 marking->Start();
1771
1772 Handle<JSFunction> f =
1773 v8::Utils::OpenHandle(
1774 *v8::Handle<v8::Function>::Cast(
1775 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1776
1777 CHECK(f->IsOptimized());
1778
1779 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1780 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001781 // Discard any pending GC requests otherwise we will get GC when we enter
1782 // code below.
1783 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001784 }
1785
1786 CHECK(marking->IsMarking());
1787
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001788 {
1789 v8::HandleScope scope;
1790 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1791 v8::Handle<v8::Function> g =
1792 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1793 g->Call(global, 0, NULL);
1794 }
1795
1796 HEAP->incremental_marking()->set_should_hurry(true);
1797 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1798}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001799
1800
1801TEST(PrototypeTransitionClearing) {
1802 InitializeVM();
1803 v8::HandleScope scope;
1804
1805 CompileRun(
1806 "var base = {};"
1807 "var live = [];"
1808 "for (var i = 0; i < 10; i++) {"
1809 " var object = {};"
1810 " var prototype = {};"
1811 " object.__proto__ = prototype;"
1812 " if (i >= 3) live.push(object, prototype);"
1813 "}");
1814
1815 Handle<JSObject> baseObject =
1816 v8::Utils::OpenHandle(
1817 *v8::Handle<v8::Object>::Cast(
1818 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1819
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001820 // Verify that only dead prototype transitions are cleared.
1821 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001822 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001823 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001824 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001825
1826 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001827 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001828 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001829 int j = Map::kProtoTransitionHeaderSize +
1830 i * Map::kProtoTransitionElementsPerEntry;
1831 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001832 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1833 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001834 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001835
1836 // Make sure next prototype is placed on an old-space evacuation candidate.
1837 Handle<JSObject> prototype;
1838 PagedSpace* space = HEAP->old_pointer_space();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001839 {
1840 AlwaysAllocateScope always_allocate;
1841 SimulateFullSpace(space);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001842 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001843 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001844
1845 // Add a prototype on an evacuation candidate and verify that transition
1846 // clearing correctly records slots in prototype transition array.
1847 i::FLAG_always_compact = true;
1848 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001849 CHECK(!space->LastPage()->Contains(
1850 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001851 CHECK(space->LastPage()->Contains(prototype->address()));
1852 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1853 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1854 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1855 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001856}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001857
1858
1859TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1860 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001861#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001862 i::FLAG_verify_heap = true;
1863#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001864
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001865 InitializeVM();
1866 if (!i::V8::UseCrankshaft()) return;
1867 v8::HandleScope outer_scope;
1868
1869 {
1870 v8::HandleScope scope;
1871 CompileRun(
1872 "function f () {"
1873 " var s = 0;"
1874 " for (var i = 0; i < 100; i++) s += i;"
1875 " return s;"
1876 "}"
1877 "f(); f();"
1878 "%OptimizeFunctionOnNextCall(f);"
1879 "f();");
1880 }
1881 Handle<JSFunction> f =
1882 v8::Utils::OpenHandle(
1883 *v8::Handle<v8::Function>::Cast(
1884 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1885 CHECK(f->IsOptimized());
1886
1887 IncrementalMarking* marking = HEAP->incremental_marking();
1888 marking->Abort();
1889 marking->Start();
1890
1891 // The following two calls will increment HEAP->global_ic_age().
1892 const int kLongIdlePauseInMs = 1000;
1893 v8::V8::ContextDisposedNotification();
1894 v8::V8::IdleNotification(kLongIdlePauseInMs);
1895
1896 while (!marking->IsStopped() && !marking->IsComplete()) {
1897 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1898 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001899 if (!marking->IsStopped() || marking->should_hurry()) {
1900 // We don't normally finish a GC via Step(), we normally finish by
1901 // setting the stack guard and then do the final steps in the stack
1902 // guard interrupt. But here we didn't ask for that, and there is no
1903 // JS code running to trigger the interrupt, so we explicitly finalize
1904 // here.
1905 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1906 "Test finalizing incremental mark-sweep");
1907 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001908
1909 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1910 CHECK_EQ(0, f->shared()->opt_count());
1911 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1912}
1913
1914
1915TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1916 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001917#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001918 i::FLAG_verify_heap = true;
1919#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001920
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001921 InitializeVM();
1922 if (!i::V8::UseCrankshaft()) return;
1923 v8::HandleScope outer_scope;
1924
1925 {
1926 v8::HandleScope scope;
1927 CompileRun(
1928 "function f () {"
1929 " var s = 0;"
1930 " for (var i = 0; i < 100; i++) s += i;"
1931 " return s;"
1932 "}"
1933 "f(); f();"
1934 "%OptimizeFunctionOnNextCall(f);"
1935 "f();");
1936 }
1937 Handle<JSFunction> f =
1938 v8::Utils::OpenHandle(
1939 *v8::Handle<v8::Function>::Cast(
1940 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1941 CHECK(f->IsOptimized());
1942
1943 HEAP->incremental_marking()->Abort();
1944
1945 // The following two calls will increment HEAP->global_ic_age().
1946 // Since incremental marking is off, IdleNotification will do full GC.
1947 const int kLongIdlePauseInMs = 1000;
1948 v8::V8::ContextDisposedNotification();
1949 v8::V8::IdleNotification(kLongIdlePauseInMs);
1950
1951 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1952 CHECK_EQ(0, f->shared()->opt_count());
1953 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1954}
1955
1956
1957// Test that HAllocateObject will always return an object in new-space.
1958TEST(OptimizedAllocationAlwaysInNewSpace) {
1959 i::FLAG_allow_natives_syntax = true;
1960 InitializeVM();
1961 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001962 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001963 v8::HandleScope scope;
1964
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001965 SimulateFullSpace(HEAP->new_space());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001966 AlwaysAllocateScope always_allocate;
1967 v8::Local<v8::Value> res = CompileRun(
1968 "function c(x) {"
1969 " this.x = x;"
1970 " for (var i = 0; i < 32; i++) {"
1971 " this['x' + i] = x;"
1972 " }"
1973 "}"
1974 "function f(x) { return new c(x); };"
1975 "f(1); f(2); f(3);"
1976 "%OptimizeFunctionOnNextCall(f);"
1977 "f(4);");
1978 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
1979
1980 Handle<JSObject> o =
1981 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
1982
1983 CHECK(HEAP->InNewSpace(*o));
1984}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001985
1986
1987static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001988 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001989}
1990
1991
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001992// Test that map transitions are cleared and maps are collected with
1993// incremental marking as well.
1994TEST(Regress1465) {
1995 i::FLAG_allow_natives_syntax = true;
1996 i::FLAG_trace_incremental_marking = true;
1997 InitializeVM();
1998 v8::HandleScope scope;
1999 static const int transitions_count = 256;
2000
2001 {
2002 AlwaysAllocateScope always_allocate;
2003 for (int i = 0; i < transitions_count; i++) {
2004 EmbeddedVector<char, 64> buffer;
2005 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
2006 CompileRun(buffer.start());
2007 }
2008 CompileRun("var root = new Object;");
2009 }
2010
2011 Handle<JSObject> root =
2012 v8::Utils::OpenHandle(
2013 *v8::Handle<v8::Object>::Cast(
2014 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2015
2016 // Count number of live transitions before marking.
2017 int transitions_before = CountMapTransitions(root->map());
2018 CompileRun("%DebugPrint(root);");
2019 CHECK_EQ(transitions_count, transitions_before);
2020
2021 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002022 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002023
2024 // Count number of live transitions after marking. Note that one transition
2025 // is left, because 'o' still holds an instance of one transition target.
2026 int transitions_after = CountMapTransitions(root->map());
2027 CompileRun("%DebugPrint(root);");
2028 CHECK_EQ(1, transitions_after);
2029}
verwaest@chromium.org37141392012-05-31 13:27:02 +00002030
2031
2032TEST(Regress2143a) {
2033 i::FLAG_collect_maps = true;
2034 i::FLAG_incremental_marking = true;
2035 InitializeVM();
2036 v8::HandleScope scope;
2037
2038 // Prepare a map transition from the root object together with a yet
2039 // untransitioned root object.
2040 CompileRun("var root = new Object;"
2041 "root.foo = 0;"
2042 "root = new Object;");
2043
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002044 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002045
2046 // Compile a StoreIC that performs the prepared map transition. This
2047 // will restart incremental marking and should make sure the root is
2048 // marked grey again.
2049 CompileRun("function f(o) {"
2050 " o.foo = 0;"
2051 "}"
2052 "f(new Object);"
2053 "f(root);");
2054
2055 // This bug only triggers with aggressive IC clearing.
2056 HEAP->AgeInlineCaches();
2057
2058 // Explicitly request GC to perform final marking step and sweeping.
2059 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002060
2061 Handle<JSObject> root =
2062 v8::Utils::OpenHandle(
2063 *v8::Handle<v8::Object>::Cast(
2064 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2065
2066 // The root object should be in a sane state.
2067 CHECK(root->IsJSObject());
2068 CHECK(root->map()->IsMap());
2069}
2070
2071
2072TEST(Regress2143b) {
2073 i::FLAG_collect_maps = true;
2074 i::FLAG_incremental_marking = true;
2075 i::FLAG_allow_natives_syntax = true;
2076 InitializeVM();
2077 v8::HandleScope scope;
2078
2079 // Prepare a map transition from the root object together with a yet
2080 // untransitioned root object.
2081 CompileRun("var root = new Object;"
2082 "root.foo = 0;"
2083 "root = new Object;");
2084
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002085 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002086
2087 // Compile an optimized LStoreNamedField that performs the prepared
2088 // map transition. This will restart incremental marking and should
2089 // make sure the root is marked grey again.
2090 CompileRun("function f(o) {"
2091 " o.foo = 0;"
2092 "}"
2093 "f(new Object);"
2094 "f(new Object);"
2095 "%OptimizeFunctionOnNextCall(f);"
2096 "f(root);"
2097 "%DeoptimizeFunction(f);");
2098
2099 // This bug only triggers with aggressive IC clearing.
2100 HEAP->AgeInlineCaches();
2101
2102 // Explicitly request GC to perform final marking step and sweeping.
2103 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002104
2105 Handle<JSObject> root =
2106 v8::Utils::OpenHandle(
2107 *v8::Handle<v8::Object>::Cast(
2108 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2109
2110 // The root object should be in a sane state.
2111 CHECK(root->IsJSObject());
2112 CHECK(root->map()->IsMap());
2113}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002114
2115
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002116TEST(ReleaseOverReservedPages) {
2117 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002118 // The optimizer can allocate stuff, messing up the test.
2119 i::FLAG_crankshaft = false;
2120 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002121 InitializeVM();
2122 v8::HandleScope scope;
2123 static const int number_of_test_pages = 20;
2124
2125 // Prepare many pages with low live-bytes count.
2126 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
2127 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2128 for (int i = 0; i < number_of_test_pages; i++) {
2129 AlwaysAllocateScope always_allocate;
2130 SimulateFullSpace(old_pointer_space);
2131 FACTORY->NewFixedArray(1, TENURED);
2132 }
2133 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2134
2135 // Triggering one GC will cause a lot of garbage to be discovered but
2136 // even spread across all allocated pages.
2137 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002138 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002139
2140 // Triggering subsequent GCs should cause at least half of the pages
2141 // to be released to the OS after at most two cycles.
2142 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
2143 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2144 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
2145 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
2146
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002147 // Triggering a last-resort GC should cause all pages to be released to the
2148 // OS so that other processes can seize the memory. If we get a failure here
2149 // where there are 2 pages left instead of 1, then we should increase the
2150 // size of the first page a little in SizeOfFirstPage in spaces.cc. The
2151 // first page should be small in order to reduce memory used when the VM
2152 // boots, but if the 20 small arrays don't fit on the first page then that's
2153 // an indication that it is too small.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002154 HEAP->CollectAllAvailableGarbage("triggered really hard");
2155 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2156}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002157
2158
2159TEST(Regress2237) {
2160 InitializeVM();
2161 v8::HandleScope scope;
2162 Handle<String> slice(HEAP->empty_string());
2163
2164 {
2165 // Generate a parent that lives in new-space.
2166 v8::HandleScope inner_scope;
2167 const char* c = "This text is long enough to trigger sliced strings.";
2168 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002169 CHECK(s->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002170 CHECK(HEAP->InNewSpace(*s));
2171
2172 // Generate a sliced string that is based on the above parent and
2173 // lives in old-space.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002174 SimulateFullSpace(HEAP->new_space());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002175 AlwaysAllocateScope always_allocate;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002176 Handle<String> t = FACTORY->NewProperSubString(s, 5, 35);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002177 CHECK(t->IsSlicedString());
2178 CHECK(!HEAP->InNewSpace(*t));
2179 *slice.location() = *t.location();
2180 }
2181
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002182 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002183 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002184 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002185}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002186
2187
2188#ifdef OBJECT_PRINT
2189TEST(PrintSharedFunctionInfo) {
2190 InitializeVM();
2191 v8::HandleScope scope;
2192 const char* source = "f = function() { return 987654321; }\n"
2193 "g = function() { return 123456789; }\n";
2194 CompileRun(source);
2195 Handle<JSFunction> g =
2196 v8::Utils::OpenHandle(
2197 *v8::Handle<v8::Function>::Cast(
2198 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2199
2200 AssertNoAllocation no_alloc;
2201 g->shared()->PrintLn();
2202}
2203#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002204
2205
2206TEST(Regress2211) {
2207 InitializeVM();
2208 v8::HandleScope scope;
2209
2210 v8::Handle<v8::String> value = v8_str("val string");
2211 Smi* hash = Smi::FromInt(321);
2212 Heap* heap = Isolate::Current()->heap();
2213
2214 for (int i = 0; i < 2; i++) {
2215 // Store identity hash first and common hidden property second.
2216 v8::Handle<v8::Object> obj = v8::Object::New();
2217 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2218 CHECK(internal_obj->HasFastProperties());
2219
2220 // In the first iteration, set hidden value first and identity hash second.
2221 // In the second iteration, reverse the order.
2222 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2223 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2224 ALLOW_CREATION);
2225 CHECK(!maybe_obj->IsFailure());
2226 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2227
2228 // Check values.
2229 CHECK_EQ(hash,
2230 internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
2231 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2232
2233 // Check size.
2234 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2235 ObjectHashTable* hashtable = ObjectHashTable::cast(
2236 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2237 // HashTable header (5) and 4 initial entries (8).
2238 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2239 }
2240}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002241
2242
2243TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2244 if (i::FLAG_always_opt) return;
2245 InitializeVM();
2246 v8::HandleScope scope;
2247 v8::Local<v8::Value> fun1, fun2;
2248
2249 {
2250 LocalContext env;
2251 CompileRun("function fun() {};");
2252 fun1 = env->Global()->Get(v8_str("fun"));
2253 }
2254
2255 {
2256 LocalContext env;
2257 CompileRun("function fun() {};");
2258 fun2 = env->Global()->Get(v8_str("fun"));
2259 }
2260
2261 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002262 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002263 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2264 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2265 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2266 Handle<JSFunction> f =
2267 v8::Utils::OpenHandle(
2268 *v8::Handle<v8::Function>::Cast(
2269 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2270 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2271 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2272
2273 CHECK_EQ(2, cells->CellCount());
2274 CHECK(cells->Cell(0)->value()->IsJSFunction());
2275 CHECK(cells->Cell(1)->value()->IsJSFunction());
2276
2277 SimulateIncrementalMarking();
2278 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2279
2280 CHECK_EQ(2, cells->CellCount());
2281 CHECK(cells->Cell(0)->value()->IsTheHole());
2282 CHECK(cells->Cell(1)->value()->IsTheHole());
2283}
2284
2285
2286static Code* FindFirstIC(Code* code, Code::Kind kind) {
2287 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2288 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2289 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2290 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2291 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2292 RelocInfo* info = it.rinfo();
2293 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2294 if (target->is_inline_cache_stub() && target->kind() == kind) {
2295 return target;
2296 }
2297 }
2298 return NULL;
2299}
2300
2301
2302TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2303 if (i::FLAG_always_opt) return;
2304 InitializeVM();
2305 v8::HandleScope scope;
2306
2307 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002308 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002309 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2310 "function f(o) { return o.x; } f(obj); f(obj);");
2311 Handle<JSFunction> f =
2312 v8::Utils::OpenHandle(
2313 *v8::Handle<v8::Function>::Cast(
2314 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2315
2316 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2317 CHECK(ic_before->ic_state() == MONOMORPHIC);
2318
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002319 SimulateIncrementalMarking();
2320 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2321
2322 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2323 CHECK(ic_after->ic_state() == MONOMORPHIC);
2324}
2325
2326
2327TEST(IncrementalMarkingClearsMonomorhpicIC) {
2328 if (i::FLAG_always_opt) return;
2329 InitializeVM();
2330 v8::HandleScope scope;
2331 v8::Local<v8::Value> obj1;
2332
2333 {
2334 LocalContext env;
2335 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2336 obj1 = env->Global()->Get(v8_str("obj"));
2337 }
2338
2339 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002340 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002341 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2342 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2343 Handle<JSFunction> f =
2344 v8::Utils::OpenHandle(
2345 *v8::Handle<v8::Function>::Cast(
2346 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2347
2348 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2349 CHECK(ic_before->ic_state() == MONOMORPHIC);
2350
2351 // Fire context dispose notification.
2352 v8::V8::ContextDisposedNotification();
2353 SimulateIncrementalMarking();
2354 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2355
2356 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2357 CHECK(ic_after->ic_state() == UNINITIALIZED);
2358}
2359
2360
2361TEST(IncrementalMarkingClearsPolymorhpicIC) {
2362 if (i::FLAG_always_opt) return;
2363 InitializeVM();
2364 v8::HandleScope scope;
2365 v8::Local<v8::Value> obj1, obj2;
2366
2367 {
2368 LocalContext env;
2369 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2370 obj1 = env->Global()->Get(v8_str("obj"));
2371 }
2372
2373 {
2374 LocalContext env;
2375 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2376 obj2 = env->Global()->Get(v8_str("obj"));
2377 }
2378
2379 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002380 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002381 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2382 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2383 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2384 Handle<JSFunction> f =
2385 v8::Utils::OpenHandle(
2386 *v8::Handle<v8::Function>::Cast(
2387 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2388
2389 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2390 CHECK(ic_before->ic_state() == MEGAMORPHIC);
2391
2392 // Fire context dispose notification.
2393 v8::V8::ContextDisposedNotification();
2394 SimulateIncrementalMarking();
2395 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2396
2397 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2398 CHECK(ic_after->ic_state() == UNINITIALIZED);
2399}
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002400
2401
2402class SourceResource: public v8::String::ExternalAsciiStringResource {
2403 public:
2404 explicit SourceResource(const char* data)
2405 : data_(data), length_(strlen(data)) { }
2406
2407 virtual void Dispose() {
2408 i::DeleteArray(data_);
2409 data_ = NULL;
2410 }
2411
2412 const char* data() const { return data_; }
2413
2414 size_t length() const { return length_; }
2415
2416 bool IsDisposed() { return data_ == NULL; }
2417
2418 private:
2419 const char* data_;
2420 size_t length_;
2421};
2422
2423
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002424void ReleaseStackTraceDataTest(const char* source) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002425 // Test that the data retained by the Error.stack accessor is released
2426 // after the first time the accessor is fired. We use external string
2427 // to check whether the data is being released since the external string
2428 // resource's callback is fired when the external string is GC'ed.
2429 InitializeVM();
2430 v8::HandleScope scope;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002431 SourceResource* resource = new SourceResource(i::StrDup(source));
2432 {
2433 v8::HandleScope scope;
2434 v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
2435 v8::Script::Compile(source_string)->Run();
2436 CHECK(!resource->IsDisposed());
2437 }
2438 HEAP->CollectAllAvailableGarbage();
ulan@chromium.org4121f232012-12-27 15:57:11 +00002439 // External source is being retained by the stack trace.
2440 CHECK(!resource->IsDisposed());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002441
ulan@chromium.org4121f232012-12-27 15:57:11 +00002442 CompileRun("error.stack;");
2443 HEAP->CollectAllAvailableGarbage();
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}