blob: f5bac2c5def2edcc1246805cdcdb82c79c17cccb [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
1784TEST(PrototypeTransitionClearing) {
1785 InitializeVM();
1786 v8::HandleScope scope;
1787
1788 CompileRun(
1789 "var base = {};"
1790 "var live = [];"
1791 "for (var i = 0; i < 10; i++) {"
1792 " var object = {};"
1793 " var prototype = {};"
1794 " object.__proto__ = prototype;"
1795 " if (i >= 3) live.push(object, prototype);"
1796 "}");
1797
1798 Handle<JSObject> baseObject =
1799 v8::Utils::OpenHandle(
1800 *v8::Handle<v8::Object>::Cast(
1801 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1802
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001803 // Verify that only dead prototype transitions are cleared.
1804 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001805 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001806 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001807 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001808
1809 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001810 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001811 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001812 int j = Map::kProtoTransitionHeaderSize +
1813 i * Map::kProtoTransitionElementsPerEntry;
1814 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001815 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1816 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001817 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001818
1819 // Make sure next prototype is placed on an old-space evacuation candidate.
1820 Handle<JSObject> prototype;
1821 PagedSpace* space = HEAP->old_pointer_space();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001822 {
1823 AlwaysAllocateScope always_allocate;
1824 SimulateFullSpace(space);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001825 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001826 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001827
1828 // Add a prototype on an evacuation candidate and verify that transition
1829 // clearing correctly records slots in prototype transition array.
1830 i::FLAG_always_compact = true;
1831 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001832 CHECK(!space->LastPage()->Contains(
1833 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001834 CHECK(space->LastPage()->Contains(prototype->address()));
1835 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1836 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1837 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1838 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001839}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001840
1841
1842TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1843 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001844#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001845 i::FLAG_verify_heap = true;
1846#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001847
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001848 InitializeVM();
1849 if (!i::V8::UseCrankshaft()) return;
1850 v8::HandleScope outer_scope;
1851
1852 {
1853 v8::HandleScope scope;
1854 CompileRun(
1855 "function f () {"
1856 " var s = 0;"
1857 " for (var i = 0; i < 100; i++) s += i;"
1858 " return s;"
1859 "}"
1860 "f(); f();"
1861 "%OptimizeFunctionOnNextCall(f);"
1862 "f();");
1863 }
1864 Handle<JSFunction> f =
1865 v8::Utils::OpenHandle(
1866 *v8::Handle<v8::Function>::Cast(
1867 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1868 CHECK(f->IsOptimized());
1869
1870 IncrementalMarking* marking = HEAP->incremental_marking();
1871 marking->Abort();
1872 marking->Start();
1873
1874 // The following two calls will increment HEAP->global_ic_age().
1875 const int kLongIdlePauseInMs = 1000;
1876 v8::V8::ContextDisposedNotification();
1877 v8::V8::IdleNotification(kLongIdlePauseInMs);
1878
1879 while (!marking->IsStopped() && !marking->IsComplete()) {
1880 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1881 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001882 if (!marking->IsStopped() || marking->should_hurry()) {
1883 // We don't normally finish a GC via Step(), we normally finish by
1884 // setting the stack guard and then do the final steps in the stack
1885 // guard interrupt. But here we didn't ask for that, and there is no
1886 // JS code running to trigger the interrupt, so we explicitly finalize
1887 // here.
1888 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1889 "Test finalizing incremental mark-sweep");
1890 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001891
1892 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1893 CHECK_EQ(0, f->shared()->opt_count());
1894 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1895}
1896
1897
1898TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1899 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001900#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001901 i::FLAG_verify_heap = true;
1902#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001903
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001904 InitializeVM();
1905 if (!i::V8::UseCrankshaft()) return;
1906 v8::HandleScope outer_scope;
1907
1908 {
1909 v8::HandleScope scope;
1910 CompileRun(
1911 "function f () {"
1912 " var s = 0;"
1913 " for (var i = 0; i < 100; i++) s += i;"
1914 " return s;"
1915 "}"
1916 "f(); f();"
1917 "%OptimizeFunctionOnNextCall(f);"
1918 "f();");
1919 }
1920 Handle<JSFunction> f =
1921 v8::Utils::OpenHandle(
1922 *v8::Handle<v8::Function>::Cast(
1923 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1924 CHECK(f->IsOptimized());
1925
1926 HEAP->incremental_marking()->Abort();
1927
1928 // The following two calls will increment HEAP->global_ic_age().
1929 // Since incremental marking is off, IdleNotification will do full GC.
1930 const int kLongIdlePauseInMs = 1000;
1931 v8::V8::ContextDisposedNotification();
1932 v8::V8::IdleNotification(kLongIdlePauseInMs);
1933
1934 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1935 CHECK_EQ(0, f->shared()->opt_count());
1936 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1937}
1938
1939
1940// Test that HAllocateObject will always return an object in new-space.
1941TEST(OptimizedAllocationAlwaysInNewSpace) {
1942 i::FLAG_allow_natives_syntax = true;
1943 InitializeVM();
1944 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
1945 v8::HandleScope scope;
1946
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001947 SimulateFullSpace(HEAP->new_space());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001948 AlwaysAllocateScope always_allocate;
1949 v8::Local<v8::Value> res = CompileRun(
1950 "function c(x) {"
1951 " this.x = x;"
1952 " for (var i = 0; i < 32; i++) {"
1953 " this['x' + i] = x;"
1954 " }"
1955 "}"
1956 "function f(x) { return new c(x); };"
1957 "f(1); f(2); f(3);"
1958 "%OptimizeFunctionOnNextCall(f);"
1959 "f(4);");
1960 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
1961
1962 Handle<JSObject> o =
1963 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
1964
1965 CHECK(HEAP->InNewSpace(*o));
1966}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001967
1968
1969static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001970 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001971}
1972
1973
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001974// Test that map transitions are cleared and maps are collected with
1975// incremental marking as well.
1976TEST(Regress1465) {
1977 i::FLAG_allow_natives_syntax = true;
1978 i::FLAG_trace_incremental_marking = true;
1979 InitializeVM();
1980 v8::HandleScope scope;
1981 static const int transitions_count = 256;
1982
1983 {
1984 AlwaysAllocateScope always_allocate;
1985 for (int i = 0; i < transitions_count; i++) {
1986 EmbeddedVector<char, 64> buffer;
1987 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
1988 CompileRun(buffer.start());
1989 }
1990 CompileRun("var root = new Object;");
1991 }
1992
1993 Handle<JSObject> root =
1994 v8::Utils::OpenHandle(
1995 *v8::Handle<v8::Object>::Cast(
1996 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
1997
1998 // Count number of live transitions before marking.
1999 int transitions_before = CountMapTransitions(root->map());
2000 CompileRun("%DebugPrint(root);");
2001 CHECK_EQ(transitions_count, transitions_before);
2002
2003 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002004 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002005
2006 // Count number of live transitions after marking. Note that one transition
2007 // is left, because 'o' still holds an instance of one transition target.
2008 int transitions_after = CountMapTransitions(root->map());
2009 CompileRun("%DebugPrint(root);");
2010 CHECK_EQ(1, transitions_after);
2011}
verwaest@chromium.org37141392012-05-31 13:27:02 +00002012
2013
2014TEST(Regress2143a) {
2015 i::FLAG_collect_maps = true;
2016 i::FLAG_incremental_marking = true;
2017 InitializeVM();
2018 v8::HandleScope scope;
2019
2020 // Prepare a map transition from the root object together with a yet
2021 // untransitioned root object.
2022 CompileRun("var root = new Object;"
2023 "root.foo = 0;"
2024 "root = new Object;");
2025
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002026 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002027
2028 // Compile a StoreIC that performs the prepared map transition. This
2029 // will restart incremental marking and should make sure the root is
2030 // marked grey again.
2031 CompileRun("function f(o) {"
2032 " o.foo = 0;"
2033 "}"
2034 "f(new Object);"
2035 "f(root);");
2036
2037 // This bug only triggers with aggressive IC clearing.
2038 HEAP->AgeInlineCaches();
2039
2040 // Explicitly request GC to perform final marking step and sweeping.
2041 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002042
2043 Handle<JSObject> root =
2044 v8::Utils::OpenHandle(
2045 *v8::Handle<v8::Object>::Cast(
2046 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2047
2048 // The root object should be in a sane state.
2049 CHECK(root->IsJSObject());
2050 CHECK(root->map()->IsMap());
2051}
2052
2053
2054TEST(Regress2143b) {
2055 i::FLAG_collect_maps = true;
2056 i::FLAG_incremental_marking = true;
2057 i::FLAG_allow_natives_syntax = true;
2058 InitializeVM();
2059 v8::HandleScope scope;
2060
2061 // Prepare a map transition from the root object together with a yet
2062 // untransitioned root object.
2063 CompileRun("var root = new Object;"
2064 "root.foo = 0;"
2065 "root = new Object;");
2066
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002067 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002068
2069 // Compile an optimized LStoreNamedField that performs the prepared
2070 // map transition. This will restart incremental marking and should
2071 // make sure the root is marked grey again.
2072 CompileRun("function f(o) {"
2073 " o.foo = 0;"
2074 "}"
2075 "f(new Object);"
2076 "f(new Object);"
2077 "%OptimizeFunctionOnNextCall(f);"
2078 "f(root);"
2079 "%DeoptimizeFunction(f);");
2080
2081 // This bug only triggers with aggressive IC clearing.
2082 HEAP->AgeInlineCaches();
2083
2084 // Explicitly request GC to perform final marking step and sweeping.
2085 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002086
2087 Handle<JSObject> root =
2088 v8::Utils::OpenHandle(
2089 *v8::Handle<v8::Object>::Cast(
2090 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2091
2092 // The root object should be in a sane state.
2093 CHECK(root->IsJSObject());
2094 CHECK(root->map()->IsMap());
2095}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002096
2097
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002098TEST(ReleaseOverReservedPages) {
2099 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002100 // The optimizer can allocate stuff, messing up the test.
2101 i::FLAG_crankshaft = false;
2102 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002103 InitializeVM();
2104 v8::HandleScope scope;
2105 static const int number_of_test_pages = 20;
2106
2107 // Prepare many pages with low live-bytes count.
2108 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
2109 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2110 for (int i = 0; i < number_of_test_pages; i++) {
2111 AlwaysAllocateScope always_allocate;
2112 SimulateFullSpace(old_pointer_space);
2113 FACTORY->NewFixedArray(1, TENURED);
2114 }
2115 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2116
2117 // Triggering one GC will cause a lot of garbage to be discovered but
2118 // even spread across all allocated pages.
2119 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
2120 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2121
2122 // Triggering subsequent GCs should cause at least half of the pages
2123 // to be released to the OS after at most two cycles.
2124 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
2125 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2126 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
2127 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
2128
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002129 // Triggering a last-resort GC should cause all pages to be released to the
2130 // OS so that other processes can seize the memory. If we get a failure here
2131 // where there are 2 pages left instead of 1, then we should increase the
2132 // size of the first page a little in SizeOfFirstPage in spaces.cc. The
2133 // first page should be small in order to reduce memory used when the VM
2134 // boots, but if the 20 small arrays don't fit on the first page then that's
2135 // an indication that it is too small.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002136 HEAP->CollectAllAvailableGarbage("triggered really hard");
2137 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2138}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002139
2140
2141TEST(Regress2237) {
2142 InitializeVM();
2143 v8::HandleScope scope;
2144 Handle<String> slice(HEAP->empty_string());
2145
2146 {
2147 // Generate a parent that lives in new-space.
2148 v8::HandleScope inner_scope;
2149 const char* c = "This text is long enough to trigger sliced strings.";
2150 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002151 CHECK(s->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002152 CHECK(HEAP->InNewSpace(*s));
2153
2154 // Generate a sliced string that is based on the above parent and
2155 // lives in old-space.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002156 SimulateFullSpace(HEAP->new_space());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002157 AlwaysAllocateScope always_allocate;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002158 Handle<String> t = FACTORY->NewProperSubString(s, 5, 35);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002159 CHECK(t->IsSlicedString());
2160 CHECK(!HEAP->InNewSpace(*t));
2161 *slice.location() = *t.location();
2162 }
2163
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002164 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002165 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002166 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002167}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002168
2169
2170#ifdef OBJECT_PRINT
2171TEST(PrintSharedFunctionInfo) {
2172 InitializeVM();
2173 v8::HandleScope scope;
2174 const char* source = "f = function() { return 987654321; }\n"
2175 "g = function() { return 123456789; }\n";
2176 CompileRun(source);
2177 Handle<JSFunction> g =
2178 v8::Utils::OpenHandle(
2179 *v8::Handle<v8::Function>::Cast(
2180 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2181
2182 AssertNoAllocation no_alloc;
2183 g->shared()->PrintLn();
2184}
2185#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002186
2187
2188TEST(Regress2211) {
2189 InitializeVM();
2190 v8::HandleScope scope;
2191
2192 v8::Handle<v8::String> value = v8_str("val string");
2193 Smi* hash = Smi::FromInt(321);
2194 Heap* heap = Isolate::Current()->heap();
2195
2196 for (int i = 0; i < 2; i++) {
2197 // Store identity hash first and common hidden property second.
2198 v8::Handle<v8::Object> obj = v8::Object::New();
2199 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2200 CHECK(internal_obj->HasFastProperties());
2201
2202 // In the first iteration, set hidden value first and identity hash second.
2203 // In the second iteration, reverse the order.
2204 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2205 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2206 ALLOW_CREATION);
2207 CHECK(!maybe_obj->IsFailure());
2208 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2209
2210 // Check values.
2211 CHECK_EQ(hash,
2212 internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
2213 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2214
2215 // Check size.
2216 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2217 ObjectHashTable* hashtable = ObjectHashTable::cast(
2218 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2219 // HashTable header (5) and 4 initial entries (8).
2220 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2221 }
2222}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002223
2224
2225TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2226 if (i::FLAG_always_opt) return;
2227 InitializeVM();
2228 v8::HandleScope scope;
2229 v8::Local<v8::Value> fun1, fun2;
2230
2231 {
2232 LocalContext env;
2233 CompileRun("function fun() {};");
2234 fun1 = env->Global()->Get(v8_str("fun"));
2235 }
2236
2237 {
2238 LocalContext env;
2239 CompileRun("function fun() {};");
2240 fun2 = env->Global()->Get(v8_str("fun"));
2241 }
2242
2243 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002244 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002245 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2246 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2247 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2248 Handle<JSFunction> f =
2249 v8::Utils::OpenHandle(
2250 *v8::Handle<v8::Function>::Cast(
2251 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2252 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2253 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2254
2255 CHECK_EQ(2, cells->CellCount());
2256 CHECK(cells->Cell(0)->value()->IsJSFunction());
2257 CHECK(cells->Cell(1)->value()->IsJSFunction());
2258
2259 SimulateIncrementalMarking();
2260 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2261
2262 CHECK_EQ(2, cells->CellCount());
2263 CHECK(cells->Cell(0)->value()->IsTheHole());
2264 CHECK(cells->Cell(1)->value()->IsTheHole());
2265}
2266
2267
2268static Code* FindFirstIC(Code* code, Code::Kind kind) {
2269 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2270 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2271 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2272 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2273 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2274 RelocInfo* info = it.rinfo();
2275 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2276 if (target->is_inline_cache_stub() && target->kind() == kind) {
2277 return target;
2278 }
2279 }
2280 return NULL;
2281}
2282
2283
2284TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2285 if (i::FLAG_always_opt) return;
2286 InitializeVM();
2287 v8::HandleScope scope;
2288
2289 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002290 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002291 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2292 "function f(o) { return o.x; } f(obj); f(obj);");
2293 Handle<JSFunction> f =
2294 v8::Utils::OpenHandle(
2295 *v8::Handle<v8::Function>::Cast(
2296 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2297
2298 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2299 CHECK(ic_before->ic_state() == MONOMORPHIC);
2300
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002301 SimulateIncrementalMarking();
2302 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2303
2304 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2305 CHECK(ic_after->ic_state() == MONOMORPHIC);
2306}
2307
2308
2309TEST(IncrementalMarkingClearsMonomorhpicIC) {
2310 if (i::FLAG_always_opt) return;
2311 InitializeVM();
2312 v8::HandleScope scope;
2313 v8::Local<v8::Value> obj1;
2314
2315 {
2316 LocalContext env;
2317 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2318 obj1 = env->Global()->Get(v8_str("obj"));
2319 }
2320
2321 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002322 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002323 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2324 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2325 Handle<JSFunction> f =
2326 v8::Utils::OpenHandle(
2327 *v8::Handle<v8::Function>::Cast(
2328 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2329
2330 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2331 CHECK(ic_before->ic_state() == MONOMORPHIC);
2332
2333 // Fire context dispose notification.
2334 v8::V8::ContextDisposedNotification();
2335 SimulateIncrementalMarking();
2336 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2337
2338 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2339 CHECK(ic_after->ic_state() == UNINITIALIZED);
2340}
2341
2342
2343TEST(IncrementalMarkingClearsPolymorhpicIC) {
2344 if (i::FLAG_always_opt) return;
2345 InitializeVM();
2346 v8::HandleScope scope;
2347 v8::Local<v8::Value> obj1, obj2;
2348
2349 {
2350 LocalContext env;
2351 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2352 obj1 = env->Global()->Get(v8_str("obj"));
2353 }
2354
2355 {
2356 LocalContext env;
2357 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2358 obj2 = env->Global()->Get(v8_str("obj"));
2359 }
2360
2361 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002362 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002363 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2364 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2365 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2366 Handle<JSFunction> f =
2367 v8::Utils::OpenHandle(
2368 *v8::Handle<v8::Function>::Cast(
2369 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2370
2371 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2372 CHECK(ic_before->ic_state() == MEGAMORPHIC);
2373
2374 // Fire context dispose notification.
2375 v8::V8::ContextDisposedNotification();
2376 SimulateIncrementalMarking();
2377 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2378
2379 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2380 CHECK(ic_after->ic_state() == UNINITIALIZED);
2381}
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002382
2383
2384class SourceResource: public v8::String::ExternalAsciiStringResource {
2385 public:
2386 explicit SourceResource(const char* data)
2387 : data_(data), length_(strlen(data)) { }
2388
2389 virtual void Dispose() {
2390 i::DeleteArray(data_);
2391 data_ = NULL;
2392 }
2393
2394 const char* data() const { return data_; }
2395
2396 size_t length() const { return length_; }
2397
2398 bool IsDisposed() { return data_ == NULL; }
2399
2400 private:
2401 const char* data_;
2402 size_t length_;
2403};
2404
2405
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002406void ReleaseStackTraceDataTest(const char* source) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002407 // Test that the data retained by the Error.stack accessor is released
2408 // after the first time the accessor is fired. We use external string
2409 // to check whether the data is being released since the external string
2410 // resource's callback is fired when the external string is GC'ed.
2411 InitializeVM();
2412 v8::HandleScope scope;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002413 SourceResource* resource = new SourceResource(i::StrDup(source));
2414 {
2415 v8::HandleScope scope;
2416 v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
2417 v8::Script::Compile(source_string)->Run();
2418 CHECK(!resource->IsDisposed());
2419 }
2420 HEAP->CollectAllAvailableGarbage();
2421 // External source is being retained by the stack trace.
2422 CHECK(!resource->IsDisposed());
2423
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002424 CompileRun("error.stack;");
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002425 HEAP->CollectAllAvailableGarbage();
2426 // External source has been released.
2427 CHECK(resource->IsDisposed());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002428 delete resource;
2429}
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002430
2431
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002432TEST(ReleaseStackTraceData) {
2433 static const char* source1 = "var error = null; "
2434 /* Normal Error */ "try { "
2435 " throw new Error(); "
2436 "} catch (e) { "
2437 " error = e; "
2438 "} ";
2439 static const char* source2 = "var error = null; "
2440 /* Stack overflow */ "try { "
2441 " (function f() { f(); })(); "
2442 "} catch (e) { "
2443 " error = e; "
2444 "} ";
2445 ReleaseStackTraceDataTest(source1);
2446 ReleaseStackTraceDataTest(source2);
2447}
2448
2449
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002450TEST(Regression144230) {
2451 InitializeVM();
2452 v8::HandleScope scope;
2453
2454 // First make sure that the uninitialized CallIC stub is on a single page
2455 // that will later be selected as an evacuation candidate.
2456 {
2457 v8::HandleScope inner_scope;
2458 AlwaysAllocateScope always_allocate;
2459 SimulateFullSpace(HEAP->code_space());
2460 ISOLATE->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET);
2461 }
2462
2463 // Second compile a CallIC and execute it once so that it gets patched to
2464 // the pre-monomorphic stub. These code objects are on yet another page.
2465 {
2466 v8::HandleScope inner_scope;
2467 AlwaysAllocateScope always_allocate;
2468 SimulateFullSpace(HEAP->code_space());
2469 CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};"
2470 "function call() { o.f(1,2,3,4,5,6,7,8,9); };"
2471 "call();");
2472 }
2473
2474 // Third we fill up the last page of the code space so that it does not get
2475 // chosen as an evacuation candidate.
2476 {
2477 v8::HandleScope inner_scope;
2478 AlwaysAllocateScope always_allocate;
2479 CompileRun("for (var i = 0; i < 2000; i++) {"
2480 " eval('function f' + i + '() { return ' + i +'; };' +"
2481 " 'f' + i + '();');"
2482 "}");
2483 }
2484 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2485
2486 // Fourth is the tricky part. Make sure the code containing the CallIC is
2487 // visited first without clearing the IC. The shared function info is then
2488 // visited later, causing the CallIC to be cleared.
2489 Handle<String> name = FACTORY->LookupAsciiSymbol("call");
2490 Handle<GlobalObject> global(ISOLATE->context()->global_object());
2491 MaybeObject* maybe_call = global->GetProperty(*name);
2492 JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
2493 USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode));
2494 ISOLATE->compilation_cache()->Clear();
2495 call->shared()->set_ic_age(HEAP->global_ic_age() + 1);
2496 Handle<Object> call_code(call->code());
2497 Handle<Object> call_function(call);
2498
2499 // Now we are ready to mess up the heap.
2500 HEAP->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
2501
2502 // Either heap verification caught the problem already or we go kaboom once
2503 // the CallIC is executed the next time.
2504 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode));
2505 CompileRun("call();");
2506}