blob: 8dee692d15c7c7fa6f05aab7ae6ffb8a9d9b13b7 [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();
29 CHECK(marking->IsStopped());
30 marking->Start();
31 CHECK(marking->IsMarking());
32 while (!marking->IsComplete()) {
33 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
34 }
35 CHECK(marking->IsComplete());
36}
37
38
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000039static void CheckMap(Map* map, int type, int instance_size) {
40 CHECK(map->IsHeapObject());
41#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000042 CHECK(HEAP->Contains(map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000043#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000044 CHECK_EQ(HEAP->meta_map(), map->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000045 CHECK_EQ(type, map->instance_type());
46 CHECK_EQ(instance_size, map->instance_size());
47}
48
49
50TEST(HeapMaps) {
51 InitializeVM();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000052 CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
53 CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
54 CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
55 CheckMap(HEAP->string_map(), STRING_TYPE, kVariableSizeSentinel);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000056}
57
58
59static void CheckOddball(Object* obj, const char* string) {
60 CHECK(obj->IsOddball());
61 bool exc;
62 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
63 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
64}
65
66
67static void CheckSmi(int value, const char* string) {
68 bool exc;
69 Object* print_string =
70 *Execution::ToString(Handle<Object>(Smi::FromInt(value)), &exc);
71 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
72}
73
74
75static void CheckNumber(double value, const char* string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000076 Object* obj = HEAP->NumberFromDouble(value)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000077 CHECK(obj->IsNumber());
78 bool exc;
79 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
80 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
81}
82
83
84static void CheckFindCodeObject() {
85 // Test FindCodeObject
86#define __ assm.
87
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000088 Assembler assm(Isolate::Current(), NULL, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000089
90 __ nop(); // supported on all architectures
91
92 CodeDesc desc;
93 assm.GetCode(&desc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000094 Object* code = HEAP->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +000095 desc,
96 Code::ComputeFlags(Code::STUB),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000097 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000098 CHECK(code->IsCode());
99
100 HeapObject* obj = HeapObject::cast(code);
101 Address obj_addr = obj->address();
102
103 for (int i = 0; i < obj->Size(); i += kPointerSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000104 Object* found = HEAP->FindCodeObject(obj_addr + i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000105 CHECK_EQ(code, found);
106 }
107
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000108 Object* copy = HEAP->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000109 desc,
110 Code::ComputeFlags(Code::STUB),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000112 CHECK(copy->IsCode());
113 HeapObject* obj_copy = HeapObject::cast(copy);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114 Object* not_right = HEAP->FindCodeObject(obj_copy->address() +
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000115 obj_copy->Size() / 2);
116 CHECK(not_right != code);
117}
118
119
120TEST(HeapObjects) {
121 InitializeVM();
122
123 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 Object* value = HEAP->NumberFromDouble(1.000123)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000125 CHECK(value->IsHeapNumber());
126 CHECK(value->IsNumber());
127 CHECK_EQ(1.000123, value->Number());
128
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000129 value = HEAP->NumberFromDouble(1.0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000130 CHECK(value->IsSmi());
131 CHECK(value->IsNumber());
132 CHECK_EQ(1.0, value->Number());
133
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000134 value = HEAP->NumberFromInt32(1024)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000135 CHECK(value->IsSmi());
136 CHECK(value->IsNumber());
137 CHECK_EQ(1024.0, value->Number());
138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000139 value = HEAP->NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000140 CHECK(value->IsSmi());
141 CHECK(value->IsNumber());
142 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
143
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000144 value = HEAP->NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000145 CHECK(value->IsSmi());
146 CHECK(value->IsNumber());
147 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
148
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000149#ifndef V8_TARGET_ARCH_X64
150 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000151 value = HEAP->NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000152 CHECK(value->IsHeapNumber());
153 CHECK(value->IsNumber());
154 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000155#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000156
lrn@chromium.org303ada72010-10-27 09:33:13 +0000157 MaybeObject* maybe_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000158 HEAP->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 value = maybe_value->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000160 CHECK(value->IsHeapNumber());
161 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000162 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
163 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000164
165 // nan oddball checks
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000166 CHECK(HEAP->nan_value()->IsNumber());
167 CHECK(isnan(HEAP->nan_value()->Number()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000168
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000169 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000170 CHECK(s->IsString());
171 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000172
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000173 String* object_symbol = String::cast(HEAP->Object_symbol());
174 CHECK(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000175 Isolate::Current()->context()->global_object()->HasLocalProperty(
176 object_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000177
178 // Check ToString for oddballs
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000179 CheckOddball(HEAP->true_value(), "true");
180 CheckOddball(HEAP->false_value(), "false");
181 CheckOddball(HEAP->null_value(), "null");
182 CheckOddball(HEAP->undefined_value(), "undefined");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000183
184 // Check ToString for Smis
185 CheckSmi(0, "0");
186 CheckSmi(42, "42");
187 CheckSmi(-42, "-42");
188
189 // Check ToString for Numbers
190 CheckNumber(1.1, "1.1");
191
192 CheckFindCodeObject();
193}
194
195
196TEST(Tagging) {
197 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000198 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000199 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000200 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000201 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000202 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000203 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000204 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000205 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000206 CHECK(Failure::Exception()->IsFailure());
207 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
208 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
209}
210
211
212TEST(GarbageCollection) {
213 InitializeVM();
214
215 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000216 // Check GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000217 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000218
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000219 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
220 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
221 Handle<String> prop_namex = FACTORY->LookupAsciiSymbol("theSlotx");
222 Handle<String> obj_name = FACTORY->LookupAsciiSymbol("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000223
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000224 {
225 v8::HandleScope inner_scope;
226 // Allocate a function and keep it in global object's property.
227 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000228 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000229 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000230 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000231 function->set_initial_map(*initial_map);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000232 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000233 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000234 // Allocate an object. Unrooted after leaving the scope.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000235 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000236 obj->SetProperty(
237 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
238 obj->SetProperty(
239 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000240
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000241 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
242 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
243 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000244
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000245 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000246
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000247 // Function should be alive.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000248 CHECK(Isolate::Current()->context()->global_object()->
249 HasLocalProperty(*name));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000250 // Check function is retained.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000251 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000252 GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000253 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000254 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000255
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000256 {
257 HandleScope inner_scope;
258 // Allocate another object, make it reachable from global.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000259 Handle<JSObject> obj = FACTORY->NewJSObject(function);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000260 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000261 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
262 obj->SetProperty(
263 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000264 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000265
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000266 // After gc, it should survive.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000267 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000268
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000269 CHECK(Isolate::Current()->context()->global_object()->
270 HasLocalProperty(*obj_name));
271 CHECK(Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000272 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000273 Object* obj = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000274 GetProperty(*obj_name)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000275 JSObject* js_obj = JSObject::cast(obj);
276 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000277}
278
279
280static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000281 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000282 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000283 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000284 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000285 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
286 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000287}
288
289
290TEST(String) {
291 InitializeVM();
292
293 VerifyStringAllocation("a");
294 VerifyStringAllocation("ab");
295 VerifyStringAllocation("abc");
296 VerifyStringAllocation("abcd");
297 VerifyStringAllocation("fiskerdrengen er paa havet");
298}
299
300
301TEST(LocalHandles) {
302 InitializeVM();
303
304 v8::HandleScope scope;
305 const char* name = "Kasper the spunky";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000306 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000307 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000308}
309
310
311TEST(GlobalHandles) {
312 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000313 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000314
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000315 Handle<Object> h1;
316 Handle<Object> h2;
317 Handle<Object> h3;
318 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000319
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000320 {
321 HandleScope scope;
322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000323 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
324 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000325
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000326 h1 = global_handles->Create(*i);
327 h2 = global_handles->Create(*u);
328 h3 = global_handles->Create(*i);
329 h4 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000330 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000331
332 // after gc, it should survive
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000333 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000334
335 CHECK((*h1)->IsString());
336 CHECK((*h2)->IsHeapNumber());
337 CHECK((*h3)->IsString());
338 CHECK((*h4)->IsHeapNumber());
339
340 CHECK_EQ(*h3, *h1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000341 global_handles->Destroy(h1.location());
342 global_handles->Destroy(h3.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000343
344 CHECK_EQ(*h4, *h2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000345 global_handles->Destroy(h2.location());
346 global_handles->Destroy(h4.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000347}
348
349
350static bool WeakPointerCleared = false;
351
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000352static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000353 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000354 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000355 handle.Dispose();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000356}
357
358
359TEST(WeakGlobalHandlesScavenge) {
360 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000361 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000362
363 WeakPointerCleared = false;
364
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000365 Handle<Object> h1;
366 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000367
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000368 {
369 HandleScope scope;
370
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000371 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
372 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000373
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000374 h1 = global_handles->Create(*i);
375 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000376 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000377
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000378 global_handles->MakeWeak(h2.location(),
379 reinterpret_cast<void*>(1234),
380 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000381
382 // Scavenge treats weak pointers as normal roots.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000383 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000384
385 CHECK((*h1)->IsString());
386 CHECK((*h2)->IsHeapNumber());
387
388 CHECK(!WeakPointerCleared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000389 CHECK(!global_handles->IsNearDeath(h2.location()));
390 CHECK(!global_handles->IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000391
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000392 global_handles->Destroy(h1.location());
393 global_handles->Destroy(h2.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000394}
395
396
397TEST(WeakGlobalHandlesMark) {
398 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000399 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000400
401 WeakPointerCleared = false;
402
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000403 Handle<Object> h1;
404 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000405
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000406 {
407 HandleScope scope;
408
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000409 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
410 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000411
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000412 h1 = global_handles->Create(*i);
413 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000414 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000415
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000416 HEAP->CollectGarbage(OLD_POINTER_SPACE);
417 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000418 // Make sure the object is promoted.
419
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000420 global_handles->MakeWeak(h2.location(),
421 reinterpret_cast<void*>(1234),
422 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000423 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
424 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
425
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000426 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000427
428 CHECK((*h1)->IsString());
429
430 CHECK(WeakPointerCleared);
431 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433 global_handles->Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000434}
435
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000436
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000437TEST(DeleteWeakGlobalHandle) {
438 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000439 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000440
441 WeakPointerCleared = false;
442
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000443 Handle<Object> h;
444
445 {
446 HandleScope scope;
447
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000448 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
449 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000450 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000451
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000452 global_handles->MakeWeak(h.location(),
453 reinterpret_cast<void*>(1234),
454 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000455
456 // Scanvenge does not recognize weak reference.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000457 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000458
459 CHECK(!WeakPointerCleared);
460
461 // Mark-compact treats weak reference properly.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000462 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000463
464 CHECK(WeakPointerCleared);
465}
466
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000467
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000468static const char* not_so_random_string_table[] = {
469 "abstract",
470 "boolean",
471 "break",
472 "byte",
473 "case",
474 "catch",
475 "char",
476 "class",
477 "const",
478 "continue",
479 "debugger",
480 "default",
481 "delete",
482 "do",
483 "double",
484 "else",
485 "enum",
486 "export",
487 "extends",
488 "false",
489 "final",
490 "finally",
491 "float",
492 "for",
493 "function",
494 "goto",
495 "if",
496 "implements",
497 "import",
498 "in",
499 "instanceof",
500 "int",
501 "interface",
502 "long",
503 "native",
504 "new",
505 "null",
506 "package",
507 "private",
508 "protected",
509 "public",
510 "return",
511 "short",
512 "static",
513 "super",
514 "switch",
515 "synchronized",
516 "this",
517 "throw",
518 "throws",
519 "transient",
520 "true",
521 "try",
522 "typeof",
523 "var",
524 "void",
525 "volatile",
526 "while",
527 "with",
528 0
529};
530
531
532static void CheckSymbols(const char** strings) {
533 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000534 Object* a;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000535 MaybeObject* maybe_a = HEAP->LookupAsciiSymbol(string);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000536 // LookupAsciiSymbol may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000537 if (!maybe_a->ToObject(&a)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000538 CHECK(a->IsSymbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000539 Object* b;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 MaybeObject* maybe_b = HEAP->LookupAsciiSymbol(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000541 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000542 CHECK_EQ(b, a);
543 CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
544 }
545}
546
547
548TEST(SymbolTable) {
549 InitializeVM();
550
551 CheckSymbols(not_so_random_string_table);
552 CheckSymbols(not_so_random_string_table);
553}
554
555
556TEST(FunctionAllocation) {
557 InitializeVM();
558
559 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000560 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000561 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000562 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000563 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000564 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000565 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000566
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
568 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000569 obj->SetProperty(
570 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000571 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000572 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000573 function->SetProperty(
574 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000575 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000576}
577
578
579TEST(ObjectProperties) {
580 InitializeVM();
581
582 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000583 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000584 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000585 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000586 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000587 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000588 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
589 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
590 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000591
592 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000593 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000594
595 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000596 obj->SetProperty(
597 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000598 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000599
600 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000601 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
602 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000603
604 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000605 obj->SetProperty(
606 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
607 obj->SetProperty(
608 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000609 CHECK(obj->HasLocalProperty(*first));
610 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000611
612 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000613 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
614 CHECK(obj->HasLocalProperty(*second));
615 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
616 CHECK(!obj->HasLocalProperty(*first));
617 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000618
619 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000620 obj->SetProperty(
621 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
622 obj->SetProperty(
623 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000624 CHECK(obj->HasLocalProperty(*first));
625 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000626
627 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000628 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
629 CHECK(obj->HasLocalProperty(*first));
630 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
631 CHECK(!obj->HasLocalProperty(*first));
632 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000633
634 // check string and symbol match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000635 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000636 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000637 obj->SetProperty(
638 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000639 Handle<String> s1_symbol = FACTORY->LookupAsciiSymbol(string1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000640 CHECK(obj->HasLocalProperty(*s1_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000641
642 // check symbol and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000643 const char* string2 = "fugl";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000644 Handle<String> s2_symbol = FACTORY->LookupAsciiSymbol(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000645 obj->SetProperty(
646 *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000648 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000649}
650
651
652TEST(JSObjectMaps) {
653 InitializeVM();
654
655 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000656 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000657 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000658 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000659 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000661 function->set_initial_map(*initial_map);
662
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000663 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
664 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000665
666 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000667 obj->SetProperty(
668 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000669 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000670
671 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000672 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000673}
674
675
676TEST(JSArray) {
677 InitializeVM();
678
679 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000680 Handle<String> name = FACTORY->LookupAsciiSymbol("Array");
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000681 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000682 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000683 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000684 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000685
686 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000687 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000688 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000689 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000690 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000691
692 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000693 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000694 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000695 // Must be in fast mode.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000696 CHECK(array->HasFastSmiOrObjectElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000697
698 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000699 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000700 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000701 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000702
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000703 // Set array length with larger than smi value.
704 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000705 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000706 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000707
708 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000709 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000710 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000711 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000712
713 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000714 array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000715 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000716 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000717 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000718 CHECK_EQ(array->GetElement(int_length), *name);
719 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000720}
721
722
723TEST(JSObjectCopy) {
724 InitializeVM();
725
726 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000727 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000728 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000729 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000730 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000731 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000732 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
733 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
734 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000735
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000736 obj->SetProperty(
737 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
738 obj->SetProperty(
739 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000740
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000741 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
742 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000743
744 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000745 Handle<JSObject> clone = Copy(obj);
746 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000747
748 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
749 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
750
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000751 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
752 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000753
754 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000755 clone->SetProperty(
756 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
757 clone->SetProperty(
758 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000759
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000760 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
761 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000762
763 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
764 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
765
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000766 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
767 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000768}
769
770
771TEST(StringAllocation) {
772 InitializeVM();
773
774
775 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
776 for (int length = 0; length < 100; length++) {
777 v8::HandleScope scope;
778 char* non_ascii = NewArray<char>(3 * length + 1);
779 char* ascii = NewArray<char>(length + 1);
780 non_ascii[3 * length] = 0;
781 ascii[length] = 0;
782 for (int i = 0; i < length; i++) {
783 ascii[i] = 'a';
784 non_ascii[3 * i] = chars[0];
785 non_ascii[3 * i + 1] = chars[1];
786 non_ascii[3 * i + 2] = chars[2];
787 }
788 Handle<String> non_ascii_sym =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000789 FACTORY->LookupSymbol(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000790 CHECK_EQ(length, non_ascii_sym->length());
791 Handle<String> ascii_sym =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000792 FACTORY->LookupSymbol(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000793 CHECK_EQ(length, ascii_sym->length());
794 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000795 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000796 non_ascii_str->Hash();
797 CHECK_EQ(length, non_ascii_str->length());
798 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000799 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000800 ascii_str->Hash();
801 CHECK_EQ(length, ascii_str->length());
802 DeleteArray(non_ascii);
803 DeleteArray(ascii);
804 }
805}
806
807
808static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
809 // Count the number of objects found in the heap.
810 int found_count = 0;
811 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000812 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000813 for (int i = 0; i < size; i++) {
814 if (*objs[i] == obj) {
815 found_count++;
816 }
817 }
818 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000819 return found_count;
820}
821
822
823TEST(Iteration) {
824 InitializeVM();
825 v8::HandleScope scope;
826
827 // Array of objects to scan haep for.
828 const int objs_count = 6;
829 Handle<Object> objs[objs_count];
830 int next_objs_index = 0;
831
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000832 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000833 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000834 objs[next_objs_index++] = FACTORY->NewJSArray(10,
835 FAST_HOLEY_ELEMENTS,
836 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000837
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000838 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000839 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000840 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000841 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000842 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000843
844 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000845 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000846 char* str = new char[large_size];
847 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
848 str[large_size - 1] = '\0';
849 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000850 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000851 delete[] str;
852
853 // Add a Map object to look for.
854 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
855
856 CHECK_EQ(objs_count, next_objs_index);
857 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
858}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000859
860
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000861TEST(EmptyHandleEscapeFrom) {
862 InitializeVM();
863
864 v8::HandleScope scope;
865 Handle<JSObject> runaway;
866
867 {
868 v8::HandleScope nested;
869 Handle<JSObject> empty;
870 runaway = empty.EscapeFrom(&nested);
871 }
872
873 CHECK(runaway.is_null());
874}
875
876
877static int LenFromSize(int size) {
878 return (size - FixedArray::kHeaderSize) / kPointerSize;
879}
880
881
882TEST(Regression39128) {
883 // Test case for crbug.com/39128.
884 InitializeVM();
885
886 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000887 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000888
889 v8::HandleScope scope;
890
891 // The plan: create JSObject which references objects in new space.
892 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000893 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000894
895 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000896 Handle<JSFunction> object_ctor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000897 Isolate::Current()->native_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000898 CHECK(object_ctor->has_initial_map());
899 Handle<Map> object_map(object_ctor->initial_map());
900 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000901 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000902 int n_properties = my_map->inobject_properties();
903 CHECK_GT(n_properties, 0);
904
905 int object_size = my_map->instance_size();
906
907 // Step 2: allocate a lot of objects so to almost fill new space: we need
908 // just enough room to allocate JSObject and thus fill the newspace.
909
910 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000911 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000912 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000913 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000914 Address* top_addr = new_space->allocation_top_address();
915 Address* limit_addr = new_space->allocation_limit_address();
916 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000917 CHECK(!HEAP->always_allocate());
918 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
919 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000920 CHECK(new_space->Contains(array));
921 }
922
923 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000924 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000925 int fixed_array_len = LenFromSize(to_fill);
926 CHECK(fixed_array_len < FixedArray::kMaxLength);
927
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 CHECK(!HEAP->always_allocate());
929 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
930 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000931 CHECK(new_space->Contains(array));
932
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000933 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000934 CHECK(new_space->Contains(object));
935 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000936 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000937 CHECK_EQ(0, jsobject->properties()->length());
938 // Create a reference to object in new space in jsobject.
939 jsobject->FastPropertyAtPut(-1, array);
940
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000941 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000942
943 // Step 4: clone jsobject, but force always allocate first to create a clone
944 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000945 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000946 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000947 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000948 JSObject* clone = JSObject::cast(clone_obj);
949 if (clone->address() != old_pointer_space_top) {
950 // Alas, got allocated from free list, we cannot do checks.
951 return;
952 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000953 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000954}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000955
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000956
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000957TEST(TestCodeFlushing) {
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000958 // If we do not flush code this test is invalid.
959 if (!FLAG_flush_code) return;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000960 i::FLAG_allow_natives_syntax = true;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000961 InitializeVM();
962 v8::HandleScope scope;
963 const char* source = "function foo() {"
964 " var x = 42;"
965 " var y = 42;"
966 " var z = x + y;"
967 "};"
968 "foo()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000970
971 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000972 { v8::HandleScope scope;
973 CompileRun(source);
974 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000975
976 // Check function is compiled.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000977 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000978 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000979 CHECK(func_value->IsJSFunction());
980 Handle<JSFunction> function(JSFunction::cast(func_value));
981 CHECK(function->shared()->is_compiled());
982
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000983 // The code will survive at least two GCs.
984 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
985 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000986 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000987
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000988 // Simulate several GCs that use full marking.
989 const int kAgingThreshold = 6;
990 for (int i = 0; i < kAgingThreshold; i++) {
991 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
992 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000993
994 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000995 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
996 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000997 // Call foo to get it recompiled.
998 CompileRun("foo()");
999 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001000 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001001}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001002
1003
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001004TEST(TestCodeFlushingIncremental) {
1005 // If we do not flush code this test is invalid.
1006 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1007 i::FLAG_allow_natives_syntax = true;
1008 InitializeVM();
1009 v8::HandleScope scope;
1010 const char* source = "function foo() {"
1011 " var x = 42;"
1012 " var y = 42;"
1013 " var z = x + y;"
1014 "};"
1015 "foo()";
1016 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
1017
1018 // This compile will add the code to the compilation cache.
1019 { v8::HandleScope scope;
1020 CompileRun(source);
1021 }
1022
1023 // Check function is compiled.
1024 Object* func_value = Isolate::Current()->context()->global_object()->
1025 GetProperty(*foo_name)->ToObjectChecked();
1026 CHECK(func_value->IsJSFunction());
1027 Handle<JSFunction> function(JSFunction::cast(func_value));
1028 CHECK(function->shared()->is_compiled());
1029
1030 // The code will survive at least two GCs.
1031 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1032 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1033 CHECK(function->shared()->is_compiled());
1034
1035 // Simulate several GCs that use incremental marking.
1036 const int kAgingThreshold = 6;
1037 for (int i = 0; i < kAgingThreshold; i++) {
1038 HEAP->incremental_marking()->Abort();
1039 SimulateIncrementalMarking();
1040 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1041 }
1042 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1043 CHECK(!function->is_compiled() || function->IsOptimized());
1044
1045 // This compile will compile the function again.
1046 { v8::HandleScope scope;
1047 CompileRun("foo();");
1048 }
1049
1050 // Simulate several GCs that use incremental marking but make sure
1051 // the loop breaks once the function is enqueued as a candidate.
1052 for (int i = 0; i < kAgingThreshold; i++) {
1053 HEAP->incremental_marking()->Abort();
1054 SimulateIncrementalMarking();
1055 if (!function->next_function_link()->IsUndefined()) break;
1056 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1057 }
1058
1059 // Force optimization while incremental marking is active and while
1060 // the function is enqueued as a candidate.
1061 { v8::HandleScope scope;
1062 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1063 }
1064
1065 // Simulate one final GC to make sure the candidate queue is sane.
1066 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1067 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1068 CHECK(function->is_compiled() || !function->IsOptimized());
1069}
1070
1071
1072TEST(TestCodeFlushingIncrementalScavenge) {
1073 // If we do not flush code this test is invalid.
1074 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1075 i::FLAG_allow_natives_syntax = true;
1076 InitializeVM();
1077 v8::HandleScope scope;
1078 const char* source = "var foo = function() {"
1079 " var x = 42;"
1080 " var y = 42;"
1081 " var z = x + y;"
1082 "};"
1083 "foo();"
1084 "var bar = function() {"
1085 " var x = 23;"
1086 "};"
1087 "bar();";
1088 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
1089 Handle<String> bar_name = FACTORY->LookupAsciiSymbol("bar");
1090
1091 // Perfrom one initial GC to enable code flushing.
1092 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1093
1094 // This compile will add the code to the compilation cache.
1095 { v8::HandleScope scope;
1096 CompileRun(source);
1097 }
1098
1099 // Check functions are compiled.
1100 Object* func_value = Isolate::Current()->context()->global_object()->
1101 GetProperty(*foo_name)->ToObjectChecked();
1102 CHECK(func_value->IsJSFunction());
1103 Handle<JSFunction> function(JSFunction::cast(func_value));
1104 CHECK(function->shared()->is_compiled());
1105 Object* func_value2 = Isolate::Current()->context()->global_object()->
1106 GetProperty(*bar_name)->ToObjectChecked();
1107 CHECK(func_value2->IsJSFunction());
1108 Handle<JSFunction> function2(JSFunction::cast(func_value2));
1109 CHECK(function2->shared()->is_compiled());
1110
1111 // Clear references to functions so that one of them can die.
1112 { v8::HandleScope scope;
1113 CompileRun("foo = 0; bar = 0;");
1114 }
1115
1116 // Bump the code age so that flushing is triggered while the function
1117 // object is still located in new-space.
1118 const int kAgingThreshold = 6;
1119 function->shared()->set_code_age(kAgingThreshold);
1120 function2->shared()->set_code_age(kAgingThreshold);
1121
1122 // Simulate incremental marking so that the functions are enqueued as
1123 // code flushing candidates. Then kill one of the functions. Finally
1124 // perform a scavenge while incremental marking is still running.
1125 SimulateIncrementalMarking();
1126 *function2.location() = NULL;
1127 HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking");
1128
1129 // Simulate one final GC to make sure the candidate queue is sane.
1130 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1131 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1132 CHECK(!function->is_compiled() || function->IsOptimized());
1133}
1134
1135
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001136TEST(TestCodeFlushingIncrementalAbort) {
1137 // If we do not flush code this test is invalid.
1138 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1139 i::FLAG_allow_natives_syntax = true;
1140 InitializeVM();
1141 v8::HandleScope scope;
1142 const char* source = "function foo() {"
1143 " var x = 42;"
1144 " var y = 42;"
1145 " var z = x + y;"
1146 "};"
1147 "foo()";
1148 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
1149
1150 // This compile will add the code to the compilation cache.
1151 { v8::HandleScope scope;
1152 CompileRun(source);
1153 }
1154
1155 // Check function is compiled.
1156 Object* func_value = Isolate::Current()->context()->global_object()->
1157 GetProperty(*foo_name)->ToObjectChecked();
1158 CHECK(func_value->IsJSFunction());
1159 Handle<JSFunction> function(JSFunction::cast(func_value));
1160 CHECK(function->shared()->is_compiled());
1161
1162 // The code will survive at least two GCs.
1163 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1164 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1165 CHECK(function->shared()->is_compiled());
1166
1167 // Bump the code age so that flushing is triggered.
1168 const int kAgingThreshold = 6;
1169 function->shared()->set_code_age(kAgingThreshold);
1170
1171 // Simulate incremental marking so that the function is enqueued as
1172 // code flushing candidate.
1173 SimulateIncrementalMarking();
1174
1175 // Enable the debugger and add a breakpoint while incremental marking
1176 // is running so that incremental marking aborts and code flushing is
1177 // disabled.
1178 int position = 0;
1179 Handle<Object> breakpoint_object(Smi::FromInt(0));
1180 ISOLATE->debug()->SetBreakPoint(function, breakpoint_object, &position);
1181 ISOLATE->debug()->ClearAllBreakPoints();
1182
1183 // Force optimization now that code flushing is disabled.
1184 { v8::HandleScope scope;
1185 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1186 }
1187
1188 // Simulate one final GC to make sure the candidate queue is sane.
1189 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1190 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1191 CHECK(function->is_compiled() || !function->IsOptimized());
1192}
1193
1194
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001195// Count the number of native contexts in the weak list of native contexts.
1196int CountNativeContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001197 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001198 Object* object = HEAP->native_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001199 while (!object->IsUndefined()) {
1200 count++;
1201 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1202 }
1203 return count;
1204}
1205
1206
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001207// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001208// functions attached to a native context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001209static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1210 int count = 0;
1211 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1212 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1213 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1214 count++;
1215 object = JSFunction::cast(object)->next_function_link();
1216 }
1217 return count;
1218}
1219
1220
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001221TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001222 v8::V8::Initialize();
1223
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001224 static const int kNumTestContexts = 10;
1225
1226 v8::HandleScope scope;
1227 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1228
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001229 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001230
1231 // Create a number of global contests which gets linked together.
1232 for (int i = 0; i < kNumTestContexts; i++) {
1233 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001234
1235 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1236
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001237 CHECK_EQ(i + 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001238
1239 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001240
1241 // Create a handle scope so no function objects get stuch in the outer
1242 // handle scope
1243 v8::HandleScope scope;
1244 const char* source = "function f1() { };"
1245 "function f2() { };"
1246 "function f3() { };"
1247 "function f4() { };"
1248 "function f5() { };";
1249 CompileRun(source);
1250 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1251 CompileRun("f1()");
1252 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1253 CompileRun("f2()");
1254 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1255 CompileRun("f3()");
1256 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1257 CompileRun("f4()");
1258 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1259 CompileRun("f5()");
1260 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1261
1262 // Remove function f1, and
1263 CompileRun("f1=null");
1264
1265 // Scavenge treats these references as strong.
1266 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001268 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1269 }
1270
1271 // Mark compact handles the weak references.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001272 ISOLATE->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001273 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001274 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1275
1276 // Get rid of f3 and f5 in the same way.
1277 CompileRun("f3=null");
1278 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001279 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001280 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1281 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001282 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001283 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1284 CompileRun("f5=null");
1285 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001286 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001287 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1288 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001289 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001290 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1291
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001292 ctx[i]->Exit();
1293 }
1294
1295 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001296 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001297
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001298 // Dispose the native contexts one by one.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001299 for (int i = 0; i < kNumTestContexts; i++) {
1300 ctx[i].Dispose();
1301 ctx[i].Clear();
1302
1303 // Scavenge treats these references as strong.
1304 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001305 HEAP->PerformScavenge();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001306 CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001307 }
1308
1309 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001310 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001311 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001312 }
1313
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001314 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001315}
1316
1317
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001318// Count the number of native contexts in the weak list of native contexts
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001319// causing a GC after the specified number of elements.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001320static int CountNativeContextsWithGC(int n) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001321 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001322 Handle<Object> object(HEAP->native_contexts_list());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001323 while (!object->IsUndefined()) {
1324 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001325 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001326 object =
1327 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1328 }
1329 return count;
1330}
1331
1332
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001333// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001334// functions attached to a native context causing a GC after the
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001335// specified number of elements.
1336static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1337 int n) {
1338 int count = 0;
1339 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1340 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1341 while (object->IsJSFunction() &&
1342 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1343 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001344 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001345 object = Handle<Object>(
1346 Object::cast(JSFunction::cast(*object)->next_function_link()));
1347 }
1348 return count;
1349}
1350
1351
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001352TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001353 v8::V8::Initialize();
1354
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001355 static const int kNumTestContexts = 10;
1356
1357 v8::HandleScope scope;
1358 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1359
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001360 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001361
1362 // Create an number of contexts and check the length of the weak list both
1363 // with and without GCs while iterating the list.
1364 for (int i = 0; i < kNumTestContexts; i++) {
1365 ctx[i] = v8::Context::New();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001366 CHECK_EQ(i + 1, CountNativeContexts());
1367 CHECK_EQ(i + 1, CountNativeContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001368 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001369
1370 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1371
1372 // Compile a number of functions the length of the weak list of optimized
1373 // functions both with and without GCs while iterating the list.
1374 ctx[0]->Enter();
1375 const char* source = "function f1() { };"
1376 "function f2() { };"
1377 "function f3() { };"
1378 "function f4() { };"
1379 "function f5() { };";
1380 CompileRun(source);
1381 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1382 CompileRun("f1()");
1383 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1384 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1385 CompileRun("f2()");
1386 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1387 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1388 CompileRun("f3()");
1389 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1390 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1391 CompileRun("f4()");
1392 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1393 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1394 CompileRun("f5()");
1395 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1396 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1397
1398 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001399}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001400
1401
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001402TEST(TestSizeOfObjects) {
1403 v8::V8::Initialize();
1404
1405 // Get initial heap size after several full GCs, which will stabilize
1406 // the heap size and return with sweeping finished completely.
1407 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1408 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1409 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1410 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001411 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001412 CHECK(HEAP->old_pointer_space()->IsSweepingComplete());
1413 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1414
1415 {
1416 // Allocate objects on several different old-space pages so that
1417 // lazy sweeping kicks in for subsequent GC runs.
1418 AlwaysAllocateScope always_allocate;
1419 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1420 for (int i = 1; i <= 100; i++) {
1421 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1422 CHECK_EQ(initial_size + i * filler_size,
1423 static_cast<int>(HEAP->SizeOfObjects()));
1424 }
1425 }
1426
1427 // The heap size should go back to initial size after a full GC, even
1428 // though sweeping didn't finish yet.
1429 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001430
1431 // Normally sweeping would not be complete here, but no guarantees.
1432
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001433 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1434
1435 // Advancing the sweeper step-wise should not change the heap size.
1436 while (!HEAP->old_pointer_space()->IsSweepingComplete()) {
1437 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1438 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1439 }
1440}
1441
1442
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001443TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1444 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001445 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001446 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001447 HeapIterator iterator;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001448 intptr_t size_of_objects_2 = 0;
1449 for (HeapObject* obj = iterator.next();
1450 obj != NULL;
1451 obj = iterator.next()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001452 if (!obj->IsFreeSpace()) {
1453 size_of_objects_2 += obj->Size();
1454 }
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001455 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001456 // Delta must be within 5% of the larger result.
1457 // TODO(gc): Tighten this up by distinguishing between byte
1458 // arrays that are real and those that merely mark free space
1459 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001460 if (size_of_objects_1 > size_of_objects_2) {
1461 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1462 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1463 "Iterator: %" V8_PTR_PREFIX "d, "
1464 "delta: %" V8_PTR_PREFIX "d\n",
1465 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001466 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001467 } else {
1468 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1469 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1470 "Iterator: %" V8_PTR_PREFIX "d, "
1471 "delta: %" V8_PTR_PREFIX "d\n",
1472 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001473 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001474 }
1475}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001476
1477
danno@chromium.orgc612e022011-11-10 11:38:15 +00001478static void FillUpNewSpace(NewSpace* new_space) {
1479 // Fill up new space to the point that it is completely full. Make sure
1480 // that the scavenger does not undo the filling.
1481 v8::HandleScope scope;
1482 AlwaysAllocateScope always_allocate;
1483 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001484 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001485 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001486 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001487 }
1488}
1489
1490
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001491TEST(GrowAndShrinkNewSpace) {
1492 InitializeVM();
1493 NewSpace* new_space = HEAP->new_space();
1494
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001495 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1496 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001497 // The max size cannot exceed the reserved size, since semispaces must be
1498 // always within the reserved space. We can't test new space growing and
1499 // shrinking if the reserved size is the same as the minimum (initial) size.
1500 return;
1501 }
1502
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001503 // Explicitly growing should double the space capacity.
1504 intptr_t old_capacity, new_capacity;
1505 old_capacity = new_space->Capacity();
1506 new_space->Grow();
1507 new_capacity = new_space->Capacity();
1508 CHECK(2 * old_capacity == new_capacity);
1509
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001510 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001511 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001512 new_capacity = new_space->Capacity();
1513 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001514
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001515 // Explicitly shrinking should not affect space capacity.
1516 old_capacity = new_space->Capacity();
1517 new_space->Shrink();
1518 new_capacity = new_space->Capacity();
1519 CHECK(old_capacity == new_capacity);
1520
1521 // Let the scavenger empty the new space.
1522 HEAP->CollectGarbage(NEW_SPACE);
1523 CHECK_LE(new_space->Size(), old_capacity);
1524
1525 // Explicitly shrinking should halve the space capacity.
1526 old_capacity = new_space->Capacity();
1527 new_space->Shrink();
1528 new_capacity = new_space->Capacity();
1529 CHECK(old_capacity == 2 * new_capacity);
1530
1531 // Consecutive shrinking should not affect space capacity.
1532 old_capacity = new_space->Capacity();
1533 new_space->Shrink();
1534 new_space->Shrink();
1535 new_space->Shrink();
1536 new_capacity = new_space->Capacity();
1537 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001538}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001539
1540
1541TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1542 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001543
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001544 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1545 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001546 // The max size cannot exceed the reserved size, since semispaces must be
1547 // always within the reserved space. We can't test new space growing and
1548 // shrinking if the reserved size is the same as the minimum (initial) size.
1549 return;
1550 }
1551
danno@chromium.orgc612e022011-11-10 11:38:15 +00001552 v8::HandleScope scope;
1553 NewSpace* new_space = HEAP->new_space();
1554 intptr_t old_capacity, new_capacity;
1555 old_capacity = new_space->Capacity();
1556 new_space->Grow();
1557 new_capacity = new_space->Capacity();
1558 CHECK(2 * old_capacity == new_capacity);
1559 FillUpNewSpace(new_space);
1560 HEAP->CollectAllAvailableGarbage();
1561 new_capacity = new_space->Capacity();
1562 CHECK(old_capacity == new_capacity);
1563}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001564
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001565
1566static int NumberOfGlobalObjects() {
1567 int count = 0;
1568 HeapIterator iterator;
1569 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1570 if (obj->IsGlobalObject()) count++;
1571 }
1572 return count;
1573}
1574
1575
1576// Test that we don't embed maps from foreign contexts into
1577// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001578TEST(LeakNativeContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001579 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001580 v8::HandleScope outer_scope;
1581 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1582 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1583 ctx1->Enter();
1584
1585 HEAP->CollectAllAvailableGarbage();
1586 CHECK_EQ(4, NumberOfGlobalObjects());
1587
1588 {
1589 v8::HandleScope inner_scope;
1590 CompileRun("var v = {x: 42}");
1591 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1592 ctx2->Enter();
1593 ctx2->Global()->Set(v8_str("o"), v);
1594 v8::Local<v8::Value> res = CompileRun(
1595 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001596 "for (var i = 0; i < 10; ++i) f();"
1597 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001598 "f();");
1599 CHECK_EQ(42, res->Int32Value());
1600 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1601 ctx2->Exit();
1602 ctx1->Exit();
1603 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001604 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001605 }
1606 HEAP->CollectAllAvailableGarbage();
1607 CHECK_EQ(2, NumberOfGlobalObjects());
1608 ctx2.Dispose();
1609 HEAP->CollectAllAvailableGarbage();
1610 CHECK_EQ(0, NumberOfGlobalObjects());
1611}
1612
1613
1614// Test that we don't embed functions from foreign contexts into
1615// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001616TEST(LeakNativeContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001617 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001618 v8::HandleScope outer_scope;
1619 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1620 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1621 ctx1->Enter();
1622
1623 HEAP->CollectAllAvailableGarbage();
1624 CHECK_EQ(4, NumberOfGlobalObjects());
1625
1626 {
1627 v8::HandleScope inner_scope;
1628 CompileRun("var v = function() { return 42; }");
1629 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1630 ctx2->Enter();
1631 ctx2->Global()->Set(v8_str("o"), v);
1632 v8::Local<v8::Value> res = CompileRun(
1633 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001634 "for (var i = 0; i < 10; ++i) f(o);"
1635 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001636 "f(o);");
1637 CHECK_EQ(42, res->Int32Value());
1638 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1639 ctx2->Exit();
1640 ctx1->Exit();
1641 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001642 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001643 }
1644 HEAP->CollectAllAvailableGarbage();
1645 CHECK_EQ(2, NumberOfGlobalObjects());
1646 ctx2.Dispose();
1647 HEAP->CollectAllAvailableGarbage();
1648 CHECK_EQ(0, NumberOfGlobalObjects());
1649}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001650
1651
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001652TEST(LeakNativeContextViaMapKeyed) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001653 i::FLAG_allow_natives_syntax = true;
1654 v8::HandleScope outer_scope;
1655 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1656 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1657 ctx1->Enter();
1658
1659 HEAP->CollectAllAvailableGarbage();
1660 CHECK_EQ(4, NumberOfGlobalObjects());
1661
1662 {
1663 v8::HandleScope inner_scope;
1664 CompileRun("var v = [42, 43]");
1665 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1666 ctx2->Enter();
1667 ctx2->Global()->Set(v8_str("o"), v);
1668 v8::Local<v8::Value> res = CompileRun(
1669 "function f() { return o[0]; }"
1670 "for (var i = 0; i < 10; ++i) f();"
1671 "%OptimizeFunctionOnNextCall(f);"
1672 "f();");
1673 CHECK_EQ(42, res->Int32Value());
1674 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1675 ctx2->Exit();
1676 ctx1->Exit();
1677 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001678 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001679 }
1680 HEAP->CollectAllAvailableGarbage();
1681 CHECK_EQ(2, NumberOfGlobalObjects());
1682 ctx2.Dispose();
1683 HEAP->CollectAllAvailableGarbage();
1684 CHECK_EQ(0, NumberOfGlobalObjects());
1685}
1686
1687
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001688TEST(LeakNativeContextViaMapProto) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001689 i::FLAG_allow_natives_syntax = true;
1690 v8::HandleScope outer_scope;
1691 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1692 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1693 ctx1->Enter();
1694
1695 HEAP->CollectAllAvailableGarbage();
1696 CHECK_EQ(4, NumberOfGlobalObjects());
1697
1698 {
1699 v8::HandleScope inner_scope;
1700 CompileRun("var v = { y: 42}");
1701 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1702 ctx2->Enter();
1703 ctx2->Global()->Set(v8_str("o"), v);
1704 v8::Local<v8::Value> res = CompileRun(
1705 "function f() {"
1706 " var p = {x: 42};"
1707 " p.__proto__ = o;"
1708 " return p.x;"
1709 "}"
1710 "for (var i = 0; i < 10; ++i) f();"
1711 "%OptimizeFunctionOnNextCall(f);"
1712 "f();");
1713 CHECK_EQ(42, res->Int32Value());
1714 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1715 ctx2->Exit();
1716 ctx1->Exit();
1717 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001718 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001719 }
1720 HEAP->CollectAllAvailableGarbage();
1721 CHECK_EQ(2, NumberOfGlobalObjects());
1722 ctx2.Dispose();
1723 HEAP->CollectAllAvailableGarbage();
1724 CHECK_EQ(0, NumberOfGlobalObjects());
1725}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001726
1727
1728TEST(InstanceOfStubWriteBarrier) {
1729 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001730#ifdef VERIFY_HEAP
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001731 i::FLAG_verify_heap = true;
1732#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001733
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001734 InitializeVM();
1735 if (!i::V8::UseCrankshaft()) return;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001736 if (i::FLAG_force_marking_deque_overflows) return;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001737 v8::HandleScope outer_scope;
1738
1739 {
1740 v8::HandleScope scope;
1741 CompileRun(
1742 "function foo () { }"
1743 "function mkbar () { return new (new Function(\"\")) (); }"
1744 "function f (x) { return (x instanceof foo); }"
1745 "function g () { f(mkbar()); }"
1746 "f(new foo()); f(new foo());"
1747 "%OptimizeFunctionOnNextCall(f);"
1748 "f(new foo()); g();");
1749 }
1750
1751 IncrementalMarking* marking = HEAP->incremental_marking();
1752 marking->Abort();
1753 marking->Start();
1754
1755 Handle<JSFunction> f =
1756 v8::Utils::OpenHandle(
1757 *v8::Handle<v8::Function>::Cast(
1758 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1759
1760 CHECK(f->IsOptimized());
1761
1762 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1763 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001764 // Discard any pending GC requests otherwise we will get GC when we enter
1765 // code below.
1766 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001767 }
1768
1769 CHECK(marking->IsMarking());
1770
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001771 {
1772 v8::HandleScope scope;
1773 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1774 v8::Handle<v8::Function> g =
1775 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1776 g->Call(global, 0, NULL);
1777 }
1778
1779 HEAP->incremental_marking()->set_should_hurry(true);
1780 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1781}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001782
1783
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001784// Implemented in the test-alloc.cc test suite.
1785void SimulateFullSpace(PagedSpace* space);
1786
1787
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001788TEST(PrototypeTransitionClearing) {
1789 InitializeVM();
1790 v8::HandleScope scope;
1791
1792 CompileRun(
1793 "var base = {};"
1794 "var live = [];"
1795 "for (var i = 0; i < 10; i++) {"
1796 " var object = {};"
1797 " var prototype = {};"
1798 " object.__proto__ = prototype;"
1799 " if (i >= 3) live.push(object, prototype);"
1800 "}");
1801
1802 Handle<JSObject> baseObject =
1803 v8::Utils::OpenHandle(
1804 *v8::Handle<v8::Object>::Cast(
1805 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1806
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001807 // Verify that only dead prototype transitions are cleared.
1808 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001809 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001810 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001811 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001812
1813 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001814 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001815 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001816 int j = Map::kProtoTransitionHeaderSize +
1817 i * Map::kProtoTransitionElementsPerEntry;
1818 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001819 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1820 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001821 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001822
1823 // Make sure next prototype is placed on an old-space evacuation candidate.
1824 Handle<JSObject> prototype;
1825 PagedSpace* space = HEAP->old_pointer_space();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001826 {
1827 AlwaysAllocateScope always_allocate;
1828 SimulateFullSpace(space);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001829 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001830 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001831
1832 // Add a prototype on an evacuation candidate and verify that transition
1833 // clearing correctly records slots in prototype transition array.
1834 i::FLAG_always_compact = true;
1835 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001836 CHECK(!space->LastPage()->Contains(
1837 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001838 CHECK(space->LastPage()->Contains(prototype->address()));
1839 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1840 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1841 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1842 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001843}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001844
1845
1846TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1847 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001848#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001849 i::FLAG_verify_heap = true;
1850#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001851
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001852 InitializeVM();
1853 if (!i::V8::UseCrankshaft()) return;
1854 v8::HandleScope outer_scope;
1855
1856 {
1857 v8::HandleScope scope;
1858 CompileRun(
1859 "function f () {"
1860 " var s = 0;"
1861 " for (var i = 0; i < 100; i++) s += i;"
1862 " return s;"
1863 "}"
1864 "f(); f();"
1865 "%OptimizeFunctionOnNextCall(f);"
1866 "f();");
1867 }
1868 Handle<JSFunction> f =
1869 v8::Utils::OpenHandle(
1870 *v8::Handle<v8::Function>::Cast(
1871 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1872 CHECK(f->IsOptimized());
1873
1874 IncrementalMarking* marking = HEAP->incremental_marking();
1875 marking->Abort();
1876 marking->Start();
1877
1878 // The following two calls will increment HEAP->global_ic_age().
1879 const int kLongIdlePauseInMs = 1000;
1880 v8::V8::ContextDisposedNotification();
1881 v8::V8::IdleNotification(kLongIdlePauseInMs);
1882
1883 while (!marking->IsStopped() && !marking->IsComplete()) {
1884 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1885 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001886 if (!marking->IsStopped() || marking->should_hurry()) {
1887 // We don't normally finish a GC via Step(), we normally finish by
1888 // setting the stack guard and then do the final steps in the stack
1889 // guard interrupt. But here we didn't ask for that, and there is no
1890 // JS code running to trigger the interrupt, so we explicitly finalize
1891 // here.
1892 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1893 "Test finalizing incremental mark-sweep");
1894 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001895
1896 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1897 CHECK_EQ(0, f->shared()->opt_count());
1898 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1899}
1900
1901
1902TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1903 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001904#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001905 i::FLAG_verify_heap = true;
1906#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001907
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001908 InitializeVM();
1909 if (!i::V8::UseCrankshaft()) return;
1910 v8::HandleScope outer_scope;
1911
1912 {
1913 v8::HandleScope scope;
1914 CompileRun(
1915 "function f () {"
1916 " var s = 0;"
1917 " for (var i = 0; i < 100; i++) s += i;"
1918 " return s;"
1919 "}"
1920 "f(); f();"
1921 "%OptimizeFunctionOnNextCall(f);"
1922 "f();");
1923 }
1924 Handle<JSFunction> f =
1925 v8::Utils::OpenHandle(
1926 *v8::Handle<v8::Function>::Cast(
1927 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1928 CHECK(f->IsOptimized());
1929
1930 HEAP->incremental_marking()->Abort();
1931
1932 // The following two calls will increment HEAP->global_ic_age().
1933 // Since incremental marking is off, IdleNotification will do full GC.
1934 const int kLongIdlePauseInMs = 1000;
1935 v8::V8::ContextDisposedNotification();
1936 v8::V8::IdleNotification(kLongIdlePauseInMs);
1937
1938 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1939 CHECK_EQ(0, f->shared()->opt_count());
1940 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1941}
1942
1943
1944// Test that HAllocateObject will always return an object in new-space.
1945TEST(OptimizedAllocationAlwaysInNewSpace) {
1946 i::FLAG_allow_natives_syntax = true;
1947 InitializeVM();
1948 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
1949 v8::HandleScope scope;
1950
1951 FillUpNewSpace(HEAP->new_space());
1952 AlwaysAllocateScope always_allocate;
1953 v8::Local<v8::Value> res = CompileRun(
1954 "function c(x) {"
1955 " this.x = x;"
1956 " for (var i = 0; i < 32; i++) {"
1957 " this['x' + i] = x;"
1958 " }"
1959 "}"
1960 "function f(x) { return new c(x); };"
1961 "f(1); f(2); f(3);"
1962 "%OptimizeFunctionOnNextCall(f);"
1963 "f(4);");
1964 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
1965
1966 Handle<JSObject> o =
1967 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
1968
1969 CHECK(HEAP->InNewSpace(*o));
1970}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001971
1972
1973static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001974 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001975}
1976
1977
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001978// Test that map transitions are cleared and maps are collected with
1979// incremental marking as well.
1980TEST(Regress1465) {
1981 i::FLAG_allow_natives_syntax = true;
1982 i::FLAG_trace_incremental_marking = true;
1983 InitializeVM();
1984 v8::HandleScope scope;
1985 static const int transitions_count = 256;
1986
1987 {
1988 AlwaysAllocateScope always_allocate;
1989 for (int i = 0; i < transitions_count; i++) {
1990 EmbeddedVector<char, 64> buffer;
1991 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
1992 CompileRun(buffer.start());
1993 }
1994 CompileRun("var root = new Object;");
1995 }
1996
1997 Handle<JSObject> root =
1998 v8::Utils::OpenHandle(
1999 *v8::Handle<v8::Object>::Cast(
2000 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2001
2002 // Count number of live transitions before marking.
2003 int transitions_before = CountMapTransitions(root->map());
2004 CompileRun("%DebugPrint(root);");
2005 CHECK_EQ(transitions_count, transitions_before);
2006
2007 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002008 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002009
2010 // Count number of live transitions after marking. Note that one transition
2011 // is left, because 'o' still holds an instance of one transition target.
2012 int transitions_after = CountMapTransitions(root->map());
2013 CompileRun("%DebugPrint(root);");
2014 CHECK_EQ(1, transitions_after);
2015}
verwaest@chromium.org37141392012-05-31 13:27:02 +00002016
2017
2018TEST(Regress2143a) {
2019 i::FLAG_collect_maps = true;
2020 i::FLAG_incremental_marking = true;
2021 InitializeVM();
2022 v8::HandleScope scope;
2023
2024 // Prepare a map transition from the root object together with a yet
2025 // untransitioned root object.
2026 CompileRun("var root = new Object;"
2027 "root.foo = 0;"
2028 "root = new Object;");
2029
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002030 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002031
2032 // Compile a StoreIC that performs the prepared map transition. This
2033 // will restart incremental marking and should make sure the root is
2034 // marked grey again.
2035 CompileRun("function f(o) {"
2036 " o.foo = 0;"
2037 "}"
2038 "f(new Object);"
2039 "f(root);");
2040
2041 // This bug only triggers with aggressive IC clearing.
2042 HEAP->AgeInlineCaches();
2043
2044 // Explicitly request GC to perform final marking step and sweeping.
2045 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002046
2047 Handle<JSObject> root =
2048 v8::Utils::OpenHandle(
2049 *v8::Handle<v8::Object>::Cast(
2050 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2051
2052 // The root object should be in a sane state.
2053 CHECK(root->IsJSObject());
2054 CHECK(root->map()->IsMap());
2055}
2056
2057
2058TEST(Regress2143b) {
2059 i::FLAG_collect_maps = true;
2060 i::FLAG_incremental_marking = true;
2061 i::FLAG_allow_natives_syntax = true;
2062 InitializeVM();
2063 v8::HandleScope scope;
2064
2065 // Prepare a map transition from the root object together with a yet
2066 // untransitioned root object.
2067 CompileRun("var root = new Object;"
2068 "root.foo = 0;"
2069 "root = new Object;");
2070
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002071 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002072
2073 // Compile an optimized LStoreNamedField that performs the prepared
2074 // map transition. This will restart incremental marking and should
2075 // make sure the root is marked grey again.
2076 CompileRun("function f(o) {"
2077 " o.foo = 0;"
2078 "}"
2079 "f(new Object);"
2080 "f(new Object);"
2081 "%OptimizeFunctionOnNextCall(f);"
2082 "f(root);"
2083 "%DeoptimizeFunction(f);");
2084
2085 // This bug only triggers with aggressive IC clearing.
2086 HEAP->AgeInlineCaches();
2087
2088 // Explicitly request GC to perform final marking step and sweeping.
2089 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002090
2091 Handle<JSObject> root =
2092 v8::Utils::OpenHandle(
2093 *v8::Handle<v8::Object>::Cast(
2094 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2095
2096 // The root object should be in a sane state.
2097 CHECK(root->IsJSObject());
2098 CHECK(root->map()->IsMap());
2099}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002100
2101
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002102TEST(ReleaseOverReservedPages) {
2103 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002104 // The optimizer can allocate stuff, messing up the test.
2105 i::FLAG_crankshaft = false;
2106 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002107 InitializeVM();
2108 v8::HandleScope scope;
2109 static const int number_of_test_pages = 20;
2110
2111 // Prepare many pages with low live-bytes count.
2112 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
2113 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2114 for (int i = 0; i < number_of_test_pages; i++) {
2115 AlwaysAllocateScope always_allocate;
2116 SimulateFullSpace(old_pointer_space);
2117 FACTORY->NewFixedArray(1, TENURED);
2118 }
2119 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2120
2121 // Triggering one GC will cause a lot of garbage to be discovered but
2122 // even spread across all allocated pages.
2123 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
2124 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2125
2126 // Triggering subsequent GCs should cause at least half of the pages
2127 // to be released to the OS after at most two cycles.
2128 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
2129 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2130 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
2131 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
2132
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002133 // Triggering a last-resort GC should cause all pages to be released to the
2134 // OS so that other processes can seize the memory. If we get a failure here
2135 // where there are 2 pages left instead of 1, then we should increase the
2136 // size of the first page a little in SizeOfFirstPage in spaces.cc. The
2137 // first page should be small in order to reduce memory used when the VM
2138 // boots, but if the 20 small arrays don't fit on the first page then that's
2139 // an indication that it is too small.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002140 HEAP->CollectAllAvailableGarbage("triggered really hard");
2141 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2142}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002143
2144
2145TEST(Regress2237) {
2146 InitializeVM();
2147 v8::HandleScope scope;
2148 Handle<String> slice(HEAP->empty_string());
2149
2150 {
2151 // Generate a parent that lives in new-space.
2152 v8::HandleScope inner_scope;
2153 const char* c = "This text is long enough to trigger sliced strings.";
2154 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002155 CHECK(s->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002156 CHECK(HEAP->InNewSpace(*s));
2157
2158 // Generate a sliced string that is based on the above parent and
2159 // lives in old-space.
2160 FillUpNewSpace(HEAP->new_space());
2161 AlwaysAllocateScope always_allocate;
2162 Handle<String> t;
2163 // TODO(mstarzinger): Unfortunately FillUpNewSpace() still leaves
2164 // some slack, so we need to allocate a few sliced strings.
2165 for (int i = 0; i < 16; i++) {
2166 t = FACTORY->NewProperSubString(s, 5, 35);
2167 }
2168 CHECK(t->IsSlicedString());
2169 CHECK(!HEAP->InNewSpace(*t));
2170 *slice.location() = *t.location();
2171 }
2172
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002173 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002174 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002175 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002176}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002177
2178
2179#ifdef OBJECT_PRINT
2180TEST(PrintSharedFunctionInfo) {
2181 InitializeVM();
2182 v8::HandleScope scope;
2183 const char* source = "f = function() { return 987654321; }\n"
2184 "g = function() { return 123456789; }\n";
2185 CompileRun(source);
2186 Handle<JSFunction> g =
2187 v8::Utils::OpenHandle(
2188 *v8::Handle<v8::Function>::Cast(
2189 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2190
2191 AssertNoAllocation no_alloc;
2192 g->shared()->PrintLn();
2193}
2194#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002195
2196
2197TEST(Regress2211) {
2198 InitializeVM();
2199 v8::HandleScope scope;
2200
2201 v8::Handle<v8::String> value = v8_str("val string");
2202 Smi* hash = Smi::FromInt(321);
2203 Heap* heap = Isolate::Current()->heap();
2204
2205 for (int i = 0; i < 2; i++) {
2206 // Store identity hash first and common hidden property second.
2207 v8::Handle<v8::Object> obj = v8::Object::New();
2208 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2209 CHECK(internal_obj->HasFastProperties());
2210
2211 // In the first iteration, set hidden value first and identity hash second.
2212 // In the second iteration, reverse the order.
2213 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2214 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2215 ALLOW_CREATION);
2216 CHECK(!maybe_obj->IsFailure());
2217 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2218
2219 // Check values.
2220 CHECK_EQ(hash,
2221 internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
2222 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2223
2224 // Check size.
2225 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2226 ObjectHashTable* hashtable = ObjectHashTable::cast(
2227 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2228 // HashTable header (5) and 4 initial entries (8).
2229 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2230 }
2231}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002232
2233
2234TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2235 if (i::FLAG_always_opt) return;
2236 InitializeVM();
2237 v8::HandleScope scope;
2238 v8::Local<v8::Value> fun1, fun2;
2239
2240 {
2241 LocalContext env;
2242 CompileRun("function fun() {};");
2243 fun1 = env->Global()->Get(v8_str("fun"));
2244 }
2245
2246 {
2247 LocalContext env;
2248 CompileRun("function fun() {};");
2249 fun2 = env->Global()->Get(v8_str("fun"));
2250 }
2251
2252 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002253 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002254 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2255 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2256 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2257 Handle<JSFunction> f =
2258 v8::Utils::OpenHandle(
2259 *v8::Handle<v8::Function>::Cast(
2260 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2261 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2262 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2263
2264 CHECK_EQ(2, cells->CellCount());
2265 CHECK(cells->Cell(0)->value()->IsJSFunction());
2266 CHECK(cells->Cell(1)->value()->IsJSFunction());
2267
2268 SimulateIncrementalMarking();
2269 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2270
2271 CHECK_EQ(2, cells->CellCount());
2272 CHECK(cells->Cell(0)->value()->IsTheHole());
2273 CHECK(cells->Cell(1)->value()->IsTheHole());
2274}
2275
2276
2277static Code* FindFirstIC(Code* code, Code::Kind kind) {
2278 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2279 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2280 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2281 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2282 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2283 RelocInfo* info = it.rinfo();
2284 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2285 if (target->is_inline_cache_stub() && target->kind() == kind) {
2286 return target;
2287 }
2288 }
2289 return NULL;
2290}
2291
2292
2293TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2294 if (i::FLAG_always_opt) return;
2295 InitializeVM();
2296 v8::HandleScope scope;
2297
2298 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002299 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002300 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2301 "function f(o) { return o.x; } f(obj); f(obj);");
2302 Handle<JSFunction> f =
2303 v8::Utils::OpenHandle(
2304 *v8::Handle<v8::Function>::Cast(
2305 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2306
2307 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2308 CHECK(ic_before->ic_state() == MONOMORPHIC);
2309
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002310 SimulateIncrementalMarking();
2311 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2312
2313 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2314 CHECK(ic_after->ic_state() == MONOMORPHIC);
2315}
2316
2317
2318TEST(IncrementalMarkingClearsMonomorhpicIC) {
2319 if (i::FLAG_always_opt) return;
2320 InitializeVM();
2321 v8::HandleScope scope;
2322 v8::Local<v8::Value> obj1;
2323
2324 {
2325 LocalContext env;
2326 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2327 obj1 = env->Global()->Get(v8_str("obj"));
2328 }
2329
2330 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002331 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002332 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2333 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2334 Handle<JSFunction> f =
2335 v8::Utils::OpenHandle(
2336 *v8::Handle<v8::Function>::Cast(
2337 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2338
2339 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2340 CHECK(ic_before->ic_state() == MONOMORPHIC);
2341
2342 // Fire context dispose notification.
2343 v8::V8::ContextDisposedNotification();
2344 SimulateIncrementalMarking();
2345 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2346
2347 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2348 CHECK(ic_after->ic_state() == UNINITIALIZED);
2349}
2350
2351
2352TEST(IncrementalMarkingClearsPolymorhpicIC) {
2353 if (i::FLAG_always_opt) return;
2354 InitializeVM();
2355 v8::HandleScope scope;
2356 v8::Local<v8::Value> obj1, obj2;
2357
2358 {
2359 LocalContext env;
2360 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2361 obj1 = env->Global()->Get(v8_str("obj"));
2362 }
2363
2364 {
2365 LocalContext env;
2366 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2367 obj2 = env->Global()->Get(v8_str("obj"));
2368 }
2369
2370 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002371 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002372 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2373 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2374 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2375 Handle<JSFunction> f =
2376 v8::Utils::OpenHandle(
2377 *v8::Handle<v8::Function>::Cast(
2378 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2379
2380 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2381 CHECK(ic_before->ic_state() == MEGAMORPHIC);
2382
2383 // Fire context dispose notification.
2384 v8::V8::ContextDisposedNotification();
2385 SimulateIncrementalMarking();
2386 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2387
2388 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2389 CHECK(ic_after->ic_state() == UNINITIALIZED);
2390}
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002391
2392
2393class SourceResource: public v8::String::ExternalAsciiStringResource {
2394 public:
2395 explicit SourceResource(const char* data)
2396 : data_(data), length_(strlen(data)) { }
2397
2398 virtual void Dispose() {
2399 i::DeleteArray(data_);
2400 data_ = NULL;
2401 }
2402
2403 const char* data() const { return data_; }
2404
2405 size_t length() const { return length_; }
2406
2407 bool IsDisposed() { return data_ == NULL; }
2408
2409 private:
2410 const char* data_;
2411 size_t length_;
2412};
2413
2414
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002415void ReleaseStackTraceDataTest(const char* source) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002416 // Test that the data retained by the Error.stack accessor is released
2417 // after the first time the accessor is fired. We use external string
2418 // to check whether the data is being released since the external string
2419 // resource's callback is fired when the external string is GC'ed.
2420 InitializeVM();
2421 v8::HandleScope scope;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002422 SourceResource* resource = new SourceResource(i::StrDup(source));
2423 {
2424 v8::HandleScope scope;
2425 v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
2426 v8::Script::Compile(source_string)->Run();
2427 CHECK(!resource->IsDisposed());
2428 }
2429 HEAP->CollectAllAvailableGarbage();
2430 // External source is being retained by the stack trace.
2431 CHECK(!resource->IsDisposed());
2432
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002433 CompileRun("error.stack;");
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002434 HEAP->CollectAllAvailableGarbage();
2435 // External source has been released.
2436 CHECK(resource->IsDisposed());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002437 delete resource;
2438}
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002439
2440
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002441TEST(ReleaseStackTraceData) {
2442 static const char* source1 = "var error = null; "
2443 /* Normal Error */ "try { "
2444 " throw new Error(); "
2445 "} catch (e) { "
2446 " error = e; "
2447 "} ";
2448 static const char* source2 = "var error = null; "
2449 /* Stack overflow */ "try { "
2450 " (function f() { f(); })(); "
2451 "} catch (e) { "
2452 " error = e; "
2453 "} ";
2454 ReleaseStackTraceDataTest(source1);
2455 ReleaseStackTraceDataTest(source2);
2456}
2457
2458
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002459TEST(Regression144230) {
2460 InitializeVM();
2461 v8::HandleScope scope;
2462
2463 // First make sure that the uninitialized CallIC stub is on a single page
2464 // that will later be selected as an evacuation candidate.
2465 {
2466 v8::HandleScope inner_scope;
2467 AlwaysAllocateScope always_allocate;
2468 SimulateFullSpace(HEAP->code_space());
2469 ISOLATE->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET);
2470 }
2471
2472 // Second compile a CallIC and execute it once so that it gets patched to
2473 // the pre-monomorphic stub. These code objects are on yet another page.
2474 {
2475 v8::HandleScope inner_scope;
2476 AlwaysAllocateScope always_allocate;
2477 SimulateFullSpace(HEAP->code_space());
2478 CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};"
2479 "function call() { o.f(1,2,3,4,5,6,7,8,9); };"
2480 "call();");
2481 }
2482
2483 // Third we fill up the last page of the code space so that it does not get
2484 // chosen as an evacuation candidate.
2485 {
2486 v8::HandleScope inner_scope;
2487 AlwaysAllocateScope always_allocate;
2488 CompileRun("for (var i = 0; i < 2000; i++) {"
2489 " eval('function f' + i + '() { return ' + i +'; };' +"
2490 " 'f' + i + '();');"
2491 "}");
2492 }
2493 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2494
2495 // Fourth is the tricky part. Make sure the code containing the CallIC is
2496 // visited first without clearing the IC. The shared function info is then
2497 // visited later, causing the CallIC to be cleared.
2498 Handle<String> name = FACTORY->LookupAsciiSymbol("call");
2499 Handle<GlobalObject> global(ISOLATE->context()->global_object());
2500 MaybeObject* maybe_call = global->GetProperty(*name);
2501 JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
2502 USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode));
2503 ISOLATE->compilation_cache()->Clear();
2504 call->shared()->set_ic_age(HEAP->global_ic_age() + 1);
2505 Handle<Object> call_code(call->code());
2506 Handle<Object> call_function(call);
2507
2508 // Now we are ready to mess up the heap.
2509 HEAP->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
2510
2511 // Either heap verification caught the problem already or we go kaboom once
2512 // the CallIC is executed the next time.
2513 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode));
2514 CompileRun("call();");
2515}