blob: d6285db026bba0d530576b0216ec44f506274f7c [file] [log] [blame]
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001// Copyright 2012 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002
3#include <stdlib.h>
4
5#include "v8.h"
6
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007#include "compilation-cache.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008#include "execution.h"
9#include "factory.h"
10#include "macro-assembler.h"
11#include "global-handles.h"
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000012#include "stub-cache.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000013#include "cctest.h"
14
15using namespace v8::internal;
16
17static v8::Persistent<v8::Context> env;
18
19static void InitializeVM() {
20 if (env.IsEmpty()) env = v8::Context::New();
21 v8::HandleScope scope;
22 env->Enter();
23}
24
25
26static void CheckMap(Map* map, int type, int instance_size) {
27 CHECK(map->IsHeapObject());
28#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000029 CHECK(HEAP->Contains(map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000030#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000031 CHECK_EQ(HEAP->meta_map(), map->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000032 CHECK_EQ(type, map->instance_type());
33 CHECK_EQ(instance_size, map->instance_size());
34}
35
36
37TEST(HeapMaps) {
38 InitializeVM();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000039 CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
40 CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
41 CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
42 CheckMap(HEAP->string_map(), STRING_TYPE, kVariableSizeSentinel);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000043}
44
45
46static void CheckOddball(Object* obj, const char* string) {
47 CHECK(obj->IsOddball());
48 bool exc;
49 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
50 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
51}
52
53
54static void CheckSmi(int value, const char* string) {
55 bool exc;
56 Object* print_string =
57 *Execution::ToString(Handle<Object>(Smi::FromInt(value)), &exc);
58 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
59}
60
61
62static void CheckNumber(double value, const char* string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000063 Object* obj = HEAP->NumberFromDouble(value)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000064 CHECK(obj->IsNumber());
65 bool exc;
66 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
67 CHECK(String::cast(print_string)->IsEqualTo(CStrVector(string)));
68}
69
70
71static void CheckFindCodeObject() {
72 // Test FindCodeObject
73#define __ assm.
74
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000075 Assembler assm(Isolate::Current(), NULL, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000076
77 __ nop(); // supported on all architectures
78
79 CodeDesc desc;
80 assm.GetCode(&desc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000081 Object* code = HEAP->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +000082 desc,
83 Code::ComputeFlags(Code::STUB),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000084 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000085 CHECK(code->IsCode());
86
87 HeapObject* obj = HeapObject::cast(code);
88 Address obj_addr = obj->address();
89
90 for (int i = 0; i < obj->Size(); i += kPointerSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000091 Object* found = HEAP->FindCodeObject(obj_addr + i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000092 CHECK_EQ(code, found);
93 }
94
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000095 Object* copy = HEAP->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +000096 desc,
97 Code::ComputeFlags(Code::STUB),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000098 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000099 CHECK(copy->IsCode());
100 HeapObject* obj_copy = HeapObject::cast(copy);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000101 Object* not_right = HEAP->FindCodeObject(obj_copy->address() +
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000102 obj_copy->Size() / 2);
103 CHECK(not_right != code);
104}
105
106
107TEST(HeapObjects) {
108 InitializeVM();
109
110 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000111 Object* value = HEAP->NumberFromDouble(1.000123)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000112 CHECK(value->IsHeapNumber());
113 CHECK(value->IsNumber());
114 CHECK_EQ(1.000123, value->Number());
115
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000116 value = HEAP->NumberFromDouble(1.0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000117 CHECK(value->IsSmi());
118 CHECK(value->IsNumber());
119 CHECK_EQ(1.0, value->Number());
120
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000121 value = HEAP->NumberFromInt32(1024)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000122 CHECK(value->IsSmi());
123 CHECK(value->IsNumber());
124 CHECK_EQ(1024.0, value->Number());
125
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 value = HEAP->NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000127 CHECK(value->IsSmi());
128 CHECK(value->IsNumber());
129 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
130
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000131 value = HEAP->NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000132 CHECK(value->IsSmi());
133 CHECK(value->IsNumber());
134 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
135
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000136#ifndef V8_TARGET_ARCH_X64
137 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000138 value = HEAP->NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000139 CHECK(value->IsHeapNumber());
140 CHECK(value->IsNumber());
141 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000142#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000143
lrn@chromium.org303ada72010-10-27 09:33:13 +0000144 MaybeObject* maybe_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000145 HEAP->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000146 value = maybe_value->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000147 CHECK(value->IsHeapNumber());
148 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000149 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
150 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000151
152 // nan oddball checks
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000153 CHECK(HEAP->nan_value()->IsNumber());
154 CHECK(isnan(HEAP->nan_value()->Number()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000155
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000156 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000157 CHECK(s->IsString());
158 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000159
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 String* object_symbol = String::cast(HEAP->Object_symbol());
161 CHECK(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000162 Isolate::Current()->context()->global_object()->HasLocalProperty(
163 object_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000164
165 // Check ToString for oddballs
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000166 CheckOddball(HEAP->true_value(), "true");
167 CheckOddball(HEAP->false_value(), "false");
168 CheckOddball(HEAP->null_value(), "null");
169 CheckOddball(HEAP->undefined_value(), "undefined");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000170
171 // Check ToString for Smis
172 CheckSmi(0, "0");
173 CheckSmi(42, "42");
174 CheckSmi(-42, "-42");
175
176 // Check ToString for Numbers
177 CheckNumber(1.1, "1.1");
178
179 CheckFindCodeObject();
180}
181
182
183TEST(Tagging) {
184 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000185 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000186 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000187 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000188 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000189 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000190 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000191 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000192 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000193 CHECK(Failure::Exception()->IsFailure());
194 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
195 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
196}
197
198
199TEST(GarbageCollection) {
200 InitializeVM();
201
202 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000203 // Check GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000204 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000205
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000206 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
207 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
208 Handle<String> prop_namex = FACTORY->LookupAsciiSymbol("theSlotx");
209 Handle<String> obj_name = FACTORY->LookupAsciiSymbol("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000210
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000211 {
212 v8::HandleScope inner_scope;
213 // Allocate a function and keep it in global object's property.
214 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000215 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000216 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000217 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000218 function->set_initial_map(*initial_map);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000219 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000220 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000221 // Allocate an object. Unrooted after leaving the scope.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000222 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000223 obj->SetProperty(
224 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
225 obj->SetProperty(
226 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000227
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000228 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
229 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
230 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000231
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000232 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000233
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000234 // Function should be alive.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000235 CHECK(Isolate::Current()->context()->global_object()->
236 HasLocalProperty(*name));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000237 // Check function is retained.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000238 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000239 GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000240 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000241 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000242
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000243 {
244 HandleScope inner_scope;
245 // Allocate another object, make it reachable from global.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000246 Handle<JSObject> obj = FACTORY->NewJSObject(function);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000247 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000248 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
249 obj->SetProperty(
250 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000251 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000252
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000253 // After gc, it should survive.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000254 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000255
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000256 CHECK(Isolate::Current()->context()->global_object()->
257 HasLocalProperty(*obj_name));
258 CHECK(Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000259 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000260 Object* obj = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000261 GetProperty(*obj_name)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000262 JSObject* js_obj = JSObject::cast(obj);
263 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000264}
265
266
267static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000268 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000269 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000270 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000271 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000272 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
273 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000274}
275
276
277TEST(String) {
278 InitializeVM();
279
280 VerifyStringAllocation("a");
281 VerifyStringAllocation("ab");
282 VerifyStringAllocation("abc");
283 VerifyStringAllocation("abcd");
284 VerifyStringAllocation("fiskerdrengen er paa havet");
285}
286
287
288TEST(LocalHandles) {
289 InitializeVM();
290
291 v8::HandleScope scope;
292 const char* name = "Kasper the spunky";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000293 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000294 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000295}
296
297
298TEST(GlobalHandles) {
299 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000300 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000301
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000302 Handle<Object> h1;
303 Handle<Object> h2;
304 Handle<Object> h3;
305 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000306
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000307 {
308 HandleScope scope;
309
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000310 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
311 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000312
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000313 h1 = global_handles->Create(*i);
314 h2 = global_handles->Create(*u);
315 h3 = global_handles->Create(*i);
316 h4 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000317 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000318
319 // after gc, it should survive
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000320 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000321
322 CHECK((*h1)->IsString());
323 CHECK((*h2)->IsHeapNumber());
324 CHECK((*h3)->IsString());
325 CHECK((*h4)->IsHeapNumber());
326
327 CHECK_EQ(*h3, *h1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000328 global_handles->Destroy(h1.location());
329 global_handles->Destroy(h3.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000330
331 CHECK_EQ(*h4, *h2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000332 global_handles->Destroy(h2.location());
333 global_handles->Destroy(h4.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000334}
335
336
337static bool WeakPointerCleared = false;
338
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000339static void TestWeakGlobalHandleCallback(v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000340 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000341 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
fschneider@chromium.orged78ffd2010-07-21 11:05:19 +0000342 handle.Dispose();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000343}
344
345
346TEST(WeakGlobalHandlesScavenge) {
347 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000348 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000349
350 WeakPointerCleared = false;
351
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000352 Handle<Object> h1;
353 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000354
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000355 {
356 HandleScope scope;
357
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000358 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
359 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000360
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000361 h1 = global_handles->Create(*i);
362 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000363 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000364
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000365 global_handles->MakeWeak(h2.location(),
366 reinterpret_cast<void*>(1234),
367 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000368
369 // Scavenge treats weak pointers as normal roots.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000370 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000371
372 CHECK((*h1)->IsString());
373 CHECK((*h2)->IsHeapNumber());
374
375 CHECK(!WeakPointerCleared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000376 CHECK(!global_handles->IsNearDeath(h2.location()));
377 CHECK(!global_handles->IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000378
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000379 global_handles->Destroy(h1.location());
380 global_handles->Destroy(h2.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000381}
382
383
384TEST(WeakGlobalHandlesMark) {
385 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000386 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000387
388 WeakPointerCleared = false;
389
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000390 Handle<Object> h1;
391 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000392
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000393 {
394 HandleScope scope;
395
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000396 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
397 Handle<Object> u = FACTORY->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000398
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000399 h1 = global_handles->Create(*i);
400 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000401 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000402
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000403 HEAP->CollectGarbage(OLD_POINTER_SPACE);
404 HEAP->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000405 // Make sure the object is promoted.
406
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000407 global_handles->MakeWeak(h2.location(),
408 reinterpret_cast<void*>(1234),
409 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000410 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
411 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
412
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000413 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000414
415 CHECK((*h1)->IsString());
416
417 CHECK(WeakPointerCleared);
418 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000419
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000420 global_handles->Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000421}
422
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000423
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000424TEST(DeleteWeakGlobalHandle) {
425 InitializeVM();
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000426 GlobalHandles* global_handles = Isolate::Current()->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000427
428 WeakPointerCleared = false;
429
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000430 Handle<Object> h;
431
432 {
433 HandleScope scope;
434
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 Handle<Object> i = FACTORY->NewStringFromAscii(CStrVector("fisk"));
436 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000437 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000438
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000439 global_handles->MakeWeak(h.location(),
440 reinterpret_cast<void*>(1234),
441 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000442
443 // Scanvenge does not recognize weak reference.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000444 HEAP->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000445
446 CHECK(!WeakPointerCleared);
447
448 // Mark-compact treats weak reference properly.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000449 HEAP->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000450
451 CHECK(WeakPointerCleared);
452}
453
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000454
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000455static const char* not_so_random_string_table[] = {
456 "abstract",
457 "boolean",
458 "break",
459 "byte",
460 "case",
461 "catch",
462 "char",
463 "class",
464 "const",
465 "continue",
466 "debugger",
467 "default",
468 "delete",
469 "do",
470 "double",
471 "else",
472 "enum",
473 "export",
474 "extends",
475 "false",
476 "final",
477 "finally",
478 "float",
479 "for",
480 "function",
481 "goto",
482 "if",
483 "implements",
484 "import",
485 "in",
486 "instanceof",
487 "int",
488 "interface",
489 "long",
490 "native",
491 "new",
492 "null",
493 "package",
494 "private",
495 "protected",
496 "public",
497 "return",
498 "short",
499 "static",
500 "super",
501 "switch",
502 "synchronized",
503 "this",
504 "throw",
505 "throws",
506 "transient",
507 "true",
508 "try",
509 "typeof",
510 "var",
511 "void",
512 "volatile",
513 "while",
514 "with",
515 0
516};
517
518
519static void CheckSymbols(const char** strings) {
520 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000521 Object* a;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000522 MaybeObject* maybe_a = HEAP->LookupAsciiSymbol(string);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +0000523 // LookupAsciiSymbol may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000524 if (!maybe_a->ToObject(&a)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000525 CHECK(a->IsSymbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000526 Object* b;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000527 MaybeObject* maybe_b = HEAP->LookupAsciiSymbol(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000528 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000529 CHECK_EQ(b, a);
530 CHECK(String::cast(b)->IsEqualTo(CStrVector(string)));
531 }
532}
533
534
535TEST(SymbolTable) {
536 InitializeVM();
537
538 CheckSymbols(not_so_random_string_table);
539 CheckSymbols(not_so_random_string_table);
540}
541
542
543TEST(FunctionAllocation) {
544 InitializeVM();
545
546 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000547 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000548 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000549 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000550 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000551 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000552 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000553
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000554 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
555 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000556 obj->SetProperty(
557 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000558 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000559 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000560 function->SetProperty(
561 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000562 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000563}
564
565
566TEST(ObjectProperties) {
567 InitializeVM();
568
569 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000570 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000571 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000572 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000573 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000574 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000575 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
576 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
577 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000578
579 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000580 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000581
582 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000583 obj->SetProperty(
584 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000585 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000586
587 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000588 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
589 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000590
591 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000592 obj->SetProperty(
593 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
594 obj->SetProperty(
595 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000596 CHECK(obj->HasLocalProperty(*first));
597 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000598
599 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000600 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
601 CHECK(obj->HasLocalProperty(*second));
602 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
603 CHECK(!obj->HasLocalProperty(*first));
604 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000605
606 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000607 obj->SetProperty(
608 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
609 obj->SetProperty(
610 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000611 CHECK(obj->HasLocalProperty(*first));
612 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000613
614 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000615 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
616 CHECK(obj->HasLocalProperty(*first));
617 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
618 CHECK(!obj->HasLocalProperty(*first));
619 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000620
621 // check string and symbol match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000622 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000623 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000624 obj->SetProperty(
625 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 Handle<String> s1_symbol = FACTORY->LookupAsciiSymbol(string1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000627 CHECK(obj->HasLocalProperty(*s1_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000628
629 // check symbol and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000630 const char* string2 = "fugl";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000631 Handle<String> s2_symbol = FACTORY->LookupAsciiSymbol(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000632 obj->SetProperty(
633 *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000634 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000635 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000636}
637
638
639TEST(JSObjectMaps) {
640 InitializeVM();
641
642 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000643 Handle<String> name = FACTORY->LookupAsciiSymbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000644 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000645 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000646 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000647 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000648 function->set_initial_map(*initial_map);
649
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000650 Handle<String> prop_name = FACTORY->LookupAsciiSymbol("theSlot");
651 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000652
653 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000654 obj->SetProperty(
655 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000656 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000657
658 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000659 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000660}
661
662
663TEST(JSArray) {
664 InitializeVM();
665
666 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000667 Handle<String> name = FACTORY->LookupAsciiSymbol("Array");
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000668 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000669 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000670 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000671 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000672
673 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000674 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000675 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000676 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000677 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000678
679 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000680 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000681 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000682 // Must be in fast mode.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000683 CHECK(array->HasFastSmiOrObjectElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000684
685 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000686 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000687 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000688 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000689
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000690 // Set array length with larger than smi value.
691 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000692 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000693 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000694
695 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000696 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000697 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000698 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000699
700 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000701 array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000702 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000703 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000704 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000705 CHECK_EQ(array->GetElement(int_length), *name);
706 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000707}
708
709
710TEST(JSObjectCopy) {
711 InitializeVM();
712
713 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000714 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000715 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000716 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000717 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000718 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000719 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
720 Handle<String> first = FACTORY->LookupAsciiSymbol("first");
721 Handle<String> second = FACTORY->LookupAsciiSymbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000722
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000723 obj->SetProperty(
724 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
725 obj->SetProperty(
726 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000727
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000728 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
729 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000730
731 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000732 Handle<JSObject> clone = Copy(obj);
733 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000734
735 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
736 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
737
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000738 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
739 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000740
741 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000742 clone->SetProperty(
743 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
744 clone->SetProperty(
745 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000746
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000747 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
748 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000749
750 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
751 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
752
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000753 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
754 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000755}
756
757
758TEST(StringAllocation) {
759 InitializeVM();
760
761
762 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
763 for (int length = 0; length < 100; length++) {
764 v8::HandleScope scope;
765 char* non_ascii = NewArray<char>(3 * length + 1);
766 char* ascii = NewArray<char>(length + 1);
767 non_ascii[3 * length] = 0;
768 ascii[length] = 0;
769 for (int i = 0; i < length; i++) {
770 ascii[i] = 'a';
771 non_ascii[3 * i] = chars[0];
772 non_ascii[3 * i + 1] = chars[1];
773 non_ascii[3 * i + 2] = chars[2];
774 }
775 Handle<String> non_ascii_sym =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000776 FACTORY->LookupSymbol(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000777 CHECK_EQ(length, non_ascii_sym->length());
778 Handle<String> ascii_sym =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000779 FACTORY->LookupSymbol(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000780 CHECK_EQ(length, ascii_sym->length());
781 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000782 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000783 non_ascii_str->Hash();
784 CHECK_EQ(length, non_ascii_str->length());
785 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000786 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000787 ascii_str->Hash();
788 CHECK_EQ(length, ascii_str->length());
789 DeleteArray(non_ascii);
790 DeleteArray(ascii);
791 }
792}
793
794
795static int ObjectsFoundInHeap(Handle<Object> objs[], int size) {
796 // Count the number of objects found in the heap.
797 int found_count = 0;
798 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000799 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000800 for (int i = 0; i < size; i++) {
801 if (*objs[i] == obj) {
802 found_count++;
803 }
804 }
805 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000806 return found_count;
807}
808
809
810TEST(Iteration) {
811 InitializeVM();
812 v8::HandleScope scope;
813
814 // Array of objects to scan haep for.
815 const int objs_count = 6;
816 Handle<Object> objs[objs_count];
817 int next_objs_index = 0;
818
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000819 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000820 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000821 objs[next_objs_index++] = FACTORY->NewJSArray(10,
822 FAST_HOLEY_ELEMENTS,
823 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000824
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000825 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000826 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000827 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000828 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000829 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000830
831 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000832 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000833 char* str = new char[large_size];
834 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
835 str[large_size - 1] = '\0';
836 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000837 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000838 delete[] str;
839
840 // Add a Map object to look for.
841 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
842
843 CHECK_EQ(objs_count, next_objs_index);
844 CHECK_EQ(objs_count, ObjectsFoundInHeap(objs, objs_count));
845}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000846
847
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000848TEST(EmptyHandleEscapeFrom) {
849 InitializeVM();
850
851 v8::HandleScope scope;
852 Handle<JSObject> runaway;
853
854 {
855 v8::HandleScope nested;
856 Handle<JSObject> empty;
857 runaway = empty.EscapeFrom(&nested);
858 }
859
860 CHECK(runaway.is_null());
861}
862
863
864static int LenFromSize(int size) {
865 return (size - FixedArray::kHeaderSize) / kPointerSize;
866}
867
868
869TEST(Regression39128) {
870 // Test case for crbug.com/39128.
871 InitializeVM();
872
873 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000874 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000875
876 v8::HandleScope scope;
877
878 // The plan: create JSObject which references objects in new space.
879 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000880 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000881
882 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000883 Handle<JSFunction> object_ctor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000884 Isolate::Current()->native_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000885 CHECK(object_ctor->has_initial_map());
886 Handle<Map> object_map(object_ctor->initial_map());
887 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000888 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000889 int n_properties = my_map->inobject_properties();
890 CHECK_GT(n_properties, 0);
891
892 int object_size = my_map->instance_size();
893
894 // Step 2: allocate a lot of objects so to almost fill new space: we need
895 // just enough room to allocate JSObject and thus fill the newspace.
896
897 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000898 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000899 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000900 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000901 Address* top_addr = new_space->allocation_top_address();
902 Address* limit_addr = new_space->allocation_limit_address();
903 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000904 CHECK(!HEAP->always_allocate());
905 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
906 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000907 CHECK(new_space->Contains(array));
908 }
909
910 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000911 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000912 int fixed_array_len = LenFromSize(to_fill);
913 CHECK(fixed_array_len < FixedArray::kMaxLength);
914
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000915 CHECK(!HEAP->always_allocate());
916 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
917 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000918 CHECK(new_space->Contains(array));
919
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000920 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000921 CHECK(new_space->Contains(object));
922 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000923 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000924 CHECK_EQ(0, jsobject->properties()->length());
925 // Create a reference to object in new space in jsobject.
926 jsobject->FastPropertyAtPut(-1, array);
927
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000928 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000929
930 // Step 4: clone jsobject, but force always allocate first to create a clone
931 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000932 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000933 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000934 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000935 JSObject* clone = JSObject::cast(clone_obj);
936 if (clone->address() != old_pointer_space_top) {
937 // Alas, got allocated from free list, we cannot do checks.
938 return;
939 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000940 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000941}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000942
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000943
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000944TEST(TestCodeFlushing) {
945 i::FLAG_allow_natives_syntax = true;
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000946 // If we do not flush code this test is invalid.
947 if (!FLAG_flush_code) return;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000948 InitializeVM();
949 v8::HandleScope scope;
950 const char* source = "function foo() {"
951 " var x = 42;"
952 " var y = 42;"
953 " var z = x + y;"
954 "};"
955 "foo()";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000956 Handle<String> foo_name = FACTORY->LookupAsciiSymbol("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000957
958 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000959 { v8::HandleScope scope;
960 CompileRun(source);
961 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000962
963 // Check function is compiled.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000964 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000965 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000966 CHECK(func_value->IsJSFunction());
967 Handle<JSFunction> function(JSFunction::cast(func_value));
968 CHECK(function->shared()->is_compiled());
969
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000970 // TODO(1609) Currently incremental marker does not support code flushing.
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000971 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
972 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000973
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000974 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000975
erik.corry@gmail.combbceb572012-03-09 10:52:05 +0000976 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
977 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
978 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
979 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
980 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
981 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000982
983 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000984 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
985 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000986 // Call foo to get it recompiled.
987 CompileRun("foo()");
988 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000989 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000990}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000991
992
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000993// Count the number of native contexts in the weak list of native contexts.
994int CountNativeContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000995 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000996 Object* object = HEAP->native_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000997 while (!object->IsUndefined()) {
998 count++;
999 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1000 }
1001 return count;
1002}
1003
1004
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001005// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001006// functions attached to a native context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001007static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1008 int count = 0;
1009 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1010 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1011 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1012 count++;
1013 object = JSFunction::cast(object)->next_function_link();
1014 }
1015 return count;
1016}
1017
1018
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001019TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 v8::V8::Initialize();
1021
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001022 static const int kNumTestContexts = 10;
1023
1024 v8::HandleScope scope;
1025 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1026
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001027 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001028
1029 // Create a number of global contests which gets linked together.
1030 for (int i = 0; i < kNumTestContexts; i++) {
1031 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001032
1033 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1034
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001035 CHECK_EQ(i + 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001036
1037 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001038
1039 // Create a handle scope so no function objects get stuch in the outer
1040 // handle scope
1041 v8::HandleScope scope;
1042 const char* source = "function f1() { };"
1043 "function f2() { };"
1044 "function f3() { };"
1045 "function f4() { };"
1046 "function f5() { };";
1047 CompileRun(source);
1048 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1049 CompileRun("f1()");
1050 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1051 CompileRun("f2()");
1052 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1053 CompileRun("f3()");
1054 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1055 CompileRun("f4()");
1056 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1057 CompileRun("f5()");
1058 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1059
1060 // Remove function f1, and
1061 CompileRun("f1=null");
1062
1063 // Scavenge treats these references as strong.
1064 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001065 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001066 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1067 }
1068
1069 // Mark compact handles the weak references.
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 ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1072
1073 // Get rid of f3 and f5 in the same way.
1074 CompileRun("f3=null");
1075 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001077 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1078 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001079 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001080 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1081 CompileRun("f5=null");
1082 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001084 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1085 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001086 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001087 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1088
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001089 ctx[i]->Exit();
1090 }
1091
1092 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001093 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001094
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001095 // Dispose the native contexts one by one.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001096 for (int i = 0; i < kNumTestContexts; i++) {
1097 ctx[i].Dispose();
1098 ctx[i].Clear();
1099
1100 // Scavenge treats these references as strong.
1101 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001102 HEAP->PerformScavenge();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001103 CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001104 }
1105
1106 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001107 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001108 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001109 }
1110
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001111 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001112}
1113
1114
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001115// Count the number of native contexts in the weak list of native contexts
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001116// causing a GC after the specified number of elements.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001117static int CountNativeContextsWithGC(int n) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001118 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001119 Handle<Object> object(HEAP->native_contexts_list());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001120 while (!object->IsUndefined()) {
1121 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001122 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001123 object =
1124 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1125 }
1126 return count;
1127}
1128
1129
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001130// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001131// functions attached to a native context causing a GC after the
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001132// specified number of elements.
1133static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1134 int n) {
1135 int count = 0;
1136 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1137 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1138 while (object->IsJSFunction() &&
1139 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1140 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001141 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001142 object = Handle<Object>(
1143 Object::cast(JSFunction::cast(*object)->next_function_link()));
1144 }
1145 return count;
1146}
1147
1148
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001149TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001150 v8::V8::Initialize();
1151
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001152 static const int kNumTestContexts = 10;
1153
1154 v8::HandleScope scope;
1155 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1156
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001157 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001158
1159 // Create an number of contexts and check the length of the weak list both
1160 // with and without GCs while iterating the list.
1161 for (int i = 0; i < kNumTestContexts; i++) {
1162 ctx[i] = v8::Context::New();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001163 CHECK_EQ(i + 1, CountNativeContexts());
1164 CHECK_EQ(i + 1, CountNativeContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001165 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001166
1167 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1168
1169 // Compile a number of functions the length of the weak list of optimized
1170 // functions both with and without GCs while iterating the list.
1171 ctx[0]->Enter();
1172 const char* source = "function f1() { };"
1173 "function f2() { };"
1174 "function f3() { };"
1175 "function f4() { };"
1176 "function f5() { };";
1177 CompileRun(source);
1178 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1179 CompileRun("f1()");
1180 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1181 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1182 CompileRun("f2()");
1183 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1184 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1185 CompileRun("f3()");
1186 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1187 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1188 CompileRun("f4()");
1189 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1190 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1191 CompileRun("f5()");
1192 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1193 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1194
1195 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001196}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001197
1198
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001199TEST(TestSizeOfObjects) {
1200 v8::V8::Initialize();
1201
1202 // Get initial heap size after several full GCs, which will stabilize
1203 // the heap size and return with sweeping finished completely.
1204 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1205 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1206 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1207 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001208 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001209 CHECK(HEAP->old_pointer_space()->IsSweepingComplete());
1210 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1211
1212 {
1213 // Allocate objects on several different old-space pages so that
1214 // lazy sweeping kicks in for subsequent GC runs.
1215 AlwaysAllocateScope always_allocate;
1216 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1217 for (int i = 1; i <= 100; i++) {
1218 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1219 CHECK_EQ(initial_size + i * filler_size,
1220 static_cast<int>(HEAP->SizeOfObjects()));
1221 }
1222 }
1223
1224 // The heap size should go back to initial size after a full GC, even
1225 // though sweeping didn't finish yet.
1226 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001227
1228 // Normally sweeping would not be complete here, but no guarantees.
1229
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001230 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1231
1232 // Advancing the sweeper step-wise should not change the heap size.
1233 while (!HEAP->old_pointer_space()->IsSweepingComplete()) {
1234 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1235 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1236 }
1237}
1238
1239
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001240TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1241 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001242 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001243 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001244 HeapIterator iterator;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001245 intptr_t size_of_objects_2 = 0;
1246 for (HeapObject* obj = iterator.next();
1247 obj != NULL;
1248 obj = iterator.next()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001249 if (!obj->IsFreeSpace()) {
1250 size_of_objects_2 += obj->Size();
1251 }
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001252 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001253 // Delta must be within 5% of the larger result.
1254 // TODO(gc): Tighten this up by distinguishing between byte
1255 // arrays that are real and those that merely mark free space
1256 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001257 if (size_of_objects_1 > size_of_objects_2) {
1258 intptr_t delta = size_of_objects_1 - size_of_objects_2;
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);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001263 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001264 } else {
1265 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1266 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1267 "Iterator: %" V8_PTR_PREFIX "d, "
1268 "delta: %" V8_PTR_PREFIX "d\n",
1269 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001270 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001271 }
1272}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001273
1274
danno@chromium.orgc612e022011-11-10 11:38:15 +00001275static void FillUpNewSpace(NewSpace* new_space) {
1276 // Fill up new space to the point that it is completely full. Make sure
1277 // that the scavenger does not undo the filling.
1278 v8::HandleScope scope;
1279 AlwaysAllocateScope always_allocate;
1280 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001281 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001282 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001283 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001284 }
1285}
1286
1287
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001288TEST(GrowAndShrinkNewSpace) {
1289 InitializeVM();
1290 NewSpace* new_space = HEAP->new_space();
1291
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001292 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1293 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001294 // The max size cannot exceed the reserved size, since semispaces must be
1295 // always within the reserved space. We can't test new space growing and
1296 // shrinking if the reserved size is the same as the minimum (initial) size.
1297 return;
1298 }
1299
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001300 // Explicitly growing should double the space capacity.
1301 intptr_t old_capacity, new_capacity;
1302 old_capacity = new_space->Capacity();
1303 new_space->Grow();
1304 new_capacity = new_space->Capacity();
1305 CHECK(2 * old_capacity == new_capacity);
1306
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001307 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001308 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001309 new_capacity = new_space->Capacity();
1310 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001311
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001312 // Explicitly shrinking should not affect space capacity.
1313 old_capacity = new_space->Capacity();
1314 new_space->Shrink();
1315 new_capacity = new_space->Capacity();
1316 CHECK(old_capacity == new_capacity);
1317
1318 // Let the scavenger empty the new space.
1319 HEAP->CollectGarbage(NEW_SPACE);
1320 CHECK_LE(new_space->Size(), old_capacity);
1321
1322 // Explicitly shrinking should halve the space capacity.
1323 old_capacity = new_space->Capacity();
1324 new_space->Shrink();
1325 new_capacity = new_space->Capacity();
1326 CHECK(old_capacity == 2 * new_capacity);
1327
1328 // Consecutive shrinking should not affect space capacity.
1329 old_capacity = new_space->Capacity();
1330 new_space->Shrink();
1331 new_space->Shrink();
1332 new_space->Shrink();
1333 new_capacity = new_space->Capacity();
1334 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001335}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001336
1337
1338TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1339 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001340
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001341 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1342 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001343 // The max size cannot exceed the reserved size, since semispaces must be
1344 // always within the reserved space. We can't test new space growing and
1345 // shrinking if the reserved size is the same as the minimum (initial) size.
1346 return;
1347 }
1348
danno@chromium.orgc612e022011-11-10 11:38:15 +00001349 v8::HandleScope scope;
1350 NewSpace* new_space = HEAP->new_space();
1351 intptr_t old_capacity, new_capacity;
1352 old_capacity = new_space->Capacity();
1353 new_space->Grow();
1354 new_capacity = new_space->Capacity();
1355 CHECK(2 * old_capacity == new_capacity);
1356 FillUpNewSpace(new_space);
1357 HEAP->CollectAllAvailableGarbage();
1358 new_capacity = new_space->Capacity();
1359 CHECK(old_capacity == new_capacity);
1360}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001361
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001362
1363static int NumberOfGlobalObjects() {
1364 int count = 0;
1365 HeapIterator iterator;
1366 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1367 if (obj->IsGlobalObject()) count++;
1368 }
1369 return count;
1370}
1371
1372
1373// Test that we don't embed maps from foreign contexts into
1374// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001375TEST(LeakNativeContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001376 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001377 v8::HandleScope outer_scope;
1378 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1379 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1380 ctx1->Enter();
1381
1382 HEAP->CollectAllAvailableGarbage();
1383 CHECK_EQ(4, NumberOfGlobalObjects());
1384
1385 {
1386 v8::HandleScope inner_scope;
1387 CompileRun("var v = {x: 42}");
1388 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1389 ctx2->Enter();
1390 ctx2->Global()->Set(v8_str("o"), v);
1391 v8::Local<v8::Value> res = CompileRun(
1392 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001393 "for (var i = 0; i < 10; ++i) f();"
1394 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001395 "f();");
1396 CHECK_EQ(42, res->Int32Value());
1397 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1398 ctx2->Exit();
1399 ctx1->Exit();
1400 ctx1.Dispose();
1401 }
1402 HEAP->CollectAllAvailableGarbage();
1403 CHECK_EQ(2, NumberOfGlobalObjects());
1404 ctx2.Dispose();
1405 HEAP->CollectAllAvailableGarbage();
1406 CHECK_EQ(0, NumberOfGlobalObjects());
1407}
1408
1409
1410// Test that we don't embed functions from foreign contexts into
1411// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001412TEST(LeakNativeContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001413 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001414 v8::HandleScope outer_scope;
1415 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1416 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1417 ctx1->Enter();
1418
1419 HEAP->CollectAllAvailableGarbage();
1420 CHECK_EQ(4, NumberOfGlobalObjects());
1421
1422 {
1423 v8::HandleScope inner_scope;
1424 CompileRun("var v = function() { return 42; }");
1425 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1426 ctx2->Enter();
1427 ctx2->Global()->Set(v8_str("o"), v);
1428 v8::Local<v8::Value> res = CompileRun(
1429 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001430 "for (var i = 0; i < 10; ++i) f(o);"
1431 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001432 "f(o);");
1433 CHECK_EQ(42, res->Int32Value());
1434 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1435 ctx2->Exit();
1436 ctx1->Exit();
1437 ctx1.Dispose();
1438 }
1439 HEAP->CollectAllAvailableGarbage();
1440 CHECK_EQ(2, NumberOfGlobalObjects());
1441 ctx2.Dispose();
1442 HEAP->CollectAllAvailableGarbage();
1443 CHECK_EQ(0, NumberOfGlobalObjects());
1444}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001445
1446
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001447TEST(LeakNativeContextViaMapKeyed) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001448 i::FLAG_allow_natives_syntax = true;
1449 v8::HandleScope outer_scope;
1450 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1451 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1452 ctx1->Enter();
1453
1454 HEAP->CollectAllAvailableGarbage();
1455 CHECK_EQ(4, NumberOfGlobalObjects());
1456
1457 {
1458 v8::HandleScope inner_scope;
1459 CompileRun("var v = [42, 43]");
1460 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1461 ctx2->Enter();
1462 ctx2->Global()->Set(v8_str("o"), v);
1463 v8::Local<v8::Value> res = CompileRun(
1464 "function f() { return o[0]; }"
1465 "for (var i = 0; i < 10; ++i) f();"
1466 "%OptimizeFunctionOnNextCall(f);"
1467 "f();");
1468 CHECK_EQ(42, res->Int32Value());
1469 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1470 ctx2->Exit();
1471 ctx1->Exit();
1472 ctx1.Dispose();
1473 }
1474 HEAP->CollectAllAvailableGarbage();
1475 CHECK_EQ(2, NumberOfGlobalObjects());
1476 ctx2.Dispose();
1477 HEAP->CollectAllAvailableGarbage();
1478 CHECK_EQ(0, NumberOfGlobalObjects());
1479}
1480
1481
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001482TEST(LeakNativeContextViaMapProto) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001483 i::FLAG_allow_natives_syntax = true;
1484 v8::HandleScope outer_scope;
1485 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1486 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1487 ctx1->Enter();
1488
1489 HEAP->CollectAllAvailableGarbage();
1490 CHECK_EQ(4, NumberOfGlobalObjects());
1491
1492 {
1493 v8::HandleScope inner_scope;
1494 CompileRun("var v = { y: 42}");
1495 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1496 ctx2->Enter();
1497 ctx2->Global()->Set(v8_str("o"), v);
1498 v8::Local<v8::Value> res = CompileRun(
1499 "function f() {"
1500 " var p = {x: 42};"
1501 " p.__proto__ = o;"
1502 " return p.x;"
1503 "}"
1504 "for (var i = 0; i < 10; ++i) f();"
1505 "%OptimizeFunctionOnNextCall(f);"
1506 "f();");
1507 CHECK_EQ(42, res->Int32Value());
1508 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1509 ctx2->Exit();
1510 ctx1->Exit();
1511 ctx1.Dispose();
1512 }
1513 HEAP->CollectAllAvailableGarbage();
1514 CHECK_EQ(2, NumberOfGlobalObjects());
1515 ctx2.Dispose();
1516 HEAP->CollectAllAvailableGarbage();
1517 CHECK_EQ(0, NumberOfGlobalObjects());
1518}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001519
1520
1521TEST(InstanceOfStubWriteBarrier) {
1522 i::FLAG_allow_natives_syntax = true;
1523#ifdef DEBUG
1524 i::FLAG_verify_heap = true;
1525#endif
1526 InitializeVM();
1527 if (!i::V8::UseCrankshaft()) return;
1528 v8::HandleScope outer_scope;
1529
1530 {
1531 v8::HandleScope scope;
1532 CompileRun(
1533 "function foo () { }"
1534 "function mkbar () { return new (new Function(\"\")) (); }"
1535 "function f (x) { return (x instanceof foo); }"
1536 "function g () { f(mkbar()); }"
1537 "f(new foo()); f(new foo());"
1538 "%OptimizeFunctionOnNextCall(f);"
1539 "f(new foo()); g();");
1540 }
1541
1542 IncrementalMarking* marking = HEAP->incremental_marking();
1543 marking->Abort();
1544 marking->Start();
1545
1546 Handle<JSFunction> f =
1547 v8::Utils::OpenHandle(
1548 *v8::Handle<v8::Function>::Cast(
1549 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1550
1551 CHECK(f->IsOptimized());
1552
1553 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1554 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001555 // Discard any pending GC requests otherwise we will get GC when we enter
1556 // code below.
1557 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001558 }
1559
1560 CHECK(marking->IsMarking());
1561
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001562 {
1563 v8::HandleScope scope;
1564 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1565 v8::Handle<v8::Function> g =
1566 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1567 g->Call(global, 0, NULL);
1568 }
1569
1570 HEAP->incremental_marking()->set_should_hurry(true);
1571 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1572}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001573
1574
1575TEST(PrototypeTransitionClearing) {
1576 InitializeVM();
1577 v8::HandleScope scope;
1578
1579 CompileRun(
1580 "var base = {};"
1581 "var live = [];"
1582 "for (var i = 0; i < 10; i++) {"
1583 " var object = {};"
1584 " var prototype = {};"
1585 " object.__proto__ = prototype;"
1586 " if (i >= 3) live.push(object, prototype);"
1587 "}");
1588
1589 Handle<JSObject> baseObject =
1590 v8::Utils::OpenHandle(
1591 *v8::Handle<v8::Object>::Cast(
1592 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1593
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001594 // Verify that only dead prototype transitions are cleared.
1595 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001596 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001597 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001598 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001599
1600 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001601 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001602 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001603 int j = Map::kProtoTransitionHeaderSize +
1604 i * Map::kProtoTransitionElementsPerEntry;
1605 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001606 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1607 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001608 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001609
1610 // Make sure next prototype is placed on an old-space evacuation candidate.
1611 Handle<JSObject> prototype;
1612 PagedSpace* space = HEAP->old_pointer_space();
1613 do {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001614 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001615 } while (space->FirstPage() == space->LastPage() ||
1616 !space->LastPage()->Contains(prototype->address()));
1617
1618 // Add a prototype on an evacuation candidate and verify that transition
1619 // clearing correctly records slots in prototype transition array.
1620 i::FLAG_always_compact = true;
1621 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001622 CHECK(!space->LastPage()->Contains(
1623 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001624 CHECK(space->LastPage()->Contains(prototype->address()));
1625 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1626 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1627 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1628 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001629}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001630
1631
1632TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1633 i::FLAG_allow_natives_syntax = true;
1634#ifdef DEBUG
1635 i::FLAG_verify_heap = true;
1636#endif
1637 InitializeVM();
1638 if (!i::V8::UseCrankshaft()) return;
1639 v8::HandleScope outer_scope;
1640
1641 {
1642 v8::HandleScope scope;
1643 CompileRun(
1644 "function f () {"
1645 " var s = 0;"
1646 " for (var i = 0; i < 100; i++) s += i;"
1647 " return s;"
1648 "}"
1649 "f(); f();"
1650 "%OptimizeFunctionOnNextCall(f);"
1651 "f();");
1652 }
1653 Handle<JSFunction> f =
1654 v8::Utils::OpenHandle(
1655 *v8::Handle<v8::Function>::Cast(
1656 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1657 CHECK(f->IsOptimized());
1658
1659 IncrementalMarking* marking = HEAP->incremental_marking();
1660 marking->Abort();
1661 marking->Start();
1662
1663 // The following two calls will increment HEAP->global_ic_age().
1664 const int kLongIdlePauseInMs = 1000;
1665 v8::V8::ContextDisposedNotification();
1666 v8::V8::IdleNotification(kLongIdlePauseInMs);
1667
1668 while (!marking->IsStopped() && !marking->IsComplete()) {
1669 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1670 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001671 if (!marking->IsStopped() || marking->should_hurry()) {
1672 // We don't normally finish a GC via Step(), we normally finish by
1673 // setting the stack guard and then do the final steps in the stack
1674 // guard interrupt. But here we didn't ask for that, and there is no
1675 // JS code running to trigger the interrupt, so we explicitly finalize
1676 // here.
1677 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1678 "Test finalizing incremental mark-sweep");
1679 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001680
1681 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1682 CHECK_EQ(0, f->shared()->opt_count());
1683 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1684}
1685
1686
1687TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1688 i::FLAG_allow_natives_syntax = true;
1689#ifdef DEBUG
1690 i::FLAG_verify_heap = true;
1691#endif
1692 InitializeVM();
1693 if (!i::V8::UseCrankshaft()) return;
1694 v8::HandleScope outer_scope;
1695
1696 {
1697 v8::HandleScope scope;
1698 CompileRun(
1699 "function f () {"
1700 " var s = 0;"
1701 " for (var i = 0; i < 100; i++) s += i;"
1702 " return s;"
1703 "}"
1704 "f(); f();"
1705 "%OptimizeFunctionOnNextCall(f);"
1706 "f();");
1707 }
1708 Handle<JSFunction> f =
1709 v8::Utils::OpenHandle(
1710 *v8::Handle<v8::Function>::Cast(
1711 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1712 CHECK(f->IsOptimized());
1713
1714 HEAP->incremental_marking()->Abort();
1715
1716 // The following two calls will increment HEAP->global_ic_age().
1717 // Since incremental marking is off, IdleNotification will do full GC.
1718 const int kLongIdlePauseInMs = 1000;
1719 v8::V8::ContextDisposedNotification();
1720 v8::V8::IdleNotification(kLongIdlePauseInMs);
1721
1722 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1723 CHECK_EQ(0, f->shared()->opt_count());
1724 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1725}
1726
1727
1728// Test that HAllocateObject will always return an object in new-space.
1729TEST(OptimizedAllocationAlwaysInNewSpace) {
1730 i::FLAG_allow_natives_syntax = true;
1731 InitializeVM();
1732 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
1733 v8::HandleScope scope;
1734
1735 FillUpNewSpace(HEAP->new_space());
1736 AlwaysAllocateScope always_allocate;
1737 v8::Local<v8::Value> res = CompileRun(
1738 "function c(x) {"
1739 " this.x = x;"
1740 " for (var i = 0; i < 32; i++) {"
1741 " this['x' + i] = x;"
1742 " }"
1743 "}"
1744 "function f(x) { return new c(x); };"
1745 "f(1); f(2); f(3);"
1746 "%OptimizeFunctionOnNextCall(f);"
1747 "f(4);");
1748 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
1749
1750 Handle<JSObject> o =
1751 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
1752
1753 CHECK(HEAP->InNewSpace(*o));
1754}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001755
1756
1757static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00001758 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001759}
1760
1761
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001762// Go through all incremental marking steps in one swoop.
1763static void SimulateIncrementalMarking() {
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001764 IncrementalMarking* marking = HEAP->incremental_marking();
1765 CHECK(marking->IsStopped());
1766 marking->Start();
1767 CHECK(marking->IsMarking());
1768 while (!marking->IsComplete()) {
1769 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1770 }
1771 CHECK(marking->IsComplete());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001772}
1773
1774
1775// Test that map transitions are cleared and maps are collected with
1776// incremental marking as well.
1777TEST(Regress1465) {
1778 i::FLAG_allow_natives_syntax = true;
1779 i::FLAG_trace_incremental_marking = true;
1780 InitializeVM();
1781 v8::HandleScope scope;
1782 static const int transitions_count = 256;
1783
1784 {
1785 AlwaysAllocateScope always_allocate;
1786 for (int i = 0; i < transitions_count; i++) {
1787 EmbeddedVector<char, 64> buffer;
1788 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
1789 CompileRun(buffer.start());
1790 }
1791 CompileRun("var root = new Object;");
1792 }
1793
1794 Handle<JSObject> root =
1795 v8::Utils::OpenHandle(
1796 *v8::Handle<v8::Object>::Cast(
1797 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
1798
1799 // Count number of live transitions before marking.
1800 int transitions_before = CountMapTransitions(root->map());
1801 CompileRun("%DebugPrint(root);");
1802 CHECK_EQ(transitions_count, transitions_before);
1803
1804 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001805 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00001806
1807 // Count number of live transitions after marking. Note that one transition
1808 // is left, because 'o' still holds an instance of one transition target.
1809 int transitions_after = CountMapTransitions(root->map());
1810 CompileRun("%DebugPrint(root);");
1811 CHECK_EQ(1, transitions_after);
1812}
verwaest@chromium.org37141392012-05-31 13:27:02 +00001813
1814
1815TEST(Regress2143a) {
1816 i::FLAG_collect_maps = true;
1817 i::FLAG_incremental_marking = true;
1818 InitializeVM();
1819 v8::HandleScope scope;
1820
1821 // Prepare a map transition from the root object together with a yet
1822 // untransitioned root object.
1823 CompileRun("var root = new Object;"
1824 "root.foo = 0;"
1825 "root = new Object;");
1826
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001827 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00001828
1829 // Compile a StoreIC that performs the prepared map transition. This
1830 // will restart incremental marking and should make sure the root is
1831 // marked grey again.
1832 CompileRun("function f(o) {"
1833 " o.foo = 0;"
1834 "}"
1835 "f(new Object);"
1836 "f(root);");
1837
1838 // This bug only triggers with aggressive IC clearing.
1839 HEAP->AgeInlineCaches();
1840
1841 // Explicitly request GC to perform final marking step and sweeping.
1842 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00001843
1844 Handle<JSObject> root =
1845 v8::Utils::OpenHandle(
1846 *v8::Handle<v8::Object>::Cast(
1847 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
1848
1849 // The root object should be in a sane state.
1850 CHECK(root->IsJSObject());
1851 CHECK(root->map()->IsMap());
1852}
1853
1854
1855TEST(Regress2143b) {
1856 i::FLAG_collect_maps = true;
1857 i::FLAG_incremental_marking = true;
1858 i::FLAG_allow_natives_syntax = true;
1859 InitializeVM();
1860 v8::HandleScope scope;
1861
1862 // Prepare a map transition from the root object together with a yet
1863 // untransitioned root object.
1864 CompileRun("var root = new Object;"
1865 "root.foo = 0;"
1866 "root = new Object;");
1867
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001868 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00001869
1870 // Compile an optimized LStoreNamedField that performs the prepared
1871 // map transition. This will restart incremental marking and should
1872 // make sure the root is marked grey again.
1873 CompileRun("function f(o) {"
1874 " o.foo = 0;"
1875 "}"
1876 "f(new Object);"
1877 "f(new Object);"
1878 "%OptimizeFunctionOnNextCall(f);"
1879 "f(root);"
1880 "%DeoptimizeFunction(f);");
1881
1882 // This bug only triggers with aggressive IC clearing.
1883 HEAP->AgeInlineCaches();
1884
1885 // Explicitly request GC to perform final marking step and sweeping.
1886 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00001887
1888 Handle<JSObject> root =
1889 v8::Utils::OpenHandle(
1890 *v8::Handle<v8::Object>::Cast(
1891 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
1892
1893 // The root object should be in a sane state.
1894 CHECK(root->IsJSObject());
1895 CHECK(root->map()->IsMap());
1896}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001897
1898
1899// Implemented in the test-alloc.cc test suite.
1900void SimulateFullSpace(PagedSpace* space);
1901
1902
1903TEST(ReleaseOverReservedPages) {
1904 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001905 // The optimizer can allocate stuff, messing up the test.
1906 i::FLAG_crankshaft = false;
1907 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001908 InitializeVM();
1909 v8::HandleScope scope;
1910 static const int number_of_test_pages = 20;
1911
1912 // Prepare many pages with low live-bytes count.
1913 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
1914 CHECK_EQ(1, old_pointer_space->CountTotalPages());
1915 for (int i = 0; i < number_of_test_pages; i++) {
1916 AlwaysAllocateScope always_allocate;
1917 SimulateFullSpace(old_pointer_space);
1918 FACTORY->NewFixedArray(1, TENURED);
1919 }
1920 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
1921
1922 // Triggering one GC will cause a lot of garbage to be discovered but
1923 // even spread across all allocated pages.
1924 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
1925 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
1926
1927 // Triggering subsequent GCs should cause at least half of the pages
1928 // to be released to the OS after at most two cycles.
1929 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
1930 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
1931 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
1932 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
1933
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001934 // Triggering a last-resort GC should cause all pages to be released to the
1935 // OS so that other processes can seize the memory. If we get a failure here
1936 // where there are 2 pages left instead of 1, then we should increase the
1937 // size of the first page a little in SizeOfFirstPage in spaces.cc. The
1938 // first page should be small in order to reduce memory used when the VM
1939 // boots, but if the 20 small arrays don't fit on the first page then that's
1940 // an indication that it is too small.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00001941 HEAP->CollectAllAvailableGarbage("triggered really hard");
1942 CHECK_EQ(1, old_pointer_space->CountTotalPages());
1943}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00001944
1945
1946TEST(Regress2237) {
1947 InitializeVM();
1948 v8::HandleScope scope;
1949 Handle<String> slice(HEAP->empty_string());
1950
1951 {
1952 // Generate a parent that lives in new-space.
1953 v8::HandleScope inner_scope;
1954 const char* c = "This text is long enough to trigger sliced strings.";
1955 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
1956 CHECK(s->IsSeqAsciiString());
1957 CHECK(HEAP->InNewSpace(*s));
1958
1959 // Generate a sliced string that is based on the above parent and
1960 // lives in old-space.
1961 FillUpNewSpace(HEAP->new_space());
1962 AlwaysAllocateScope always_allocate;
1963 Handle<String> t;
1964 // TODO(mstarzinger): Unfortunately FillUpNewSpace() still leaves
1965 // some slack, so we need to allocate a few sliced strings.
1966 for (int i = 0; i < 16; i++) {
1967 t = FACTORY->NewProperSubString(s, 5, 35);
1968 }
1969 CHECK(t->IsSlicedString());
1970 CHECK(!HEAP->InNewSpace(*t));
1971 *slice.location() = *t.location();
1972 }
1973
1974 CHECK(SlicedString::cast(*slice)->parent()->IsSeqAsciiString());
1975 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1976 CHECK(SlicedString::cast(*slice)->parent()->IsSeqAsciiString());
1977}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00001978
1979
1980#ifdef OBJECT_PRINT
1981TEST(PrintSharedFunctionInfo) {
1982 InitializeVM();
1983 v8::HandleScope scope;
1984 const char* source = "f = function() { return 987654321; }\n"
1985 "g = function() { return 123456789; }\n";
1986 CompileRun(source);
1987 Handle<JSFunction> g =
1988 v8::Utils::OpenHandle(
1989 *v8::Handle<v8::Function>::Cast(
1990 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
1991
1992 AssertNoAllocation no_alloc;
1993 g->shared()->PrintLn();
1994}
1995#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00001996
1997
1998TEST(Regress2211) {
1999 InitializeVM();
2000 v8::HandleScope scope;
2001
2002 v8::Handle<v8::String> value = v8_str("val string");
2003 Smi* hash = Smi::FromInt(321);
2004 Heap* heap = Isolate::Current()->heap();
2005
2006 for (int i = 0; i < 2; i++) {
2007 // Store identity hash first and common hidden property second.
2008 v8::Handle<v8::Object> obj = v8::Object::New();
2009 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2010 CHECK(internal_obj->HasFastProperties());
2011
2012 // In the first iteration, set hidden value first and identity hash second.
2013 // In the second iteration, reverse the order.
2014 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2015 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2016 ALLOW_CREATION);
2017 CHECK(!maybe_obj->IsFailure());
2018 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2019
2020 // Check values.
2021 CHECK_EQ(hash,
2022 internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
2023 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2024
2025 // Check size.
2026 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2027 ObjectHashTable* hashtable = ObjectHashTable::cast(
2028 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2029 // HashTable header (5) and 4 initial entries (8).
2030 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2031 }
2032}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002033
2034
2035TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2036 if (i::FLAG_always_opt) return;
2037 InitializeVM();
2038 v8::HandleScope scope;
2039 v8::Local<v8::Value> fun1, fun2;
2040
2041 {
2042 LocalContext env;
2043 CompileRun("function fun() {};");
2044 fun1 = env->Global()->Get(v8_str("fun"));
2045 }
2046
2047 {
2048 LocalContext env;
2049 CompileRun("function fun() {};");
2050 fun2 = env->Global()->Get(v8_str("fun"));
2051 }
2052
2053 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002054 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002055 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2056 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2057 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2058 Handle<JSFunction> f =
2059 v8::Utils::OpenHandle(
2060 *v8::Handle<v8::Function>::Cast(
2061 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2062 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2063 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2064
2065 CHECK_EQ(2, cells->CellCount());
2066 CHECK(cells->Cell(0)->value()->IsJSFunction());
2067 CHECK(cells->Cell(1)->value()->IsJSFunction());
2068
2069 SimulateIncrementalMarking();
2070 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2071
2072 CHECK_EQ(2, cells->CellCount());
2073 CHECK(cells->Cell(0)->value()->IsTheHole());
2074 CHECK(cells->Cell(1)->value()->IsTheHole());
2075}
2076
2077
2078static Code* FindFirstIC(Code* code, Code::Kind kind) {
2079 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2080 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2081 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2082 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2083 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2084 RelocInfo* info = it.rinfo();
2085 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2086 if (target->is_inline_cache_stub() && target->kind() == kind) {
2087 return target;
2088 }
2089 }
2090 return NULL;
2091}
2092
2093
2094TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2095 if (i::FLAG_always_opt) return;
2096 InitializeVM();
2097 v8::HandleScope scope;
2098
2099 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002100 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002101 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2102 "function f(o) { return o.x; } f(obj); f(obj);");
2103 Handle<JSFunction> f =
2104 v8::Utils::OpenHandle(
2105 *v8::Handle<v8::Function>::Cast(
2106 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2107
2108 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2109 CHECK(ic_before->ic_state() == MONOMORPHIC);
2110
danno@chromium.orgeb831462012-08-24 11:57:08 +00002111 // Fire context dispose notification.
2112 v8::V8::ContextDisposedNotification();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002113 SimulateIncrementalMarking();
2114 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2115
2116 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2117 CHECK(ic_after->ic_state() == MONOMORPHIC);
2118}
2119
2120
2121TEST(IncrementalMarkingClearsMonomorhpicIC) {
2122 if (i::FLAG_always_opt) return;
2123 InitializeVM();
2124 v8::HandleScope scope;
2125 v8::Local<v8::Value> obj1;
2126
2127 {
2128 LocalContext env;
2129 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2130 obj1 = env->Global()->Get(v8_str("obj"));
2131 }
2132
2133 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002134 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002135 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2136 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2137 Handle<JSFunction> f =
2138 v8::Utils::OpenHandle(
2139 *v8::Handle<v8::Function>::Cast(
2140 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2141
2142 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2143 CHECK(ic_before->ic_state() == MONOMORPHIC);
2144
2145 // Fire context dispose notification.
2146 v8::V8::ContextDisposedNotification();
2147 SimulateIncrementalMarking();
2148 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2149
2150 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2151 CHECK(ic_after->ic_state() == UNINITIALIZED);
2152}
2153
2154
2155TEST(IncrementalMarkingClearsPolymorhpicIC) {
2156 if (i::FLAG_always_opt) return;
2157 InitializeVM();
2158 v8::HandleScope scope;
2159 v8::Local<v8::Value> obj1, obj2;
2160
2161 {
2162 LocalContext env;
2163 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2164 obj1 = env->Global()->Get(v8_str("obj"));
2165 }
2166
2167 {
2168 LocalContext env;
2169 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2170 obj2 = env->Global()->Get(v8_str("obj"));
2171 }
2172
2173 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002174 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002175 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2176 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2177 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2178 Handle<JSFunction> f =
2179 v8::Utils::OpenHandle(
2180 *v8::Handle<v8::Function>::Cast(
2181 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2182
2183 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2184 CHECK(ic_before->ic_state() == MEGAMORPHIC);
2185
2186 // Fire context dispose notification.
2187 v8::V8::ContextDisposedNotification();
2188 SimulateIncrementalMarking();
2189 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2190
2191 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2192 CHECK(ic_after->ic_state() == UNINITIALIZED);
2193}
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002194
2195
2196class SourceResource: public v8::String::ExternalAsciiStringResource {
2197 public:
2198 explicit SourceResource(const char* data)
2199 : data_(data), length_(strlen(data)) { }
2200
2201 virtual void Dispose() {
2202 i::DeleteArray(data_);
2203 data_ = NULL;
2204 }
2205
2206 const char* data() const { return data_; }
2207
2208 size_t length() const { return length_; }
2209
2210 bool IsDisposed() { return data_ == NULL; }
2211
2212 private:
2213 const char* data_;
2214 size_t length_;
2215};
2216
2217
2218TEST(ReleaseStackTraceData) {
2219 // Test that the data retained by the Error.stack accessor is released
2220 // after the first time the accessor is fired. We use external string
2221 // to check whether the data is being released since the external string
2222 // resource's callback is fired when the external string is GC'ed.
2223 InitializeVM();
2224 v8::HandleScope scope;
2225 static const char* source = "var error = 1; "
2226 "try { "
2227 " throw new Error(); "
2228 "} catch (e) { "
2229 " error = e; "
2230 "} ";
2231 SourceResource* resource = new SourceResource(i::StrDup(source));
2232 {
2233 v8::HandleScope scope;
2234 v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
2235 v8::Script::Compile(source_string)->Run();
2236 CHECK(!resource->IsDisposed());
2237 }
2238 HEAP->CollectAllAvailableGarbage();
2239 // External source is being retained by the stack trace.
2240 CHECK(!resource->IsDisposed());
2241
2242 CompileRun("error.stack; error.stack;");
2243 HEAP->CollectAllAvailableGarbage();
2244 // External source has been released.
2245 CHECK(resource->IsDisposed());
2246
2247 delete resource;
2248}
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002249
2250
2251TEST(Regression144230) {
2252 InitializeVM();
2253 v8::HandleScope scope;
2254
2255 // First make sure that the uninitialized CallIC stub is on a single page
2256 // that will later be selected as an evacuation candidate.
2257 {
2258 v8::HandleScope inner_scope;
2259 AlwaysAllocateScope always_allocate;
2260 SimulateFullSpace(HEAP->code_space());
2261 ISOLATE->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET);
2262 }
2263
2264 // Second compile a CallIC and execute it once so that it gets patched to
2265 // the pre-monomorphic stub. These code objects are on yet another page.
2266 {
2267 v8::HandleScope inner_scope;
2268 AlwaysAllocateScope always_allocate;
2269 SimulateFullSpace(HEAP->code_space());
2270 CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};"
2271 "function call() { o.f(1,2,3,4,5,6,7,8,9); };"
2272 "call();");
2273 }
2274
2275 // Third we fill up the last page of the code space so that it does not get
2276 // chosen as an evacuation candidate.
2277 {
2278 v8::HandleScope inner_scope;
2279 AlwaysAllocateScope always_allocate;
2280 CompileRun("for (var i = 0; i < 2000; i++) {"
2281 " eval('function f' + i + '() { return ' + i +'; };' +"
2282 " 'f' + i + '();');"
2283 "}");
2284 }
2285 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2286
2287 // Fourth is the tricky part. Make sure the code containing the CallIC is
2288 // visited first without clearing the IC. The shared function info is then
2289 // visited later, causing the CallIC to be cleared.
2290 Handle<String> name = FACTORY->LookupAsciiSymbol("call");
2291 Handle<GlobalObject> global(ISOLATE->context()->global_object());
2292 MaybeObject* maybe_call = global->GetProperty(*name);
2293 JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
2294 USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode));
2295 ISOLATE->compilation_cache()->Clear();
2296 call->shared()->set_ic_age(HEAP->global_ic_age() + 1);
2297 Handle<Object> call_code(call->code());
2298 Handle<Object> call_function(call);
2299
2300 // Now we are ready to mess up the heap.
2301 HEAP->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
2302
2303 // Either heap verification caught the problem already or we go kaboom once
2304 // the CallIC is executed the next time.
2305 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode));
2306 CompileRun("call();");
2307}