blob: 72079dc2ae8180ccd29cdb385485436296892967 [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(
160 Isolate::Current()->context()->global()->HasLocalProperty(object_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000161
162 // Check ToString for oddballs
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000163 CheckOddball(HEAP->true_value(), "true");
164 CheckOddball(HEAP->false_value(), "false");
165 CheckOddball(HEAP->null_value(), "null");
166 CheckOddball(HEAP->undefined_value(), "undefined");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000167
168 // Check ToString for Smis
169 CheckSmi(0, "0");
170 CheckSmi(42, "42");
171 CheckSmi(-42, "-42");
172
173 // Check ToString for Numbers
174 CheckNumber(1.1, "1.1");
175
176 CheckFindCodeObject();
177}
178
179
180TEST(Tagging) {
181 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000182 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000183 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000184 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000185 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000186 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000187 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000188 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000189 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000190 CHECK(Failure::Exception()->IsFailure());
191 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
192 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
193}
194
195
196TEST(GarbageCollection) {
197 InitializeVM();
198
199 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000200 // Check GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000201 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000202
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000203 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
204 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
205 Handle<String> prop_namex = FACTORY->LookupAsciiSymbol("theSlotx");
206 Handle<String> obj_name = FACTORY->LookupAsciiSymbol("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000207
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000208 {
209 v8::HandleScope inner_scope;
210 // Allocate a function and keep it in global object's property.
211 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000212 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000213 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000214 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000215 function->set_initial_map(*initial_map);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000216 Isolate::Current()->context()->global()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000217 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000218 // Allocate an object. Unrooted after leaving the scope.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000219 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000220 obj->SetProperty(
221 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
222 obj->SetProperty(
223 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000224
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000225 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
226 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
227 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000228
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000229 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000230
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000231 // Function should be alive.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000232 CHECK(Isolate::Current()->context()->global()->HasLocalProperty(*name));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000233 // Check function is retained.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000234 Object* func_value = Isolate::Current()->context()->global()->
235 GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000236 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000237 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000238
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000239 {
240 HandleScope inner_scope;
241 // Allocate another object, make it reachable from global.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000242 Handle<JSObject> obj = FACTORY->NewJSObject(function);
243 Isolate::Current()->context()->global()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000244 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
245 obj->SetProperty(
246 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000247 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000248
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000249 // After gc, it should survive.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000250 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000251
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000252 CHECK(Isolate::Current()->context()->global()->HasLocalProperty(*obj_name));
253 CHECK(Isolate::Current()->context()->global()->
254 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
255 Object* obj = Isolate::Current()->context()->global()->
256 GetProperty(*obj_name)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000257 JSObject* js_obj = JSObject::cast(obj);
258 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000259}
260
261
262static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000263 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000264 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000265 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000266 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000267 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
268 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000269}
270
271
272TEST(String) {
273 InitializeVM();
274
275 VerifyStringAllocation("a");
276 VerifyStringAllocation("ab");
277 VerifyStringAllocation("abc");
278 VerifyStringAllocation("abcd");
279 VerifyStringAllocation("fiskerdrengen er paa havet");
280}
281
282
283TEST(LocalHandles) {
284 InitializeVM();
285
286 v8::HandleScope scope;
287 const char* name = "Kasper the spunky";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000288 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000289 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000290}
291
292
293TEST(GlobalHandles) {
294 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000295 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000296
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000297 Handle<Object> h1;
298 Handle<Object> h2;
299 Handle<Object> h3;
300 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000301
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000302 {
303 HandleScope scope;
304
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000305 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
306 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000307
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000308 h1 = global_handles->Create(*i);
309 h2 = global_handles->Create(*u);
310 h3 = global_handles->Create(*i);
311 h4 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000312 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000313
314 // after gc, it should survive
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000316
317 CHECK((*h1)->IsString());
318 CHECK((*h2)->IsHeapNumber());
319 CHECK((*h3)->IsString());
320 CHECK((*h4)->IsHeapNumber());
321
322 CHECK_EQ(*h3, *h1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000323 global_handles->Destroy(h1.location());
324 global_handles->Destroy(h3.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000325
326 CHECK_EQ(*h4, *h2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000327 global_handles->Destroy(h2.location());
328 global_handles->Destroy(h4.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000329}
330
331
332static bool WeakPointerCleared = false;
333
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000334static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000335 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000336 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000337 handle.Dispose();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000338}
339
340
341TEST(WeakGlobalHandlesScavenge) {
342 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000343 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000344
345 WeakPointerCleared = false;
346
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000347 Handle<Object> h1;
348 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000349
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000350 {
351 HandleScope scope;
352
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000353 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
354 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000356 h1 = global_handles->Create(*i);
357 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000358 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 global_handles->MakeWeak(h2.location(),
361 reinterpret_cast<void*>(1234),
362 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000363
364 // Scavenge treats weak pointers as normal roots.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000365 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000366
367 CHECK((*h1)->IsString());
368 CHECK((*h2)->IsHeapNumber());
369
370 CHECK(!WeakPointerCleared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000371 CHECK(!global_handles->IsNearDeath(h2.location()));
372 CHECK(!global_handles->IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000373
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000374 global_handles->Destroy(h1.location());
375 global_handles->Destroy(h2.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000376}
377
378
379TEST(WeakGlobalHandlesMark) {
380 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000381 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000382
383 WeakPointerCleared = false;
384
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000385 Handle<Object> h1;
386 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000387
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000388 {
389 HandleScope scope;
390
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000391 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
392 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000393
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000394 h1 = global_handles->Create(*i);
395 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000396 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000397
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000398 HEAP->CollectGarbage(OLD_POINTER_SPACE);
399 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000400 // Make sure the object is promoted.
401
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000402 global_handles->MakeWeak(h2.location(),
403 reinterpret_cast<void*>(1234),
404 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000405 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
406 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000408 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000409
410 CHECK((*h1)->IsString());
411
412 CHECK(WeakPointerCleared);
413 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000414
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000415 global_handles->Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000416}
417
418TEST(DeleteWeakGlobalHandle) {
419 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000420 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000421
422 WeakPointerCleared = false;
423
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000424 Handle<Object> h;
425
426 {
427 HandleScope scope;
428
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000429 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
430 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000431 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000433 global_handles->MakeWeak(h.location(),
434 reinterpret_cast<void*>(1234),
435 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000436
437 // Scanvenge does not recognize weak reference.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000438 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000439
440 CHECK(!WeakPointerCleared);
441
442 // Mark-compact treats weak reference properly.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000443 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000444
445 CHECK(WeakPointerCleared);
446}
447
448static const char* not_so_random_string_table[] = {
449 "abstract",
450 "boolean",
451 "break",
452 "byte",
453 "case",
454 "catch",
455 "char",
456 "class",
457 "const",
458 "continue",
459 "debugger",
460 "default",
461 "delete",
462 "do",
463 "double",
464 "else",
465 "enum",
466 "export",
467 "extends",
468 "false",
469 "final",
470 "finally",
471 "float",
472 "for",
473 "function",
474 "goto",
475 "if",
476 "implements",
477 "import",
478 "in",
479 "instanceof",
480 "int",
481 "interface",
482 "long",
483 "native",
484 "new",
485 "null",
486 "package",
487 "private",
488 "protected",
489 "public",
490 "return",
491 "short",
492 "static",
493 "super",
494 "switch",
495 "synchronized",
496 "this",
497 "throw",
498 "throws",
499 "transient",
500 "true",
501 "try",
502 "typeof",
503 "var",
504 "void",
505 "volatile",
506 "while",
507 "with",
508 0
509};
510
511
512static void CheckSymbols(const char** strings) {
513 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000514 Object* a;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000515 MaybeObject* maybe_a = HEAP->LookupAsciiSymbol(string);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000516 // LookupAsciiSymbol may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000517 if (!maybe_a->ToObject(&a)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000518 CHECK(a->IsSymbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000519 Object* b;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000520 MaybeObject* maybe_b = HEAP->LookupAsciiSymbol(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000521 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000522 CHECK_EQ(b, a);
523 CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
524 }
525}
526
527
528TEST(SymbolTable) {
529 InitializeVM();
530
531 CheckSymbols(not_so_random_string_table);
532 CheckSymbols(not_so_random_string_table);
533}
534
535
536TEST(FunctionAllocation) {
537 InitializeVM();
538
539 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000540 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000541 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000542 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000543 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000544 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000545 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000546
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000547 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
548 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000549 obj->SetProperty(
550 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000551 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000552 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000553 function->SetProperty(
554 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000555 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000556}
557
558
559TEST(ObjectProperties) {
560 InitializeVM();
561
562 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000563 String* object_symbol = String::cast(HEAP->Object_symbol());
564 Object* raw_object = Isolate::Current()->context()->global()->
565 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000566 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000567 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000568 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
569 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
570 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000571
572 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000573 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000574
575 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000576 obj->SetProperty(
577 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
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 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000581 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
582 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000583
584 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000585 obj->SetProperty(
586 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
587 obj->SetProperty(
588 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000589 CHECK(obj->HasLocalProperty(*first));
590 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000591
592 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000593 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
594 CHECK(obj->HasLocalProperty(*second));
595 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
596 CHECK(!obj->HasLocalProperty(*first));
597 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000598
599 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000600 obj->SetProperty(
601 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
602 obj->SetProperty(
603 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000604 CHECK(obj->HasLocalProperty(*first));
605 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000606
607 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000608 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
609 CHECK(obj->HasLocalProperty(*first));
610 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
611 CHECK(!obj->HasLocalProperty(*first));
612 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000613
614 // check string and symbol match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000615 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000616 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000617 obj->SetProperty(
618 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000619 Handle<String> s1_symbol = FACTORY->LookupAsciiSymbol(string1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000620 CHECK(obj->HasLocalProperty(*s1_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000621
622 // check symbol and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000623 const char* string2 = "fugl";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000624 Handle<String> s2_symbol = FACTORY->LookupAsciiSymbol(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000625 obj->SetProperty(
626 *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000627 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000628 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000629}
630
631
632TEST(JSObjectMaps) {
633 InitializeVM();
634
635 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000636 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000637 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000639 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000640 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000641 function->set_initial_map(*initial_map);
642
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000643 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
644 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000645
646 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000647 obj->SetProperty(
648 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000649 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000650
651 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000652 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000653}
654
655
656TEST(JSArray) {
657 InitializeVM();
658
659 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000660 Handle<String> name = FACTORY->LookupAsciiSymbol("Array");
661 Object* raw_object = Isolate::Current()->context()->global()->
662 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000663 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000664 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000665
666 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000667 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000668 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000669 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000670 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000671
672 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000673 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000674 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000675 // Must be in fast mode.
676 CHECK(array->HasFastTypeElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000677
678 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000679 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000680 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000681 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000682
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000683 // Set array length with larger than smi value.
684 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000685 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000686 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000687
688 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000689 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000690 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000691 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000692
693 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000694 array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000695 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000696 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000697 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000698 CHECK_EQ(array->GetElement(int_length), *name);
699 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000700}
701
702
703TEST(JSObjectCopy) {
704 InitializeVM();
705
706 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000707 String* object_symbol = String::cast(HEAP->Object_symbol());
708 Object* raw_object = Isolate::Current()->context()->global()->
709 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000710 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000711 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000712 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
713 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
714 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000715
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000716 obj->SetProperty(
717 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
718 obj->SetProperty(
719 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000720
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000721 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
722 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000723
724 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000725 Handle<JSObject> clone = Copy(obj);
726 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000727
728 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
729 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
730
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000731 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
732 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000733
734 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000735 clone->SetProperty(
736 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
737 clone->SetProperty(
738 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000739
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000740 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
741 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000742
743 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
744 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
745
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000746 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
747 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000748}
749
750
751TEST(StringAllocation) {
752 InitializeVM();
753
754
755 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
756 for (int length = 0; length < 100; length++) {
757 v8::HandleScope scope;
758 char* non_ascii = NewArray<char>(3 * length + 1);
759 char* ascii = NewArray<char>(length + 1);
760 non_ascii[3 * length] = 0;
761 ascii[length] = 0;
762 for (int i = 0; i < length; i++) {
763 ascii[i] = 'a';
764 non_ascii[3 * i] = chars[0];
765 non_ascii[3 * i + 1] = chars[1];
766 non_ascii[3 * i + 2] = chars[2];
767 }
768 Handle<String> non_ascii_sym =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000769 FACTORY->LookupSymbol(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000770 CHECK_EQ(length, non_ascii_sym->length());
771 Handle<String> ascii_sym =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000772 FACTORY->LookupSymbol(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000773 CHECK_EQ(length, ascii_sym->length());
774 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000775 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000776 non_ascii_str->Hash();
777 CHECK_EQ(length, non_ascii_str->length());
778 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000779 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000780 ascii_str->Hash();
781 CHECK_EQ(length, ascii_str->length());
782 DeleteArray(non_ascii);
783 DeleteArray(ascii);
784 }
785}
786
787
788static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
789 // Count the number of objects found in the heap.
790 int found_count = 0;
791 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000792 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000793 for (int i = 0; i < size; i++) {
794 if (*objs[i] == obj) {
795 found_count++;
796 }
797 }
798 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000799 return found_count;
800}
801
802
803TEST(Iteration) {
804 InitializeVM();
805 v8::HandleScope scope;
806
807 // Array of objects to scan haep for.
808 const int objs_count = 6;
809 Handle<Object> objs[objs_count];
810 int next_objs_index = 0;
811
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000812 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000813 objs[next_objs_index++] = FACTORY->NewJSArray(10);
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000814 objs[next_objs_index++] = FACTORY->NewJSArray(10, FAST_ELEMENTS, TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000815
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000816 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000817 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000818 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000819 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000820 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000821
822 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000823 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000824 char* str = new char[large_size];
825 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
826 str[large_size - 1] = '\0';
827 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000828 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000829 delete[] str;
830
831 // Add a Map object to look for.
832 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
833
834 CHECK_EQ(objs_count, next_objs_index);
835 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
836}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000837
838
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000839TEST(EmptyHandleEscapeFrom) {
840 InitializeVM();
841
842 v8::HandleScope scope;
843 Handle<JSObject> runaway;
844
845 {
846 v8::HandleScope nested;
847 Handle<JSObject> empty;
848 runaway = empty.EscapeFrom(&nested);
849 }
850
851 CHECK(runaway.is_null());
852}
853
854
855static int LenFromSize(int size) {
856 return (size - FixedArray::kHeaderSize) / kPointerSize;
857}
858
859
860TEST(Regression39128) {
861 // Test case for crbug.com/39128.
862 InitializeVM();
863
864 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000865 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000866
867 v8::HandleScope scope;
868
869 // The plan: create JSObject which references objects in new space.
870 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000871 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000872
873 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000874 Handle<JSFunction> object_ctor(
875 Isolate::Current()->global_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000876 CHECK(object_ctor->has_initial_map());
877 Handle<Map> object_map(object_ctor->initial_map());
878 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000879 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000880 int n_properties = my_map->inobject_properties();
881 CHECK_GT(n_properties, 0);
882
883 int object_size = my_map->instance_size();
884
885 // Step 2: allocate a lot of objects so to almost fill new space: we need
886 // just enough room to allocate JSObject and thus fill the newspace.
887
888 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000889 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000890 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000891 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000892 Address* top_addr = new_space->allocation_top_address();
893 Address* limit_addr = new_space->allocation_limit_address();
894 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000895 CHECK(!HEAP->always_allocate());
896 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
897 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000898 CHECK(new_space->Contains(array));
899 }
900
901 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000902 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000903 int fixed_array_len = LenFromSize(to_fill);
904 CHECK(fixed_array_len < FixedArray::kMaxLength);
905
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000906 CHECK(!HEAP->always_allocate());
907 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
908 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000909 CHECK(new_space->Contains(array));
910
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000911 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000912 CHECK(new_space->Contains(object));
913 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000914 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000915 CHECK_EQ(0, jsobject->properties()->length());
916 // Create a reference to object in new space in jsobject.
917 jsobject->FastPropertyAtPut(-1, array);
918
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000919 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000920
921 // Step 4: clone jsobject, but force always allocate first to create a clone
922 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000923 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000924 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000925 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000926 JSObject* clone = JSObject::cast(clone_obj);
927 if (clone->address() != old_pointer_space_top) {
928 // Alas, got allocated from free list, we cannot do checks.
929 return;
930 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000932}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000933
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000934
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000935TEST(TestCodeFlushing) {
936 i::FLAG_allow_natives_syntax = true;
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000937 // If we do not flush code this test is invalid.
938 if (!FLAG_flush_code) return;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000939 InitializeVM();
940 v8::HandleScope scope;
941 const char* source = "function foo() {"
942 " var x = 42;"
943 " var y = 42;"
944 " var z = x + y;"
945 "};"
946 "foo()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000947 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000948
949 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000950 { v8::HandleScope scope;
951 CompileRun(source);
952 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000953
954 // Check function is compiled.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000955 Object* func_value = Isolate::Current()->context()->global()->
956 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000957 CHECK(func_value->IsJSFunction());
958 Handle<JSFunction> function(JSFunction::cast(func_value));
959 CHECK(function->shared()->is_compiled());
960
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000961 // TODO(1609) Currently incremental marker does not support code flushing.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000962 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
963 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000964
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000965 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000966
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000967 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
968 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
969 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
970 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
971 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
972 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000973
974 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000975 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
976 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000977 // Call foo to get it recompiled.
978 CompileRun("foo()");
979 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000980 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000981}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000982
983
984// Count the number of global contexts in the weak list of global contexts.
985static int CountGlobalContexts() {
986 int count = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000987 Object* object = HEAP->global_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000988 while (!object->IsUndefined()) {
989 count++;
990 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
991 }
992 return count;
993}
994
995
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000996// Count the number of user functions in the weak list of optimized
997// functions attached to a global context.
998static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
999 int count = 0;
1000 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1001 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1002 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1003 count++;
1004 object = JSFunction::cast(object)->next_function_link();
1005 }
1006 return count;
1007}
1008
1009
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001010TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001011 v8::V8::Initialize();
1012
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001013 static const int kNumTestContexts = 10;
1014
1015 v8::HandleScope scope;
1016 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1017
1018 CHECK_EQ(0, CountGlobalContexts());
1019
1020 // Create a number of global contests which gets linked together.
1021 for (int i = 0; i < kNumTestContexts; i++) {
1022 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001023
1024 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1025
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001026 CHECK_EQ(i + 1, CountGlobalContexts());
1027
1028 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001029
1030 // Create a handle scope so no function objects get stuch in the outer
1031 // handle scope
1032 v8::HandleScope scope;
1033 const char* source = "function f1() { };"
1034 "function f2() { };"
1035 "function f3() { };"
1036 "function f4() { };"
1037 "function f5() { };";
1038 CompileRun(source);
1039 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1040 CompileRun("f1()");
1041 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1042 CompileRun("f2()");
1043 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1044 CompileRun("f3()");
1045 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1046 CompileRun("f4()");
1047 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1048 CompileRun("f5()");
1049 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1050
1051 // Remove function f1, and
1052 CompileRun("f1=null");
1053
1054 // Scavenge treats these references as strong.
1055 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001056 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001057 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1058 }
1059
1060 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001061 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001062 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1063
1064 // Get rid of f3 and f5 in the same way.
1065 CompileRun("f3=null");
1066 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001067 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001068 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1069 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001070 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001071 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1072 CompileRun("f5=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 ? 3 : 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 ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1079
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001080 ctx[i]->Exit();
1081 }
1082
1083 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001084 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001085
1086 // Dispose the global contexts one by one.
1087 for (int i = 0; i < kNumTestContexts; i++) {
1088 ctx[i].Dispose();
1089 ctx[i].Clear();
1090
1091 // Scavenge treats these references as strong.
1092 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001093 HEAP->PerformScavenge();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001094 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts());
1095 }
1096
1097 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001098 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001099 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts());
1100 }
1101
1102 CHECK_EQ(0, CountGlobalContexts());
1103}
1104
1105
1106// Count the number of global contexts in the weak list of global contexts
1107// causing a GC after the specified number of elements.
1108static int CountGlobalContextsWithGC(int n) {
1109 int count = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001110 Handle<Object> object(HEAP->global_contexts_list());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001111 while (!object->IsUndefined()) {
1112 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001113 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001114 object =
1115 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1116 }
1117 return count;
1118}
1119
1120
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001121// Count the number of user functions in the weak list of optimized
1122// functions attached to a global context causing a GC after the
1123// specified number of elements.
1124static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1125 int n) {
1126 int count = 0;
1127 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1128 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1129 while (object->IsJSFunction() &&
1130 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1131 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001132 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001133 object = Handle<Object>(
1134 Object::cast(JSFunction::cast(*object)->next_function_link()));
1135 }
1136 return count;
1137}
1138
1139
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001140TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001141 v8::V8::Initialize();
1142
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001143 static const int kNumTestContexts = 10;
1144
1145 v8::HandleScope scope;
1146 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1147
1148 CHECK_EQ(0, CountGlobalContexts());
1149
1150 // Create an number of contexts and check the length of the weak list both
1151 // with and without GCs while iterating the list.
1152 for (int i = 0; i < kNumTestContexts; i++) {
1153 ctx[i] = v8::Context::New();
1154 CHECK_EQ(i + 1, CountGlobalContexts());
1155 CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001156 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001157
1158 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1159
1160 // Compile a number of functions the length of the weak list of optimized
1161 // functions both with and without GCs while iterating the list.
1162 ctx[0]->Enter();
1163 const char* source = "function f1() { };"
1164 "function f2() { };"
1165 "function f3() { };"
1166 "function f4() { };"
1167 "function f5() { };";
1168 CompileRun(source);
1169 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1170 CompileRun("f1()");
1171 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1172 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1173 CompileRun("f2()");
1174 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1175 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1176 CompileRun("f3()");
1177 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1178 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1179 CompileRun("f4()");
1180 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1181 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1182 CompileRun("f5()");
1183 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1184 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1185
1186 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001187}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001188
1189
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001190TEST(TestSizeOfObjects) {
1191 v8::V8::Initialize();
1192
1193 // Get initial heap size after several full GCs, which will stabilize
1194 // the heap size and return with sweeping finished completely.
1195 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1196 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1197 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1198 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1199 CHECK(HEAP->old_pointer_space()->IsSweepingComplete());
1200 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1201
1202 {
1203 // Allocate objects on several different old-space pages so that
1204 // lazy sweeping kicks in for subsequent GC runs.
1205 AlwaysAllocateScope always_allocate;
1206 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1207 for (int i = 1; i <= 100; i++) {
1208 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1209 CHECK_EQ(initial_size + i * filler_size,
1210 static_cast<int>(HEAP->SizeOfObjects()));
1211 }
1212 }
1213
1214 // The heap size should go back to initial size after a full GC, even
1215 // though sweeping didn't finish yet.
1216 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001217
1218 // Normally sweeping would not be complete here, but no guarantees.
1219
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001220 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1221
1222 // Advancing the sweeper step-wise should not change the heap size.
1223 while (!HEAP->old_pointer_space()->IsSweepingComplete()) {
1224 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1225 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1226 }
1227}
1228
1229
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001230TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1231 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001232 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001233 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001234 HeapIterator iterator;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001235 intptr_t size_of_objects_2 = 0;
1236 for (HeapObject* obj = iterator.next();
1237 obj != NULL;
1238 obj = iterator.next()) {
1239 size_of_objects_2 += obj->Size();
1240 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001241 // Delta must be within 5% of the larger result.
1242 // TODO(gc): Tighten this up by distinguishing between byte
1243 // arrays that are real and those that merely mark free space
1244 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001245 if (size_of_objects_1 > size_of_objects_2) {
1246 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1247 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1248 "Iterator: %" V8_PTR_PREFIX "d, "
1249 "delta: %" V8_PTR_PREFIX "d\n",
1250 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001251 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001252 } else {
1253 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1254 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1255 "Iterator: %" V8_PTR_PREFIX "d, "
1256 "delta: %" V8_PTR_PREFIX "d\n",
1257 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001258 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001259 }
1260}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001261
1262
danno@chromium.orgc612e022011-11-10 11:38:15 +00001263static void FillUpNewSpace(NewSpace* new_space) {
1264 // Fill up new space to the point that it is completely full. Make sure
1265 // that the scavenger does not undo the filling.
1266 v8::HandleScope scope;
1267 AlwaysAllocateScope always_allocate;
1268 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001269 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001270 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001271 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001272 }
1273}
1274
1275
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001276TEST(GrowAndShrinkNewSpace) {
1277 InitializeVM();
1278 NewSpace* new_space = HEAP->new_space();
1279
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001280 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
1281 // The max size cannot exceed the reserved size, since semispaces must be
1282 // always within the reserved space. We can't test new space growing and
1283 // shrinking if the reserved size is the same as the minimum (initial) size.
1284 return;
1285 }
1286
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001287 // Explicitly growing should double the space capacity.
1288 intptr_t old_capacity, new_capacity;
1289 old_capacity = new_space->Capacity();
1290 new_space->Grow();
1291 new_capacity = new_space->Capacity();
1292 CHECK(2 * old_capacity == new_capacity);
1293
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001294 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001295 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001296 new_capacity = new_space->Capacity();
1297 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001298
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001299 // Explicitly shrinking should not affect space capacity.
1300 old_capacity = new_space->Capacity();
1301 new_space->Shrink();
1302 new_capacity = new_space->Capacity();
1303 CHECK(old_capacity == new_capacity);
1304
1305 // Let the scavenger empty the new space.
1306 HEAP->CollectGarbage(NEW_SPACE);
1307 CHECK_LE(new_space->Size(), old_capacity);
1308
1309 // Explicitly shrinking should halve the space capacity.
1310 old_capacity = new_space->Capacity();
1311 new_space->Shrink();
1312 new_capacity = new_space->Capacity();
1313 CHECK(old_capacity == 2 * new_capacity);
1314
1315 // Consecutive shrinking should not affect space capacity.
1316 old_capacity = new_space->Capacity();
1317 new_space->Shrink();
1318 new_space->Shrink();
1319 new_space->Shrink();
1320 new_capacity = new_space->Capacity();
1321 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001322}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001323
1324
1325TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1326 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001327
1328 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
1329 // The max size cannot exceed the reserved size, since semispaces must be
1330 // always within the reserved space. We can't test new space growing and
1331 // shrinking if the reserved size is the same as the minimum (initial) size.
1332 return;
1333 }
1334
danno@chromium.orgc612e022011-11-10 11:38:15 +00001335 v8::HandleScope scope;
1336 NewSpace* new_space = HEAP->new_space();
1337 intptr_t old_capacity, new_capacity;
1338 old_capacity = new_space->Capacity();
1339 new_space->Grow();
1340 new_capacity = new_space->Capacity();
1341 CHECK(2 * old_capacity == new_capacity);
1342 FillUpNewSpace(new_space);
1343 HEAP->CollectAllAvailableGarbage();
1344 new_capacity = new_space->Capacity();
1345 CHECK(old_capacity == new_capacity);
1346}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001347
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001348
1349static int NumberOfGlobalObjects() {
1350 int count = 0;
1351 HeapIterator iterator;
1352 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1353 if (obj->IsGlobalObject()) count++;
1354 }
1355 return count;
1356}
1357
1358
1359// Test that we don't embed maps from foreign contexts into
1360// optimized code.
1361TEST(LeakGlobalContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001362 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001363 v8::HandleScope outer_scope;
1364 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1365 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1366 ctx1->Enter();
1367
1368 HEAP->CollectAllAvailableGarbage();
1369 CHECK_EQ(4, NumberOfGlobalObjects());
1370
1371 {
1372 v8::HandleScope inner_scope;
1373 CompileRun("var v = {x: 42}");
1374 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1375 ctx2->Enter();
1376 ctx2->Global()->Set(v8_str("o"), v);
1377 v8::Local<v8::Value> res = CompileRun(
1378 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001379 "for (var i = 0; i < 10; ++i) f();"
1380 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001381 "f();");
1382 CHECK_EQ(42, res->Int32Value());
1383 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1384 ctx2->Exit();
1385 ctx1->Exit();
1386 ctx1.Dispose();
1387 }
1388 HEAP->CollectAllAvailableGarbage();
1389 CHECK_EQ(2, NumberOfGlobalObjects());
1390 ctx2.Dispose();
1391 HEAP->CollectAllAvailableGarbage();
1392 CHECK_EQ(0, NumberOfGlobalObjects());
1393}
1394
1395
1396// Test that we don't embed functions from foreign contexts into
1397// optimized code.
1398TEST(LeakGlobalContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001399 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001400 v8::HandleScope outer_scope;
1401 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1402 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1403 ctx1->Enter();
1404
1405 HEAP->CollectAllAvailableGarbage();
1406 CHECK_EQ(4, NumberOfGlobalObjects());
1407
1408 {
1409 v8::HandleScope inner_scope;
1410 CompileRun("var v = function() { return 42; }");
1411 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1412 ctx2->Enter();
1413 ctx2->Global()->Set(v8_str("o"), v);
1414 v8::Local<v8::Value> res = CompileRun(
1415 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001416 "for (var i = 0; i < 10; ++i) f(o);"
1417 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001418 "f(o);");
1419 CHECK_EQ(42, res->Int32Value());
1420 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1421 ctx2->Exit();
1422 ctx1->Exit();
1423 ctx1.Dispose();
1424 }
1425 HEAP->CollectAllAvailableGarbage();
1426 CHECK_EQ(2, NumberOfGlobalObjects());
1427 ctx2.Dispose();
1428 HEAP->CollectAllAvailableGarbage();
1429 CHECK_EQ(0, NumberOfGlobalObjects());
1430}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001431
1432
1433TEST(LeakGlobalContextViaMapKeyed) {
1434 i::FLAG_allow_natives_syntax = true;
1435 v8::HandleScope outer_scope;
1436 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1437 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1438 ctx1->Enter();
1439
1440 HEAP->CollectAllAvailableGarbage();
1441 CHECK_EQ(4, NumberOfGlobalObjects());
1442
1443 {
1444 v8::HandleScope inner_scope;
1445 CompileRun("var v = [42, 43]");
1446 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1447 ctx2->Enter();
1448 ctx2->Global()->Set(v8_str("o"), v);
1449 v8::Local<v8::Value> res = CompileRun(
1450 "function f() { return o[0]; }"
1451 "for (var i = 0; i < 10; ++i) f();"
1452 "%OptimizeFunctionOnNextCall(f);"
1453 "f();");
1454 CHECK_EQ(42, res->Int32Value());
1455 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1456 ctx2->Exit();
1457 ctx1->Exit();
1458 ctx1.Dispose();
1459 }
1460 HEAP->CollectAllAvailableGarbage();
1461 CHECK_EQ(2, NumberOfGlobalObjects());
1462 ctx2.Dispose();
1463 HEAP->CollectAllAvailableGarbage();
1464 CHECK_EQ(0, NumberOfGlobalObjects());
1465}
1466
1467
1468TEST(LeakGlobalContextViaMapProto) {
1469 i::FLAG_allow_natives_syntax = true;
1470 v8::HandleScope outer_scope;
1471 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1472 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1473 ctx1->Enter();
1474
1475 HEAP->CollectAllAvailableGarbage();
1476 CHECK_EQ(4, NumberOfGlobalObjects());
1477
1478 {
1479 v8::HandleScope inner_scope;
1480 CompileRun("var v = { y: 42}");
1481 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1482 ctx2->Enter();
1483 ctx2->Global()->Set(v8_str("o"), v);
1484 v8::Local<v8::Value> res = CompileRun(
1485 "function f() {"
1486 " var p = {x: 42};"
1487 " p.__proto__ = o;"
1488 " return p.x;"
1489 "}"
1490 "for (var i = 0; i < 10; ++i) f();"
1491 "%OptimizeFunctionOnNextCall(f);"
1492 "f();");
1493 CHECK_EQ(42, res->Int32Value());
1494 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1495 ctx2->Exit();
1496 ctx1->Exit();
1497 ctx1.Dispose();
1498 }
1499 HEAP->CollectAllAvailableGarbage();
1500 CHECK_EQ(2, NumberOfGlobalObjects());
1501 ctx2.Dispose();
1502 HEAP->CollectAllAvailableGarbage();
1503 CHECK_EQ(0, NumberOfGlobalObjects());
1504}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001505
1506
1507TEST(InstanceOfStubWriteBarrier) {
1508 i::FLAG_allow_natives_syntax = true;
1509#ifdef DEBUG
1510 i::FLAG_verify_heap = true;
1511#endif
1512 InitializeVM();
1513 if (!i::V8::UseCrankshaft()) return;
1514 v8::HandleScope outer_scope;
1515
1516 {
1517 v8::HandleScope scope;
1518 CompileRun(
1519 "function foo () { }"
1520 "function mkbar () { return new (new Function(\"\")) (); }"
1521 "function f (x) { return (x instanceof foo); }"
1522 "function g () { f(mkbar()); }"
1523 "f(new foo()); f(new foo());"
1524 "%OptimizeFunctionOnNextCall(f);"
1525 "f(new foo()); g();");
1526 }
1527
1528 IncrementalMarking* marking = HEAP->incremental_marking();
1529 marking->Abort();
1530 marking->Start();
1531
1532 Handle<JSFunction> f =
1533 v8::Utils::OpenHandle(
1534 *v8::Handle<v8::Function>::Cast(
1535 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1536
1537 CHECK(f->IsOptimized());
1538
1539 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1540 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001541 // Discard any pending GC requests otherwise we will get GC when we enter
1542 // code below.
1543 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001544 }
1545
1546 CHECK(marking->IsMarking());
1547
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001548 {
1549 v8::HandleScope scope;
1550 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1551 v8::Handle<v8::Function> g =
1552 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1553 g->Call(global, 0, NULL);
1554 }
1555
1556 HEAP->incremental_marking()->set_should_hurry(true);
1557 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1558}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001559
1560
1561TEST(PrototypeTransitionClearing) {
1562 InitializeVM();
1563 v8::HandleScope scope;
1564
1565 CompileRun(
1566 "var base = {};"
1567 "var live = [];"
1568 "for (var i = 0; i < 10; i++) {"
1569 " var object = {};"
1570 " var prototype = {};"
1571 " object.__proto__ = prototype;"
1572 " if (i >= 3) live.push(object, prototype);"
1573 "}");
1574
1575 Handle<JSObject> baseObject =
1576 v8::Utils::OpenHandle(
1577 *v8::Handle<v8::Object>::Cast(
1578 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1579
1580 // Verify that only dead prototype transitions are cleared.
1581 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
1582 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1583 CHECK_EQ(10 - 3, baseObject->map()->NumberOfProtoTransitions());
1584
1585 // Verify that prototype transitions array was compacted.
1586 FixedArray* trans = baseObject->map()->prototype_transitions();
1587 for (int i = 0; i < 10 - 3; i++) {
1588 int j = Map::kProtoTransitionHeaderSize +
1589 i * Map::kProtoTransitionElementsPerEntry;
1590 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
1591 CHECK(trans->get(j + Map::kProtoTransitionPrototypeOffset)->IsJSObject());
1592 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001593
1594 // Make sure next prototype is placed on an old-space evacuation candidate.
1595 Handle<JSObject> prototype;
1596 PagedSpace* space = HEAP->old_pointer_space();
1597 do {
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001598 prototype = FACTORY->NewJSArray(32 * KB, FAST_ELEMENTS, TENURED);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001599 } while (space->FirstPage() == space->LastPage() ||
1600 !space->LastPage()->Contains(prototype->address()));
1601
1602 // Add a prototype on an evacuation candidate and verify that transition
1603 // clearing correctly records slots in prototype transition array.
1604 i::FLAG_always_compact = true;
1605 Handle<Map> map(baseObject->map());
1606 CHECK(!space->LastPage()->Contains(map->prototype_transitions()->address()));
1607 CHECK(space->LastPage()->Contains(prototype->address()));
1608 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1609 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1610 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1611 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001612}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001613
1614
1615TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1616 i::FLAG_allow_natives_syntax = true;
1617#ifdef DEBUG
1618 i::FLAG_verify_heap = true;
1619#endif
1620 InitializeVM();
1621 if (!i::V8::UseCrankshaft()) return;
1622 v8::HandleScope outer_scope;
1623
1624 {
1625 v8::HandleScope scope;
1626 CompileRun(
1627 "function f () {"
1628 " var s = 0;"
1629 " for (var i = 0; i < 100; i++) s += i;"
1630 " return s;"
1631 "}"
1632 "f(); f();"
1633 "%OptimizeFunctionOnNextCall(f);"
1634 "f();");
1635 }
1636 Handle<JSFunction> f =
1637 v8::Utils::OpenHandle(
1638 *v8::Handle<v8::Function>::Cast(
1639 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1640 CHECK(f->IsOptimized());
1641
1642 IncrementalMarking* marking = HEAP->incremental_marking();
1643 marking->Abort();
1644 marking->Start();
1645
1646 // The following two calls will increment HEAP->global_ic_age().
1647 const int kLongIdlePauseInMs = 1000;
1648 v8::V8::ContextDisposedNotification();
1649 v8::V8::IdleNotification(kLongIdlePauseInMs);
1650
1651 while (!marking->IsStopped() && !marking->IsComplete()) {
1652 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1653 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001654 if (!marking->IsStopped() || marking->should_hurry()) {
1655 // We don't normally finish a GC via Step(), we normally finish by
1656 // setting the stack guard and then do the final steps in the stack
1657 // guard interrupt. But here we didn't ask for that, and there is no
1658 // JS code running to trigger the interrupt, so we explicitly finalize
1659 // here.
1660 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1661 "Test finalizing incremental mark-sweep");
1662 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001663
1664 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1665 CHECK_EQ(0, f->shared()->opt_count());
1666 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1667}
1668
1669
1670TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1671 i::FLAG_allow_natives_syntax = true;
1672#ifdef DEBUG
1673 i::FLAG_verify_heap = true;
1674#endif
1675 InitializeVM();
1676 if (!i::V8::UseCrankshaft()) return;
1677 v8::HandleScope outer_scope;
1678
1679 {
1680 v8::HandleScope scope;
1681 CompileRun(
1682 "function f () {"
1683 " var s = 0;"
1684 " for (var i = 0; i < 100; i++) s += i;"
1685 " return s;"
1686 "}"
1687 "f(); f();"
1688 "%OptimizeFunctionOnNextCall(f);"
1689 "f();");
1690 }
1691 Handle<JSFunction> f =
1692 v8::Utils::OpenHandle(
1693 *v8::Handle<v8::Function>::Cast(
1694 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1695 CHECK(f->IsOptimized());
1696
1697 HEAP->incremental_marking()->Abort();
1698
1699 // The following two calls will increment HEAP->global_ic_age().
1700 // Since incremental marking is off, IdleNotification will do full GC.
1701 const int kLongIdlePauseInMs = 1000;
1702 v8::V8::ContextDisposedNotification();
1703 v8::V8::IdleNotification(kLongIdlePauseInMs);
1704
1705 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1706 CHECK_EQ(0, f->shared()->opt_count());
1707 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1708}
1709
1710
1711// Test that HAllocateObject will always return an object in new-space.
1712TEST(OptimizedAllocationAlwaysInNewSpace) {
1713 i::FLAG_allow_natives_syntax = true;
1714 InitializeVM();
1715 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
1716 v8::HandleScope scope;
1717
1718 FillUpNewSpace(HEAP->new_space());
1719 AlwaysAllocateScope always_allocate;
1720 v8::Local<v8::Value> res = CompileRun(
1721 "function c(x) {"
1722 " this.x = x;"
1723 " for (var i = 0; i < 32; i++) {"
1724 " this['x' + i] = x;"
1725 " }"
1726 "}"
1727 "function f(x) { return new c(x); };"
1728 "f(1); f(2); f(3);"
1729 "%OptimizeFunctionOnNextCall(f);"
1730 "f(4);");
1731 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
1732
1733 Handle<JSObject> o =
1734 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
1735
1736 CHECK(HEAP->InNewSpace(*o));
1737}