blob: 1e43d8b1a31e08226745d052dbfdacecf1799781 [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);
65 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
66}
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);
73 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
74}
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);
82 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
83}
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
167 // nan oddball checks
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 CHECK(HEAP->nan_value()->IsNumber());
169 CHECK(isnan(HEAP->nan_value()->Number()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000170
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000171 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000172 CHECK(s->IsString());
173 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000174
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000175 String* object_symbol = String::cast(HEAP->Object_symbol());
176 CHECK(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000177 Isolate::Current()->context()->global_object()->HasLocalProperty(
178 object_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000179
180 // Check ToString for oddballs
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000181 CheckOddball(HEAP->true_value(), "true");
182 CheckOddball(HEAP->false_value(), "false");
183 CheckOddball(HEAP->null_value(), "null");
184 CheckOddball(HEAP->undefined_value(), "undefined");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000185
186 // Check ToString for Smis
187 CheckSmi(0, "0");
188 CheckSmi(42, "42");
189 CheckSmi(-42, "-42");
190
191 // Check ToString for Numbers
192 CheckNumber(1.1, "1.1");
193
194 CheckFindCodeObject();
195}
196
197
198TEST(Tagging) {
199 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000200 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000201 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000202 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000203 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000204 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000205 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000206 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000207 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000208 CHECK(Failure::Exception()->IsFailure());
209 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
210 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
211}
212
213
214TEST(GarbageCollection) {
215 InitializeVM();
216
217 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000218 // Check GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000219 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000220
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000221 Handle<String> name = FACTORY->LookupUtf8Symbol("theFunction");
222 Handle<String> prop_name = FACTORY->LookupUtf8Symbol("theSlot");
223 Handle<String> prop_namex = FACTORY->LookupUtf8Symbol("theSlotx");
224 Handle<String> obj_name = FACTORY->LookupUtf8Symbol("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000225
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000226 {
227 v8::HandleScope inner_scope;
228 // Allocate a function and keep it in global object's property.
229 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000230 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000231 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000232 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000233 function->set_initial_map(*initial_map);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000234 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000235 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000236 // Allocate an object. Unrooted after leaving the scope.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000238 obj->SetProperty(
239 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
240 obj->SetProperty(
241 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000242
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000243 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
244 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
245 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000246
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000247 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000248
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000249 // Function should be alive.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000250 CHECK(Isolate::Current()->context()->global_object()->
251 HasLocalProperty(*name));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000252 // Check function is retained.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000253 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000254 GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000255 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000256 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000257
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000258 {
259 HandleScope inner_scope;
260 // Allocate another object, make it reachable from global.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000261 Handle<JSObject> obj = FACTORY->NewJSObject(function);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000262 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000263 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
264 obj->SetProperty(
265 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000266 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000267
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000268 // After gc, it should survive.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000269 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000270
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000271 CHECK(Isolate::Current()->context()->global_object()->
272 HasLocalProperty(*obj_name));
273 CHECK(Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000274 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000275 Object* obj = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000276 GetProperty(*obj_name)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000277 JSObject* js_obj = JSObject::cast(obj);
278 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000279}
280
281
282static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000283 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000284 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000285 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000286 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000287 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
288 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000289}
290
291
292TEST(String) {
293 InitializeVM();
294
295 VerifyStringAllocation("a");
296 VerifyStringAllocation("ab");
297 VerifyStringAllocation("abc");
298 VerifyStringAllocation("abcd");
299 VerifyStringAllocation("fiskerdrengen er paa havet");
300}
301
302
303TEST(LocalHandles) {
304 InitializeVM();
305
306 v8::HandleScope scope;
307 const char* name = "Kasper the spunky";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000308 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000309 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000310}
311
312
313TEST(GlobalHandles) {
314 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000315 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000316
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000317 Handle<Object> h1;
318 Handle<Object> h2;
319 Handle<Object> h3;
320 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000321
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000322 {
323 HandleScope scope;
324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000325 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
326 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000327
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000328 h1 = global_handles->Create(*i);
329 h2 = global_handles->Create(*u);
330 h3 = global_handles->Create(*i);
331 h4 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000332 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000333
334 // after gc, it should survive
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000335 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000336
337 CHECK((*h1)->IsString());
338 CHECK((*h2)->IsHeapNumber());
339 CHECK((*h3)->IsString());
340 CHECK((*h4)->IsHeapNumber());
341
342 CHECK_EQ(*h3, *h1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000343 global_handles->Destroy(h1.location());
344 global_handles->Destroy(h3.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000345
346 CHECK_EQ(*h4, *h2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000347 global_handles->Destroy(h2.location());
348 global_handles->Destroy(h4.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000349}
350
351
352static bool WeakPointerCleared = false;
353
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000354static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000355 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000356 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000357 handle.Dispose();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000358}
359
360
361TEST(WeakGlobalHandlesScavenge) {
362 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000363 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000364
365 WeakPointerCleared = false;
366
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000367 Handle<Object> h1;
368 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000369
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000370 {
371 HandleScope scope;
372
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000373 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
374 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000375
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000376 h1 = global_handles->Create(*i);
377 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000378 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000379
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000380 global_handles->MakeWeak(h2.location(),
381 reinterpret_cast<void*>(1234),
382 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000383
384 // Scavenge treats weak pointers as normal roots.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000385 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000386
387 CHECK((*h1)->IsString());
388 CHECK((*h2)->IsHeapNumber());
389
390 CHECK(!WeakPointerCleared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000391 CHECK(!global_handles->IsNearDeath(h2.location()));
392 CHECK(!global_handles->IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000393
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000394 global_handles->Destroy(h1.location());
395 global_handles->Destroy(h2.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000396}
397
398
399TEST(WeakGlobalHandlesMark) {
400 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000401 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000402
403 WeakPointerCleared = false;
404
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000405 Handle<Object> h1;
406 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000407
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000408 {
409 HandleScope scope;
410
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
412 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000413
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000414 h1 = global_handles->Create(*i);
415 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000416 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000417
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000418 // Make sure the objects are promoted.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000419 HEAP->CollectGarbage(OLD_POINTER_SPACE);
420 HEAP->CollectGarbage(NEW_SPACE);
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000421 CHECK(!HEAP->InNewSpace(*h1) && !HEAP->InNewSpace(*h2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000422
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000423 global_handles->MakeWeak(h2.location(),
424 reinterpret_cast<void*>(1234),
425 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000426 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
427 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
428
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000429 // Incremental marking potentially marked handles before they turned weak.
430 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000431
432 CHECK((*h1)->IsString());
433
434 CHECK(WeakPointerCleared);
435 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000436
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000437 global_handles->Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000438}
439
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000440
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000441TEST(DeleteWeakGlobalHandle) {
442 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000443 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000444
445 WeakPointerCleared = false;
446
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000447 Handle<Object> h;
448
449 {
450 HandleScope scope;
451
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000452 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
453 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000454 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000455
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000456 global_handles->MakeWeak(h.location(),
457 reinterpret_cast<void*>(1234),
458 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000459
460 // Scanvenge does not recognize weak reference.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000461 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000462
463 CHECK(!WeakPointerCleared);
464
465 // Mark-compact treats weak reference properly.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000466 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000467
468 CHECK(WeakPointerCleared);
469}
470
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000471
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000472static const char* not_so_random_string_table[] = {
473 "abstract",
474 "boolean",
475 "break",
476 "byte",
477 "case",
478 "catch",
479 "char",
480 "class",
481 "const",
482 "continue",
483 "debugger",
484 "default",
485 "delete",
486 "do",
487 "double",
488 "else",
489 "enum",
490 "export",
491 "extends",
492 "false",
493 "final",
494 "finally",
495 "float",
496 "for",
497 "function",
498 "goto",
499 "if",
500 "implements",
501 "import",
502 "in",
503 "instanceof",
504 "int",
505 "interface",
506 "long",
507 "native",
508 "new",
509 "null",
510 "package",
511 "private",
512 "protected",
513 "public",
514 "return",
515 "short",
516 "static",
517 "super",
518 "switch",
519 "synchronized",
520 "this",
521 "throw",
522 "throws",
523 "transient",
524 "true",
525 "try",
526 "typeof",
527 "var",
528 "void",
529 "volatile",
530 "while",
531 "with",
532 0
533};
534
535
536static void CheckSymbols(const char** strings) {
537 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000538 Object* a;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000539 MaybeObject* maybe_a = HEAP->LookupUtf8Symbol(string);
540 // LookupUtf8Symbol may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000541 if (!maybe_a->ToObject(&a)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000542 CHECK(a->IsSymbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000543 Object* b;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000544 MaybeObject* maybe_b = HEAP->LookupUtf8Symbol(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000545 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000546 CHECK_EQ(b, a);
547 CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
548 }
549}
550
551
552TEST(SymbolTable) {
553 InitializeVM();
554
555 CheckSymbols(not_so_random_string_table);
556 CheckSymbols(not_so_random_string_table);
557}
558
559
560TEST(FunctionAllocation) {
561 InitializeVM();
562
563 v8::HandleScope sc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000564 Handle<String> name = FACTORY->LookupUtf8Symbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000565 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000566 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000567 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000569 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000570
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000571 Handle<String> prop_name = FACTORY->LookupUtf8Symbol("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000572 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000573 obj->SetProperty(
574 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000575 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000576 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000577 function->SetProperty(
578 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000579 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000580}
581
582
583TEST(ObjectProperties) {
584 InitializeVM();
585
586 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000588 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000589 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000590 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000591 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000592 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000593 Handle<String> first = FACTORY->LookupUtf8Symbol("first");
594 Handle<String> second = FACTORY->LookupUtf8Symbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000595
596 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000597 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000598
599 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000600 obj->SetProperty(
601 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000602 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000603
604 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000605 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
606 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000607
608 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000609 obj->SetProperty(
610 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
611 obj->SetProperty(
612 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000613 CHECK(obj->HasLocalProperty(*first));
614 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000615
616 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000617 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
618 CHECK(obj->HasLocalProperty(*second));
619 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
620 CHECK(!obj->HasLocalProperty(*first));
621 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000622
623 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000624 obj->SetProperty(
625 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
626 obj->SetProperty(
627 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000628 CHECK(obj->HasLocalProperty(*first));
629 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000630
631 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000632 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
633 CHECK(obj->HasLocalProperty(*first));
634 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
635 CHECK(!obj->HasLocalProperty(*first));
636 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000637
638 // check string and symbol match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000639 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000641 obj->SetProperty(
642 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000643 Handle<String> s1_symbol = FACTORY->LookupUtf8Symbol(string1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000644 CHECK(obj->HasLocalProperty(*s1_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000645
646 // check symbol and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000647 const char* string2 = "fugl";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000648 Handle<String> s2_symbol = FACTORY->LookupUtf8Symbol(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000649 obj->SetProperty(
650 *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000651 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000652 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000653}
654
655
656TEST(JSObjectMaps) {
657 InitializeVM();
658
659 v8::HandleScope sc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000660 Handle<String> name = FACTORY->LookupUtf8Symbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000661 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000662 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000663 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000664 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000665 function->set_initial_map(*initial_map);
666
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000667 Handle<String> prop_name = FACTORY->LookupUtf8Symbol("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000668 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000669
670 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000671 obj->SetProperty(
672 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000673 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000674
675 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000676 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000677}
678
679
680TEST(JSArray) {
681 InitializeVM();
682
683 v8::HandleScope sc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000684 Handle<String> name = FACTORY->LookupUtf8Symbol("Array");
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000685 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000686 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000687 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000688 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000689
690 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000691 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000692 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000693 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000694 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000695
696 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000697 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000698 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000699 // Must be in fast mode.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000700 CHECK(array->HasFastSmiOrObjectElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000701
702 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000703 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000704 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000705 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000706
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000707 // Set array length with larger than smi value.
708 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000709 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000710 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000711
712 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000713 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000714 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000715 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000716
717 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000718 array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000719 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000720 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000721 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000722 CHECK_EQ(array->GetElement(int_length), *name);
723 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000724}
725
726
727TEST(JSObjectCopy) {
728 InitializeVM();
729
730 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000731 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000732 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000733 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000734 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000735 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000736 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000737 Handle<String> first = FACTORY->LookupUtf8Symbol("first");
738 Handle<String> second = FACTORY->LookupUtf8Symbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000739
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000740 obj->SetProperty(
741 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
742 obj->SetProperty(
743 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000744
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000745 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
746 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000747
748 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000749 Handle<JSObject> clone = Copy(obj);
750 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000751
752 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
753 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
754
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000755 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
756 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000757
758 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000759 clone->SetProperty(
760 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
761 clone->SetProperty(
762 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000763
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000764 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
765 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000766
767 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
768 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
769
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000770 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
771 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000772}
773
774
775TEST(StringAllocation) {
776 InitializeVM();
777
778
779 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
780 for (int length = 0; length < 100; length++) {
781 v8::HandleScope scope;
782 char* non_ascii = NewArray<char>(3 * length + 1);
783 char* ascii = NewArray<char>(length + 1);
784 non_ascii[3 * length] = 0;
785 ascii[length] = 0;
786 for (int i = 0; i < length; i++) {
787 ascii[i] = 'a';
788 non_ascii[3 * i] = chars[0];
789 non_ascii[3 * i + 1] = chars[1];
790 non_ascii[3 * i + 2] = chars[2];
791 }
792 Handle<String> non_ascii_sym =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000793 FACTORY->LookupUtf8Symbol(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000794 CHECK_EQ(length, non_ascii_sym->length());
795 Handle<String> ascii_sym =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000796 FACTORY->LookupOneByteSymbol(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000797 CHECK_EQ(length, ascii_sym->length());
798 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000799 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000800 non_ascii_str->Hash();
801 CHECK_EQ(length, non_ascii_str->length());
802 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000803 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000804 ascii_str->Hash();
805 CHECK_EQ(length, ascii_str->length());
806 DeleteArray(non_ascii);
807 DeleteArray(ascii);
808 }
809}
810
811
812static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
813 // Count the number of objects found in the heap.
814 int found_count = 0;
815 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000816 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000817 for (int i = 0; i < size; i++) {
818 if (*objs[i] == obj) {
819 found_count++;
820 }
821 }
822 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000823 return found_count;
824}
825
826
827TEST(Iteration) {
828 InitializeVM();
829 v8::HandleScope scope;
830
831 // Array of objects to scan haep for.
832 const int objs_count = 6;
833 Handle<Object> objs[objs_count];
834 int next_objs_index = 0;
835
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000836 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000837 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000838 objs[next_objs_index++] = FACTORY->NewJSArray(10,
839 FAST_HOLEY_ELEMENTS,
840 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000841
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000842 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000843 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000845 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000846 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000847
848 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000849 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000850 char* str = new char[large_size];
851 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
852 str[large_size - 1] = '\0';
853 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000854 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000855 delete[] str;
856
857 // Add a Map object to look for.
858 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
859
860 CHECK_EQ(objs_count, next_objs_index);
861 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
862}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000863
864
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000865TEST(EmptyHandleEscapeFrom) {
866 InitializeVM();
867
868 v8::HandleScope scope;
869 Handle<JSObject> runaway;
870
871 {
872 v8::HandleScope nested;
873 Handle<JSObject> empty;
874 runaway = empty.EscapeFrom(&nested);
875 }
876
877 CHECK(runaway.is_null());
878}
879
880
881static int LenFromSize(int size) {
882 return (size - FixedArray::kHeaderSize) / kPointerSize;
883}
884
885
886TEST(Regression39128) {
887 // Test case for crbug.com/39128.
888 InitializeVM();
889
890 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000891 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000892
893 v8::HandleScope scope;
894
895 // The plan: create JSObject which references objects in new space.
896 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000897 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000898
899 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000900 Handle<JSFunction> object_ctor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000901 Isolate::Current()->native_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000902 CHECK(object_ctor->has_initial_map());
903 Handle<Map> object_map(object_ctor->initial_map());
904 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000905 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000906 int n_properties = my_map->inobject_properties();
907 CHECK_GT(n_properties, 0);
908
909 int object_size = my_map->instance_size();
910
911 // Step 2: allocate a lot of objects so to almost fill new space: we need
912 // just enough room to allocate JSObject and thus fill the newspace.
913
914 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000915 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000916 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000917 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000918 Address* top_addr = new_space->allocation_top_address();
919 Address* limit_addr = new_space->allocation_limit_address();
920 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000921 CHECK(!HEAP->always_allocate());
922 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
923 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000924 CHECK(new_space->Contains(array));
925 }
926
927 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000928 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000929 int fixed_array_len = LenFromSize(to_fill);
930 CHECK(fixed_array_len < FixedArray::kMaxLength);
931
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 CHECK(!HEAP->always_allocate());
933 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
934 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000935 CHECK(new_space->Contains(array));
936
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000937 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000938 CHECK(new_space->Contains(object));
939 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000940 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000941 CHECK_EQ(0, jsobject->properties()->length());
942 // Create a reference to object in new space in jsobject.
943 jsobject->FastPropertyAtPut(-1, array);
944
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000945 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000946
947 // Step 4: clone jsobject, but force always allocate first to create a clone
948 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000949 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000950 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000951 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000952 JSObject* clone = JSObject::cast(clone_obj);
953 if (clone->address() != old_pointer_space_top) {
954 // Alas, got allocated from free list, we cannot do checks.
955 return;
956 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000957 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000958}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000959
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000960
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000961TEST(TestCodeFlushing) {
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000962 // If we do not flush code this test is invalid.
963 if (!FLAG_flush_code) return;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000964 i::FLAG_allow_natives_syntax = true;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000965 InitializeVM();
966 v8::HandleScope scope;
967 const char* source = "function foo() {"
968 " var x = 42;"
969 " var y = 42;"
970 " var z = x + y;"
971 "};"
972 "foo()";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000973 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000974
975 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000976 { v8::HandleScope scope;
977 CompileRun(source);
978 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000979
980 // Check function is compiled.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000981 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000982 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000983 CHECK(func_value->IsJSFunction());
984 Handle<JSFunction> function(JSFunction::cast(func_value));
985 CHECK(function->shared()->is_compiled());
986
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000987 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000988 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
989 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000990 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000991
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000992 // Simulate several GCs that use full marking.
993 const int kAgingThreshold = 6;
994 for (int i = 0; i < kAgingThreshold; i++) {
995 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
996 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000997
998 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000999 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1000 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001001 // Call foo to get it recompiled.
1002 CompileRun("foo()");
1003 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001004 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001005}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001006
1007
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001008TEST(TestCodeFlushingIncremental) {
1009 // If we do not flush code this test is invalid.
1010 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1011 i::FLAG_allow_natives_syntax = true;
1012 InitializeVM();
1013 v8::HandleScope scope;
1014 const char* source = "function foo() {"
1015 " var x = 42;"
1016 " var y = 42;"
1017 " var z = x + y;"
1018 "};"
1019 "foo()";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001020 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001021
1022 // This compile will add the code to the compilation cache.
1023 { v8::HandleScope scope;
1024 CompileRun(source);
1025 }
1026
1027 // Check function is compiled.
1028 Object* func_value = Isolate::Current()->context()->global_object()->
1029 GetProperty(*foo_name)->ToObjectChecked();
1030 CHECK(func_value->IsJSFunction());
1031 Handle<JSFunction> function(JSFunction::cast(func_value));
1032 CHECK(function->shared()->is_compiled());
1033
1034 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001035 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1036 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001037 CHECK(function->shared()->is_compiled());
1038
1039 // Simulate several GCs that use incremental marking.
1040 const int kAgingThreshold = 6;
1041 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001042 SimulateIncrementalMarking();
1043 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1044 }
1045 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1046 CHECK(!function->is_compiled() || function->IsOptimized());
1047
1048 // This compile will compile the function again.
1049 { v8::HandleScope scope;
1050 CompileRun("foo();");
1051 }
1052
1053 // Simulate several GCs that use incremental marking but make sure
1054 // the loop breaks once the function is enqueued as a candidate.
1055 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001056 SimulateIncrementalMarking();
1057 if (!function->next_function_link()->IsUndefined()) break;
1058 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1059 }
1060
1061 // Force optimization while incremental marking is active and while
1062 // the function is enqueued as a candidate.
1063 { v8::HandleScope scope;
1064 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1065 }
1066
1067 // Simulate one final GC to make sure the candidate queue is sane.
1068 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1069 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1070 CHECK(function->is_compiled() || !function->IsOptimized());
1071}
1072
1073
1074TEST(TestCodeFlushingIncrementalScavenge) {
1075 // If we do not flush code this test is invalid.
1076 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1077 i::FLAG_allow_natives_syntax = true;
1078 InitializeVM();
1079 v8::HandleScope scope;
1080 const char* source = "var foo = function() {"
1081 " var x = 42;"
1082 " var y = 42;"
1083 " var z = x + y;"
1084 "};"
1085 "foo();"
1086 "var bar = function() {"
1087 " var x = 23;"
1088 "};"
1089 "bar();";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001090 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
1091 Handle<String> bar_name = FACTORY->LookupUtf8Symbol("bar");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001092
1093 // Perfrom one initial GC to enable code flushing.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001094 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001095
1096 // This compile will add the code to the compilation cache.
1097 { v8::HandleScope scope;
1098 CompileRun(source);
1099 }
1100
1101 // Check functions are compiled.
1102 Object* func_value = Isolate::Current()->context()->global_object()->
1103 GetProperty(*foo_name)->ToObjectChecked();
1104 CHECK(func_value->IsJSFunction());
1105 Handle<JSFunction> function(JSFunction::cast(func_value));
1106 CHECK(function->shared()->is_compiled());
1107 Object* func_value2 = Isolate::Current()->context()->global_object()->
1108 GetProperty(*bar_name)->ToObjectChecked();
1109 CHECK(func_value2->IsJSFunction());
1110 Handle<JSFunction> function2(JSFunction::cast(func_value2));
1111 CHECK(function2->shared()->is_compiled());
1112
1113 // Clear references to functions so that one of them can die.
1114 { v8::HandleScope scope;
1115 CompileRun("foo = 0; bar = 0;");
1116 }
1117
1118 // Bump the code age so that flushing is triggered while the function
1119 // object is still located in new-space.
1120 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001121 for (int i = 0; i < kAgingThreshold; i++) {
1122 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1123 function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1124 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001125
1126 // Simulate incremental marking so that the functions are enqueued as
1127 // code flushing candidates. Then kill one of the functions. Finally
1128 // perform a scavenge while incremental marking is still running.
1129 SimulateIncrementalMarking();
1130 *function2.location() = NULL;
1131 HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking");
1132
1133 // Simulate one final GC to make sure the candidate queue is sane.
1134 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1135 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1136 CHECK(!function->is_compiled() || function->IsOptimized());
1137}
1138
1139
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001140TEST(TestCodeFlushingIncrementalAbort) {
1141 // If we do not flush code this test is invalid.
1142 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1143 i::FLAG_allow_natives_syntax = true;
1144 InitializeVM();
1145 v8::HandleScope scope;
1146 const char* source = "function foo() {"
1147 " var x = 42;"
1148 " var y = 42;"
1149 " var z = x + y;"
1150 "};"
1151 "foo()";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001152 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001153
1154 // This compile will add the code to the compilation cache.
1155 { v8::HandleScope scope;
1156 CompileRun(source);
1157 }
1158
1159 // Check function is compiled.
1160 Object* func_value = Isolate::Current()->context()->global_object()->
1161 GetProperty(*foo_name)->ToObjectChecked();
1162 CHECK(func_value->IsJSFunction());
1163 Handle<JSFunction> function(JSFunction::cast(func_value));
1164 CHECK(function->shared()->is_compiled());
1165
1166 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001167 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1168 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001169 CHECK(function->shared()->is_compiled());
1170
1171 // Bump the code age so that flushing is triggered.
1172 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001173 for (int i = 0; i < kAgingThreshold; i++) {
1174 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1175 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001176
1177 // Simulate incremental marking so that the function is enqueued as
1178 // code flushing candidate.
1179 SimulateIncrementalMarking();
1180
1181 // Enable the debugger and add a breakpoint while incremental marking
1182 // is running so that incremental marking aborts and code flushing is
1183 // disabled.
1184 int position = 0;
1185 Handle<Object> breakpoint_object(Smi::FromInt(0));
1186 ISOLATE->debug()->SetBreakPoint(function, breakpoint_object, &position);
1187 ISOLATE->debug()->ClearAllBreakPoints();
1188
1189 // Force optimization now that code flushing is disabled.
1190 { v8::HandleScope scope;
1191 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1192 }
1193
1194 // Simulate one final GC to make sure the candidate queue is sane.
1195 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1196 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1197 CHECK(function->is_compiled() || !function->IsOptimized());
1198}
1199
1200
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001201// Count the number of native contexts in the weak list of native contexts.
1202int CountNativeContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001203 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001204 Object* object = HEAP->native_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001205 while (!object->IsUndefined()) {
1206 count++;
1207 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1208 }
1209 return count;
1210}
1211
1212
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001213// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001214// functions attached to a native context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001215static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1216 int count = 0;
1217 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1218 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1219 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1220 count++;
1221 object = JSFunction::cast(object)->next_function_link();
1222 }
1223 return count;
1224}
1225
1226
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001227TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001228 v8::V8::Initialize();
1229
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001230 // Some flags turn Scavenge collections into Mark-sweep collections
1231 // and hence are incompatible with this test case.
1232 if (FLAG_gc_global || FLAG_stress_compaction) return;
1233
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001234 static const int kNumTestContexts = 10;
1235
1236 v8::HandleScope scope;
1237 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1238
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001239 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001240
1241 // Create a number of global contests which gets linked together.
1242 for (int i = 0; i < kNumTestContexts; i++) {
1243 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001244
1245 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1246
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001247 CHECK_EQ(i + 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001248
1249 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001250
1251 // Create a handle scope so no function objects get stuch in the outer
1252 // handle scope
1253 v8::HandleScope scope;
1254 const char* source = "function f1() { };"
1255 "function f2() { };"
1256 "function f3() { };"
1257 "function f4() { };"
1258 "function f5() { };";
1259 CompileRun(source);
1260 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1261 CompileRun("f1()");
1262 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1263 CompileRun("f2()");
1264 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1265 CompileRun("f3()");
1266 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1267 CompileRun("f4()");
1268 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1269 CompileRun("f5()");
1270 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1271
1272 // Remove function f1, and
1273 CompileRun("f1=null");
1274
1275 // Scavenge treats these references as strong.
1276 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001277 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001278 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1279 }
1280
1281 // Mark compact handles the weak references.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001282 ISOLATE->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001283 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001284 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1285
1286 // Get rid of f3 and f5 in the same way.
1287 CompileRun("f3=null");
1288 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001289 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001290 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1291 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001292 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001293 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1294 CompileRun("f5=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 ? 3 : 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 ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1301
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001302 ctx[i]->Exit();
1303 }
1304
1305 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001306 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001307
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001308 // Dispose the native contexts one by one.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001309 for (int i = 0; i < kNumTestContexts; i++) {
1310 ctx[i].Dispose();
1311 ctx[i].Clear();
1312
1313 // Scavenge treats these references as strong.
1314 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001315 HEAP->PerformScavenge();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001316 CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001317 }
1318
1319 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001320 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001321 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001322 }
1323
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001324 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001325}
1326
1327
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001328// Count the number of native contexts in the weak list of native contexts
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001329// causing a GC after the specified number of elements.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001330static int CountNativeContextsWithGC(int n) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001331 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001332 Handle<Object> object(HEAP->native_contexts_list());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001333 while (!object->IsUndefined()) {
1334 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001335 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001336 object =
1337 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1338 }
1339 return count;
1340}
1341
1342
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001343// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001344// functions attached to a native context causing a GC after the
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001345// specified number of elements.
1346static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1347 int n) {
1348 int count = 0;
1349 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1350 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1351 while (object->IsJSFunction() &&
1352 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1353 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001354 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001355 object = Handle<Object>(
1356 Object::cast(JSFunction::cast(*object)->next_function_link()));
1357 }
1358 return count;
1359}
1360
1361
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001362TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001363 v8::V8::Initialize();
1364
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001365 static const int kNumTestContexts = 10;
1366
1367 v8::HandleScope scope;
1368 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1369
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001370 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001371
1372 // Create an number of contexts and check the length of the weak list both
1373 // with and without GCs while iterating the list.
1374 for (int i = 0; i < kNumTestContexts; i++) {
1375 ctx[i] = v8::Context::New();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001376 CHECK_EQ(i + 1, CountNativeContexts());
1377 CHECK_EQ(i + 1, CountNativeContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001378 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001379
1380 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1381
1382 // Compile a number of functions the length of the weak list of optimized
1383 // functions both with and without GCs while iterating the list.
1384 ctx[0]->Enter();
1385 const char* source = "function f1() { };"
1386 "function f2() { };"
1387 "function f3() { };"
1388 "function f4() { };"
1389 "function f5() { };";
1390 CompileRun(source);
1391 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1392 CompileRun("f1()");
1393 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1394 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1395 CompileRun("f2()");
1396 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1397 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1398 CompileRun("f3()");
1399 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1400 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1401 CompileRun("f4()");
1402 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1403 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1404 CompileRun("f5()");
1405 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1406 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1407
1408 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001409}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001410
1411
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001412TEST(TestSizeOfObjects) {
1413 v8::V8::Initialize();
1414
1415 // Get initial heap size after several full GCs, which will stabilize
1416 // the heap size and return with sweeping finished completely.
1417 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1418 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1419 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1420 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001421 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001422 CHECK(HEAP->old_pointer_space()->IsSweepingComplete());
1423 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1424
1425 {
1426 // Allocate objects on several different old-space pages so that
1427 // lazy sweeping kicks in for subsequent GC runs.
1428 AlwaysAllocateScope always_allocate;
1429 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1430 for (int i = 1; i <= 100; i++) {
1431 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1432 CHECK_EQ(initial_size + i * filler_size,
1433 static_cast<int>(HEAP->SizeOfObjects()));
1434 }
1435 }
1436
1437 // The heap size should go back to initial size after a full GC, even
1438 // though sweeping didn't finish yet.
1439 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001440
1441 // Normally sweeping would not be complete here, but no guarantees.
1442
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001443 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1444
1445 // Advancing the sweeper step-wise should not change the heap size.
1446 while (!HEAP->old_pointer_space()->IsSweepingComplete()) {
1447 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1448 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1449 }
1450}
1451
1452
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001453TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1454 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001455 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001456 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001457 HeapIterator iterator;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001458 intptr_t size_of_objects_2 = 0;
1459 for (HeapObject* obj = iterator.next();
1460 obj != NULL;
1461 obj = iterator.next()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001462 if (!obj->IsFreeSpace()) {
1463 size_of_objects_2 += obj->Size();
1464 }
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001465 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001466 // Delta must be within 5% of the larger result.
1467 // TODO(gc): Tighten this up by distinguishing between byte
1468 // arrays that are real and those that merely mark free space
1469 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001470 if (size_of_objects_1 > size_of_objects_2) {
1471 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1472 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1473 "Iterator: %" V8_PTR_PREFIX "d, "
1474 "delta: %" V8_PTR_PREFIX "d\n",
1475 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001476 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001477 } else {
1478 intptr_t delta = size_of_objects_2 - size_of_objects_1;
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_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001484 }
1485}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001486
1487
danno@chromium.orgc612e022011-11-10 11:38:15 +00001488static void FillUpNewSpace(NewSpace* new_space) {
1489 // Fill up new space to the point that it is completely full. Make sure
1490 // that the scavenger does not undo the filling.
1491 v8::HandleScope scope;
1492 AlwaysAllocateScope always_allocate;
1493 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001494 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001495 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001496 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001497 }
1498}
1499
1500
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501TEST(GrowAndShrinkNewSpace) {
1502 InitializeVM();
1503 NewSpace* new_space = HEAP->new_space();
1504
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001505 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1506 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001507 // The max size cannot exceed the reserved size, since semispaces must be
1508 // always within the reserved space. We can't test new space growing and
1509 // shrinking if the reserved size is the same as the minimum (initial) size.
1510 return;
1511 }
1512
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001513 // Explicitly growing should double the space capacity.
1514 intptr_t old_capacity, new_capacity;
1515 old_capacity = new_space->Capacity();
1516 new_space->Grow();
1517 new_capacity = new_space->Capacity();
1518 CHECK(2 * old_capacity == new_capacity);
1519
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001520 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001521 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001522 new_capacity = new_space->Capacity();
1523 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001524
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001525 // Explicitly shrinking should not affect space capacity.
1526 old_capacity = new_space->Capacity();
1527 new_space->Shrink();
1528 new_capacity = new_space->Capacity();
1529 CHECK(old_capacity == new_capacity);
1530
1531 // Let the scavenger empty the new space.
1532 HEAP->CollectGarbage(NEW_SPACE);
1533 CHECK_LE(new_space->Size(), old_capacity);
1534
1535 // Explicitly shrinking should halve the space capacity.
1536 old_capacity = new_space->Capacity();
1537 new_space->Shrink();
1538 new_capacity = new_space->Capacity();
1539 CHECK(old_capacity == 2 * new_capacity);
1540
1541 // Consecutive shrinking should not affect space capacity.
1542 old_capacity = new_space->Capacity();
1543 new_space->Shrink();
1544 new_space->Shrink();
1545 new_space->Shrink();
1546 new_capacity = new_space->Capacity();
1547 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001548}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001549
1550
1551TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1552 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001553
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001554 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1555 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001556 // The max size cannot exceed the reserved size, since semispaces must be
1557 // always within the reserved space. We can't test new space growing and
1558 // shrinking if the reserved size is the same as the minimum (initial) size.
1559 return;
1560 }
1561
danno@chromium.orgc612e022011-11-10 11:38:15 +00001562 v8::HandleScope scope;
1563 NewSpace* new_space = HEAP->new_space();
1564 intptr_t old_capacity, new_capacity;
1565 old_capacity = new_space->Capacity();
1566 new_space->Grow();
1567 new_capacity = new_space->Capacity();
1568 CHECK(2 * old_capacity == new_capacity);
1569 FillUpNewSpace(new_space);
1570 HEAP->CollectAllAvailableGarbage();
1571 new_capacity = new_space->Capacity();
1572 CHECK(old_capacity == new_capacity);
1573}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001574
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001575
1576static int NumberOfGlobalObjects() {
1577 int count = 0;
1578 HeapIterator iterator;
1579 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1580 if (obj->IsGlobalObject()) count++;
1581 }
1582 return count;
1583}
1584
1585
1586// Test that we don't embed maps from foreign contexts into
1587// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001588TEST(LeakNativeContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001589 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001590 v8::HandleScope outer_scope;
1591 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1592 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1593 ctx1->Enter();
1594
1595 HEAP->CollectAllAvailableGarbage();
1596 CHECK_EQ(4, NumberOfGlobalObjects());
1597
1598 {
1599 v8::HandleScope inner_scope;
1600 CompileRun("var v = {x: 42}");
1601 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1602 ctx2->Enter();
1603 ctx2->Global()->Set(v8_str("o"), v);
1604 v8::Local<v8::Value> res = CompileRun(
1605 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001606 "for (var i = 0; i < 10; ++i) f();"
1607 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001608 "f();");
1609 CHECK_EQ(42, res->Int32Value());
1610 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1611 ctx2->Exit();
1612 ctx1->Exit();
1613 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001614 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001615 }
1616 HEAP->CollectAllAvailableGarbage();
1617 CHECK_EQ(2, NumberOfGlobalObjects());
1618 ctx2.Dispose();
1619 HEAP->CollectAllAvailableGarbage();
1620 CHECK_EQ(0, NumberOfGlobalObjects());
1621}
1622
1623
1624// Test that we don't embed functions from foreign contexts into
1625// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001626TEST(LeakNativeContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001627 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001628 v8::HandleScope outer_scope;
1629 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1630 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1631 ctx1->Enter();
1632
1633 HEAP->CollectAllAvailableGarbage();
1634 CHECK_EQ(4, NumberOfGlobalObjects());
1635
1636 {
1637 v8::HandleScope inner_scope;
1638 CompileRun("var v = function() { return 42; }");
1639 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1640 ctx2->Enter();
1641 ctx2->Global()->Set(v8_str("o"), v);
1642 v8::Local<v8::Value> res = CompileRun(
1643 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001644 "for (var i = 0; i < 10; ++i) f(o);"
1645 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001646 "f(o);");
1647 CHECK_EQ(42, res->Int32Value());
1648 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1649 ctx2->Exit();
1650 ctx1->Exit();
1651 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001652 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001653 }
1654 HEAP->CollectAllAvailableGarbage();
1655 CHECK_EQ(2, NumberOfGlobalObjects());
1656 ctx2.Dispose();
1657 HEAP->CollectAllAvailableGarbage();
1658 CHECK_EQ(0, NumberOfGlobalObjects());
1659}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001660
1661
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001662TEST(LeakNativeContextViaMapKeyed) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001663 i::FLAG_allow_natives_syntax = true;
1664 v8::HandleScope outer_scope;
1665 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1666 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1667 ctx1->Enter();
1668
1669 HEAP->CollectAllAvailableGarbage();
1670 CHECK_EQ(4, NumberOfGlobalObjects());
1671
1672 {
1673 v8::HandleScope inner_scope;
1674 CompileRun("var v = [42, 43]");
1675 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1676 ctx2->Enter();
1677 ctx2->Global()->Set(v8_str("o"), v);
1678 v8::Local<v8::Value> res = CompileRun(
1679 "function f() { return o[0]; }"
1680 "for (var i = 0; i < 10; ++i) f();"
1681 "%OptimizeFunctionOnNextCall(f);"
1682 "f();");
1683 CHECK_EQ(42, res->Int32Value());
1684 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1685 ctx2->Exit();
1686 ctx1->Exit();
1687 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001688 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001689 }
1690 HEAP->CollectAllAvailableGarbage();
1691 CHECK_EQ(2, NumberOfGlobalObjects());
1692 ctx2.Dispose();
1693 HEAP->CollectAllAvailableGarbage();
1694 CHECK_EQ(0, NumberOfGlobalObjects());
1695}
1696
1697
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001698TEST(LeakNativeContextViaMapProto) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001699 i::FLAG_allow_natives_syntax = true;
1700 v8::HandleScope outer_scope;
1701 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1702 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1703 ctx1->Enter();
1704
1705 HEAP->CollectAllAvailableGarbage();
1706 CHECK_EQ(4, NumberOfGlobalObjects());
1707
1708 {
1709 v8::HandleScope inner_scope;
1710 CompileRun("var v = { y: 42}");
1711 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1712 ctx2->Enter();
1713 ctx2->Global()->Set(v8_str("o"), v);
1714 v8::Local<v8::Value> res = CompileRun(
1715 "function f() {"
1716 " var p = {x: 42};"
1717 " p.__proto__ = o;"
1718 " return p.x;"
1719 "}"
1720 "for (var i = 0; i < 10; ++i) f();"
1721 "%OptimizeFunctionOnNextCall(f);"
1722 "f();");
1723 CHECK_EQ(42, res->Int32Value());
1724 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1725 ctx2->Exit();
1726 ctx1->Exit();
1727 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001728 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001729 }
1730 HEAP->CollectAllAvailableGarbage();
1731 CHECK_EQ(2, NumberOfGlobalObjects());
1732 ctx2.Dispose();
1733 HEAP->CollectAllAvailableGarbage();
1734 CHECK_EQ(0, NumberOfGlobalObjects());
1735}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001736
1737
1738TEST(InstanceOfStubWriteBarrier) {
1739 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001740#ifdef VERIFY_HEAP
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001741 i::FLAG_verify_heap = true;
1742#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001743
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001744 InitializeVM();
1745 if (!i::V8::UseCrankshaft()) return;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001746 if (i::FLAG_force_marking_deque_overflows) return;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001747 v8::HandleScope outer_scope;
1748
1749 {
1750 v8::HandleScope scope;
1751 CompileRun(
1752 "function foo () { }"
1753 "function mkbar () { return new (new Function(\"\")) (); }"
1754 "function f (x) { return (x instanceof foo); }"
1755 "function g () { f(mkbar()); }"
1756 "f(new foo()); f(new foo());"
1757 "%OptimizeFunctionOnNextCall(f);"
1758 "f(new foo()); g();");
1759 }
1760
1761 IncrementalMarking* marking = HEAP->incremental_marking();
1762 marking->Abort();
1763 marking->Start();
1764
1765 Handle<JSFunction> f =
1766 v8::Utils::OpenHandle(
1767 *v8::Handle<v8::Function>::Cast(
1768 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1769
1770 CHECK(f->IsOptimized());
1771
1772 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1773 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001774 // Discard any pending GC requests otherwise we will get GC when we enter
1775 // code below.
1776 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001777 }
1778
1779 CHECK(marking->IsMarking());
1780
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001781 {
1782 v8::HandleScope scope;
1783 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1784 v8::Handle<v8::Function> g =
1785 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1786 g->Call(global, 0, NULL);
1787 }
1788
1789 HEAP->incremental_marking()->set_should_hurry(true);
1790 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1791}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001792
1793
1794TEST(PrototypeTransitionClearing) {
1795 InitializeVM();
1796 v8::HandleScope scope;
1797
1798 CompileRun(
1799 "var base = {};"
1800 "var live = [];"
1801 "for (var i = 0; i < 10; i++) {"
1802 " var object = {};"
1803 " var prototype = {};"
1804 " object.__proto__ = prototype;"
1805 " if (i >= 3) live.push(object, prototype);"
1806 "}");
1807
1808 Handle<JSObject> baseObject =
1809 v8::Utils::OpenHandle(
1810 *v8::Handle<v8::Object>::Cast(
1811 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1812
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001813 // Verify that only dead prototype transitions are cleared.
1814 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001815 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001816 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001817 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001818
1819 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001820 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001821 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001822 int j = Map::kProtoTransitionHeaderSize +
1823 i * Map::kProtoTransitionElementsPerEntry;
1824 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001825 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1826 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001827 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001828
1829 // Make sure next prototype is placed on an old-space evacuation candidate.
1830 Handle<JSObject> prototype;
1831 PagedSpace* space = HEAP->old_pointer_space();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001832 {
1833 AlwaysAllocateScope always_allocate;
1834 SimulateFullSpace(space);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001835 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001836 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001837
1838 // Add a prototype on an evacuation candidate and verify that transition
1839 // clearing correctly records slots in prototype transition array.
1840 i::FLAG_always_compact = true;
1841 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001842 CHECK(!space->LastPage()->Contains(
1843 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001844 CHECK(space->LastPage()->Contains(prototype->address()));
1845 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1846 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1847 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1848 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001849}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001850
1851
1852TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1853 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001854#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001855 i::FLAG_verify_heap = true;
1856#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001857
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001858 InitializeVM();
1859 if (!i::V8::UseCrankshaft()) return;
1860 v8::HandleScope outer_scope;
1861
1862 {
1863 v8::HandleScope scope;
1864 CompileRun(
1865 "function f () {"
1866 " var s = 0;"
1867 " for (var i = 0; i < 100; i++) s += i;"
1868 " return s;"
1869 "}"
1870 "f(); f();"
1871 "%OptimizeFunctionOnNextCall(f);"
1872 "f();");
1873 }
1874 Handle<JSFunction> f =
1875 v8::Utils::OpenHandle(
1876 *v8::Handle<v8::Function>::Cast(
1877 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1878 CHECK(f->IsOptimized());
1879
1880 IncrementalMarking* marking = HEAP->incremental_marking();
1881 marking->Abort();
1882 marking->Start();
1883
1884 // The following two calls will increment HEAP->global_ic_age().
1885 const int kLongIdlePauseInMs = 1000;
1886 v8::V8::ContextDisposedNotification();
1887 v8::V8::IdleNotification(kLongIdlePauseInMs);
1888
1889 while (!marking->IsStopped() && !marking->IsComplete()) {
1890 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1891 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001892 if (!marking->IsStopped() || marking->should_hurry()) {
1893 // We don't normally finish a GC via Step(), we normally finish by
1894 // setting the stack guard and then do the final steps in the stack
1895 // guard interrupt. But here we didn't ask for that, and there is no
1896 // JS code running to trigger the interrupt, so we explicitly finalize
1897 // here.
1898 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1899 "Test finalizing incremental mark-sweep");
1900 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001901
1902 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1903 CHECK_EQ(0, f->shared()->opt_count());
1904 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1905}
1906
1907
1908TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1909 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001910#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001911 i::FLAG_verify_heap = true;
1912#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001913
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001914 InitializeVM();
1915 if (!i::V8::UseCrankshaft()) return;
1916 v8::HandleScope outer_scope;
1917
1918 {
1919 v8::HandleScope scope;
1920 CompileRun(
1921 "function f () {"
1922 " var s = 0;"
1923 " for (var i = 0; i < 100; i++) s += i;"
1924 " return s;"
1925 "}"
1926 "f(); f();"
1927 "%OptimizeFunctionOnNextCall(f);"
1928 "f();");
1929 }
1930 Handle<JSFunction> f =
1931 v8::Utils::OpenHandle(
1932 *v8::Handle<v8::Function>::Cast(
1933 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1934 CHECK(f->IsOptimized());
1935
1936 HEAP->incremental_marking()->Abort();
1937
1938 // The following two calls will increment HEAP->global_ic_age().
1939 // Since incremental marking is off, IdleNotification will do full GC.
1940 const int kLongIdlePauseInMs = 1000;
1941 v8::V8::ContextDisposedNotification();
1942 v8::V8::IdleNotification(kLongIdlePauseInMs);
1943
1944 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1945 CHECK_EQ(0, f->shared()->opt_count());
1946 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1947}
1948
1949
1950// Test that HAllocateObject will always return an object in new-space.
1951TEST(OptimizedAllocationAlwaysInNewSpace) {
1952 i::FLAG_allow_natives_syntax = true;
1953 InitializeVM();
1954 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001955 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001956 v8::HandleScope scope;
1957
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001958 SimulateFullSpace(HEAP->new_space());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001959 AlwaysAllocateScope always_allocate;
1960 v8::Local<v8::Value> res = CompileRun(
1961 "function c(x) {"
1962 " this.x = x;"
1963 " for (var i = 0; i < 32; i++) {"
1964 " this['x' + i] = x;"
1965 " }"
1966 "}"
1967 "function f(x) { return new c(x); };"
1968 "f(1); f(2); f(3);"
1969 "%OptimizeFunctionOnNextCall(f);"
1970 "f(4);");
1971 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
1972
1973 Handle<JSObject> o =
1974 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
1975
1976 CHECK(HEAP->InNewSpace(*o));
1977}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001978
1979
1980static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001981 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001982}
1983
1984
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001985// Test that map transitions are cleared and maps are collected with
1986// incremental marking as well.
1987TEST(Regress1465) {
1988 i::FLAG_allow_natives_syntax = true;
1989 i::FLAG_trace_incremental_marking = true;
1990 InitializeVM();
1991 v8::HandleScope scope;
1992 static const int transitions_count = 256;
1993
1994 {
1995 AlwaysAllocateScope always_allocate;
1996 for (int i = 0; i < transitions_count; i++) {
1997 EmbeddedVector<char, 64> buffer;
1998 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
1999 CompileRun(buffer.start());
2000 }
2001 CompileRun("var root = new Object;");
2002 }
2003
2004 Handle<JSObject> root =
2005 v8::Utils::OpenHandle(
2006 *v8::Handle<v8::Object>::Cast(
2007 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2008
2009 // Count number of live transitions before marking.
2010 int transitions_before = CountMapTransitions(root->map());
2011 CompileRun("%DebugPrint(root);");
2012 CHECK_EQ(transitions_count, transitions_before);
2013
2014 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002015 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002016
2017 // Count number of live transitions after marking. Note that one transition
2018 // is left, because 'o' still holds an instance of one transition target.
2019 int transitions_after = CountMapTransitions(root->map());
2020 CompileRun("%DebugPrint(root);");
2021 CHECK_EQ(1, transitions_after);
2022}
verwaest@chromium.org37141392012-05-31 13:27:02 +00002023
2024
2025TEST(Regress2143a) {
2026 i::FLAG_collect_maps = true;
2027 i::FLAG_incremental_marking = true;
2028 InitializeVM();
2029 v8::HandleScope scope;
2030
2031 // Prepare a map transition from the root object together with a yet
2032 // untransitioned root object.
2033 CompileRun("var root = new Object;"
2034 "root.foo = 0;"
2035 "root = new Object;");
2036
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002037 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002038
2039 // Compile a StoreIC that performs the prepared map transition. This
2040 // will restart incremental marking and should make sure the root is
2041 // marked grey again.
2042 CompileRun("function f(o) {"
2043 " o.foo = 0;"
2044 "}"
2045 "f(new Object);"
2046 "f(root);");
2047
2048 // This bug only triggers with aggressive IC clearing.
2049 HEAP->AgeInlineCaches();
2050
2051 // Explicitly request GC to perform final marking step and sweeping.
2052 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002053
2054 Handle<JSObject> root =
2055 v8::Utils::OpenHandle(
2056 *v8::Handle<v8::Object>::Cast(
2057 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2058
2059 // The root object should be in a sane state.
2060 CHECK(root->IsJSObject());
2061 CHECK(root->map()->IsMap());
2062}
2063
2064
2065TEST(Regress2143b) {
2066 i::FLAG_collect_maps = true;
2067 i::FLAG_incremental_marking = true;
2068 i::FLAG_allow_natives_syntax = true;
2069 InitializeVM();
2070 v8::HandleScope scope;
2071
2072 // Prepare a map transition from the root object together with a yet
2073 // untransitioned root object.
2074 CompileRun("var root = new Object;"
2075 "root.foo = 0;"
2076 "root = new Object;");
2077
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002078 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002079
2080 // Compile an optimized LStoreNamedField that performs the prepared
2081 // map transition. This will restart incremental marking and should
2082 // make sure the root is marked grey again.
2083 CompileRun("function f(o) {"
2084 " o.foo = 0;"
2085 "}"
2086 "f(new Object);"
2087 "f(new Object);"
2088 "%OptimizeFunctionOnNextCall(f);"
2089 "f(root);"
2090 "%DeoptimizeFunction(f);");
2091
2092 // This bug only triggers with aggressive IC clearing.
2093 HEAP->AgeInlineCaches();
2094
2095 // Explicitly request GC to perform final marking step and sweeping.
2096 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002097
2098 Handle<JSObject> root =
2099 v8::Utils::OpenHandle(
2100 *v8::Handle<v8::Object>::Cast(
2101 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2102
2103 // The root object should be in a sane state.
2104 CHECK(root->IsJSObject());
2105 CHECK(root->map()->IsMap());
2106}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002107
2108
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002109TEST(ReleaseOverReservedPages) {
2110 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002111 // The optimizer can allocate stuff, messing up the test.
2112 i::FLAG_crankshaft = false;
2113 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002114 InitializeVM();
2115 v8::HandleScope scope;
2116 static const int number_of_test_pages = 20;
2117
2118 // Prepare many pages with low live-bytes count.
2119 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
2120 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2121 for (int i = 0; i < number_of_test_pages; i++) {
2122 AlwaysAllocateScope always_allocate;
2123 SimulateFullSpace(old_pointer_space);
2124 FACTORY->NewFixedArray(1, TENURED);
2125 }
2126 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2127
2128 // Triggering one GC will cause a lot of garbage to be discovered but
2129 // even spread across all allocated pages.
2130 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002131 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002132
2133 // Triggering subsequent GCs should cause at least half of the pages
2134 // to be released to the OS after at most two cycles.
2135 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
2136 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2137 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
2138 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
2139
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002140 // Triggering a last-resort GC should cause all pages to be released to the
2141 // OS so that other processes can seize the memory. If we get a failure here
2142 // where there are 2 pages left instead of 1, then we should increase the
2143 // size of the first page a little in SizeOfFirstPage in spaces.cc. The
2144 // first page should be small in order to reduce memory used when the VM
2145 // boots, but if the 20 small arrays don't fit on the first page then that's
2146 // an indication that it is too small.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002147 HEAP->CollectAllAvailableGarbage("triggered really hard");
2148 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2149}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002150
2151
2152TEST(Regress2237) {
2153 InitializeVM();
2154 v8::HandleScope scope;
2155 Handle<String> slice(HEAP->empty_string());
2156
2157 {
2158 // Generate a parent that lives in new-space.
2159 v8::HandleScope inner_scope;
2160 const char* c = "This text is long enough to trigger sliced strings.";
2161 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002162 CHECK(s->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002163 CHECK(HEAP->InNewSpace(*s));
2164
2165 // Generate a sliced string that is based on the above parent and
2166 // lives in old-space.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002167 SimulateFullSpace(HEAP->new_space());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002168 AlwaysAllocateScope always_allocate;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002169 Handle<String> t = FACTORY->NewProperSubString(s, 5, 35);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002170 CHECK(t->IsSlicedString());
2171 CHECK(!HEAP->InNewSpace(*t));
2172 *slice.location() = *t.location();
2173 }
2174
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002175 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002176 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002177 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002178}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002179
2180
2181#ifdef OBJECT_PRINT
2182TEST(PrintSharedFunctionInfo) {
2183 InitializeVM();
2184 v8::HandleScope scope;
2185 const char* source = "f = function() { return 987654321; }\n"
2186 "g = function() { return 123456789; }\n";
2187 CompileRun(source);
2188 Handle<JSFunction> g =
2189 v8::Utils::OpenHandle(
2190 *v8::Handle<v8::Function>::Cast(
2191 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2192
2193 AssertNoAllocation no_alloc;
2194 g->shared()->PrintLn();
2195}
2196#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002197
2198
2199TEST(Regress2211) {
2200 InitializeVM();
2201 v8::HandleScope scope;
2202
2203 v8::Handle<v8::String> value = v8_str("val string");
2204 Smi* hash = Smi::FromInt(321);
2205 Heap* heap = Isolate::Current()->heap();
2206
2207 for (int i = 0; i < 2; i++) {
2208 // Store identity hash first and common hidden property second.
2209 v8::Handle<v8::Object> obj = v8::Object::New();
2210 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2211 CHECK(internal_obj->HasFastProperties());
2212
2213 // In the first iteration, set hidden value first and identity hash second.
2214 // In the second iteration, reverse the order.
2215 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2216 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2217 ALLOW_CREATION);
2218 CHECK(!maybe_obj->IsFailure());
2219 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2220
2221 // Check values.
2222 CHECK_EQ(hash,
2223 internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
2224 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2225
2226 // Check size.
2227 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2228 ObjectHashTable* hashtable = ObjectHashTable::cast(
2229 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2230 // HashTable header (5) and 4 initial entries (8).
2231 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2232 }
2233}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002234
2235
2236TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2237 if (i::FLAG_always_opt) return;
2238 InitializeVM();
2239 v8::HandleScope scope;
2240 v8::Local<v8::Value> fun1, fun2;
2241
2242 {
2243 LocalContext env;
2244 CompileRun("function fun() {};");
2245 fun1 = env->Global()->Get(v8_str("fun"));
2246 }
2247
2248 {
2249 LocalContext env;
2250 CompileRun("function fun() {};");
2251 fun2 = env->Global()->Get(v8_str("fun"));
2252 }
2253
2254 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002255 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002256 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2257 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2258 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2259 Handle<JSFunction> f =
2260 v8::Utils::OpenHandle(
2261 *v8::Handle<v8::Function>::Cast(
2262 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2263 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2264 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2265
2266 CHECK_EQ(2, cells->CellCount());
2267 CHECK(cells->Cell(0)->value()->IsJSFunction());
2268 CHECK(cells->Cell(1)->value()->IsJSFunction());
2269
2270 SimulateIncrementalMarking();
2271 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2272
2273 CHECK_EQ(2, cells->CellCount());
2274 CHECK(cells->Cell(0)->value()->IsTheHole());
2275 CHECK(cells->Cell(1)->value()->IsTheHole());
2276}
2277
2278
2279static Code* FindFirstIC(Code* code, Code::Kind kind) {
2280 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2281 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2282 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2283 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2284 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2285 RelocInfo* info = it.rinfo();
2286 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2287 if (target->is_inline_cache_stub() && target->kind() == kind) {
2288 return target;
2289 }
2290 }
2291 return NULL;
2292}
2293
2294
2295TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2296 if (i::FLAG_always_opt) return;
2297 InitializeVM();
2298 v8::HandleScope scope;
2299
2300 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002301 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002302 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2303 "function f(o) { return o.x; } f(obj); f(obj);");
2304 Handle<JSFunction> f =
2305 v8::Utils::OpenHandle(
2306 *v8::Handle<v8::Function>::Cast(
2307 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2308
2309 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2310 CHECK(ic_before->ic_state() == MONOMORPHIC);
2311
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002312 SimulateIncrementalMarking();
2313 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2314
2315 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2316 CHECK(ic_after->ic_state() == MONOMORPHIC);
2317}
2318
2319
2320TEST(IncrementalMarkingClearsMonomorhpicIC) {
2321 if (i::FLAG_always_opt) return;
2322 InitializeVM();
2323 v8::HandleScope scope;
2324 v8::Local<v8::Value> obj1;
2325
2326 {
2327 LocalContext env;
2328 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2329 obj1 = env->Global()->Get(v8_str("obj"));
2330 }
2331
2332 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002333 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002334 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2335 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2336 Handle<JSFunction> f =
2337 v8::Utils::OpenHandle(
2338 *v8::Handle<v8::Function>::Cast(
2339 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2340
2341 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2342 CHECK(ic_before->ic_state() == MONOMORPHIC);
2343
2344 // Fire context dispose notification.
2345 v8::V8::ContextDisposedNotification();
2346 SimulateIncrementalMarking();
2347 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2348
2349 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2350 CHECK(ic_after->ic_state() == UNINITIALIZED);
2351}
2352
2353
2354TEST(IncrementalMarkingClearsPolymorhpicIC) {
2355 if (i::FLAG_always_opt) return;
2356 InitializeVM();
2357 v8::HandleScope scope;
2358 v8::Local<v8::Value> obj1, obj2;
2359
2360 {
2361 LocalContext env;
2362 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2363 obj1 = env->Global()->Get(v8_str("obj"));
2364 }
2365
2366 {
2367 LocalContext env;
2368 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2369 obj2 = env->Global()->Get(v8_str("obj"));
2370 }
2371
2372 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002373 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002374 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2375 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2376 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2377 Handle<JSFunction> f =
2378 v8::Utils::OpenHandle(
2379 *v8::Handle<v8::Function>::Cast(
2380 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2381
2382 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2383 CHECK(ic_before->ic_state() == MEGAMORPHIC);
2384
2385 // Fire context dispose notification.
2386 v8::V8::ContextDisposedNotification();
2387 SimulateIncrementalMarking();
2388 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2389
2390 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2391 CHECK(ic_after->ic_state() == UNINITIALIZED);
2392}
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002393
2394
2395class SourceResource: public v8::String::ExternalAsciiStringResource {
2396 public:
2397 explicit SourceResource(const char* data)
2398 : data_(data), length_(strlen(data)) { }
2399
2400 virtual void Dispose() {
2401 i::DeleteArray(data_);
2402 data_ = NULL;
2403 }
2404
2405 const char* data() const { return data_; }
2406
2407 size_t length() const { return length_; }
2408
2409 bool IsDisposed() { return data_ == NULL; }
2410
2411 private:
2412 const char* data_;
2413 size_t length_;
2414};
2415
2416
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002417void ReleaseStackTraceDataTest(const char* source) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002418 // Test that the data retained by the Error.stack accessor is released
2419 // after the first time the accessor is fired. We use external string
2420 // to check whether the data is being released since the external string
2421 // resource's callback is fired when the external string is GC'ed.
2422 InitializeVM();
2423 v8::HandleScope scope;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002424 SourceResource* resource = new SourceResource(i::StrDup(source));
2425 {
2426 v8::HandleScope scope;
2427 v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
2428 v8::Script::Compile(source_string)->Run();
2429 CHECK(!resource->IsDisposed());
2430 }
2431 HEAP->CollectAllAvailableGarbage();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002432
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002433 // External source has been released.
2434 CHECK(resource->IsDisposed());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002435 delete resource;
2436}
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002437
2438
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002439TEST(ReleaseStackTraceData) {
2440 static const char* source1 = "var error = null; "
2441 /* Normal Error */ "try { "
2442 " throw new Error(); "
2443 "} catch (e) { "
2444 " error = e; "
2445 "} ";
2446 static const char* source2 = "var error = null; "
2447 /* Stack overflow */ "try { "
2448 " (function f() { f(); })(); "
2449 "} catch (e) { "
2450 " error = e; "
2451 "} ";
2452 ReleaseStackTraceDataTest(source1);
2453 ReleaseStackTraceDataTest(source2);
2454}
2455
2456
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002457TEST(Regression144230) {
2458 InitializeVM();
2459 v8::HandleScope scope;
2460
2461 // First make sure that the uninitialized CallIC stub is on a single page
2462 // that will later be selected as an evacuation candidate.
2463 {
2464 v8::HandleScope inner_scope;
2465 AlwaysAllocateScope always_allocate;
2466 SimulateFullSpace(HEAP->code_space());
2467 ISOLATE->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET);
2468 }
2469
2470 // Second compile a CallIC and execute it once so that it gets patched to
2471 // the pre-monomorphic stub. These code objects are on yet another page.
2472 {
2473 v8::HandleScope inner_scope;
2474 AlwaysAllocateScope always_allocate;
2475 SimulateFullSpace(HEAP->code_space());
2476 CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};"
2477 "function call() { o.f(1,2,3,4,5,6,7,8,9); };"
2478 "call();");
2479 }
2480
2481 // Third we fill up the last page of the code space so that it does not get
2482 // chosen as an evacuation candidate.
2483 {
2484 v8::HandleScope inner_scope;
2485 AlwaysAllocateScope always_allocate;
2486 CompileRun("for (var i = 0; i < 2000; i++) {"
2487 " eval('function f' + i + '() { return ' + i +'; };' +"
2488 " 'f' + i + '();');"
2489 "}");
2490 }
2491 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2492
2493 // Fourth is the tricky part. Make sure the code containing the CallIC is
2494 // visited first without clearing the IC. The shared function info is then
2495 // visited later, causing the CallIC to be cleared.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002496 Handle<String> name = FACTORY->LookupUtf8Symbol("call");
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002497 Handle<GlobalObject> global(ISOLATE->context()->global_object());
2498 MaybeObject* maybe_call = global->GetProperty(*name);
2499 JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
2500 USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode));
2501 ISOLATE->compilation_cache()->Clear();
2502 call->shared()->set_ic_age(HEAP->global_ic_age() + 1);
2503 Handle<Object> call_code(call->code());
2504 Handle<Object> call_function(call);
2505
2506 // Now we are ready to mess up the heap.
2507 HEAP->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
2508
2509 // Either heap verification caught the problem already or we go kaboom once
2510 // the CallIC is executed the next time.
2511 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode));
2512 CompileRun("call();");
2513}
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002514
2515
2516TEST(Regress159140) {
2517 i::FLAG_allow_natives_syntax = true;
2518 i::FLAG_flush_code_incrementally = true;
2519 InitializeVM();
2520 v8::HandleScope scope;
2521
2522 // Perform one initial GC to enable code flushing.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002523 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002524
2525 // Prepare several closures that are all eligible for code flushing
2526 // because all reachable ones are not optimized. Make sure that the
2527 // optimized code object is directly reachable through a handle so
2528 // that it is marked black during incremental marking.
2529 Handle<Code> code;
2530 {
2531 HandleScope inner_scope;
2532 CompileRun("function h(x) {}"
2533 "function mkClosure() {"
2534 " return function(x) { return x + 1; };"
2535 "}"
2536 "var f = mkClosure();"
2537 "var g = mkClosure();"
2538 "f(1); f(2);"
2539 "g(1); g(2);"
2540 "h(1); h(2);"
2541 "%OptimizeFunctionOnNextCall(f); f(3);"
2542 "%OptimizeFunctionOnNextCall(h); h(3);");
2543
2544 Handle<JSFunction> f =
2545 v8::Utils::OpenHandle(
2546 *v8::Handle<v8::Function>::Cast(
2547 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2548 CHECK(f->is_compiled());
2549 CompileRun("f = null;");
2550
2551 Handle<JSFunction> g =
2552 v8::Utils::OpenHandle(
2553 *v8::Handle<v8::Function>::Cast(
2554 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2555 CHECK(g->is_compiled());
2556 const int kAgingThreshold = 6;
2557 for (int i = 0; i < kAgingThreshold; i++) {
2558 g->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2559 }
2560
2561 code = inner_scope.CloseAndEscape(Handle<Code>(f->code()));
2562 }
2563
2564 // Simulate incremental marking so that the functions are enqueued as
2565 // code flushing candidates. Then optimize one function. Finally
2566 // finish the GC to complete code flushing.
2567 SimulateIncrementalMarking();
2568 CompileRun("%OptimizeFunctionOnNextCall(g); g(3);");
2569 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2570
2571 // Unoptimized code is missing and the deoptimizer will go ballistic.
2572 CompileRun("g('bozo');");
2573}
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002574
2575
2576TEST(Regress165495) {
2577 i::FLAG_allow_natives_syntax = true;
2578 i::FLAG_flush_code_incrementally = true;
2579 InitializeVM();
2580 v8::HandleScope scope;
2581
2582 // Perform one initial GC to enable code flushing.
2583 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
2584
2585 // Prepare an optimized closure that the optimized code map will get
2586 // populated. Then age the unoptimized code to trigger code flushing
2587 // but make sure the optimized code is unreachable.
2588 {
2589 HandleScope inner_scope;
2590 CompileRun("function mkClosure() {"
2591 " return function(x) { return x + 1; };"
2592 "}"
2593 "var f = mkClosure();"
2594 "f(1); f(2);"
2595 "%OptimizeFunctionOnNextCall(f); f(3);");
2596
2597 Handle<JSFunction> f =
2598 v8::Utils::OpenHandle(
2599 *v8::Handle<v8::Function>::Cast(
2600 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2601 CHECK(f->is_compiled());
2602 const int kAgingThreshold = 6;
2603 for (int i = 0; i < kAgingThreshold; i++) {
2604 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2605 }
2606
2607 CompileRun("f = null;");
2608 }
2609
2610 // Simulate incremental marking so that unoptimized code is flushed
2611 // even though it still is cached in the optimized code map.
2612 SimulateIncrementalMarking();
2613 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2614
2615 // Make a new closure that will get code installed from the code map.
2616 // Unoptimized code is missing and the deoptimizer will go ballistic.
2617 CompileRun("var g = mkClosure(); g('bozo');");
2618}