blob: ec2fb3dd6e0e4ef85a4ceb2e9d0b7b7ab251a389 [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
7#include "execution.h"
8#include "factory.h"
9#include "macro-assembler.h"
10#include "global-handles.h"
11#include "cctest.h"
12
13using namespace v8::internal;
14
15static v8::Persistent<v8::Context> env;
16
17static void InitializeVM() {
18 if (env.IsEmpty()) env = v8::Context::New();
19 v8::HandleScope scope;
20 env->Enter();
21}
22
23
24static void CheckMap(Map* map, int type, int instance_size) {
25 CHECK(map->IsHeapObject());
26#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000027 CHECK(HEAP->Contains(map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000028#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000029 CHECK_EQ(HEAP->meta_map(), map->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000030 CHECK_EQ(type, map->instance_type());
31 CHECK_EQ(instance_size, map->instance_size());
32}
33
34
35TEST(HeapMaps) {
36 InitializeVM();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000037 CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
38 CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
39 CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
40 CheckMap(HEAP->string_map(), STRING_TYPE, kVariableSizeSentinel);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000041}
42
43
44static void CheckOddball(Object* obj, const char* string) {
45 CHECK(obj->IsOddball());
46 bool exc;
47 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
48 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
49}
50
51
52static void CheckSmi(int value, const char* string) {
53 bool exc;
54 Object* print_string =
55 *Execution::ToString(Handle<Object>(Smi::FromInt(value)), &exc);
56 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
57}
58
59
60static void CheckNumber(double value, const char* string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000061 Object* obj = HEAP->NumberFromDouble(value)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000062 CHECK(obj->IsNumber());
63 bool exc;
64 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
65 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
66}
67
68
69static void CheckFindCodeObject() {
70 // Test FindCodeObject
71#define __ assm.
72
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000073 Assembler assm(Isolate::Current(), NULL, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000074
75 __ nop(); // supported on all architectures
76
77 CodeDesc desc;
78 assm.GetCode(&desc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000079 Object* code = HEAP->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +000080 desc,
81 Code::ComputeFlags(Code::STUB),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000082 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000083 CHECK(code->IsCode());
84
85 HeapObject* obj = HeapObject::cast(code);
86 Address obj_addr = obj->address();
87
88 for (int i = 0; i < obj->Size(); i += kPointerSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000089 Object* found = HEAP->FindCodeObject(obj_addr + i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000090 CHECK_EQ(code, found);
91 }
92
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000093 Object* copy = HEAP->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +000094 desc,
95 Code::ComputeFlags(Code::STUB),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000096 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000097 CHECK(copy->IsCode());
98 HeapObject* obj_copy = HeapObject::cast(copy);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000099 Object* not_right = HEAP->FindCodeObject(obj_copy->address() +
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000100 obj_copy->Size() / 2);
101 CHECK(not_right != code);
102}
103
104
105TEST(HeapObjects) {
106 InitializeVM();
107
108 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000109 Object* value = HEAP->NumberFromDouble(1.000123)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000110 CHECK(value->IsHeapNumber());
111 CHECK(value->IsNumber());
112 CHECK_EQ(1.000123, value->Number());
113
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000114 value = HEAP->NumberFromDouble(1.0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000115 CHECK(value->IsSmi());
116 CHECK(value->IsNumber());
117 CHECK_EQ(1.0, value->Number());
118
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000119 value = HEAP->NumberFromInt32(1024)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000120 CHECK(value->IsSmi());
121 CHECK(value->IsNumber());
122 CHECK_EQ(1024.0, value->Number());
123
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000124 value = HEAP->NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000125 CHECK(value->IsSmi());
126 CHECK(value->IsNumber());
127 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
128
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000129 value = HEAP->NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000130 CHECK(value->IsSmi());
131 CHECK(value->IsNumber());
132 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
133
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000134#ifndef V8_TARGET_ARCH_X64
135 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000136 value = HEAP->NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000137 CHECK(value->IsHeapNumber());
138 CHECK(value->IsNumber());
139 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000140#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000141
lrn@chromium.org303ada72010-10-27 09:33:13 +0000142 MaybeObject* maybe_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000143 HEAP->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 value = maybe_value->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000145 CHECK(value->IsHeapNumber());
146 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000147 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
148 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000149
150 // nan oddball checks
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000151 CHECK(HEAP->nan_value()->IsNumber());
152 CHECK(isnan(HEAP->nan_value()->Number()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000153
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000154 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000155 CHECK(s->IsString());
156 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000157
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000158 String* object_symbol = String::cast(HEAP->Object_symbol());
159 CHECK(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000160 Isolate::Current()->context()->global_object()->HasLocalProperty(
161 object_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000162
163 // Check ToString for oddballs
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000164 CheckOddball(HEAP->true_value(), "true");
165 CheckOddball(HEAP->false_value(), "false");
166 CheckOddball(HEAP->null_value(), "null");
167 CheckOddball(HEAP->undefined_value(), "undefined");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000168
169 // Check ToString for Smis
170 CheckSmi(0, "0");
171 CheckSmi(42, "42");
172 CheckSmi(-42, "-42");
173
174 // Check ToString for Numbers
175 CheckNumber(1.1, "1.1");
176
177 CheckFindCodeObject();
178}
179
180
181TEST(Tagging) {
182 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000183 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000184 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000185 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000186 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000187 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000188 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000189 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000190 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000191 CHECK(Failure::Exception()->IsFailure());
192 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
193 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
194}
195
196
197TEST(GarbageCollection) {
198 InitializeVM();
199
200 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000201 // Check GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000202 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000203
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000204 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
205 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
206 Handle<String> prop_namex = FACTORY->LookupAsciiSymbol("theSlotx");
207 Handle<String> obj_name = FACTORY->LookupAsciiSymbol("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000208
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000209 {
210 v8::HandleScope inner_scope;
211 // Allocate a function and keep it in global object's property.
212 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000213 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000214 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000215 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000216 function->set_initial_map(*initial_map);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000217 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000218 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000219 // Allocate an object. Unrooted after leaving the scope.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000220 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000221 obj->SetProperty(
222 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
223 obj->SetProperty(
224 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000225
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000226 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
227 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
228 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000229
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000230 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000231
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000232 // Function should be alive.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000233 CHECK(Isolate::Current()->context()->global_object()->
234 HasLocalProperty(*name));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000235 // Check function is retained.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000236 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000237 GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000238 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000239 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000240
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000241 {
242 HandleScope inner_scope;
243 // Allocate another object, make it reachable from global.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000244 Handle<JSObject> obj = FACTORY->NewJSObject(function);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000245 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000246 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
247 obj->SetProperty(
248 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000249 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000250
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000251 // After gc, it should survive.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000252 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000253
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000254 CHECK(Isolate::Current()->context()->global_object()->
255 HasLocalProperty(*obj_name));
256 CHECK(Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000257 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000258 Object* obj = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000259 GetProperty(*obj_name)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000260 JSObject* js_obj = JSObject::cast(obj);
261 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000262}
263
264
265static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000266 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000267 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000268 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000269 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000270 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
271 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000272}
273
274
275TEST(String) {
276 InitializeVM();
277
278 VerifyStringAllocation("a");
279 VerifyStringAllocation("ab");
280 VerifyStringAllocation("abc");
281 VerifyStringAllocation("abcd");
282 VerifyStringAllocation("fiskerdrengen er paa havet");
283}
284
285
286TEST(LocalHandles) {
287 InitializeVM();
288
289 v8::HandleScope scope;
290 const char* name = "Kasper the spunky";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000291 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000292 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000293}
294
295
296TEST(GlobalHandles) {
297 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000298 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000299
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000300 Handle<Object> h1;
301 Handle<Object> h2;
302 Handle<Object> h3;
303 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000304
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000305 {
306 HandleScope scope;
307
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000308 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
309 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000310
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000311 h1 = global_handles->Create(*i);
312 h2 = global_handles->Create(*u);
313 h3 = global_handles->Create(*i);
314 h4 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000315 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000316
317 // after gc, it should survive
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000319
320 CHECK((*h1)->IsString());
321 CHECK((*h2)->IsHeapNumber());
322 CHECK((*h3)->IsString());
323 CHECK((*h4)->IsHeapNumber());
324
325 CHECK_EQ(*h3, *h1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000326 global_handles->Destroy(h1.location());
327 global_handles->Destroy(h3.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000328
329 CHECK_EQ(*h4, *h2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 global_handles->Destroy(h2.location());
331 global_handles->Destroy(h4.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000332}
333
334
335static bool WeakPointerCleared = false;
336
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000337static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000338 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000339 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000340 handle.Dispose();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000341}
342
343
344TEST(WeakGlobalHandlesScavenge) {
345 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000346 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000347
348 WeakPointerCleared = false;
349
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000350 Handle<Object> h1;
351 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000352
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000353 {
354 HandleScope scope;
355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000356 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
357 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000358
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000359 h1 = global_handles->Create(*i);
360 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000361 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000362
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000363 global_handles->MakeWeak(h2.location(),
364 reinterpret_cast<void*>(1234),
365 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000366
367 // Scavenge treats weak pointers as normal roots.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000368 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000369
370 CHECK((*h1)->IsString());
371 CHECK((*h2)->IsHeapNumber());
372
373 CHECK(!WeakPointerCleared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000374 CHECK(!global_handles->IsNearDeath(h2.location()));
375 CHECK(!global_handles->IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000376
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000377 global_handles->Destroy(h1.location());
378 global_handles->Destroy(h2.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000379}
380
381
382TEST(WeakGlobalHandlesMark) {
383 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000384 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000385
386 WeakPointerCleared = false;
387
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000388 Handle<Object> h1;
389 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000390
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000391 {
392 HandleScope scope;
393
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000394 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
395 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000396
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 h1 = global_handles->Create(*i);
398 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000399 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000400
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000401 HEAP->CollectGarbage(OLD_POINTER_SPACE);
402 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000403 // Make sure the object is promoted.
404
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000405 global_handles->MakeWeak(h2.location(),
406 reinterpret_cast<void*>(1234),
407 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000408 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
409 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
410
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000412
413 CHECK((*h1)->IsString());
414
415 CHECK(WeakPointerCleared);
416 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000417
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000418 global_handles->Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000419}
420
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000421
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000422TEST(DeleteWeakGlobalHandle) {
423 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000424 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000425
426 WeakPointerCleared = false;
427
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000428 Handle<Object> h;
429
430 {
431 HandleScope scope;
432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
434 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000435 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000436
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000437 global_handles->MakeWeak(h.location(),
438 reinterpret_cast<void*>(1234),
439 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000440
441 // Scanvenge does not recognize weak reference.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000442 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000443
444 CHECK(!WeakPointerCleared);
445
446 // Mark-compact treats weak reference properly.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000448
449 CHECK(WeakPointerCleared);
450}
451
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000452
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000453static const char* not_so_random_string_table[] = {
454 "abstract",
455 "boolean",
456 "break",
457 "byte",
458 "case",
459 "catch",
460 "char",
461 "class",
462 "const",
463 "continue",
464 "debugger",
465 "default",
466 "delete",
467 "do",
468 "double",
469 "else",
470 "enum",
471 "export",
472 "extends",
473 "false",
474 "final",
475 "finally",
476 "float",
477 "for",
478 "function",
479 "goto",
480 "if",
481 "implements",
482 "import",
483 "in",
484 "instanceof",
485 "int",
486 "interface",
487 "long",
488 "native",
489 "new",
490 "null",
491 "package",
492 "private",
493 "protected",
494 "public",
495 "return",
496 "short",
497 "static",
498 "super",
499 "switch",
500 "synchronized",
501 "this",
502 "throw",
503 "throws",
504 "transient",
505 "true",
506 "try",
507 "typeof",
508 "var",
509 "void",
510 "volatile",
511 "while",
512 "with",
513 0
514};
515
516
517static void CheckSymbols(const char** strings) {
518 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000519 Object* a;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000520 MaybeObject* maybe_a = HEAP->LookupAsciiSymbol(string);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000521 // LookupAsciiSymbol may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000522 if (!maybe_a->ToObject(&a)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000523 CHECK(a->IsSymbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000524 Object* b;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000525 MaybeObject* maybe_b = HEAP->LookupAsciiSymbol(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000526 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000527 CHECK_EQ(b, a);
528 CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
529 }
530}
531
532
533TEST(SymbolTable) {
534 InitializeVM();
535
536 CheckSymbols(not_so_random_string_table);
537 CheckSymbols(not_so_random_string_table);
538}
539
540
541TEST(FunctionAllocation) {
542 InitializeVM();
543
544 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000545 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000546 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000547 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000548 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000550 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000551
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
553 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000554 obj->SetProperty(
555 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000556 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000557 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000558 function->SetProperty(
559 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000560 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000561}
562
563
564TEST(ObjectProperties) {
565 InitializeVM();
566
567 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000569 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000570 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000571 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000572 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000573 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
574 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
575 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000576
577 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000578 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000579
580 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000581 obj->SetProperty(
582 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000583 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000584
585 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000586 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
587 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000588
589 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000590 obj->SetProperty(
591 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
592 obj->SetProperty(
593 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000594 CHECK(obj->HasLocalProperty(*first));
595 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000596
597 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000598 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
599 CHECK(obj->HasLocalProperty(*second));
600 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
601 CHECK(!obj->HasLocalProperty(*first));
602 CHECK(!obj->HasLocalProperty(*second));
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 second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000613 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
614 CHECK(obj->HasLocalProperty(*first));
615 CHECK(obj->DeleteProperty(*first, 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 // check string and symbol match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000620 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000621 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000622 obj->SetProperty(
623 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000624 Handle<String> s1_symbol = FACTORY->LookupAsciiSymbol(string1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000625 CHECK(obj->HasLocalProperty(*s1_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000626
627 // check symbol and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000628 const char* string2 = "fugl";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000629 Handle<String> s2_symbol = FACTORY->LookupAsciiSymbol(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000630 obj->SetProperty(
631 *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000632 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000633 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000634}
635
636
637TEST(JSObjectMaps) {
638 InitializeVM();
639
640 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000641 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000642 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000643 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000644 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000645 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000646 function->set_initial_map(*initial_map);
647
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000648 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
649 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000650
651 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000652 obj->SetProperty(
653 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000654 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000655
656 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000657 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000658}
659
660
661TEST(JSArray) {
662 InitializeVM();
663
664 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000665 Handle<String> name = FACTORY->LookupAsciiSymbol("Array");
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000666 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000667 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000668 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000669 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000670
671 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000672 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000673 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000674 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000675 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000676
677 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000678 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000679 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000680 // Must be in fast mode.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000681 CHECK(array->HasFastSmiOrObjectElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000682
683 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000684 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000685 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000686 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000687
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000688 // Set array length with larger than smi value.
689 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000690 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000691 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000692
693 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000694 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000695 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000696 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
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(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000700 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000701 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000702 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000703 CHECK_EQ(array->GetElement(int_length), *name);
704 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000705}
706
707
708TEST(JSObjectCopy) {
709 InitializeVM();
710
711 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000712 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000713 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000714 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000715 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000716 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000717 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
718 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
719 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000720
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000721 obj->SetProperty(
722 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
723 obj->SetProperty(
724 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000725
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000726 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
727 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000728
729 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000730 Handle<JSObject> clone = Copy(obj);
731 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000732
733 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
734 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
735
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000736 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
737 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000738
739 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000740 clone->SetProperty(
741 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
742 clone->SetProperty(
743 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000744
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000745 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
746 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000747
748 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
749 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
750
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000751 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
752 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000753}
754
755
756TEST(StringAllocation) {
757 InitializeVM();
758
759
760 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
761 for (int length = 0; length < 100; length++) {
762 v8::HandleScope scope;
763 char* non_ascii = NewArray<char>(3 * length + 1);
764 char* ascii = NewArray<char>(length + 1);
765 non_ascii[3 * length] = 0;
766 ascii[length] = 0;
767 for (int i = 0; i < length; i++) {
768 ascii[i] = 'a';
769 non_ascii[3 * i] = chars[0];
770 non_ascii[3 * i + 1] = chars[1];
771 non_ascii[3 * i + 2] = chars[2];
772 }
773 Handle<String> non_ascii_sym =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000774 FACTORY->LookupSymbol(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000775 CHECK_EQ(length, non_ascii_sym->length());
776 Handle<String> ascii_sym =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000777 FACTORY->LookupSymbol(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000778 CHECK_EQ(length, ascii_sym->length());
779 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000780 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000781 non_ascii_str->Hash();
782 CHECK_EQ(length, non_ascii_str->length());
783 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000784 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000785 ascii_str->Hash();
786 CHECK_EQ(length, ascii_str->length());
787 DeleteArray(non_ascii);
788 DeleteArray(ascii);
789 }
790}
791
792
793static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
794 // Count the number of objects found in the heap.
795 int found_count = 0;
796 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000797 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000798 for (int i = 0; i < size; i++) {
799 if (*objs[i] == obj) {
800 found_count++;
801 }
802 }
803 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000804 return found_count;
805}
806
807
808TEST(Iteration) {
809 InitializeVM();
810 v8::HandleScope scope;
811
812 // Array of objects to scan haep for.
813 const int objs_count = 6;
814 Handle<Object> objs[objs_count];
815 int next_objs_index = 0;
816
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000817 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000818 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000819 objs[next_objs_index++] = FACTORY->NewJSArray(10,
820 FAST_HOLEY_ELEMENTS,
821 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000822
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000823 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000824 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000825 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000826 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000827 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000828
829 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000830 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000831 char* str = new char[large_size];
832 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
833 str[large_size - 1] = '\0';
834 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000835 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000836 delete[] str;
837
838 // Add a Map object to look for.
839 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
840
841 CHECK_EQ(objs_count, next_objs_index);
842 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
843}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000844
845
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000846TEST(EmptyHandleEscapeFrom) {
847 InitializeVM();
848
849 v8::HandleScope scope;
850 Handle<JSObject> runaway;
851
852 {
853 v8::HandleScope nested;
854 Handle<JSObject> empty;
855 runaway = empty.EscapeFrom(&nested);
856 }
857
858 CHECK(runaway.is_null());
859}
860
861
862static int LenFromSize(int size) {
863 return (size - FixedArray::kHeaderSize) / kPointerSize;
864}
865
866
867TEST(Regression39128) {
868 // Test case for crbug.com/39128.
869 InitializeVM();
870
871 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000872 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000873
874 v8::HandleScope scope;
875
876 // The plan: create JSObject which references objects in new space.
877 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000878 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000879
880 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000881 Handle<JSFunction> object_ctor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000882 Isolate::Current()->native_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000883 CHECK(object_ctor->has_initial_map());
884 Handle<Map> object_map(object_ctor->initial_map());
885 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000886 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000887 int n_properties = my_map->inobject_properties();
888 CHECK_GT(n_properties, 0);
889
890 int object_size = my_map->instance_size();
891
892 // Step 2: allocate a lot of objects so to almost fill new space: we need
893 // just enough room to allocate JSObject and thus fill the newspace.
894
895 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000896 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000897 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000898 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000899 Address* top_addr = new_space->allocation_top_address();
900 Address* limit_addr = new_space->allocation_limit_address();
901 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000902 CHECK(!HEAP->always_allocate());
903 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
904 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000905 CHECK(new_space->Contains(array));
906 }
907
908 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000909 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000910 int fixed_array_len = LenFromSize(to_fill);
911 CHECK(fixed_array_len < FixedArray::kMaxLength);
912
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000913 CHECK(!HEAP->always_allocate());
914 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
915 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000916 CHECK(new_space->Contains(array));
917
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000919 CHECK(new_space->Contains(object));
920 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000921 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000922 CHECK_EQ(0, jsobject->properties()->length());
923 // Create a reference to object in new space in jsobject.
924 jsobject->FastPropertyAtPut(-1, array);
925
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000926 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000927
928 // Step 4: clone jsobject, but force always allocate first to create a clone
929 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000930 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000931 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000933 JSObject* clone = JSObject::cast(clone_obj);
934 if (clone->address() != old_pointer_space_top) {
935 // Alas, got allocated from free list, we cannot do checks.
936 return;
937 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000938 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000939}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000940
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000941
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000942TEST(TestCodeFlushing) {
943 i::FLAG_allow_natives_syntax = true;
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000944 // If we do not flush code this test is invalid.
945 if (!FLAG_flush_code) return;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000946 InitializeVM();
947 v8::HandleScope scope;
948 const char* source = "function foo() {"
949 " var x = 42;"
950 " var y = 42;"
951 " var z = x + y;"
952 "};"
953 "foo()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000954 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000955
956 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000957 { v8::HandleScope scope;
958 CompileRun(source);
959 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000960
961 // Check function is compiled.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000962 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000963 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000964 CHECK(func_value->IsJSFunction());
965 Handle<JSFunction> function(JSFunction::cast(func_value));
966 CHECK(function->shared()->is_compiled());
967
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000968 // TODO(1609) Currently incremental marker does not support code flushing.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000969 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
970 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000971
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000972 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000973
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000974 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
975 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
976 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
977 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
978 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
979 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000980
981 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000982 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
983 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000984 // Call foo to get it recompiled.
985 CompileRun("foo()");
986 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000987 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000988}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000989
990
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000991// Count the number of native contexts in the weak list of native contexts.
992int CountNativeContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000993 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000994 Object* object = HEAP->native_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000995 while (!object->IsUndefined()) {
996 count++;
997 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
998 }
999 return count;
1000}
1001
1002
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001003// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001004// functions attached to a native context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001005static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1006 int count = 0;
1007 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1008 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1009 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1010 count++;
1011 object = JSFunction::cast(object)->next_function_link();
1012 }
1013 return count;
1014}
1015
1016
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001017TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001018 v8::V8::Initialize();
1019
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001020 static const int kNumTestContexts = 10;
1021
1022 v8::HandleScope scope;
1023 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1024
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001025 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001026
1027 // Create a number of global contests which gets linked together.
1028 for (int i = 0; i < kNumTestContexts; i++) {
1029 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001030
1031 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1032
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001033 CHECK_EQ(i + 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001034
1035 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001036
1037 // Create a handle scope so no function objects get stuch in the outer
1038 // handle scope
1039 v8::HandleScope scope;
1040 const char* source = "function f1() { };"
1041 "function f2() { };"
1042 "function f3() { };"
1043 "function f4() { };"
1044 "function f5() { };";
1045 CompileRun(source);
1046 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1047 CompileRun("f1()");
1048 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1049 CompileRun("f2()");
1050 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1051 CompileRun("f3()");
1052 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1053 CompileRun("f4()");
1054 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1055 CompileRun("f5()");
1056 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1057
1058 // Remove function f1, and
1059 CompileRun("f1=null");
1060
1061 // Scavenge treats these references as strong.
1062 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001063 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001064 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1065 }
1066
1067 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001068 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001069 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1070
1071 // Get rid of f3 and f5 in the same way.
1072 CompileRun("f3=null");
1073 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001074 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001075 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1076 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001077 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001078 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1079 CompileRun("f5=null");
1080 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001081 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001082 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1083 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001084 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001085 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1086
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001087 ctx[i]->Exit();
1088 }
1089
1090 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001091 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001092
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001093 // Dispose the native contexts one by one.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001094 for (int i = 0; i < kNumTestContexts; i++) {
1095 ctx[i].Dispose();
1096 ctx[i].Clear();
1097
1098 // Scavenge treats these references as strong.
1099 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001100 HEAP->PerformScavenge();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001101 CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001102 }
1103
1104 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001105 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001106 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001107 }
1108
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001109 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001110}
1111
1112
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001113// Count the number of native contexts in the weak list of native contexts
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001114// causing a GC after the specified number of elements.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001115static int CountNativeContextsWithGC(int n) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001116 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001117 Handle<Object> object(HEAP->native_contexts_list());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001118 while (!object->IsUndefined()) {
1119 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001120 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001121 object =
1122 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1123 }
1124 return count;
1125}
1126
1127
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001128// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001129// functions attached to a native context causing a GC after the
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001130// specified number of elements.
1131static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1132 int n) {
1133 int count = 0;
1134 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1135 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1136 while (object->IsJSFunction() &&
1137 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1138 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001139 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001140 object = Handle<Object>(
1141 Object::cast(JSFunction::cast(*object)->next_function_link()));
1142 }
1143 return count;
1144}
1145
1146
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001147TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001148 v8::V8::Initialize();
1149
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001150 static const int kNumTestContexts = 10;
1151
1152 v8::HandleScope scope;
1153 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1154
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001155 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001156
1157 // Create an number of contexts and check the length of the weak list both
1158 // with and without GCs while iterating the list.
1159 for (int i = 0; i < kNumTestContexts; i++) {
1160 ctx[i] = v8::Context::New();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001161 CHECK_EQ(i + 1, CountNativeContexts());
1162 CHECK_EQ(i + 1, CountNativeContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001163 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001164
1165 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1166
1167 // Compile a number of functions the length of the weak list of optimized
1168 // functions both with and without GCs while iterating the list.
1169 ctx[0]->Enter();
1170 const char* source = "function f1() { };"
1171 "function f2() { };"
1172 "function f3() { };"
1173 "function f4() { };"
1174 "function f5() { };";
1175 CompileRun(source);
1176 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1177 CompileRun("f1()");
1178 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1179 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1180 CompileRun("f2()");
1181 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1182 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1183 CompileRun("f3()");
1184 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1185 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1186 CompileRun("f4()");
1187 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1188 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1189 CompileRun("f5()");
1190 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1191 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1192
1193 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001194}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001195
1196
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001197TEST(TestSizeOfObjects) {
1198 v8::V8::Initialize();
1199
1200 // Get initial heap size after several full GCs, which will stabilize
1201 // the heap size and return with sweeping finished completely.
1202 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1203 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1204 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1205 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001206 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001207 CHECK(HEAP->old_pointer_space()->IsSweepingComplete());
1208 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1209
1210 {
1211 // Allocate objects on several different old-space pages so that
1212 // lazy sweeping kicks in for subsequent GC runs.
1213 AlwaysAllocateScope always_allocate;
1214 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1215 for (int i = 1; i <= 100; i++) {
1216 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1217 CHECK_EQ(initial_size + i * filler_size,
1218 static_cast<int>(HEAP->SizeOfObjects()));
1219 }
1220 }
1221
1222 // The heap size should go back to initial size after a full GC, even
1223 // though sweeping didn't finish yet.
1224 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001225
1226 // Normally sweeping would not be complete here, but no guarantees.
1227
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001228 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1229
1230 // Advancing the sweeper step-wise should not change the heap size.
1231 while (!HEAP->old_pointer_space()->IsSweepingComplete()) {
1232 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1233 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1234 }
1235}
1236
1237
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001238TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1239 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001240 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001241 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001242 HeapIterator iterator;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001243 intptr_t size_of_objects_2 = 0;
1244 for (HeapObject* obj = iterator.next();
1245 obj != NULL;
1246 obj = iterator.next()) {
1247 size_of_objects_2 += obj->Size();
1248 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001249 // Delta must be within 5% of the larger result.
1250 // TODO(gc): Tighten this up by distinguishing between byte
1251 // arrays that are real and those that merely mark free space
1252 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001253 if (size_of_objects_1 > size_of_objects_2) {
1254 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1255 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1256 "Iterator: %" V8_PTR_PREFIX "d, "
1257 "delta: %" V8_PTR_PREFIX "d\n",
1258 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001259 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001260 } else {
1261 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1262 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1263 "Iterator: %" V8_PTR_PREFIX "d, "
1264 "delta: %" V8_PTR_PREFIX "d\n",
1265 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001266 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001267 }
1268}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001269
1270
danno@chromium.orgc612e022011-11-10 11:38:15 +00001271static void FillUpNewSpace(NewSpace* new_space) {
1272 // Fill up new space to the point that it is completely full. Make sure
1273 // that the scavenger does not undo the filling.
1274 v8::HandleScope scope;
1275 AlwaysAllocateScope always_allocate;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001276 LinearAllocationScope allocate_linearly;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001277 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001278 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001279 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001280 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001281 }
1282}
1283
1284
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001285TEST(GrowAndShrinkNewSpace) {
1286 InitializeVM();
1287 NewSpace* new_space = HEAP->new_space();
1288
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001289 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1290 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001291 // The max size cannot exceed the reserved size, since semispaces must be
1292 // always within the reserved space. We can't test new space growing and
1293 // shrinking if the reserved size is the same as the minimum (initial) size.
1294 return;
1295 }
1296
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001297 // Explicitly growing should double the space capacity.
1298 intptr_t old_capacity, new_capacity;
1299 old_capacity = new_space->Capacity();
1300 new_space->Grow();
1301 new_capacity = new_space->Capacity();
1302 CHECK(2 * old_capacity == new_capacity);
1303
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001304 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001305 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001306 new_capacity = new_space->Capacity();
1307 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001308
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001309 // Explicitly shrinking should not affect space capacity.
1310 old_capacity = new_space->Capacity();
1311 new_space->Shrink();
1312 new_capacity = new_space->Capacity();
1313 CHECK(old_capacity == new_capacity);
1314
1315 // Let the scavenger empty the new space.
1316 HEAP->CollectGarbage(NEW_SPACE);
1317 CHECK_LE(new_space->Size(), old_capacity);
1318
1319 // Explicitly shrinking should halve the space capacity.
1320 old_capacity = new_space->Capacity();
1321 new_space->Shrink();
1322 new_capacity = new_space->Capacity();
1323 CHECK(old_capacity == 2 * new_capacity);
1324
1325 // Consecutive shrinking should not affect space capacity.
1326 old_capacity = new_space->Capacity();
1327 new_space->Shrink();
1328 new_space->Shrink();
1329 new_space->Shrink();
1330 new_capacity = new_space->Capacity();
1331 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001332}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001333
1334
1335TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1336 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001337
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001338 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1339 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001340 // The max size cannot exceed the reserved size, since semispaces must be
1341 // always within the reserved space. We can't test new space growing and
1342 // shrinking if the reserved size is the same as the minimum (initial) size.
1343 return;
1344 }
1345
danno@chromium.orgc612e022011-11-10 11:38:15 +00001346 v8::HandleScope scope;
1347 NewSpace* new_space = HEAP->new_space();
1348 intptr_t old_capacity, new_capacity;
1349 old_capacity = new_space->Capacity();
1350 new_space->Grow();
1351 new_capacity = new_space->Capacity();
1352 CHECK(2 * old_capacity == new_capacity);
1353 FillUpNewSpace(new_space);
1354 HEAP->CollectAllAvailableGarbage();
1355 new_capacity = new_space->Capacity();
1356 CHECK(old_capacity == new_capacity);
1357}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001358
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001359
1360static int NumberOfGlobalObjects() {
1361 int count = 0;
1362 HeapIterator iterator;
1363 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1364 if (obj->IsGlobalObject()) count++;
1365 }
1366 return count;
1367}
1368
1369
1370// Test that we don't embed maps from foreign contexts into
1371// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001372TEST(LeakNativeContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001373 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001374 v8::HandleScope outer_scope;
1375 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1376 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1377 ctx1->Enter();
1378
1379 HEAP->CollectAllAvailableGarbage();
1380 CHECK_EQ(4, NumberOfGlobalObjects());
1381
1382 {
1383 v8::HandleScope inner_scope;
1384 CompileRun("var v = {x: 42}");
1385 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1386 ctx2->Enter();
1387 ctx2->Global()->Set(v8_str("o"), v);
1388 v8::Local<v8::Value> res = CompileRun(
1389 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001390 "for (var i = 0; i < 10; ++i) f();"
1391 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001392 "f();");
1393 CHECK_EQ(42, res->Int32Value());
1394 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1395 ctx2->Exit();
1396 ctx1->Exit();
1397 ctx1.Dispose();
1398 }
1399 HEAP->CollectAllAvailableGarbage();
1400 CHECK_EQ(2, NumberOfGlobalObjects());
1401 ctx2.Dispose();
1402 HEAP->CollectAllAvailableGarbage();
1403 CHECK_EQ(0, NumberOfGlobalObjects());
1404}
1405
1406
1407// Test that we don't embed functions from foreign contexts into
1408// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001409TEST(LeakNativeContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001410 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001411 v8::HandleScope outer_scope;
1412 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1413 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1414 ctx1->Enter();
1415
1416 HEAP->CollectAllAvailableGarbage();
1417 CHECK_EQ(4, NumberOfGlobalObjects());
1418
1419 {
1420 v8::HandleScope inner_scope;
1421 CompileRun("var v = function() { return 42; }");
1422 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1423 ctx2->Enter();
1424 ctx2->Global()->Set(v8_str("o"), v);
1425 v8::Local<v8::Value> res = CompileRun(
1426 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001427 "for (var i = 0; i < 10; ++i) f(o);"
1428 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001429 "f(o);");
1430 CHECK_EQ(42, res->Int32Value());
1431 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1432 ctx2->Exit();
1433 ctx1->Exit();
1434 ctx1.Dispose();
1435 }
1436 HEAP->CollectAllAvailableGarbage();
1437 CHECK_EQ(2, NumberOfGlobalObjects());
1438 ctx2.Dispose();
1439 HEAP->CollectAllAvailableGarbage();
1440 CHECK_EQ(0, NumberOfGlobalObjects());
1441}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001442
1443
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001444TEST(LeakNativeContextViaMapKeyed) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001445 i::FLAG_allow_natives_syntax = true;
1446 v8::HandleScope outer_scope;
1447 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1448 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1449 ctx1->Enter();
1450
1451 HEAP->CollectAllAvailableGarbage();
1452 CHECK_EQ(4, NumberOfGlobalObjects());
1453
1454 {
1455 v8::HandleScope inner_scope;
1456 CompileRun("var v = [42, 43]");
1457 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1458 ctx2->Enter();
1459 ctx2->Global()->Set(v8_str("o"), v);
1460 v8::Local<v8::Value> res = CompileRun(
1461 "function f() { return o[0]; }"
1462 "for (var i = 0; i < 10; ++i) f();"
1463 "%OptimizeFunctionOnNextCall(f);"
1464 "f();");
1465 CHECK_EQ(42, res->Int32Value());
1466 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1467 ctx2->Exit();
1468 ctx1->Exit();
1469 ctx1.Dispose();
1470 }
1471 HEAP->CollectAllAvailableGarbage();
1472 CHECK_EQ(2, NumberOfGlobalObjects());
1473 ctx2.Dispose();
1474 HEAP->CollectAllAvailableGarbage();
1475 CHECK_EQ(0, NumberOfGlobalObjects());
1476}
1477
1478
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001479TEST(LeakNativeContextViaMapProto) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001480 i::FLAG_allow_natives_syntax = true;
1481 v8::HandleScope outer_scope;
1482 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1483 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1484 ctx1->Enter();
1485
1486 HEAP->CollectAllAvailableGarbage();
1487 CHECK_EQ(4, NumberOfGlobalObjects());
1488
1489 {
1490 v8::HandleScope inner_scope;
1491 CompileRun("var v = { y: 42}");
1492 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1493 ctx2->Enter();
1494 ctx2->Global()->Set(v8_str("o"), v);
1495 v8::Local<v8::Value> res = CompileRun(
1496 "function f() {"
1497 " var p = {x: 42};"
1498 " p.__proto__ = o;"
1499 " return p.x;"
1500 "}"
1501 "for (var i = 0; i < 10; ++i) f();"
1502 "%OptimizeFunctionOnNextCall(f);"
1503 "f();");
1504 CHECK_EQ(42, res->Int32Value());
1505 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1506 ctx2->Exit();
1507 ctx1->Exit();
1508 ctx1.Dispose();
1509 }
1510 HEAP->CollectAllAvailableGarbage();
1511 CHECK_EQ(2, NumberOfGlobalObjects());
1512 ctx2.Dispose();
1513 HEAP->CollectAllAvailableGarbage();
1514 CHECK_EQ(0, NumberOfGlobalObjects());
1515}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001516
1517
1518TEST(InstanceOfStubWriteBarrier) {
1519 i::FLAG_allow_natives_syntax = true;
1520#ifdef DEBUG
1521 i::FLAG_verify_heap = true;
1522#endif
1523 InitializeVM();
1524 if (!i::V8::UseCrankshaft()) return;
1525 v8::HandleScope outer_scope;
1526
1527 {
1528 v8::HandleScope scope;
1529 CompileRun(
1530 "function foo () { }"
1531 "function mkbar () { return new (new Function(\"\")) (); }"
1532 "function f (x) { return (x instanceof foo); }"
1533 "function g () { f(mkbar()); }"
1534 "f(new foo()); f(new foo());"
1535 "%OptimizeFunctionOnNextCall(f);"
1536 "f(new foo()); g();");
1537 }
1538
1539 IncrementalMarking* marking = HEAP->incremental_marking();
1540 marking->Abort();
1541 marking->Start();
1542
1543 Handle<JSFunction> f =
1544 v8::Utils::OpenHandle(
1545 *v8::Handle<v8::Function>::Cast(
1546 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1547
1548 CHECK(f->IsOptimized());
1549
1550 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1551 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001552 // Discard any pending GC requests otherwise we will get GC when we enter
1553 // code below.
1554 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001555 }
1556
1557 CHECK(marking->IsMarking());
1558
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001559 {
1560 v8::HandleScope scope;
1561 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1562 v8::Handle<v8::Function> g =
1563 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1564 g->Call(global, 0, NULL);
1565 }
1566
1567 HEAP->incremental_marking()->set_should_hurry(true);
1568 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1569}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001570
1571
1572TEST(PrototypeTransitionClearing) {
1573 InitializeVM();
1574 v8::HandleScope scope;
1575
1576 CompileRun(
1577 "var base = {};"
1578 "var live = [];"
1579 "for (var i = 0; i < 10; i++) {"
1580 " var object = {};"
1581 " var prototype = {};"
1582 " object.__proto__ = prototype;"
1583 " if (i >= 3) live.push(object, prototype);"
1584 "}");
1585
1586 Handle<JSObject> baseObject =
1587 v8::Utils::OpenHandle(
1588 *v8::Handle<v8::Object>::Cast(
1589 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1590
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001591 // Verify that only dead prototype transitions are cleared.
1592 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001593 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001594 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001595 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001596
1597 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001598 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001599 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001600 int j = Map::kProtoTransitionHeaderSize +
1601 i * Map::kProtoTransitionElementsPerEntry;
1602 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001603 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1604 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001605 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001606
1607 // Make sure next prototype is placed on an old-space evacuation candidate.
1608 Handle<JSObject> prototype;
1609 PagedSpace* space = HEAP->old_pointer_space();
1610 do {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001611 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001612 } while (space->FirstPage() == space->LastPage() ||
1613 !space->LastPage()->Contains(prototype->address()));
1614
1615 // Add a prototype on an evacuation candidate and verify that transition
1616 // clearing correctly records slots in prototype transition array.
1617 i::FLAG_always_compact = true;
1618 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001619 CHECK(!space->LastPage()->Contains(
1620 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001621 CHECK(space->LastPage()->Contains(prototype->address()));
1622 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1623 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1624 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1625 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001626}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001627
1628
1629TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1630 i::FLAG_allow_natives_syntax = true;
1631#ifdef DEBUG
1632 i::FLAG_verify_heap = true;
1633#endif
1634 InitializeVM();
1635 if (!i::V8::UseCrankshaft()) return;
1636 v8::HandleScope outer_scope;
1637
1638 {
1639 v8::HandleScope scope;
1640 CompileRun(
1641 "function f () {"
1642 " var s = 0;"
1643 " for (var i = 0; i < 100; i++) s += i;"
1644 " return s;"
1645 "}"
1646 "f(); f();"
1647 "%OptimizeFunctionOnNextCall(f);"
1648 "f();");
1649 }
1650 Handle<JSFunction> f =
1651 v8::Utils::OpenHandle(
1652 *v8::Handle<v8::Function>::Cast(
1653 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1654 CHECK(f->IsOptimized());
1655
1656 IncrementalMarking* marking = HEAP->incremental_marking();
1657 marking->Abort();
1658 marking->Start();
1659
1660 // The following two calls will increment HEAP->global_ic_age().
1661 const int kLongIdlePauseInMs = 1000;
1662 v8::V8::ContextDisposedNotification();
1663 v8::V8::IdleNotification(kLongIdlePauseInMs);
1664
1665 while (!marking->IsStopped() && !marking->IsComplete()) {
1666 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1667 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001668 if (!marking->IsStopped() || marking->should_hurry()) {
1669 // We don't normally finish a GC via Step(), we normally finish by
1670 // setting the stack guard and then do the final steps in the stack
1671 // guard interrupt. But here we didn't ask for that, and there is no
1672 // JS code running to trigger the interrupt, so we explicitly finalize
1673 // here.
1674 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1675 "Test finalizing incremental mark-sweep");
1676 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001677
1678 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1679 CHECK_EQ(0, f->shared()->opt_count());
1680 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1681}
1682
1683
1684TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1685 i::FLAG_allow_natives_syntax = true;
1686#ifdef DEBUG
1687 i::FLAG_verify_heap = true;
1688#endif
1689 InitializeVM();
1690 if (!i::V8::UseCrankshaft()) return;
1691 v8::HandleScope outer_scope;
1692
1693 {
1694 v8::HandleScope scope;
1695 CompileRun(
1696 "function f () {"
1697 " var s = 0;"
1698 " for (var i = 0; i < 100; i++) s += i;"
1699 " return s;"
1700 "}"
1701 "f(); f();"
1702 "%OptimizeFunctionOnNextCall(f);"
1703 "f();");
1704 }
1705 Handle<JSFunction> f =
1706 v8::Utils::OpenHandle(
1707 *v8::Handle<v8::Function>::Cast(
1708 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1709 CHECK(f->IsOptimized());
1710
1711 HEAP->incremental_marking()->Abort();
1712
1713 // The following two calls will increment HEAP->global_ic_age().
1714 // Since incremental marking is off, IdleNotification will do full GC.
1715 const int kLongIdlePauseInMs = 1000;
1716 v8::V8::ContextDisposedNotification();
1717 v8::V8::IdleNotification(kLongIdlePauseInMs);
1718
1719 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1720 CHECK_EQ(0, f->shared()->opt_count());
1721 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1722}
1723
1724
1725// Test that HAllocateObject will always return an object in new-space.
1726TEST(OptimizedAllocationAlwaysInNewSpace) {
1727 i::FLAG_allow_natives_syntax = true;
1728 InitializeVM();
1729 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
1730 v8::HandleScope scope;
1731
1732 FillUpNewSpace(HEAP->new_space());
1733 AlwaysAllocateScope always_allocate;
1734 v8::Local<v8::Value> res = CompileRun(
1735 "function c(x) {"
1736 " this.x = x;"
1737 " for (var i = 0; i < 32; i++) {"
1738 " this['x' + i] = x;"
1739 " }"
1740 "}"
1741 "function f(x) { return new c(x); };"
1742 "f(1); f(2); f(3);"
1743 "%OptimizeFunctionOnNextCall(f);"
1744 "f(4);");
1745 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
1746
1747 Handle<JSObject> o =
1748 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
1749
1750 CHECK(HEAP->InNewSpace(*o));
1751}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001752
1753
1754static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001755 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001756}
1757
1758
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001759// Go through all incremental marking steps in one swoop.
1760static void SimulateIncrementalMarking() {
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001761 IncrementalMarking* marking = HEAP->incremental_marking();
1762 CHECK(marking->IsStopped());
1763 marking->Start();
1764 CHECK(marking->IsMarking());
1765 while (!marking->IsComplete()) {
1766 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1767 }
1768 CHECK(marking->IsComplete());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001769}
1770
1771
1772// Test that map transitions are cleared and maps are collected with
1773// incremental marking as well.
1774TEST(Regress1465) {
1775 i::FLAG_allow_natives_syntax = true;
1776 i::FLAG_trace_incremental_marking = true;
1777 InitializeVM();
1778 v8::HandleScope scope;
1779 static const int transitions_count = 256;
1780
1781 {
1782 AlwaysAllocateScope always_allocate;
1783 for (int i = 0; i < transitions_count; i++) {
1784 EmbeddedVector<char, 64> buffer;
1785 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
1786 CompileRun(buffer.start());
1787 }
1788 CompileRun("var root = new Object;");
1789 }
1790
1791 Handle<JSObject> root =
1792 v8::Utils::OpenHandle(
1793 *v8::Handle<v8::Object>::Cast(
1794 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
1795
1796 // Count number of live transitions before marking.
1797 int transitions_before = CountMapTransitions(root->map());
1798 CompileRun("%DebugPrint(root);");
1799 CHECK_EQ(transitions_count, transitions_before);
1800
1801 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001802 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001803
1804 // Count number of live transitions after marking. Note that one transition
1805 // is left, because 'o' still holds an instance of one transition target.
1806 int transitions_after = CountMapTransitions(root->map());
1807 CompileRun("%DebugPrint(root);");
1808 CHECK_EQ(1, transitions_after);
1809}
verwaest@chromium.org37141392012-05-31 13:27:02 +00001810
1811
1812TEST(Regress2143a) {
1813 i::FLAG_collect_maps = true;
1814 i::FLAG_incremental_marking = true;
1815 InitializeVM();
1816 v8::HandleScope scope;
1817
1818 // Prepare a map transition from the root object together with a yet
1819 // untransitioned root object.
1820 CompileRun("var root = new Object;"
1821 "root.foo = 0;"
1822 "root = new Object;");
1823
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001824 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00001825
1826 // Compile a StoreIC that performs the prepared map transition. This
1827 // will restart incremental marking and should make sure the root is
1828 // marked grey again.
1829 CompileRun("function f(o) {"
1830 " o.foo = 0;"
1831 "}"
1832 "f(new Object);"
1833 "f(root);");
1834
1835 // This bug only triggers with aggressive IC clearing.
1836 HEAP->AgeInlineCaches();
1837
1838 // Explicitly request GC to perform final marking step and sweeping.
1839 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00001840
1841 Handle<JSObject> root =
1842 v8::Utils::OpenHandle(
1843 *v8::Handle<v8::Object>::Cast(
1844 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
1845
1846 // The root object should be in a sane state.
1847 CHECK(root->IsJSObject());
1848 CHECK(root->map()->IsMap());
1849}
1850
1851
1852TEST(Regress2143b) {
1853 i::FLAG_collect_maps = true;
1854 i::FLAG_incremental_marking = true;
1855 i::FLAG_allow_natives_syntax = true;
1856 InitializeVM();
1857 v8::HandleScope scope;
1858
1859 // Prepare a map transition from the root object together with a yet
1860 // untransitioned root object.
1861 CompileRun("var root = new Object;"
1862 "root.foo = 0;"
1863 "root = new Object;");
1864
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001865 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00001866
1867 // Compile an optimized LStoreNamedField that performs the prepared
1868 // map transition. This will restart incremental marking and should
1869 // make sure the root is marked grey again.
1870 CompileRun("function f(o) {"
1871 " o.foo = 0;"
1872 "}"
1873 "f(new Object);"
1874 "f(new Object);"
1875 "%OptimizeFunctionOnNextCall(f);"
1876 "f(root);"
1877 "%DeoptimizeFunction(f);");
1878
1879 // This bug only triggers with aggressive IC clearing.
1880 HEAP->AgeInlineCaches();
1881
1882 // Explicitly request GC to perform final marking step and sweeping.
1883 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00001884
1885 Handle<JSObject> root =
1886 v8::Utils::OpenHandle(
1887 *v8::Handle<v8::Object>::Cast(
1888 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
1889
1890 // The root object should be in a sane state.
1891 CHECK(root->IsJSObject());
1892 CHECK(root->map()->IsMap());
1893}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001894
1895
1896// Implemented in the test-alloc.cc test suite.
1897void SimulateFullSpace(PagedSpace* space);
1898
1899
1900TEST(ReleaseOverReservedPages) {
1901 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001902 // The optimizer can allocate stuff, messing up the test.
1903 i::FLAG_crankshaft = false;
1904 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001905 InitializeVM();
1906 v8::HandleScope scope;
1907 static const int number_of_test_pages = 20;
1908
1909 // Prepare many pages with low live-bytes count.
1910 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
1911 CHECK_EQ(1, old_pointer_space->CountTotalPages());
1912 for (int i = 0; i < number_of_test_pages; i++) {
1913 AlwaysAllocateScope always_allocate;
1914 SimulateFullSpace(old_pointer_space);
1915 FACTORY->NewFixedArray(1, TENURED);
1916 }
1917 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
1918
1919 // Triggering one GC will cause a lot of garbage to be discovered but
1920 // even spread across all allocated pages.
1921 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
1922 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
1923
1924 // Triggering subsequent GCs should cause at least half of the pages
1925 // to be released to the OS after at most two cycles.
1926 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
1927 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
1928 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
1929 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
1930
1931 // Triggering a last-resort GC should cause all pages to be released
1932 // to the OS so that other processes can seize the memory.
1933 HEAP->CollectAllAvailableGarbage("triggered really hard");
1934 CHECK_EQ(1, old_pointer_space->CountTotalPages());
1935}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001936
1937
1938TEST(Regress2237) {
1939 InitializeVM();
1940 v8::HandleScope scope;
1941 Handle<String> slice(HEAP->empty_string());
1942
1943 {
1944 // Generate a parent that lives in new-space.
1945 v8::HandleScope inner_scope;
1946 const char* c = "This text is long enough to trigger sliced strings.";
1947 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
1948 CHECK(s->IsSeqAsciiString());
1949 CHECK(HEAP->InNewSpace(*s));
1950
1951 // Generate a sliced string that is based on the above parent and
1952 // lives in old-space.
1953 FillUpNewSpace(HEAP->new_space());
1954 AlwaysAllocateScope always_allocate;
1955 Handle<String> t;
1956 // TODO(mstarzinger): Unfortunately FillUpNewSpace() still leaves
1957 // some slack, so we need to allocate a few sliced strings.
1958 for (int i = 0; i < 16; i++) {
1959 t = FACTORY->NewProperSubString(s, 5, 35);
1960 }
1961 CHECK(t->IsSlicedString());
1962 CHECK(!HEAP->InNewSpace(*t));
1963 *slice.location() = *t.location();
1964 }
1965
1966 CHECK(SlicedString::cast(*slice)->parent()->IsSeqAsciiString());
1967 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1968 CHECK(SlicedString::cast(*slice)->parent()->IsSeqAsciiString());
1969}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00001970
1971
1972#ifdef OBJECT_PRINT
1973TEST(PrintSharedFunctionInfo) {
1974 InitializeVM();
1975 v8::HandleScope scope;
1976 const char* source = "f = function() { return 987654321; }\n"
1977 "g = function() { return 123456789; }\n";
1978 CompileRun(source);
1979 Handle<JSFunction> g =
1980 v8::Utils::OpenHandle(
1981 *v8::Handle<v8::Function>::Cast(
1982 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
1983
1984 AssertNoAllocation no_alloc;
1985 g->shared()->PrintLn();
1986}
1987#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001988
1989
1990TEST(Regress2211) {
1991 InitializeVM();
1992 v8::HandleScope scope;
1993
1994 v8::Handle<v8::String> value = v8_str("val string");
1995 Smi* hash = Smi::FromInt(321);
1996 Heap* heap = Isolate::Current()->heap();
1997
1998 for (int i = 0; i < 2; i++) {
1999 // Store identity hash first and common hidden property second.
2000 v8::Handle<v8::Object> obj = v8::Object::New();
2001 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2002 CHECK(internal_obj->HasFastProperties());
2003
2004 // In the first iteration, set hidden value first and identity hash second.
2005 // In the second iteration, reverse the order.
2006 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2007 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2008 ALLOW_CREATION);
2009 CHECK(!maybe_obj->IsFailure());
2010 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2011
2012 // Check values.
2013 CHECK_EQ(hash,
2014 internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
2015 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2016
2017 // Check size.
2018 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2019 ObjectHashTable* hashtable = ObjectHashTable::cast(
2020 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2021 // HashTable header (5) and 4 initial entries (8).
2022 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2023 }
2024}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002025
2026
2027TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2028 if (i::FLAG_always_opt) return;
2029 InitializeVM();
2030 v8::HandleScope scope;
2031 v8::Local<v8::Value> fun1, fun2;
2032
2033 {
2034 LocalContext env;
2035 CompileRun("function fun() {};");
2036 fun1 = env->Global()->Get(v8_str("fun"));
2037 }
2038
2039 {
2040 LocalContext env;
2041 CompileRun("function fun() {};");
2042 fun2 = env->Global()->Get(v8_str("fun"));
2043 }
2044
2045 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002046 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002047 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2048 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2049 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2050 Handle<JSFunction> f =
2051 v8::Utils::OpenHandle(
2052 *v8::Handle<v8::Function>::Cast(
2053 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2054 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2055 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2056
2057 CHECK_EQ(2, cells->CellCount());
2058 CHECK(cells->Cell(0)->value()->IsJSFunction());
2059 CHECK(cells->Cell(1)->value()->IsJSFunction());
2060
2061 SimulateIncrementalMarking();
2062 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2063
2064 CHECK_EQ(2, cells->CellCount());
2065 CHECK(cells->Cell(0)->value()->IsTheHole());
2066 CHECK(cells->Cell(1)->value()->IsTheHole());
2067}
2068
2069
2070static Code* FindFirstIC(Code* code, Code::Kind kind) {
2071 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2072 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2073 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2074 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2075 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2076 RelocInfo* info = it.rinfo();
2077 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2078 if (target->is_inline_cache_stub() && target->kind() == kind) {
2079 return target;
2080 }
2081 }
2082 return NULL;
2083}
2084
2085
2086TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2087 if (i::FLAG_always_opt) return;
2088 InitializeVM();
2089 v8::HandleScope scope;
2090
2091 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002092 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002093 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2094 "function f(o) { return o.x; } f(obj); f(obj);");
2095 Handle<JSFunction> f =
2096 v8::Utils::OpenHandle(
2097 *v8::Handle<v8::Function>::Cast(
2098 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2099
2100 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2101 CHECK(ic_before->ic_state() == MONOMORPHIC);
2102
danno@chromium.orgeb831462012-08-24 11:57:08 +00002103 // Fire context dispose notification.
2104 v8::V8::ContextDisposedNotification();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002105 SimulateIncrementalMarking();
2106 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2107
2108 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2109 CHECK(ic_after->ic_state() == MONOMORPHIC);
2110}
2111
2112
2113TEST(IncrementalMarkingClearsMonomorhpicIC) {
2114 if (i::FLAG_always_opt) return;
2115 InitializeVM();
2116 v8::HandleScope scope;
2117 v8::Local<v8::Value> obj1;
2118
2119 {
2120 LocalContext env;
2121 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2122 obj1 = env->Global()->Get(v8_str("obj"));
2123 }
2124
2125 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002126 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002127 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2128 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2129 Handle<JSFunction> f =
2130 v8::Utils::OpenHandle(
2131 *v8::Handle<v8::Function>::Cast(
2132 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2133
2134 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2135 CHECK(ic_before->ic_state() == MONOMORPHIC);
2136
2137 // Fire context dispose notification.
2138 v8::V8::ContextDisposedNotification();
2139 SimulateIncrementalMarking();
2140 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2141
2142 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2143 CHECK(ic_after->ic_state() == UNINITIALIZED);
2144}
2145
2146
2147TEST(IncrementalMarkingClearsPolymorhpicIC) {
2148 if (i::FLAG_always_opt) return;
2149 InitializeVM();
2150 v8::HandleScope scope;
2151 v8::Local<v8::Value> obj1, obj2;
2152
2153 {
2154 LocalContext env;
2155 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2156 obj1 = env->Global()->Get(v8_str("obj"));
2157 }
2158
2159 {
2160 LocalContext env;
2161 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2162 obj2 = env->Global()->Get(v8_str("obj"));
2163 }
2164
2165 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002166 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002167 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2168 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2169 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2170 Handle<JSFunction> f =
2171 v8::Utils::OpenHandle(
2172 *v8::Handle<v8::Function>::Cast(
2173 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2174
2175 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2176 CHECK(ic_before->ic_state() == MEGAMORPHIC);
2177
2178 // Fire context dispose notification.
2179 v8::V8::ContextDisposedNotification();
2180 SimulateIncrementalMarking();
2181 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2182
2183 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2184 CHECK(ic_after->ic_state() == UNINITIALIZED);
2185}