blob: 09aa613eee4e618e79fea8de93285fa07ccb37e0 [file] [log] [blame]
ager@chromium.org9258b6b2008-09-11 09:11:10 +00001// Copyright 2006-2008 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) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000294 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000295 InitializeVM();
296
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) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000342 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000343 InitializeVM();
344
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) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000380 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000381 InitializeVM();
382
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) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000419 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000420 InitializeVM();
421
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
615 static 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
623 static 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.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000670 Object* ok = array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000671
672 // Set array length to 0.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000673 ok = array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000674 CHECK_EQ(Smi::FromInt(0), array->length());
675 CHECK(array->HasFastElements()); // Must be in fast mode.
676
677 // array[length] = name.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000678 ok = array->SetElement(0, *name, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000679 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000680 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000681
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000682 // Set array length with larger than smi value.
683 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000684 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000685 ok = array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000686
687 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000688 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000689 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000690 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000691
692 // array[length] = name.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000693 ok = array->SetElement(int_length, *name, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000694 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000695 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000696 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000697 CHECK_EQ(array->GetElement(int_length), *name);
698 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000699}
700
701
702TEST(JSObjectCopy) {
703 InitializeVM();
704
705 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000706 String* object_symbol = String::cast(HEAP->Object_symbol());
707 Object* raw_object = Isolate::Current()->context()->global()->
708 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000709 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000710 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000711 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
712 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
713 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000714
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000715 obj->SetProperty(
716 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
717 obj->SetProperty(
718 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000719
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000720 Object* ok = obj->SetElement(0, *first, kNonStrictMode)->ToObjectChecked();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000721
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000722 ok = obj->SetElement(1, *second, 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
karlklose@chromium.org8f806e82011-03-07 14:06:08 +0000740 ok = clone->SetElement(0, *second, kNonStrictMode)->ToObjectChecked();
741 ok = clone->SetElement(1, *first, 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);
814 objs[next_objs_index++] = FACTORY->NewJSArray(10, 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).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000823 int large_size = HEAP->MaxObjectSizeInPagedSpace() + 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
839TEST(LargeObjectSpaceContains) {
840 InitializeVM();
841
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000842 HEAP->CollectGarbage(NEW_SPACE);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000843
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000844 Address current_top = HEAP->new_space()->top();
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000845 Page* page = Page::FromAddress(current_top);
846 Address current_page = page->address();
847 Address next_page = current_page + Page::kPageSize;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000848 int bytes_to_page = static_cast<int>(next_page - current_top);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000849 if (bytes_to_page <= FixedArray::kHeaderSize) {
850 // Alas, need to cross another page to be able to
851 // put desired value.
852 next_page += Page::kPageSize;
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000853 bytes_to_page = static_cast<int>(next_page - current_top);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000854 }
855 CHECK(bytes_to_page > FixedArray::kHeaderSize);
856
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000857 intptr_t* flags_ptr = &Page::FromAddress(next_page)->flags_;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000858 Address flags_addr = reinterpret_cast<Address>(flags_ptr);
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000859
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000860 int bytes_to_allocate =
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000861 static_cast<int>(flags_addr - current_top) + kPointerSize;
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000862
863 int n_elements = (bytes_to_allocate - FixedArray::kHeaderSize) /
864 kPointerSize;
865 CHECK_EQ(bytes_to_allocate, FixedArray::SizeFor(n_elements));
866 FixedArray* array = FixedArray::cast(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000867 HEAP->AllocateFixedArray(n_elements)->ToObjectChecked());
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000868
869 int index = n_elements - 1;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000870 CHECK_EQ(flags_ptr,
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000871 HeapObject::RawField(array, FixedArray::OffsetOfElementAt(index)));
872 array->set(index, Smi::FromInt(0));
873 // This chould have turned next page into LargeObjectPage:
874 // CHECK(Page::FromAddress(next_page)->IsLargeObjectPage());
875
876 HeapObject* addr = HeapObject::FromAddress(next_page + 2 * kPointerSize);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000877 CHECK(HEAP->new_space()->Contains(addr));
878 CHECK(!HEAP->lo_space()->Contains(addr));
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000879}
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000880
881
882TEST(EmptyHandleEscapeFrom) {
883 InitializeVM();
884
885 v8::HandleScope scope;
886 Handle<JSObject> runaway;
887
888 {
889 v8::HandleScope nested;
890 Handle<JSObject> empty;
891 runaway = empty.EscapeFrom(&nested);
892 }
893
894 CHECK(runaway.is_null());
895}
896
897
898static int LenFromSize(int size) {
899 return (size - FixedArray::kHeaderSize) / kPointerSize;
900}
901
902
903TEST(Regression39128) {
904 // Test case for crbug.com/39128.
905 InitializeVM();
906
907 // Increase the chance of 'bump-the-pointer' allocation in old space.
908 bool force_compaction = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000909 HEAP->CollectAllGarbage(force_compaction);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000910
911 v8::HandleScope scope;
912
913 // The plan: create JSObject which references objects in new space.
914 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000915 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000916
917 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 Handle<JSFunction> object_ctor(
919 Isolate::Current()->global_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000920 CHECK(object_ctor->has_initial_map());
921 Handle<Map> object_map(object_ctor->initial_map());
922 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000923 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000924 int n_properties = my_map->inobject_properties();
925 CHECK_GT(n_properties, 0);
926
927 int object_size = my_map->instance_size();
928
929 // Step 2: allocate a lot of objects so to almost fill new space: we need
930 // just enough room to allocate JSObject and thus fill the newspace.
931
932 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000933 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000934 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000935 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000936 Address* top_addr = new_space->allocation_top_address();
937 Address* limit_addr = new_space->allocation_limit_address();
938 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000939 CHECK(!HEAP->always_allocate());
940 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
941 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000942 CHECK(new_space->Contains(array));
943 }
944
945 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000946 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000947 int fixed_array_len = LenFromSize(to_fill);
948 CHECK(fixed_array_len < FixedArray::kMaxLength);
949
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000950 CHECK(!HEAP->always_allocate());
951 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
952 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000953 CHECK(new_space->Contains(array));
954
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000955 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000956 CHECK(new_space->Contains(object));
957 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000958 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000959 CHECK_EQ(0, jsobject->properties()->length());
960 // Create a reference to object in new space in jsobject.
961 jsobject->FastPropertyAtPut(-1, array);
962
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000963 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000964
965 // Step 4: clone jsobject, but force always allocate first to create a clone
966 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000967 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000968 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000969 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000970 JSObject* clone = JSObject::cast(clone_obj);
971 if (clone->address() != old_pointer_space_top) {
972 // Alas, got allocated from free list, we cannot do checks.
973 return;
974 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000975 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000976
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000977 // Step 5: verify validity of region dirty marks.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000978 Address clone_addr = clone->address();
979 Page* page = Page::FromAddress(clone_addr);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000980 // Check that region covering inobject property 1 is marked dirty.
981 CHECK(page->IsRegionDirty(clone_addr + (object_size - kPointerSize)));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000982}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000983
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000984
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000985TEST(TestCodeFlushing) {
986 i::FLAG_allow_natives_syntax = true;
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000987 // If we do not flush code this test is invalid.
988 if (!FLAG_flush_code) return;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000989 InitializeVM();
990 v8::HandleScope scope;
991 const char* source = "function foo() {"
992 " var x = 42;"
993 " var y = 42;"
994 " var z = x + y;"
995 "};"
996 "foo()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000997 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000998
999 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001000 { v8::HandleScope scope;
1001 CompileRun(source);
1002 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001003
1004 // Check function is compiled.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001005 Object* func_value = Isolate::Current()->context()->global()->
1006 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001007 CHECK(func_value->IsJSFunction());
1008 Handle<JSFunction> function(JSFunction::cast(func_value));
1009 CHECK(function->shared()->is_compiled());
1010
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001011 HEAP->CollectAllGarbage(true);
1012 HEAP->CollectAllGarbage(true);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001013
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001014 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001015
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001016 HEAP->CollectAllGarbage(true);
1017 HEAP->CollectAllGarbage(true);
1018 HEAP->CollectAllGarbage(true);
1019 HEAP->CollectAllGarbage(true);
1020 HEAP->CollectAllGarbage(true);
1021 HEAP->CollectAllGarbage(true);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001022
1023 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001024 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1025 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001026 // Call foo to get it recompiled.
1027 CompileRun("foo()");
1028 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001029 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001030}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001031
1032
1033// Count the number of global contexts in the weak list of global contexts.
1034static int CountGlobalContexts() {
1035 int count = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001036 Object* object = HEAP->global_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001037 while (!object->IsUndefined()) {
1038 count++;
1039 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1040 }
1041 return count;
1042}
1043
1044
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001045// Count the number of user functions in the weak list of optimized
1046// functions attached to a global context.
1047static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1048 int count = 0;
1049 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1050 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1051 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1052 count++;
1053 object = JSFunction::cast(object)->next_function_link();
1054 }
1055 return count;
1056}
1057
1058
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001059TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001060 v8::V8::Initialize();
1061
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001062 static const int kNumTestContexts = 10;
1063
1064 v8::HandleScope scope;
1065 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1066
1067 CHECK_EQ(0, CountGlobalContexts());
1068
1069 // Create a number of global contests which gets linked together.
1070 for (int i = 0; i < kNumTestContexts; i++) {
1071 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001072
1073 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1074
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001075 CHECK_EQ(i + 1, CountGlobalContexts());
1076
1077 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001078
1079 // Create a handle scope so no function objects get stuch in the outer
1080 // handle scope
1081 v8::HandleScope scope;
1082 const char* source = "function f1() { };"
1083 "function f2() { };"
1084 "function f3() { };"
1085 "function f4() { };"
1086 "function f5() { };";
1087 CompileRun(source);
1088 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1089 CompileRun("f1()");
1090 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1091 CompileRun("f2()");
1092 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1093 CompileRun("f3()");
1094 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1095 CompileRun("f4()");
1096 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1097 CompileRun("f5()");
1098 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1099
1100 // Remove function f1, and
1101 CompileRun("f1=null");
1102
1103 // Scavenge treats these references as strong.
1104 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001105 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001106 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1107 }
1108
1109 // Mark compact handles the weak references.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001110 HEAP->CollectAllGarbage(true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001111 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1112
1113 // Get rid of f3 and f5 in the same way.
1114 CompileRun("f3=null");
1115 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001116 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001117 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1118 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001119 HEAP->CollectAllGarbage(true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001120 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1121 CompileRun("f5=null");
1122 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001123 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001124 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1125 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001126 HEAP->CollectAllGarbage(true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001127 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1128
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001129 ctx[i]->Exit();
1130 }
1131
1132 // Force compilation cache cleanup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001133 HEAP->CollectAllGarbage(true);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001134
1135 // Dispose the global contexts one by one.
1136 for (int i = 0; i < kNumTestContexts; i++) {
1137 ctx[i].Dispose();
1138 ctx[i].Clear();
1139
1140 // Scavenge treats these references as strong.
1141 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001142 HEAP->PerformScavenge();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001143 CHECK_EQ(kNumTestContexts - i, CountGlobalContexts());
1144 }
1145
1146 // Mark compact handles the weak references.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001147 HEAP->CollectAllGarbage(true);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001148 CHECK_EQ(kNumTestContexts - i - 1, CountGlobalContexts());
1149 }
1150
1151 CHECK_EQ(0, CountGlobalContexts());
1152}
1153
1154
1155// Count the number of global contexts in the weak list of global contexts
1156// causing a GC after the specified number of elements.
1157static int CountGlobalContextsWithGC(int n) {
1158 int count = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001159 Handle<Object> object(HEAP->global_contexts_list());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001160 while (!object->IsUndefined()) {
1161 count++;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001162 if (count == n) HEAP->CollectAllGarbage(true);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001163 object =
1164 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1165 }
1166 return count;
1167}
1168
1169
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001170// Count the number of user functions in the weak list of optimized
1171// functions attached to a global context causing a GC after the
1172// specified number of elements.
1173static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1174 int n) {
1175 int count = 0;
1176 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1177 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1178 while (object->IsJSFunction() &&
1179 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1180 count++;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001181 if (count == n) HEAP->CollectAllGarbage(true);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001182 object = Handle<Object>(
1183 Object::cast(JSFunction::cast(*object)->next_function_link()));
1184 }
1185 return count;
1186}
1187
1188
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001189TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001190 v8::V8::Initialize();
1191
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001192 static const int kNumTestContexts = 10;
1193
1194 v8::HandleScope scope;
1195 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1196
1197 CHECK_EQ(0, CountGlobalContexts());
1198
1199 // Create an number of contexts and check the length of the weak list both
1200 // with and without GCs while iterating the list.
1201 for (int i = 0; i < kNumTestContexts; i++) {
1202 ctx[i] = v8::Context::New();
1203 CHECK_EQ(i + 1, CountGlobalContexts());
1204 CHECK_EQ(i + 1, CountGlobalContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001205 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001206
1207 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1208
1209 // Compile a number of functions the length of the weak list of optimized
1210 // functions both with and without GCs while iterating the list.
1211 ctx[0]->Enter();
1212 const char* source = "function f1() { };"
1213 "function f2() { };"
1214 "function f3() { };"
1215 "function f4() { };"
1216 "function f5() { };";
1217 CompileRun(source);
1218 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1219 CompileRun("f1()");
1220 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1221 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1222 CompileRun("f2()");
1223 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1224 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1225 CompileRun("f3()");
1226 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1227 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1228 CompileRun("f4()");
1229 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1230 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1231 CompileRun("f5()");
1232 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1233 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1234
1235 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001236}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001237
1238
1239TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1240 InitializeVM();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001241 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
whesse@chromium.org023421e2010-12-21 12:19:12 +00001242 HeapIterator iterator(HeapIterator::kFilterFreeListNodes);
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 }
1249 // Delta must be within 1% of the larger result.
1250 if (size_of_objects_1 > size_of_objects_2) {
1251 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1252 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1253 "Iterator: %" V8_PTR_PREFIX "d, "
1254 "delta: %" V8_PTR_PREFIX "d\n",
1255 size_of_objects_1, size_of_objects_2, delta);
1256 CHECK_GT(size_of_objects_1 / 100, delta);
1257 } else {
1258 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1259 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1260 "Iterator: %" V8_PTR_PREFIX "d, "
1261 "delta: %" V8_PTR_PREFIX "d\n",
1262 size_of_objects_1, size_of_objects_2, delta);
1263 CHECK_GT(size_of_objects_2 / 100, delta);
1264 }
1265}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001266
1267
1268class HeapIteratorTestHelper {
1269 public:
1270 HeapIteratorTestHelper(Object* a, Object* b)
1271 : a_(a), b_(b), a_found_(false), b_found_(false) {}
1272 bool a_found() { return a_found_; }
1273 bool b_found() { return b_found_; }
1274 void IterateHeap(HeapIterator::HeapObjectsFiltering mode) {
1275 HeapIterator iterator(mode);
1276 for (HeapObject* obj = iterator.next();
1277 obj != NULL;
1278 obj = iterator.next()) {
1279 if (obj == a_)
1280 a_found_ = true;
1281 else if (obj == b_)
1282 b_found_ = true;
1283 }
1284 }
1285 private:
1286 Object* a_;
1287 Object* b_;
1288 bool a_found_;
1289 bool b_found_;
1290};
1291
1292TEST(HeapIteratorFilterUnreachable) {
1293 InitializeVM();
1294 v8::HandleScope scope;
1295 CompileRun("a = {}; b = {};");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001296 v8::Handle<Object> a(ISOLATE->context()->global()->GetProperty(
1297 *FACTORY->LookupAsciiSymbol("a"))->ToObjectChecked());
1298 v8::Handle<Object> b(ISOLATE->context()->global()->GetProperty(
1299 *FACTORY->LookupAsciiSymbol("b"))->ToObjectChecked());
whesse@chromium.org023421e2010-12-21 12:19:12 +00001300 CHECK_NE(*a, *b);
1301 {
1302 HeapIteratorTestHelper helper(*a, *b);
1303 helper.IterateHeap(HeapIterator::kFilterUnreachable);
1304 CHECK(helper.a_found());
1305 CHECK(helper.b_found());
1306 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001307 CHECK(ISOLATE->context()->global()->DeleteProperty(
1308 *FACTORY->LookupAsciiSymbol("a"), JSObject::FORCE_DELETION));
whesse@chromium.org023421e2010-12-21 12:19:12 +00001309 // We ensure that GC will not happen, so our raw pointer stays valid.
1310 AssertNoAllocation no_alloc;
1311 Object* a_saved = *a;
1312 a.Clear();
1313 // Verify that "a" object still resides in the heap...
1314 {
1315 HeapIteratorTestHelper helper(a_saved, *b);
1316 helper.IterateHeap(HeapIterator::kNoFiltering);
1317 CHECK(helper.a_found());
1318 CHECK(helper.b_found());
1319 }
1320 // ...but is now unreachable.
1321 {
1322 HeapIteratorTestHelper helper(a_saved, *b);
1323 helper.IterateHeap(HeapIterator::kFilterUnreachable);
1324 CHECK(!helper.a_found());
1325 CHECK(helper.b_found());
1326 }
1327}