blob: dc5247d19709ceb93d759af578a722c84cd1cf86 [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;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001119 for (int i = 0; i < kAgingThreshold; i++) {
1120 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1121 function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1122 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001123
1124 // Simulate incremental marking so that the functions are enqueued as
1125 // code flushing candidates. Then kill one of the functions. Finally
1126 // perform a scavenge while incremental marking is still running.
1127 SimulateIncrementalMarking();
1128 *function2.location() = NULL;
1129 HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking");
1130
1131 // Simulate one final GC to make sure the candidate queue is sane.
1132 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1133 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1134 CHECK(!function->is_compiled() || function->IsOptimized());
1135}
1136
1137
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001138TEST(TestCodeFlushingIncrementalAbort) {
1139 // If we do not flush code this test is invalid.
1140 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1141 i::FLAG_allow_natives_syntax = true;
1142 InitializeVM();
1143 v8::HandleScope scope;
1144 const char* source = "function foo() {"
1145 " var x = 42;"
1146 " var y = 42;"
1147 " var z = x + y;"
1148 "};"
1149 "foo()";
1150 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
1151
1152 // This compile will add the code to the compilation cache.
1153 { v8::HandleScope scope;
1154 CompileRun(source);
1155 }
1156
1157 // Check function is compiled.
1158 Object* func_value = Isolate::Current()->context()->global_object()->
1159 GetProperty(*foo_name)->ToObjectChecked();
1160 CHECK(func_value->IsJSFunction());
1161 Handle<JSFunction> function(JSFunction::cast(func_value));
1162 CHECK(function->shared()->is_compiled());
1163
1164 // The code will survive at least two GCs.
1165 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1166 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1167 CHECK(function->shared()->is_compiled());
1168
1169 // Bump the code age so that flushing is triggered.
1170 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001171 for (int i = 0; i < kAgingThreshold; i++) {
1172 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1173 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001174
1175 // Simulate incremental marking so that the function is enqueued as
1176 // code flushing candidate.
1177 SimulateIncrementalMarking();
1178
1179 // Enable the debugger and add a breakpoint while incremental marking
1180 // is running so that incremental marking aborts and code flushing is
1181 // disabled.
1182 int position = 0;
1183 Handle<Object> breakpoint_object(Smi::FromInt(0));
1184 ISOLATE->debug()->SetBreakPoint(function, breakpoint_object, &position);
1185 ISOLATE->debug()->ClearAllBreakPoints();
1186
1187 // Force optimization now that code flushing is disabled.
1188 { v8::HandleScope scope;
1189 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1190 }
1191
1192 // Simulate one final GC to make sure the candidate queue is sane.
1193 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1194 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1195 CHECK(function->is_compiled() || !function->IsOptimized());
1196}
1197
1198
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001199// Count the number of native contexts in the weak list of native contexts.
1200int CountNativeContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001201 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001202 Object* object = HEAP->native_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001203 while (!object->IsUndefined()) {
1204 count++;
1205 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1206 }
1207 return count;
1208}
1209
1210
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001211// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001212// functions attached to a native context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001213static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1214 int count = 0;
1215 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1216 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1217 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1218 count++;
1219 object = JSFunction::cast(object)->next_function_link();
1220 }
1221 return count;
1222}
1223
1224
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001225TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001226 v8::V8::Initialize();
1227
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001228 static const int kNumTestContexts = 10;
1229
1230 v8::HandleScope scope;
1231 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1232
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001233 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001234
1235 // Create a number of global contests which gets linked together.
1236 for (int i = 0; i < kNumTestContexts; i++) {
1237 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001238
1239 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1240
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001241 CHECK_EQ(i + 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001242
1243 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001244
1245 // Create a handle scope so no function objects get stuch in the outer
1246 // handle scope
1247 v8::HandleScope scope;
1248 const char* source = "function f1() { };"
1249 "function f2() { };"
1250 "function f3() { };"
1251 "function f4() { };"
1252 "function f5() { };";
1253 CompileRun(source);
1254 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1255 CompileRun("f1()");
1256 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1257 CompileRun("f2()");
1258 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1259 CompileRun("f3()");
1260 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1261 CompileRun("f4()");
1262 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1263 CompileRun("f5()");
1264 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1265
1266 // Remove function f1, and
1267 CompileRun("f1=null");
1268
1269 // Scavenge treats these references as strong.
1270 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001271 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001272 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1273 }
1274
1275 // Mark compact handles the weak references.
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001276 ISOLATE->compilation_cache()->Clear();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001277 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001278 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1279
1280 // Get rid of f3 and f5 in the same way.
1281 CompileRun("f3=null");
1282 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001283 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001284 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1285 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001286 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001287 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1288 CompileRun("f5=null");
1289 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001290 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001291 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1292 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001293 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001294 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1295
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001296 ctx[i]->Exit();
1297 }
1298
1299 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001301
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001302 // Dispose the native contexts one by one.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001303 for (int i = 0; i < kNumTestContexts; i++) {
1304 ctx[i].Dispose();
1305 ctx[i].Clear();
1306
1307 // Scavenge treats these references as strong.
1308 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001309 HEAP->PerformScavenge();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001310 CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001311 }
1312
1313 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001314 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001315 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001316 }
1317
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001318 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001319}
1320
1321
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001322// Count the number of native contexts in the weak list of native contexts
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001323// causing a GC after the specified number of elements.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001324static int CountNativeContextsWithGC(int n) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001325 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001326 Handle<Object> object(HEAP->native_contexts_list());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001327 while (!object->IsUndefined()) {
1328 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001329 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001330 object =
1331 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1332 }
1333 return count;
1334}
1335
1336
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001337// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001338// functions attached to a native context causing a GC after the
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001339// specified number of elements.
1340static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1341 int n) {
1342 int count = 0;
1343 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1344 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1345 while (object->IsJSFunction() &&
1346 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1347 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001348 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001349 object = Handle<Object>(
1350 Object::cast(JSFunction::cast(*object)->next_function_link()));
1351 }
1352 return count;
1353}
1354
1355
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001356TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001357 v8::V8::Initialize();
1358
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001359 static const int kNumTestContexts = 10;
1360
1361 v8::HandleScope scope;
1362 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1363
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001364 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001365
1366 // Create an number of contexts and check the length of the weak list both
1367 // with and without GCs while iterating the list.
1368 for (int i = 0; i < kNumTestContexts; i++) {
1369 ctx[i] = v8::Context::New();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001370 CHECK_EQ(i + 1, CountNativeContexts());
1371 CHECK_EQ(i + 1, CountNativeContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001372 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001373
1374 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1375
1376 // Compile a number of functions the length of the weak list of optimized
1377 // functions both with and without GCs while iterating the list.
1378 ctx[0]->Enter();
1379 const char* source = "function f1() { };"
1380 "function f2() { };"
1381 "function f3() { };"
1382 "function f4() { };"
1383 "function f5() { };";
1384 CompileRun(source);
1385 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1386 CompileRun("f1()");
1387 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1388 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1389 CompileRun("f2()");
1390 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1391 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1392 CompileRun("f3()");
1393 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1394 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1395 CompileRun("f4()");
1396 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1397 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1398 CompileRun("f5()");
1399 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1400 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1401
1402 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001403}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001404
1405
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001406TEST(TestSizeOfObjects) {
1407 v8::V8::Initialize();
1408
1409 // Get initial heap size after several full GCs, which will stabilize
1410 // the heap size and return with sweeping finished completely.
1411 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1412 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1413 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1414 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001415 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001416 CHECK(HEAP->old_pointer_space()->IsSweepingComplete());
1417 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1418
1419 {
1420 // Allocate objects on several different old-space pages so that
1421 // lazy sweeping kicks in for subsequent GC runs.
1422 AlwaysAllocateScope always_allocate;
1423 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1424 for (int i = 1; i <= 100; i++) {
1425 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1426 CHECK_EQ(initial_size + i * filler_size,
1427 static_cast<int>(HEAP->SizeOfObjects()));
1428 }
1429 }
1430
1431 // The heap size should go back to initial size after a full GC, even
1432 // though sweeping didn't finish yet.
1433 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001434
1435 // Normally sweeping would not be complete here, but no guarantees.
1436
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001437 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1438
1439 // Advancing the sweeper step-wise should not change the heap size.
1440 while (!HEAP->old_pointer_space()->IsSweepingComplete()) {
1441 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1442 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1443 }
1444}
1445
1446
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001447TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1448 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001449 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001450 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001451 HeapIterator iterator;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001452 intptr_t size_of_objects_2 = 0;
1453 for (HeapObject* obj = iterator.next();
1454 obj != NULL;
1455 obj = iterator.next()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001456 if (!obj->IsFreeSpace()) {
1457 size_of_objects_2 += obj->Size();
1458 }
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001459 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001460 // Delta must be within 5% of the larger result.
1461 // TODO(gc): Tighten this up by distinguishing between byte
1462 // arrays that are real and those that merely mark free space
1463 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001464 if (size_of_objects_1 > size_of_objects_2) {
1465 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1466 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1467 "Iterator: %" V8_PTR_PREFIX "d, "
1468 "delta: %" V8_PTR_PREFIX "d\n",
1469 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001470 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001471 } else {
1472 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1473 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1474 "Iterator: %" V8_PTR_PREFIX "d, "
1475 "delta: %" V8_PTR_PREFIX "d\n",
1476 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001477 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001478 }
1479}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001480
1481
danno@chromium.orgc612e022011-11-10 11:38:15 +00001482static void FillUpNewSpace(NewSpace* new_space) {
1483 // Fill up new space to the point that it is completely full. Make sure
1484 // that the scavenger does not undo the filling.
1485 v8::HandleScope scope;
1486 AlwaysAllocateScope always_allocate;
1487 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001488 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001489 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001490 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001491 }
1492}
1493
1494
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001495TEST(GrowAndShrinkNewSpace) {
1496 InitializeVM();
1497 NewSpace* new_space = HEAP->new_space();
1498
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001499 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1500 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001501 // The max size cannot exceed the reserved size, since semispaces must be
1502 // always within the reserved space. We can't test new space growing and
1503 // shrinking if the reserved size is the same as the minimum (initial) size.
1504 return;
1505 }
1506
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001507 // Explicitly growing should double the space capacity.
1508 intptr_t old_capacity, new_capacity;
1509 old_capacity = new_space->Capacity();
1510 new_space->Grow();
1511 new_capacity = new_space->Capacity();
1512 CHECK(2 * old_capacity == new_capacity);
1513
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001514 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001515 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001516 new_capacity = new_space->Capacity();
1517 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001518
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001519 // Explicitly shrinking should not affect space capacity.
1520 old_capacity = new_space->Capacity();
1521 new_space->Shrink();
1522 new_capacity = new_space->Capacity();
1523 CHECK(old_capacity == new_capacity);
1524
1525 // Let the scavenger empty the new space.
1526 HEAP->CollectGarbage(NEW_SPACE);
1527 CHECK_LE(new_space->Size(), old_capacity);
1528
1529 // Explicitly shrinking should halve the space capacity.
1530 old_capacity = new_space->Capacity();
1531 new_space->Shrink();
1532 new_capacity = new_space->Capacity();
1533 CHECK(old_capacity == 2 * new_capacity);
1534
1535 // Consecutive shrinking should not affect space capacity.
1536 old_capacity = new_space->Capacity();
1537 new_space->Shrink();
1538 new_space->Shrink();
1539 new_space->Shrink();
1540 new_capacity = new_space->Capacity();
1541 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001542}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001543
1544
1545TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1546 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001547
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001548 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1549 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001550 // The max size cannot exceed the reserved size, since semispaces must be
1551 // always within the reserved space. We can't test new space growing and
1552 // shrinking if the reserved size is the same as the minimum (initial) size.
1553 return;
1554 }
1555
danno@chromium.orgc612e022011-11-10 11:38:15 +00001556 v8::HandleScope scope;
1557 NewSpace* new_space = HEAP->new_space();
1558 intptr_t old_capacity, new_capacity;
1559 old_capacity = new_space->Capacity();
1560 new_space->Grow();
1561 new_capacity = new_space->Capacity();
1562 CHECK(2 * old_capacity == new_capacity);
1563 FillUpNewSpace(new_space);
1564 HEAP->CollectAllAvailableGarbage();
1565 new_capacity = new_space->Capacity();
1566 CHECK(old_capacity == new_capacity);
1567}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001568
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001569
1570static int NumberOfGlobalObjects() {
1571 int count = 0;
1572 HeapIterator iterator;
1573 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1574 if (obj->IsGlobalObject()) count++;
1575 }
1576 return count;
1577}
1578
1579
1580// Test that we don't embed maps from foreign contexts into
1581// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001582TEST(LeakNativeContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001583 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001584 v8::HandleScope outer_scope;
1585 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1586 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1587 ctx1->Enter();
1588
1589 HEAP->CollectAllAvailableGarbage();
1590 CHECK_EQ(4, NumberOfGlobalObjects());
1591
1592 {
1593 v8::HandleScope inner_scope;
1594 CompileRun("var v = {x: 42}");
1595 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1596 ctx2->Enter();
1597 ctx2->Global()->Set(v8_str("o"), v);
1598 v8::Local<v8::Value> res = CompileRun(
1599 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001600 "for (var i = 0; i < 10; ++i) f();"
1601 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001602 "f();");
1603 CHECK_EQ(42, res->Int32Value());
1604 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1605 ctx2->Exit();
1606 ctx1->Exit();
1607 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001608 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001609 }
1610 HEAP->CollectAllAvailableGarbage();
1611 CHECK_EQ(2, NumberOfGlobalObjects());
1612 ctx2.Dispose();
1613 HEAP->CollectAllAvailableGarbage();
1614 CHECK_EQ(0, NumberOfGlobalObjects());
1615}
1616
1617
1618// Test that we don't embed functions from foreign contexts into
1619// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001620TEST(LeakNativeContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001621 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001622 v8::HandleScope outer_scope;
1623 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1624 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1625 ctx1->Enter();
1626
1627 HEAP->CollectAllAvailableGarbage();
1628 CHECK_EQ(4, NumberOfGlobalObjects());
1629
1630 {
1631 v8::HandleScope inner_scope;
1632 CompileRun("var v = function() { return 42; }");
1633 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1634 ctx2->Enter();
1635 ctx2->Global()->Set(v8_str("o"), v);
1636 v8::Local<v8::Value> res = CompileRun(
1637 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001638 "for (var i = 0; i < 10; ++i) f(o);"
1639 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001640 "f(o);");
1641 CHECK_EQ(42, res->Int32Value());
1642 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1643 ctx2->Exit();
1644 ctx1->Exit();
1645 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001646 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001647 }
1648 HEAP->CollectAllAvailableGarbage();
1649 CHECK_EQ(2, NumberOfGlobalObjects());
1650 ctx2.Dispose();
1651 HEAP->CollectAllAvailableGarbage();
1652 CHECK_EQ(0, NumberOfGlobalObjects());
1653}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001654
1655
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001656TEST(LeakNativeContextViaMapKeyed) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001657 i::FLAG_allow_natives_syntax = true;
1658 v8::HandleScope outer_scope;
1659 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1660 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1661 ctx1->Enter();
1662
1663 HEAP->CollectAllAvailableGarbage();
1664 CHECK_EQ(4, NumberOfGlobalObjects());
1665
1666 {
1667 v8::HandleScope inner_scope;
1668 CompileRun("var v = [42, 43]");
1669 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1670 ctx2->Enter();
1671 ctx2->Global()->Set(v8_str("o"), v);
1672 v8::Local<v8::Value> res = CompileRun(
1673 "function f() { return o[0]; }"
1674 "for (var i = 0; i < 10; ++i) f();"
1675 "%OptimizeFunctionOnNextCall(f);"
1676 "f();");
1677 CHECK_EQ(42, res->Int32Value());
1678 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1679 ctx2->Exit();
1680 ctx1->Exit();
1681 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001682 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001683 }
1684 HEAP->CollectAllAvailableGarbage();
1685 CHECK_EQ(2, NumberOfGlobalObjects());
1686 ctx2.Dispose();
1687 HEAP->CollectAllAvailableGarbage();
1688 CHECK_EQ(0, NumberOfGlobalObjects());
1689}
1690
1691
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001692TEST(LeakNativeContextViaMapProto) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001693 i::FLAG_allow_natives_syntax = true;
1694 v8::HandleScope outer_scope;
1695 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1696 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1697 ctx1->Enter();
1698
1699 HEAP->CollectAllAvailableGarbage();
1700 CHECK_EQ(4, NumberOfGlobalObjects());
1701
1702 {
1703 v8::HandleScope inner_scope;
1704 CompileRun("var v = { y: 42}");
1705 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1706 ctx2->Enter();
1707 ctx2->Global()->Set(v8_str("o"), v);
1708 v8::Local<v8::Value> res = CompileRun(
1709 "function f() {"
1710 " var p = {x: 42};"
1711 " p.__proto__ = o;"
1712 " return p.x;"
1713 "}"
1714 "for (var i = 0; i < 10; ++i) f();"
1715 "%OptimizeFunctionOnNextCall(f);"
1716 "f();");
1717 CHECK_EQ(42, res->Int32Value());
1718 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1719 ctx2->Exit();
1720 ctx1->Exit();
1721 ctx1.Dispose();
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001722 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001723 }
1724 HEAP->CollectAllAvailableGarbage();
1725 CHECK_EQ(2, NumberOfGlobalObjects());
1726 ctx2.Dispose();
1727 HEAP->CollectAllAvailableGarbage();
1728 CHECK_EQ(0, NumberOfGlobalObjects());
1729}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001730
1731
1732TEST(InstanceOfStubWriteBarrier) {
1733 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001734#ifdef VERIFY_HEAP
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001735 i::FLAG_verify_heap = true;
1736#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001737
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001738 InitializeVM();
1739 if (!i::V8::UseCrankshaft()) return;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001740 if (i::FLAG_force_marking_deque_overflows) return;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001741 v8::HandleScope outer_scope;
1742
1743 {
1744 v8::HandleScope scope;
1745 CompileRun(
1746 "function foo () { }"
1747 "function mkbar () { return new (new Function(\"\")) (); }"
1748 "function f (x) { return (x instanceof foo); }"
1749 "function g () { f(mkbar()); }"
1750 "f(new foo()); f(new foo());"
1751 "%OptimizeFunctionOnNextCall(f);"
1752 "f(new foo()); g();");
1753 }
1754
1755 IncrementalMarking* marking = HEAP->incremental_marking();
1756 marking->Abort();
1757 marking->Start();
1758
1759 Handle<JSFunction> f =
1760 v8::Utils::OpenHandle(
1761 *v8::Handle<v8::Function>::Cast(
1762 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1763
1764 CHECK(f->IsOptimized());
1765
1766 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1767 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001768 // Discard any pending GC requests otherwise we will get GC when we enter
1769 // code below.
1770 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001771 }
1772
1773 CHECK(marking->IsMarking());
1774
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001775 {
1776 v8::HandleScope scope;
1777 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1778 v8::Handle<v8::Function> g =
1779 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1780 g->Call(global, 0, NULL);
1781 }
1782
1783 HEAP->incremental_marking()->set_should_hurry(true);
1784 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1785}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001786
1787
1788TEST(PrototypeTransitionClearing) {
1789 InitializeVM();
1790 v8::HandleScope scope;
1791
1792 CompileRun(
1793 "var base = {};"
1794 "var live = [];"
1795 "for (var i = 0; i < 10; i++) {"
1796 " var object = {};"
1797 " var prototype = {};"
1798 " object.__proto__ = prototype;"
1799 " if (i >= 3) live.push(object, prototype);"
1800 "}");
1801
1802 Handle<JSObject> baseObject =
1803 v8::Utils::OpenHandle(
1804 *v8::Handle<v8::Object>::Cast(
1805 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1806
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001807 // Verify that only dead prototype transitions are cleared.
1808 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001809 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001810 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001811 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001812
1813 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001814 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001815 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001816 int j = Map::kProtoTransitionHeaderSize +
1817 i * Map::kProtoTransitionElementsPerEntry;
1818 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001819 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1820 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001821 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001822
1823 // Make sure next prototype is placed on an old-space evacuation candidate.
1824 Handle<JSObject> prototype;
1825 PagedSpace* space = HEAP->old_pointer_space();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001826 {
1827 AlwaysAllocateScope always_allocate;
1828 SimulateFullSpace(space);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001829 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001830 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001831
1832 // Add a prototype on an evacuation candidate and verify that transition
1833 // clearing correctly records slots in prototype transition array.
1834 i::FLAG_always_compact = true;
1835 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001836 CHECK(!space->LastPage()->Contains(
1837 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001838 CHECK(space->LastPage()->Contains(prototype->address()));
1839 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1840 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1841 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1842 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001843}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001844
1845
1846TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1847 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001848#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001849 i::FLAG_verify_heap = true;
1850#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001851
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001852 InitializeVM();
1853 if (!i::V8::UseCrankshaft()) return;
1854 v8::HandleScope outer_scope;
1855
1856 {
1857 v8::HandleScope scope;
1858 CompileRun(
1859 "function f () {"
1860 " var s = 0;"
1861 " for (var i = 0; i < 100; i++) s += i;"
1862 " return s;"
1863 "}"
1864 "f(); f();"
1865 "%OptimizeFunctionOnNextCall(f);"
1866 "f();");
1867 }
1868 Handle<JSFunction> f =
1869 v8::Utils::OpenHandle(
1870 *v8::Handle<v8::Function>::Cast(
1871 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1872 CHECK(f->IsOptimized());
1873
1874 IncrementalMarking* marking = HEAP->incremental_marking();
1875 marking->Abort();
1876 marking->Start();
1877
1878 // The following two calls will increment HEAP->global_ic_age().
1879 const int kLongIdlePauseInMs = 1000;
1880 v8::V8::ContextDisposedNotification();
1881 v8::V8::IdleNotification(kLongIdlePauseInMs);
1882
1883 while (!marking->IsStopped() && !marking->IsComplete()) {
1884 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1885 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001886 if (!marking->IsStopped() || marking->should_hurry()) {
1887 // We don't normally finish a GC via Step(), we normally finish by
1888 // setting the stack guard and then do the final steps in the stack
1889 // guard interrupt. But here we didn't ask for that, and there is no
1890 // JS code running to trigger the interrupt, so we explicitly finalize
1891 // here.
1892 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1893 "Test finalizing incremental mark-sweep");
1894 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001895
1896 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1897 CHECK_EQ(0, f->shared()->opt_count());
1898 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1899}
1900
1901
1902TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1903 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001904#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001905 i::FLAG_verify_heap = true;
1906#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001907
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001908 InitializeVM();
1909 if (!i::V8::UseCrankshaft()) return;
1910 v8::HandleScope outer_scope;
1911
1912 {
1913 v8::HandleScope scope;
1914 CompileRun(
1915 "function f () {"
1916 " var s = 0;"
1917 " for (var i = 0; i < 100; i++) s += i;"
1918 " return s;"
1919 "}"
1920 "f(); f();"
1921 "%OptimizeFunctionOnNextCall(f);"
1922 "f();");
1923 }
1924 Handle<JSFunction> f =
1925 v8::Utils::OpenHandle(
1926 *v8::Handle<v8::Function>::Cast(
1927 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1928 CHECK(f->IsOptimized());
1929
1930 HEAP->incremental_marking()->Abort();
1931
1932 // The following two calls will increment HEAP->global_ic_age().
1933 // Since incremental marking is off, IdleNotification will do full GC.
1934 const int kLongIdlePauseInMs = 1000;
1935 v8::V8::ContextDisposedNotification();
1936 v8::V8::IdleNotification(kLongIdlePauseInMs);
1937
1938 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1939 CHECK_EQ(0, f->shared()->opt_count());
1940 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1941}
1942
1943
1944// Test that HAllocateObject will always return an object in new-space.
1945TEST(OptimizedAllocationAlwaysInNewSpace) {
1946 i::FLAG_allow_natives_syntax = true;
1947 InitializeVM();
1948 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
1949 v8::HandleScope scope;
1950
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001951 SimulateFullSpace(HEAP->new_space());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001952 AlwaysAllocateScope always_allocate;
1953 v8::Local<v8::Value> res = CompileRun(
1954 "function c(x) {"
1955 " this.x = x;"
1956 " for (var i = 0; i < 32; i++) {"
1957 " this['x' + i] = x;"
1958 " }"
1959 "}"
1960 "function f(x) { return new c(x); };"
1961 "f(1); f(2); f(3);"
1962 "%OptimizeFunctionOnNextCall(f);"
1963 "f(4);");
1964 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
1965
1966 Handle<JSObject> o =
1967 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
1968
1969 CHECK(HEAP->InNewSpace(*o));
1970}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001971
1972
1973static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001974 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001975}
1976
1977
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001978// Test that map transitions are cleared and maps are collected with
1979// incremental marking as well.
1980TEST(Regress1465) {
1981 i::FLAG_allow_natives_syntax = true;
1982 i::FLAG_trace_incremental_marking = true;
1983 InitializeVM();
1984 v8::HandleScope scope;
1985 static const int transitions_count = 256;
1986
1987 {
1988 AlwaysAllocateScope always_allocate;
1989 for (int i = 0; i < transitions_count; i++) {
1990 EmbeddedVector<char, 64> buffer;
1991 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
1992 CompileRun(buffer.start());
1993 }
1994 CompileRun("var root = new Object;");
1995 }
1996
1997 Handle<JSObject> root =
1998 v8::Utils::OpenHandle(
1999 *v8::Handle<v8::Object>::Cast(
2000 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2001
2002 // Count number of live transitions before marking.
2003 int transitions_before = CountMapTransitions(root->map());
2004 CompileRun("%DebugPrint(root);");
2005 CHECK_EQ(transitions_count, transitions_before);
2006
2007 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002008 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002009
2010 // Count number of live transitions after marking. Note that one transition
2011 // is left, because 'o' still holds an instance of one transition target.
2012 int transitions_after = CountMapTransitions(root->map());
2013 CompileRun("%DebugPrint(root);");
2014 CHECK_EQ(1, transitions_after);
2015}
verwaest@chromium.org37141392012-05-31 13:27:02 +00002016
2017
2018TEST(Regress2143a) {
2019 i::FLAG_collect_maps = true;
2020 i::FLAG_incremental_marking = true;
2021 InitializeVM();
2022 v8::HandleScope scope;
2023
2024 // Prepare a map transition from the root object together with a yet
2025 // untransitioned root object.
2026 CompileRun("var root = new Object;"
2027 "root.foo = 0;"
2028 "root = new Object;");
2029
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002030 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002031
2032 // Compile a StoreIC that performs the prepared map transition. This
2033 // will restart incremental marking and should make sure the root is
2034 // marked grey again.
2035 CompileRun("function f(o) {"
2036 " o.foo = 0;"
2037 "}"
2038 "f(new Object);"
2039 "f(root);");
2040
2041 // This bug only triggers with aggressive IC clearing.
2042 HEAP->AgeInlineCaches();
2043
2044 // Explicitly request GC to perform final marking step and sweeping.
2045 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002046
2047 Handle<JSObject> root =
2048 v8::Utils::OpenHandle(
2049 *v8::Handle<v8::Object>::Cast(
2050 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2051
2052 // The root object should be in a sane state.
2053 CHECK(root->IsJSObject());
2054 CHECK(root->map()->IsMap());
2055}
2056
2057
2058TEST(Regress2143b) {
2059 i::FLAG_collect_maps = true;
2060 i::FLAG_incremental_marking = true;
2061 i::FLAG_allow_natives_syntax = true;
2062 InitializeVM();
2063 v8::HandleScope scope;
2064
2065 // Prepare a map transition from the root object together with a yet
2066 // untransitioned root object.
2067 CompileRun("var root = new Object;"
2068 "root.foo = 0;"
2069 "root = new Object;");
2070
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002071 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002072
2073 // Compile an optimized LStoreNamedField that performs the prepared
2074 // map transition. This will restart incremental marking and should
2075 // make sure the root is marked grey again.
2076 CompileRun("function f(o) {"
2077 " o.foo = 0;"
2078 "}"
2079 "f(new Object);"
2080 "f(new Object);"
2081 "%OptimizeFunctionOnNextCall(f);"
2082 "f(root);"
2083 "%DeoptimizeFunction(f);");
2084
2085 // This bug only triggers with aggressive IC clearing.
2086 HEAP->AgeInlineCaches();
2087
2088 // Explicitly request GC to perform final marking step and sweeping.
2089 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002090
2091 Handle<JSObject> root =
2092 v8::Utils::OpenHandle(
2093 *v8::Handle<v8::Object>::Cast(
2094 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2095
2096 // The root object should be in a sane state.
2097 CHECK(root->IsJSObject());
2098 CHECK(root->map()->IsMap());
2099}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002100
2101
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002102TEST(ReleaseOverReservedPages) {
2103 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002104 // The optimizer can allocate stuff, messing up the test.
2105 i::FLAG_crankshaft = false;
2106 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002107 InitializeVM();
2108 v8::HandleScope scope;
2109 static const int number_of_test_pages = 20;
2110
2111 // Prepare many pages with low live-bytes count.
2112 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
2113 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2114 for (int i = 0; i < number_of_test_pages; i++) {
2115 AlwaysAllocateScope always_allocate;
2116 SimulateFullSpace(old_pointer_space);
2117 FACTORY->NewFixedArray(1, TENURED);
2118 }
2119 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2120
2121 // Triggering one GC will cause a lot of garbage to be discovered but
2122 // even spread across all allocated pages.
2123 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
2124 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2125
2126 // Triggering subsequent GCs should cause at least half of the pages
2127 // to be released to the OS after at most two cycles.
2128 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
2129 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2130 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
2131 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
2132
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002133 // Triggering a last-resort GC should cause all pages to be released to the
2134 // OS so that other processes can seize the memory. If we get a failure here
2135 // where there are 2 pages left instead of 1, then we should increase the
2136 // size of the first page a little in SizeOfFirstPage in spaces.cc. The
2137 // first page should be small in order to reduce memory used when the VM
2138 // boots, but if the 20 small arrays don't fit on the first page then that's
2139 // an indication that it is too small.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002140 HEAP->CollectAllAvailableGarbage("triggered really hard");
2141 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2142}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002143
2144
2145TEST(Regress2237) {
2146 InitializeVM();
2147 v8::HandleScope scope;
2148 Handle<String> slice(HEAP->empty_string());
2149
2150 {
2151 // Generate a parent that lives in new-space.
2152 v8::HandleScope inner_scope;
2153 const char* c = "This text is long enough to trigger sliced strings.";
2154 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002155 CHECK(s->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002156 CHECK(HEAP->InNewSpace(*s));
2157
2158 // Generate a sliced string that is based on the above parent and
2159 // lives in old-space.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002160 SimulateFullSpace(HEAP->new_space());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002161 AlwaysAllocateScope always_allocate;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002162 Handle<String> t = FACTORY->NewProperSubString(s, 5, 35);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002163 CHECK(t->IsSlicedString());
2164 CHECK(!HEAP->InNewSpace(*t));
2165 *slice.location() = *t.location();
2166 }
2167
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002168 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002169 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002170 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002171}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002172
2173
2174#ifdef OBJECT_PRINT
2175TEST(PrintSharedFunctionInfo) {
2176 InitializeVM();
2177 v8::HandleScope scope;
2178 const char* source = "f = function() { return 987654321; }\n"
2179 "g = function() { return 123456789; }\n";
2180 CompileRun(source);
2181 Handle<JSFunction> g =
2182 v8::Utils::OpenHandle(
2183 *v8::Handle<v8::Function>::Cast(
2184 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2185
2186 AssertNoAllocation no_alloc;
2187 g->shared()->PrintLn();
2188}
2189#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002190
2191
2192TEST(Regress2211) {
2193 InitializeVM();
2194 v8::HandleScope scope;
2195
2196 v8::Handle<v8::String> value = v8_str("val string");
2197 Smi* hash = Smi::FromInt(321);
2198 Heap* heap = Isolate::Current()->heap();
2199
2200 for (int i = 0; i < 2; i++) {
2201 // Store identity hash first and common hidden property second.
2202 v8::Handle<v8::Object> obj = v8::Object::New();
2203 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2204 CHECK(internal_obj->HasFastProperties());
2205
2206 // In the first iteration, set hidden value first and identity hash second.
2207 // In the second iteration, reverse the order.
2208 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2209 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2210 ALLOW_CREATION);
2211 CHECK(!maybe_obj->IsFailure());
2212 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2213
2214 // Check values.
2215 CHECK_EQ(hash,
2216 internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
2217 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2218
2219 // Check size.
2220 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2221 ObjectHashTable* hashtable = ObjectHashTable::cast(
2222 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2223 // HashTable header (5) and 4 initial entries (8).
2224 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2225 }
2226}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002227
2228
2229TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2230 if (i::FLAG_always_opt) return;
2231 InitializeVM();
2232 v8::HandleScope scope;
2233 v8::Local<v8::Value> fun1, fun2;
2234
2235 {
2236 LocalContext env;
2237 CompileRun("function fun() {};");
2238 fun1 = env->Global()->Get(v8_str("fun"));
2239 }
2240
2241 {
2242 LocalContext env;
2243 CompileRun("function fun() {};");
2244 fun2 = env->Global()->Get(v8_str("fun"));
2245 }
2246
2247 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002248 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002249 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2250 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2251 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2252 Handle<JSFunction> f =
2253 v8::Utils::OpenHandle(
2254 *v8::Handle<v8::Function>::Cast(
2255 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2256 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2257 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2258
2259 CHECK_EQ(2, cells->CellCount());
2260 CHECK(cells->Cell(0)->value()->IsJSFunction());
2261 CHECK(cells->Cell(1)->value()->IsJSFunction());
2262
2263 SimulateIncrementalMarking();
2264 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2265
2266 CHECK_EQ(2, cells->CellCount());
2267 CHECK(cells->Cell(0)->value()->IsTheHole());
2268 CHECK(cells->Cell(1)->value()->IsTheHole());
2269}
2270
2271
2272static Code* FindFirstIC(Code* code, Code::Kind kind) {
2273 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2274 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2275 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2276 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2277 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2278 RelocInfo* info = it.rinfo();
2279 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2280 if (target->is_inline_cache_stub() && target->kind() == kind) {
2281 return target;
2282 }
2283 }
2284 return NULL;
2285}
2286
2287
2288TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2289 if (i::FLAG_always_opt) return;
2290 InitializeVM();
2291 v8::HandleScope scope;
2292
2293 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002294 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002295 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2296 "function f(o) { return o.x; } f(obj); f(obj);");
2297 Handle<JSFunction> f =
2298 v8::Utils::OpenHandle(
2299 *v8::Handle<v8::Function>::Cast(
2300 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2301
2302 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2303 CHECK(ic_before->ic_state() == MONOMORPHIC);
2304
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002305 SimulateIncrementalMarking();
2306 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2307
2308 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2309 CHECK(ic_after->ic_state() == MONOMORPHIC);
2310}
2311
2312
2313TEST(IncrementalMarkingClearsMonomorhpicIC) {
2314 if (i::FLAG_always_opt) return;
2315 InitializeVM();
2316 v8::HandleScope scope;
2317 v8::Local<v8::Value> obj1;
2318
2319 {
2320 LocalContext env;
2321 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2322 obj1 = env->Global()->Get(v8_str("obj"));
2323 }
2324
2325 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002326 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002327 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2328 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2329 Handle<JSFunction> f =
2330 v8::Utils::OpenHandle(
2331 *v8::Handle<v8::Function>::Cast(
2332 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2333
2334 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2335 CHECK(ic_before->ic_state() == MONOMORPHIC);
2336
2337 // Fire context dispose notification.
2338 v8::V8::ContextDisposedNotification();
2339 SimulateIncrementalMarking();
2340 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2341
2342 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2343 CHECK(ic_after->ic_state() == UNINITIALIZED);
2344}
2345
2346
2347TEST(IncrementalMarkingClearsPolymorhpicIC) {
2348 if (i::FLAG_always_opt) return;
2349 InitializeVM();
2350 v8::HandleScope scope;
2351 v8::Local<v8::Value> obj1, obj2;
2352
2353 {
2354 LocalContext env;
2355 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2356 obj1 = env->Global()->Get(v8_str("obj"));
2357 }
2358
2359 {
2360 LocalContext env;
2361 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2362 obj2 = env->Global()->Get(v8_str("obj"));
2363 }
2364
2365 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002366 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002367 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2368 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2369 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2370 Handle<JSFunction> f =
2371 v8::Utils::OpenHandle(
2372 *v8::Handle<v8::Function>::Cast(
2373 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2374
2375 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2376 CHECK(ic_before->ic_state() == MEGAMORPHIC);
2377
2378 // Fire context dispose notification.
2379 v8::V8::ContextDisposedNotification();
2380 SimulateIncrementalMarking();
2381 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2382
2383 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2384 CHECK(ic_after->ic_state() == UNINITIALIZED);
2385}
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002386
2387
2388class SourceResource: public v8::String::ExternalAsciiStringResource {
2389 public:
2390 explicit SourceResource(const char* data)
2391 : data_(data), length_(strlen(data)) { }
2392
2393 virtual void Dispose() {
2394 i::DeleteArray(data_);
2395 data_ = NULL;
2396 }
2397
2398 const char* data() const { return data_; }
2399
2400 size_t length() const { return length_; }
2401
2402 bool IsDisposed() { return data_ == NULL; }
2403
2404 private:
2405 const char* data_;
2406 size_t length_;
2407};
2408
2409
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002410void ReleaseStackTraceDataTest(const char* source) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002411 // Test that the data retained by the Error.stack accessor is released
2412 // after the first time the accessor is fired. We use external string
2413 // to check whether the data is being released since the external string
2414 // resource's callback is fired when the external string is GC'ed.
2415 InitializeVM();
2416 v8::HandleScope scope;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002417 SourceResource* resource = new SourceResource(i::StrDup(source));
2418 {
2419 v8::HandleScope scope;
2420 v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
2421 v8::Script::Compile(source_string)->Run();
2422 CHECK(!resource->IsDisposed());
2423 }
2424 HEAP->CollectAllAvailableGarbage();
2425 // External source is being retained by the stack trace.
2426 CHECK(!resource->IsDisposed());
2427
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002428 CompileRun("error.stack;");
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002429 HEAP->CollectAllAvailableGarbage();
2430 // External source has been released.
2431 CHECK(resource->IsDisposed());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002432 delete resource;
2433}
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002434
2435
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002436TEST(ReleaseStackTraceData) {
2437 static const char* source1 = "var error = null; "
2438 /* Normal Error */ "try { "
2439 " throw new Error(); "
2440 "} catch (e) { "
2441 " error = e; "
2442 "} ";
2443 static const char* source2 = "var error = null; "
2444 /* Stack overflow */ "try { "
2445 " (function f() { f(); })(); "
2446 "} catch (e) { "
2447 " error = e; "
2448 "} ";
2449 ReleaseStackTraceDataTest(source1);
2450 ReleaseStackTraceDataTest(source2);
2451}
2452
2453
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002454TEST(Regression144230) {
2455 InitializeVM();
2456 v8::HandleScope scope;
2457
2458 // First make sure that the uninitialized CallIC stub is on a single page
2459 // that will later be selected as an evacuation candidate.
2460 {
2461 v8::HandleScope inner_scope;
2462 AlwaysAllocateScope always_allocate;
2463 SimulateFullSpace(HEAP->code_space());
2464 ISOLATE->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET);
2465 }
2466
2467 // Second compile a CallIC and execute it once so that it gets patched to
2468 // the pre-monomorphic stub. These code objects are on yet another page.
2469 {
2470 v8::HandleScope inner_scope;
2471 AlwaysAllocateScope always_allocate;
2472 SimulateFullSpace(HEAP->code_space());
2473 CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};"
2474 "function call() { o.f(1,2,3,4,5,6,7,8,9); };"
2475 "call();");
2476 }
2477
2478 // Third we fill up the last page of the code space so that it does not get
2479 // chosen as an evacuation candidate.
2480 {
2481 v8::HandleScope inner_scope;
2482 AlwaysAllocateScope always_allocate;
2483 CompileRun("for (var i = 0; i < 2000; i++) {"
2484 " eval('function f' + i + '() { return ' + i +'; };' +"
2485 " 'f' + i + '();');"
2486 "}");
2487 }
2488 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2489
2490 // Fourth is the tricky part. Make sure the code containing the CallIC is
2491 // visited first without clearing the IC. The shared function info is then
2492 // visited later, causing the CallIC to be cleared.
2493 Handle<String> name = FACTORY->LookupAsciiSymbol("call");
2494 Handle<GlobalObject> global(ISOLATE->context()->global_object());
2495 MaybeObject* maybe_call = global->GetProperty(*name);
2496 JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
2497 USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode));
2498 ISOLATE->compilation_cache()->Clear();
2499 call->shared()->set_ic_age(HEAP->global_ic_age() + 1);
2500 Handle<Object> call_code(call->code());
2501 Handle<Object> call_function(call);
2502
2503 // Now we are ready to mess up the heap.
2504 HEAP->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
2505
2506 // Either heap verification caught the problem already or we go kaboom once
2507 // the CallIC is executed the next time.
2508 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode));
2509 CompileRun("call();");
2510}