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