blob: 9308eb752ed9874adafb0ab5200c263f375ab63c [file] [log] [blame]
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001// Copyright 2012 the V8 project authors. All rights reserved.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002
3#include <stdlib.h>
4
5#include "v8.h"
6
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00007#include "compilation-cache.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00008#include "execution.h"
9#include "factory.h"
10#include "macro-assembler.h"
11#include "global-handles.h"
verwaest@chromium.org33e09c82012-10-10 17:07:22 +000012#include "stub-cache.h"
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000013#include "cctest.h"
14
15using namespace v8::internal;
16
17static v8::Persistent<v8::Context> env;
18
19static void InitializeVM() {
20 if (env.IsEmpty()) env = v8::Context::New();
21 v8::HandleScope scope;
22 env->Enter();
23}
24
25
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000026// Go through all incremental marking steps in one swoop.
27static void SimulateIncrementalMarking() {
28 IncrementalMarking* marking = HEAP->incremental_marking();
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +000029 CHECK(marking->IsMarking() || marking->IsStopped());
30 if (marking->IsStopped()) {
31 marking->Start();
32 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +000033 CHECK(marking->IsMarking());
34 while (!marking->IsComplete()) {
35 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
36 }
37 CHECK(marking->IsComplete());
38}
39
40
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000041static void CheckMap(Map* map, int type, int instance_size) {
42 CHECK(map->IsHeapObject());
43#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000044 CHECK(HEAP->Contains(map));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000045#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000046 CHECK_EQ(HEAP->meta_map(), map->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000047 CHECK_EQ(type, map->instance_type());
48 CHECK_EQ(instance_size, map->instance_size());
49}
50
51
52TEST(HeapMaps) {
53 InitializeVM();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000054 CheckMap(HEAP->meta_map(), MAP_TYPE, Map::kSize);
55 CheckMap(HEAP->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
56 CheckMap(HEAP->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
57 CheckMap(HEAP->string_map(), STRING_TYPE, kVariableSizeSentinel);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000058}
59
60
61static void CheckOddball(Object* obj, const char* string) {
62 CHECK(obj->IsOddball());
63 bool exc;
64 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000065 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000066}
67
68
69static void CheckSmi(int value, const char* string) {
70 bool exc;
71 Object* print_string =
72 *Execution::ToString(Handle<Object>(Smi::FromInt(value)), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000073 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000074}
75
76
77static void CheckNumber(double value, const char* string) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000078 Object* obj = HEAP->NumberFromDouble(value)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000079 CHECK(obj->IsNumber());
80 bool exc;
81 Object* print_string = *Execution::ToString(Handle<Object>(obj), &exc);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +000082 CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000083}
84
85
86static void CheckFindCodeObject() {
87 // Test FindCodeObject
88#define __ assm.
89
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000090 Assembler assm(Isolate::Current(), NULL, 0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000091
92 __ nop(); // supported on all architectures
93
94 CodeDesc desc;
95 assm.GetCode(&desc);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000096 Object* code = HEAP->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +000097 desc,
98 Code::ComputeFlags(Code::STUB),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000099 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000100 CHECK(code->IsCode());
101
102 HeapObject* obj = HeapObject::cast(code);
103 Address obj_addr = obj->address();
104
105 for (int i = 0; i < obj->Size(); i += kPointerSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000106 Object* found = HEAP->FindCodeObject(obj_addr + i);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000107 CHECK_EQ(code, found);
108 }
109
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000110 Object* copy = HEAP->CreateCode(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000111 desc,
112 Code::ComputeFlags(Code::STUB),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000113 Handle<Object>(HEAP->undefined_value()))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000114 CHECK(copy->IsCode());
115 HeapObject* obj_copy = HeapObject::cast(copy);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000116 Object* not_right = HEAP->FindCodeObject(obj_copy->address() +
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000117 obj_copy->Size() / 2);
118 CHECK(not_right != code);
119}
120
121
122TEST(HeapObjects) {
123 InitializeVM();
124
125 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000126 Object* value = HEAP->NumberFromDouble(1.000123)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000127 CHECK(value->IsHeapNumber());
128 CHECK(value->IsNumber());
129 CHECK_EQ(1.000123, value->Number());
130
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000131 value = HEAP->NumberFromDouble(1.0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000132 CHECK(value->IsSmi());
133 CHECK(value->IsNumber());
134 CHECK_EQ(1.0, value->Number());
135
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000136 value = HEAP->NumberFromInt32(1024)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000137 CHECK(value->IsSmi());
138 CHECK(value->IsNumber());
139 CHECK_EQ(1024.0, value->Number());
140
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000141 value = HEAP->NumberFromInt32(Smi::kMinValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000142 CHECK(value->IsSmi());
143 CHECK(value->IsNumber());
144 CHECK_EQ(Smi::kMinValue, Smi::cast(value)->value());
145
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000146 value = HEAP->NumberFromInt32(Smi::kMaxValue)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000147 CHECK(value->IsSmi());
148 CHECK(value->IsNumber());
149 CHECK_EQ(Smi::kMaxValue, Smi::cast(value)->value());
150
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000151#ifndef V8_TARGET_ARCH_X64
152 // TODO(lrn): We need a NumberFromIntptr function in order to test this.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000153 value = HEAP->NumberFromInt32(Smi::kMinValue - 1)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000154 CHECK(value->IsHeapNumber());
155 CHECK(value->IsNumber());
156 CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000157#endif
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000158
lrn@chromium.org303ada72010-10-27 09:33:13 +0000159 MaybeObject* maybe_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 HEAP->NumberFromUint32(static_cast<uint32_t>(Smi::kMaxValue) + 1);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 value = maybe_value->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000162 CHECK(value->IsHeapNumber());
163 CHECK(value->IsNumber());
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +0000164 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
165 value->Number());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000166
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000167 maybe_value = HEAP->NumberFromUint32(static_cast<uint32_t>(1) << 31);
168 value = maybe_value->ToObjectChecked();
169 CHECK(value->IsHeapNumber());
170 CHECK(value->IsNumber());
171 CHECK_EQ(static_cast<double>(static_cast<uint32_t>(1) << 31),
172 value->Number());
173
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000174 // nan oddball checks
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000175 CHECK(HEAP->nan_value()->IsNumber());
176 CHECK(isnan(HEAP->nan_value()->Number()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000177
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000178 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector("fisk hest "));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000179 CHECK(s->IsString());
180 CHECK_EQ(10, s->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000181
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000182 String* object_symbol = String::cast(HEAP->Object_symbol());
183 CHECK(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000184 Isolate::Current()->context()->global_object()->HasLocalProperty(
185 object_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000186
187 // Check ToString for oddballs
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000188 CheckOddball(HEAP->true_value(), "true");
189 CheckOddball(HEAP->false_value(), "false");
190 CheckOddball(HEAP->null_value(), "null");
191 CheckOddball(HEAP->undefined_value(), "undefined");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000192
193 // Check ToString for Smis
194 CheckSmi(0, "0");
195 CheckSmi(42, "42");
196 CheckSmi(-42, "-42");
197
198 // Check ToString for Numbers
199 CheckNumber(1.1, "1.1");
200
201 CheckFindCodeObject();
202}
203
204
205TEST(Tagging) {
206 InitializeVM();
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000207 int request = 24;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000208 CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000209 CHECK(Smi::FromInt(42)->IsSmi());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000210 CHECK(Failure::RetryAfterGC(NEW_SPACE)->IsFailure());
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000211 CHECK_EQ(NEW_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000212 Failure::RetryAfterGC(NEW_SPACE)->allocation_space());
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000213 CHECK_EQ(OLD_POINTER_SPACE,
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000214 Failure::RetryAfterGC(OLD_POINTER_SPACE)->allocation_space());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000215 CHECK(Failure::Exception()->IsFailure());
216 CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
217 CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
218}
219
220
221TEST(GarbageCollection) {
222 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000223 Isolate* isolate = Isolate::Current();
224 Heap* heap = isolate->heap();
225 Factory* factory = isolate->factory();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000226
227 v8::HandleScope sc;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000228 // Check GC.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000229 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000230
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000231 Handle<String> name = factory->LookupUtf8Symbol("theFunction");
232 Handle<String> prop_name = factory->LookupUtf8Symbol("theSlot");
233 Handle<String> prop_namex = factory->LookupUtf8Symbol("theSlotx");
234 Handle<String> obj_name = factory->LookupUtf8Symbol("theObject");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000235
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000236 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000237 HandleScope inner_scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000238 // Allocate a function and keep it in global object's property.
239 Handle<JSFunction> function =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000240 factory->NewFunction(name, factory->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000241 Handle<Map> initial_map =
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000242 factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000243 function->set_initial_map(*initial_map);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000244 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000245 *name, *function, NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000246 // Allocate an object. Unrooted after leaving the scope.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000247 Handle<JSObject> obj = factory->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000248 obj->SetProperty(
249 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
250 obj->SetProperty(
251 *prop_namex, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000252
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000253 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
254 CHECK_EQ(Smi::FromInt(24), obj->GetProperty(*prop_namex));
255 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000256
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000257 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000258
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000259 // Function should be alive.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000260 CHECK(Isolate::Current()->context()->global_object()->
261 HasLocalProperty(*name));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000262 // Check function is retained.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000263 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000264 GetProperty(*name)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000265 CHECK(func_value->IsJSFunction());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000266 Handle<JSFunction> function(JSFunction::cast(func_value));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000267
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000268 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000269 HandleScope inner_scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000270 // Allocate another object, make it reachable from global.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000271 Handle<JSObject> obj = factory->NewJSObject(function);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000272 Isolate::Current()->context()->global_object()->SetProperty(
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000273 *obj_name, *obj, NONE, kNonStrictMode)->ToObjectChecked();
274 obj->SetProperty(
275 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000276 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000277
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000278 // After gc, it should survive.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000279 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000280
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000281 CHECK(Isolate::Current()->context()->global_object()->
282 HasLocalProperty(*obj_name));
283 CHECK(Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000284 GetProperty(*obj_name)->ToObjectChecked()->IsJSObject());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000285 Object* obj = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000286 GetProperty(*obj_name)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000287 JSObject* js_obj = JSObject::cast(obj);
288 CHECK_EQ(Smi::FromInt(23), js_obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000289}
290
291
292static void VerifyStringAllocation(const char* string) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000293 v8::HandleScope scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000294 Handle<String> s = FACTORY->NewStringFromUtf8(CStrVector(string));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000295 CHECK_EQ(StrLength(string), s->length());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000296 for (int index = 0; index < s->length(); index++) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000297 CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
298 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000299}
300
301
302TEST(String) {
303 InitializeVM();
304
305 VerifyStringAllocation("a");
306 VerifyStringAllocation("ab");
307 VerifyStringAllocation("abc");
308 VerifyStringAllocation("abcd");
309 VerifyStringAllocation("fiskerdrengen er paa havet");
310}
311
312
313TEST(LocalHandles) {
314 InitializeVM();
315
316 v8::HandleScope scope;
317 const char* name = "Kasper the spunky";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000318 Handle<String> string = FACTORY->NewStringFromAscii(CStrVector(name));
ager@chromium.orgc4c92722009-11-18 14:12:51 +0000319 CHECK_EQ(StrLength(name), string->length());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000320}
321
322
323TEST(GlobalHandles) {
324 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000325 Isolate* isolate = Isolate::Current();
326 Heap* heap = isolate->heap();
327 Factory* factory = isolate->factory();
328 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000329
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000330 Handle<Object> h1;
331 Handle<Object> h2;
332 Handle<Object> h3;
333 Handle<Object> h4;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000334
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000335 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000336 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000337
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000338 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
339 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000340
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000341 h1 = global_handles->Create(*i);
342 h2 = global_handles->Create(*u);
343 h3 = global_handles->Create(*i);
344 h4 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000345 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000346
347 // after gc, it should survive
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000348 heap->CollectGarbage(NEW_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000349
350 CHECK((*h1)->IsString());
351 CHECK((*h2)->IsHeapNumber());
352 CHECK((*h3)->IsString());
353 CHECK((*h4)->IsHeapNumber());
354
355 CHECK_EQ(*h3, *h1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000356 global_handles->Destroy(h1.location());
357 global_handles->Destroy(h3.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000358
359 CHECK_EQ(*h4, *h2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 global_handles->Destroy(h2.location());
361 global_handles->Destroy(h4.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000362}
363
364
365static bool WeakPointerCleared = false;
366
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000367static void TestWeakGlobalHandleCallback(v8::Isolate* isolate,
368 v8::Persistent<v8::Value> handle,
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000369 void* id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +0000370 if (1234 == reinterpret_cast<intptr_t>(id)) WeakPointerCleared = true;
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000371 handle.Dispose(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000372}
373
374
375TEST(WeakGlobalHandlesScavenge) {
376 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000377 Isolate* isolate = Isolate::Current();
378 Heap* heap = isolate->heap();
379 Factory* factory = isolate->factory();
380 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000381
382 WeakPointerCleared = false;
383
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000384 Handle<Object> h1;
385 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000386
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000387 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000388 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000389
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000390 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
391 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000392
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000393 h1 = global_handles->Create(*i);
394 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000395 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000396
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 global_handles->MakeWeak(h2.location(),
398 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000399 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000400 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000401
402 // Scavenge treats weak pointers as normal roots.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000403 heap->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000404
405 CHECK((*h1)->IsString());
406 CHECK((*h2)->IsHeapNumber());
407
408 CHECK(!WeakPointerCleared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000409 CHECK(!global_handles->IsNearDeath(h2.location()));
410 CHECK(!global_handles->IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000411
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000412 global_handles->Destroy(h1.location());
413 global_handles->Destroy(h2.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000414}
415
416
417TEST(WeakGlobalHandlesMark) {
418 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000419 Isolate* isolate = Isolate::Current();
420 Heap* heap = isolate->heap();
421 Factory* factory = isolate->factory();
422 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000423
424 WeakPointerCleared = false;
425
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000426 Handle<Object> h1;
427 Handle<Object> h2;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000428
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000429 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000430 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000431
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000432 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
433 Handle<Object> u = factory->NewNumber(1.12344);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000434
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 h1 = global_handles->Create(*i);
436 h2 = global_handles->Create(*u);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000437 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000438
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000439 // Make sure the objects are promoted.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000440 heap->CollectGarbage(OLD_POINTER_SPACE);
441 heap->CollectGarbage(NEW_SPACE);
442 CHECK(!heap->InNewSpace(*h1) && !heap->InNewSpace(*h2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000443
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000444 global_handles->MakeWeak(h2.location(),
445 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000446 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000447 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000448 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
449 CHECK(!GlobalHandles::IsNearDeath(h2.location()));
450
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +0000451 // Incremental marking potentially marked handles before they turned weak.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000452 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000453
454 CHECK((*h1)->IsString());
455
456 CHECK(WeakPointerCleared);
457 CHECK(!GlobalHandles::IsNearDeath(h1.location()));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000459 global_handles->Destroy(h1.location());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000460}
461
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000462
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000463TEST(DeleteWeakGlobalHandle) {
464 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000465 Isolate* isolate = Isolate::Current();
466 Heap* heap = isolate->heap();
467 Factory* factory = isolate->factory();
468 GlobalHandles* global_handles = isolate->global_handles();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000469
470 WeakPointerCleared = false;
471
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000472 Handle<Object> h;
473
474 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000475 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000476
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000477 Handle<Object> i = factory->NewStringFromAscii(CStrVector("fisk"));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000478 h = global_handles->Create(*i);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000479 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000480
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000481 global_handles->MakeWeak(h.location(),
482 reinterpret_cast<void*>(1234),
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +0000483 NULL,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000484 &TestWeakGlobalHandleCallback);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000485
486 // Scanvenge does not recognize weak reference.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000487 heap->PerformScavenge();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000488
489 CHECK(!WeakPointerCleared);
490
491 // Mark-compact treats weak reference properly.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +0000492 heap->CollectGarbage(OLD_POINTER_SPACE);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000493
494 CHECK(WeakPointerCleared);
495}
496
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000497
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000498static const char* not_so_random_string_table[] = {
499 "abstract",
500 "boolean",
501 "break",
502 "byte",
503 "case",
504 "catch",
505 "char",
506 "class",
507 "const",
508 "continue",
509 "debugger",
510 "default",
511 "delete",
512 "do",
513 "double",
514 "else",
515 "enum",
516 "export",
517 "extends",
518 "false",
519 "final",
520 "finally",
521 "float",
522 "for",
523 "function",
524 "goto",
525 "if",
526 "implements",
527 "import",
528 "in",
529 "instanceof",
530 "int",
531 "interface",
532 "long",
533 "native",
534 "new",
535 "null",
536 "package",
537 "private",
538 "protected",
539 "public",
540 "return",
541 "short",
542 "static",
543 "super",
544 "switch",
545 "synchronized",
546 "this",
547 "throw",
548 "throws",
549 "transient",
550 "true",
551 "try",
552 "typeof",
553 "var",
554 "void",
555 "volatile",
556 "while",
557 "with",
558 0
559};
560
561
562static void CheckSymbols(const char** strings) {
563 for (const char* string = *strings; *strings != 0; string = *strings++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000564 Object* a;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000565 MaybeObject* maybe_a = HEAP->LookupUtf8Symbol(string);
566 // LookupUtf8Symbol may return a failure if a GC is needed.
lrn@chromium.org303ada72010-10-27 09:33:13 +0000567 if (!maybe_a->ToObject(&a)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000568 CHECK(a->IsSymbol());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000569 Object* b;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000570 MaybeObject* maybe_b = HEAP->LookupUtf8Symbol(string);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000571 if (!maybe_b->ToObject(&b)) continue;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000572 CHECK_EQ(b, a);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000573 CHECK(String::cast(b)->IsUtf8EqualTo(CStrVector(string)));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000574 }
575}
576
577
578TEST(SymbolTable) {
579 InitializeVM();
580
581 CheckSymbols(not_so_random_string_table);
582 CheckSymbols(not_so_random_string_table);
583}
584
585
586TEST(FunctionAllocation) {
587 InitializeVM();
588
589 v8::HandleScope sc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000590 Handle<String> name = FACTORY->LookupUtf8Symbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000591 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000592 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000593 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000594 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000595 function->set_initial_map(*initial_map);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000596
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000597 Handle<String> prop_name = FACTORY->LookupUtf8Symbol("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 Handle<JSObject> obj = FACTORY->NewJSObject(function);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000599 obj->SetProperty(
600 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000601 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000602 // Check that we can add properties to function objects.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000603 function->SetProperty(
604 *prop_name, Smi::FromInt(24), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000605 CHECK_EQ(Smi::FromInt(24), function->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000606}
607
608
609TEST(ObjectProperties) {
610 InitializeVM();
611
612 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000614 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000615 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000616 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000617 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000619 Handle<String> first = FACTORY->LookupUtf8Symbol("first");
620 Handle<String> second = FACTORY->LookupUtf8Symbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000621
622 // check for empty
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000623 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000624
625 // add first
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000626 obj->SetProperty(
627 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000628 CHECK(obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000629
630 // delete first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000631 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
632 CHECK(!obj->HasLocalProperty(*first));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000633
634 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000635 obj->SetProperty(
636 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
637 obj->SetProperty(
638 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000639 CHECK(obj->HasLocalProperty(*first));
640 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000641
642 // delete first and then second
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000643 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
644 CHECK(obj->HasLocalProperty(*second));
645 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
646 CHECK(!obj->HasLocalProperty(*first));
647 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000648
649 // add first and then second
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000650 obj->SetProperty(
651 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
652 obj->SetProperty(
653 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000654 CHECK(obj->HasLocalProperty(*first));
655 CHECK(obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000656
657 // delete second and then first
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000658 CHECK(obj->DeleteProperty(*second, JSObject::NORMAL_DELETION));
659 CHECK(obj->HasLocalProperty(*first));
660 CHECK(obj->DeleteProperty(*first, JSObject::NORMAL_DELETION));
661 CHECK(!obj->HasLocalProperty(*first));
662 CHECK(!obj->HasLocalProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000663
664 // check string and symbol match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000665 const char* string1 = "fisk";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000666 Handle<String> s1 = FACTORY->NewStringFromAscii(CStrVector(string1));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000667 obj->SetProperty(
668 *s1, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000669 Handle<String> s1_symbol = FACTORY->LookupUtf8Symbol(string1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000670 CHECK(obj->HasLocalProperty(*s1_symbol));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000671
672 // check symbol and string match
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000673 const char* string2 = "fugl";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000674 Handle<String> s2_symbol = FACTORY->LookupUtf8Symbol(string2);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000675 obj->SetProperty(
676 *s2_symbol, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000677 Handle<String> s2 = FACTORY->NewStringFromAscii(CStrVector(string2));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000678 CHECK(obj->HasLocalProperty(*s2));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000679}
680
681
682TEST(JSObjectMaps) {
683 InitializeVM();
684
685 v8::HandleScope sc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000686 Handle<String> name = FACTORY->LookupUtf8Symbol("theFunction");
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000687 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000688 FACTORY->NewFunction(name, FACTORY->undefined_value());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000689 Handle<Map> initial_map =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000690 FACTORY->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000691 function->set_initial_map(*initial_map);
692
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000693 Handle<String> prop_name = FACTORY->LookupUtf8Symbol("theSlot");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000694 Handle<JSObject> obj = FACTORY->NewJSObject(function);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000695
696 // Set a propery
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000697 obj->SetProperty(
698 *prop_name, Smi::FromInt(23), NONE, kNonStrictMode)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000699 CHECK_EQ(Smi::FromInt(23), obj->GetProperty(*prop_name));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000700
701 // Check the map has changed
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000702 CHECK(*initial_map != obj->map());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000703}
704
705
706TEST(JSArray) {
707 InitializeVM();
708
709 v8::HandleScope sc;
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000710 Handle<String> name = FACTORY->LookupUtf8Symbol("Array");
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000711 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000712 GetProperty(*name)->ToObjectChecked();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000713 Handle<JSFunction> function = Handle<JSFunction>(
lrn@chromium.org303ada72010-10-27 09:33:13 +0000714 JSFunction::cast(raw_object));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000715
716 // Allocate the object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000717 Handle<JSObject> object = FACTORY->NewJSObject(function);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000718 Handle<JSArray> array = Handle<JSArray>::cast(object);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000719 // We just initialized the VM, no heap allocation failure yet.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000720 array->Initialize(0)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000721
722 // Set array length to 0.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000723 array->SetElementsLength(Smi::FromInt(0))->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000724 CHECK_EQ(Smi::FromInt(0), array->length());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000725 // Must be in fast mode.
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000726 CHECK(array->HasFastSmiOrObjectElements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000727
728 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000729 array->SetElement(0, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000730 CHECK_EQ(Smi::FromInt(1), array->length());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000731 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000732
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000733 // Set array length with larger than smi value.
734 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000735 FACTORY->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000736 array->SetElementsLength(*length)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000737
738 uint32_t int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000739 CHECK(length->ToArrayIndex(&int_length));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000740 CHECK_EQ(*length, array->length());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000741 CHECK(array->HasDictionaryElements()); // Must be in slow mode.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000742
743 // array[length] = name.
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000744 array->SetElement(int_length, *name, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000745 uint32_t new_int_length = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000746 CHECK(array->length()->ToArrayIndex(&new_int_length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000747 CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000748 CHECK_EQ(array->GetElement(int_length), *name);
749 CHECK_EQ(array->GetElement(0), *name);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000750}
751
752
753TEST(JSObjectCopy) {
754 InitializeVM();
755
756 v8::HandleScope sc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000757 String* object_symbol = String::cast(HEAP->Object_symbol());
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000758 Object* raw_object = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000759 GetProperty(object_symbol)->ToObjectChecked();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000760 JSFunction* object_function = JSFunction::cast(raw_object);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000761 Handle<JSFunction> constructor(object_function);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000762 Handle<JSObject> obj = FACTORY->NewJSObject(constructor);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000763 Handle<String> first = FACTORY->LookupUtf8Symbol("first");
764 Handle<String> second = FACTORY->LookupUtf8Symbol("second");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000765
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000766 obj->SetProperty(
767 *first, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
768 obj->SetProperty(
769 *second, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000770
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000771 obj->SetElement(0, *first, NONE, kNonStrictMode)->ToObjectChecked();
772 obj->SetElement(1, *second, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000773
774 // Make the clone.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000775 Handle<JSObject> clone = Copy(obj);
776 CHECK(!clone.is_identical_to(obj));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000777
778 CHECK_EQ(obj->GetElement(0), clone->GetElement(0));
779 CHECK_EQ(obj->GetElement(1), clone->GetElement(1));
780
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000781 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*first));
782 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000783
784 // Flip the values.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000785 clone->SetProperty(
786 *first, Smi::FromInt(2), NONE, kNonStrictMode)->ToObjectChecked();
787 clone->SetProperty(
788 *second, Smi::FromInt(1), NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000789
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000790 clone->SetElement(0, *second, NONE, kNonStrictMode)->ToObjectChecked();
791 clone->SetElement(1, *first, NONE, kNonStrictMode)->ToObjectChecked();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000792
793 CHECK_EQ(obj->GetElement(1), clone->GetElement(0));
794 CHECK_EQ(obj->GetElement(0), clone->GetElement(1));
795
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000796 CHECK_EQ(obj->GetProperty(*second), clone->GetProperty(*first));
797 CHECK_EQ(obj->GetProperty(*first), clone->GetProperty(*second));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000798}
799
800
801TEST(StringAllocation) {
802 InitializeVM();
803
804
805 const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
806 for (int length = 0; length < 100; length++) {
807 v8::HandleScope scope;
808 char* non_ascii = NewArray<char>(3 * length + 1);
809 char* ascii = NewArray<char>(length + 1);
810 non_ascii[3 * length] = 0;
811 ascii[length] = 0;
812 for (int i = 0; i < length; i++) {
813 ascii[i] = 'a';
814 non_ascii[3 * i] = chars[0];
815 non_ascii[3 * i + 1] = chars[1];
816 non_ascii[3 * i + 2] = chars[2];
817 }
818 Handle<String> non_ascii_sym =
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000819 FACTORY->LookupUtf8Symbol(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000820 CHECK_EQ(length, non_ascii_sym->length());
821 Handle<String> ascii_sym =
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000822 FACTORY->LookupOneByteSymbol(OneByteVector(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000823 CHECK_EQ(length, ascii_sym->length());
824 Handle<String> non_ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000825 FACTORY->NewStringFromUtf8(Vector<const char>(non_ascii, 3 * length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000826 non_ascii_str->Hash();
827 CHECK_EQ(length, non_ascii_str->length());
828 Handle<String> ascii_str =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000829 FACTORY->NewStringFromUtf8(Vector<const char>(ascii, length));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000830 ascii_str->Hash();
831 CHECK_EQ(length, ascii_str->length());
832 DeleteArray(non_ascii);
833 DeleteArray(ascii);
834 }
835}
836
837
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000838static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000839 // Count the number of objects found in the heap.
840 int found_count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000841 HeapIterator iterator(heap);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000842 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000843 for (int i = 0; i < size; i++) {
844 if (*objs[i] == obj) {
845 found_count++;
846 }
847 }
848 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000849 return found_count;
850}
851
852
853TEST(Iteration) {
854 InitializeVM();
855 v8::HandleScope scope;
856
857 // Array of objects to scan haep for.
858 const int objs_count = 6;
859 Handle<Object> objs[objs_count];
860 int next_objs_index = 0;
861
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000862 // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000863 objs[next_objs_index++] = FACTORY->NewJSArray(10);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +0000864 objs[next_objs_index++] = FACTORY->NewJSArray(10,
865 FAST_HOLEY_ELEMENTS,
866 TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000867
ager@chromium.org9258b6b2008-09-11 09:11:10 +0000868 // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000869 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000870 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000871 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000872 FACTORY->NewStringFromAscii(CStrVector("abcdefghij"), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000873
874 // Allocate a large string (for large object space).
yangguo@chromium.orgab30bb82012-02-24 14:41:46 +0000875 int large_size = Page::kMaxNonCodeHeapObjectSize + 1;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000876 char* str = new char[large_size];
877 for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
878 str[large_size - 1] = '\0';
879 objs[next_objs_index++] =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000880 FACTORY->NewStringFromAscii(CStrVector(str), TENURED);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000881 delete[] str;
882
883 // Add a Map object to look for.
884 objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
885
886 CHECK_EQ(objs_count, next_objs_index);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +0000887 CHECK_EQ(objs_count, ObjectsFoundInHeap(HEAP, objs, objs_count));
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000888}
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +0000889
890
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000891TEST(EmptyHandleEscapeFrom) {
892 InitializeVM();
893
894 v8::HandleScope scope;
895 Handle<JSObject> runaway;
896
897 {
898 v8::HandleScope nested;
899 Handle<JSObject> empty;
900 runaway = empty.EscapeFrom(&nested);
901 }
902
903 CHECK(runaway.is_null());
904}
905
906
907static int LenFromSize(int size) {
908 return (size - FixedArray::kHeaderSize) / kPointerSize;
909}
910
911
912TEST(Regression39128) {
913 // Test case for crbug.com/39128.
914 InitializeVM();
915
916 // Increase the chance of 'bump-the-pointer' allocation in old space.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000917 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000918
919 v8::HandleScope scope;
920
921 // The plan: create JSObject which references objects in new space.
922 // Then clone this object (forcing it to go into old space) and check
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000923 // that region dirty marks are updated correctly.
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000924
925 // Step 1: prepare a map for the object. We add 1 inobject property to it.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000926 Handle<JSFunction> object_ctor(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000927 Isolate::Current()->native_context()->object_function());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000928 CHECK(object_ctor->has_initial_map());
929 Handle<Map> object_map(object_ctor->initial_map());
930 // Create a map with single inobject property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 Handle<Map> my_map = FACTORY->CopyMap(object_map, 1);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000932 int n_properties = my_map->inobject_properties();
933 CHECK_GT(n_properties, 0);
934
935 int object_size = my_map->instance_size();
936
937 // Step 2: allocate a lot of objects so to almost fill new space: we need
938 // just enough room to allocate JSObject and thus fill the newspace.
939
940 int allocation_amount = Min(FixedArray::kMaxSize,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000941 HEAP->MaxObjectSizeInNewSpace());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000942 int allocation_len = LenFromSize(allocation_amount);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000943 NewSpace* new_space = HEAP->new_space();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000944 Address* top_addr = new_space->allocation_top_address();
945 Address* limit_addr = new_space->allocation_limit_address();
946 while ((*limit_addr - *top_addr) > allocation_amount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000947 CHECK(!HEAP->always_allocate());
948 Object* array = HEAP->AllocateFixedArray(allocation_len)->ToObjectChecked();
949 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000950 CHECK(new_space->Contains(array));
951 }
952
953 // Step 3: now allocate fixed array and JSObject to fill the whole new space.
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000954 int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000955 int fixed_array_len = LenFromSize(to_fill);
956 CHECK(fixed_array_len < FixedArray::kMaxLength);
957
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000958 CHECK(!HEAP->always_allocate());
959 Object* array = HEAP->AllocateFixedArray(fixed_array_len)->ToObjectChecked();
960 CHECK(!array->IsFailure());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000961 CHECK(new_space->Contains(array));
962
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000963 Object* object = HEAP->AllocateJSObjectFromMap(*my_map)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000964 CHECK(new_space->Contains(object));
965 JSObject* jsobject = JSObject::cast(object);
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000966 CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000967 CHECK_EQ(0, jsobject->properties()->length());
968 // Create a reference to object in new space in jsobject.
969 jsobject->FastPropertyAtPut(-1, array);
970
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +0000971 CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000972
973 // Step 4: clone jsobject, but force always allocate first to create a clone
974 // in old pointer space.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000975 Address old_pointer_space_top = HEAP->old_pointer_space()->top();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000976 AlwaysAllocateScope aa_scope;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000977 Object* clone_obj = HEAP->CopyJSObject(jsobject)->ToObjectChecked();
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000978 JSObject* clone = JSObject::cast(clone_obj);
979 if (clone->address() != old_pointer_space_top) {
980 // Alas, got allocated from free list, we cannot do checks.
981 return;
982 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000983 CHECK(HEAP->old_pointer_space()->Contains(clone->address()));
ager@chromium.orgb26c50a2010-03-26 09:27:16 +0000984}
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000985
whesse@chromium.org4a5224e2010-10-20 12:37:07 +0000986
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000987TEST(TestCodeFlushing) {
ricow@chromium.orgfd0930e2010-06-11 10:37:34 +0000988 // If we do not flush code this test is invalid.
989 if (!FLAG_flush_code) return;
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +0000990 i::FLAG_allow_natives_syntax = true;
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000991 InitializeVM();
992 v8::HandleScope scope;
993 const char* source = "function foo() {"
994 " var x = 42;"
995 " var y = 42;"
996 " var z = x + y;"
997 "};"
998 "foo()";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +0000999 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001000
1001 // This compile will add the code to the compilation cache.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001002 { v8::HandleScope scope;
1003 CompileRun(source);
1004 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001005
1006 // Check function is compiled.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001007 Object* func_value = Isolate::Current()->context()->global_object()->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001008 GetProperty(*foo_name)->ToObjectChecked();
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001009 CHECK(func_value->IsJSFunction());
1010 Handle<JSFunction> function(JSFunction::cast(func_value));
1011 CHECK(function->shared()->is_compiled());
1012
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001013 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001014 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1015 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001016 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001017
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001018 // Simulate several GCs that use full marking.
1019 const int kAgingThreshold = 6;
1020 for (int i = 0; i < kAgingThreshold; i++) {
1021 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1022 }
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001023
1024 // foo should no longer be in the compilation cache
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001025 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1026 CHECK(!function->is_compiled() || function->IsOptimized());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001027 // Call foo to get it recompiled.
1028 CompileRun("foo()");
1029 CHECK(function->shared()->is_compiled());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001030 CHECK(function->is_compiled());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001031}
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001032
1033
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001034TEST(TestCodeFlushingIncremental) {
1035 // If we do not flush code this test is invalid.
1036 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1037 i::FLAG_allow_natives_syntax = true;
1038 InitializeVM();
1039 v8::HandleScope scope;
1040 const char* source = "function foo() {"
1041 " var x = 42;"
1042 " var y = 42;"
1043 " var z = x + y;"
1044 "};"
1045 "foo()";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001046 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001047
1048 // This compile will add the code to the compilation cache.
1049 { v8::HandleScope scope;
1050 CompileRun(source);
1051 }
1052
1053 // Check function is compiled.
1054 Object* func_value = Isolate::Current()->context()->global_object()->
1055 GetProperty(*foo_name)->ToObjectChecked();
1056 CHECK(func_value->IsJSFunction());
1057 Handle<JSFunction> function(JSFunction::cast(func_value));
1058 CHECK(function->shared()->is_compiled());
1059
1060 // The code will survive at least two GCs.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001061 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1062 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001063 CHECK(function->shared()->is_compiled());
1064
1065 // Simulate several GCs that use incremental marking.
1066 const int kAgingThreshold = 6;
1067 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001068 SimulateIncrementalMarking();
1069 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1070 }
1071 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1072 CHECK(!function->is_compiled() || function->IsOptimized());
1073
1074 // This compile will compile the function again.
1075 { v8::HandleScope scope;
1076 CompileRun("foo();");
1077 }
1078
1079 // Simulate several GCs that use incremental marking but make sure
1080 // the loop breaks once the function is enqueued as a candidate.
1081 for (int i = 0; i < kAgingThreshold; i++) {
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001082 SimulateIncrementalMarking();
1083 if (!function->next_function_link()->IsUndefined()) break;
1084 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1085 }
1086
1087 // Force optimization while incremental marking is active and while
1088 // the function is enqueued as a candidate.
1089 { v8::HandleScope scope;
1090 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1091 }
1092
1093 // Simulate one final GC to make sure the candidate queue is sane.
1094 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1095 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1096 CHECK(function->is_compiled() || !function->IsOptimized());
1097}
1098
1099
1100TEST(TestCodeFlushingIncrementalScavenge) {
1101 // If we do not flush code this test is invalid.
1102 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1103 i::FLAG_allow_natives_syntax = true;
1104 InitializeVM();
1105 v8::HandleScope scope;
1106 const char* source = "var foo = function() {"
1107 " var x = 42;"
1108 " var y = 42;"
1109 " var z = x + y;"
1110 "};"
1111 "foo();"
1112 "var bar = function() {"
1113 " var x = 23;"
1114 "};"
1115 "bar();";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001116 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
1117 Handle<String> bar_name = FACTORY->LookupUtf8Symbol("bar");
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001118
1119 // Perfrom one initial GC to enable code flushing.
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001120 HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001121
1122 // This compile will add the code to the compilation cache.
1123 { v8::HandleScope scope;
1124 CompileRun(source);
1125 }
1126
1127 // Check functions are compiled.
1128 Object* func_value = Isolate::Current()->context()->global_object()->
1129 GetProperty(*foo_name)->ToObjectChecked();
1130 CHECK(func_value->IsJSFunction());
1131 Handle<JSFunction> function(JSFunction::cast(func_value));
1132 CHECK(function->shared()->is_compiled());
1133 Object* func_value2 = Isolate::Current()->context()->global_object()->
1134 GetProperty(*bar_name)->ToObjectChecked();
1135 CHECK(func_value2->IsJSFunction());
1136 Handle<JSFunction> function2(JSFunction::cast(func_value2));
1137 CHECK(function2->shared()->is_compiled());
1138
1139 // Clear references to functions so that one of them can die.
1140 { v8::HandleScope scope;
1141 CompileRun("foo = 0; bar = 0;");
1142 }
1143
1144 // Bump the code age so that flushing is triggered while the function
1145 // object is still located in new-space.
1146 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001147 for (int i = 0; i < kAgingThreshold; i++) {
1148 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1149 function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1150 }
verwaest@chromium.orge4ee6de2012-11-06 12:13:00 +00001151
1152 // Simulate incremental marking so that the functions are enqueued as
1153 // code flushing candidates. Then kill one of the functions. Finally
1154 // perform a scavenge while incremental marking is still running.
1155 SimulateIncrementalMarking();
1156 *function2.location() = NULL;
1157 HEAP->CollectGarbage(NEW_SPACE, "test scavenge while marking");
1158
1159 // Simulate one final GC to make sure the candidate queue is sane.
1160 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1161 CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1162 CHECK(!function->is_compiled() || function->IsOptimized());
1163}
1164
1165
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001166TEST(TestCodeFlushingIncrementalAbort) {
1167 // If we do not flush code this test is invalid.
1168 if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1169 i::FLAG_allow_natives_syntax = true;
1170 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001171 Isolate* isolate = Isolate::Current();
1172 Heap* heap = isolate->heap();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001173 v8::HandleScope scope;
1174 const char* source = "function foo() {"
1175 " var x = 42;"
1176 " var y = 42;"
1177 " var z = x + y;"
1178 "};"
1179 "foo()";
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00001180 Handle<String> foo_name = FACTORY->LookupUtf8Symbol("foo");
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001181
1182 // This compile will add the code to the compilation cache.
1183 { v8::HandleScope scope;
1184 CompileRun(source);
1185 }
1186
1187 // Check function is compiled.
1188 Object* func_value = Isolate::Current()->context()->global_object()->
1189 GetProperty(*foo_name)->ToObjectChecked();
1190 CHECK(func_value->IsJSFunction());
1191 Handle<JSFunction> function(JSFunction::cast(func_value));
1192 CHECK(function->shared()->is_compiled());
1193
1194 // The code will survive at least two GCs.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001195 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1196 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001197 CHECK(function->shared()->is_compiled());
1198
1199 // Bump the code age so that flushing is triggered.
1200 const int kAgingThreshold = 6;
mmassi@chromium.org49a44672012-12-04 13:52:03 +00001201 for (int i = 0; i < kAgingThreshold; i++) {
1202 function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1203 }
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001204
1205 // Simulate incremental marking so that the function is enqueued as
1206 // code flushing candidate.
1207 SimulateIncrementalMarking();
1208
1209 // Enable the debugger and add a breakpoint while incremental marking
1210 // is running so that incremental marking aborts and code flushing is
1211 // disabled.
1212 int position = 0;
1213 Handle<Object> breakpoint_object(Smi::FromInt(0));
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001214 isolate->debug()->SetBreakPoint(function, breakpoint_object, &position);
1215 isolate->debug()->ClearAllBreakPoints();
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001216
1217 // Force optimization now that code flushing is disabled.
1218 { v8::HandleScope scope;
1219 CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1220 }
1221
1222 // Simulate one final GC to make sure the candidate queue is sane.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001223 heap->CollectAllGarbage(Heap::kNoGCFlags);
mvstanton@chromium.orge4ac3ef2012-11-12 14:53:34 +00001224 CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1225 CHECK(function->is_compiled() || !function->IsOptimized());
1226}
1227
1228
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001229// Count the number of native contexts in the weak list of native contexts.
1230int CountNativeContexts() {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001231 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001232 Object* object = HEAP->native_contexts_list();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001233 while (!object->IsUndefined()) {
1234 count++;
1235 object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1236 }
1237 return count;
1238}
1239
1240
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001241// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001242// functions attached to a native context.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001243static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1244 int count = 0;
1245 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1246 Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1247 while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1248 count++;
1249 object = JSFunction::cast(object)->next_function_link();
1250 }
1251 return count;
1252}
1253
1254
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001255TEST(TestInternalWeakLists) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001256 v8::V8::Initialize();
1257
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001258 // Some flags turn Scavenge collections into Mark-sweep collections
1259 // and hence are incompatible with this test case.
1260 if (FLAG_gc_global || FLAG_stress_compaction) return;
1261
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001262 static const int kNumTestContexts = 10;
1263
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001264 Isolate* isolate = Isolate::Current();
1265 Heap* heap = isolate->heap();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001266 v8::HandleScope scope;
1267 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1268
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001269 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001270
1271 // Create a number of global contests which gets linked together.
1272 for (int i = 0; i < kNumTestContexts; i++) {
1273 ctx[i] = v8::Context::New();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001274
1275 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1276
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001277 CHECK_EQ(i + 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001278
1279 ctx[i]->Enter();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001280
1281 // Create a handle scope so no function objects get stuch in the outer
1282 // handle scope
1283 v8::HandleScope scope;
1284 const char* source = "function f1() { };"
1285 "function f2() { };"
1286 "function f3() { };"
1287 "function f4() { };"
1288 "function f5() { };";
1289 CompileRun(source);
1290 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1291 CompileRun("f1()");
1292 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1293 CompileRun("f2()");
1294 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1295 CompileRun("f3()");
1296 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1297 CompileRun("f4()");
1298 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1299 CompileRun("f5()");
1300 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1301
1302 // Remove function f1, and
1303 CompileRun("f1=null");
1304
1305 // Scavenge treats these references as strong.
1306 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001307 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001308 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1309 }
1310
1311 // Mark compact handles the weak references.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00001312 isolate->compilation_cache()->Clear();
1313 heap->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001314 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1315
1316 // Get rid of f3 and f5 in the same way.
1317 CompileRun("f3=null");
1318 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001319 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001320 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1321 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001322 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001323 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1324 CompileRun("f5=null");
1325 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001326 HEAP->PerformScavenge();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001327 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1328 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001329 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001330 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1331
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001332 ctx[i]->Exit();
1333 }
1334
1335 // Force compilation cache cleanup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001336 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001337
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001338 // Dispose the native contexts one by one.
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001339 for (int i = 0; i < kNumTestContexts; i++) {
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001340 ctx[i].Dispose(ctx[i]->GetIsolate());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001341 ctx[i].Clear();
1342
1343 // Scavenge treats these references as strong.
1344 for (int j = 0; j < 10; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001345 HEAP->PerformScavenge();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001346 CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001347 }
1348
1349 // Mark compact handles the weak references.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001350 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001351 CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001352 }
1353
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001354 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001355}
1356
1357
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001358// Count the number of native contexts in the weak list of native contexts
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001359// causing a GC after the specified number of elements.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001360static int CountNativeContextsWithGC(int n) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001361 int count = 0;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001362 Handle<Object> object(HEAP->native_contexts_list());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001363 while (!object->IsUndefined()) {
1364 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001365 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001366 object =
1367 Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK));
1368 }
1369 return count;
1370}
1371
1372
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001373// Count the number of user functions in the weak list of optimized
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001374// functions attached to a native context causing a GC after the
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001375// specified number of elements.
1376static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1377 int n) {
1378 int count = 0;
1379 Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1380 Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST));
1381 while (object->IsJSFunction() &&
1382 !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1383 count++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001384 if (count == n) HEAP->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001385 object = Handle<Object>(
1386 Object::cast(JSFunction::cast(*object)->next_function_link()));
1387 }
1388 return count;
1389}
1390
1391
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001392TEST(TestInternalWeakListsTraverseWithGC) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001393 v8::V8::Initialize();
1394
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001395 static const int kNumTestContexts = 10;
1396
1397 v8::HandleScope scope;
1398 v8::Persistent<v8::Context> ctx[kNumTestContexts];
1399
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001400 CHECK_EQ(0, CountNativeContexts());
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001401
1402 // Create an number of contexts and check the length of the weak list both
1403 // with and without GCs while iterating the list.
1404 for (int i = 0; i < kNumTestContexts; i++) {
1405 ctx[i] = v8::Context::New();
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001406 CHECK_EQ(i + 1, CountNativeContexts());
1407 CHECK_EQ(i + 1, CountNativeContextsWithGC(i / 2 + 1));
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001408 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001409
1410 bool opt = (FLAG_always_opt && i::V8::UseCrankshaft());
1411
1412 // Compile a number of functions the length of the weak list of optimized
1413 // functions both with and without GCs while iterating the list.
1414 ctx[0]->Enter();
1415 const char* source = "function f1() { };"
1416 "function f2() { };"
1417 "function f3() { };"
1418 "function f4() { };"
1419 "function f5() { };";
1420 CompileRun(source);
1421 CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1422 CompileRun("f1()");
1423 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1424 CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1425 CompileRun("f2()");
1426 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1427 CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1428 CompileRun("f3()");
1429 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1430 CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1431 CompileRun("f4()");
1432 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1433 CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1434 CompileRun("f5()");
1435 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1436 CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1437
1438 ctx[0]->Exit();
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00001439}
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001440
1441
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001442TEST(TestSizeOfObjects) {
1443 v8::V8::Initialize();
1444
1445 // Get initial heap size after several full GCs, which will stabilize
1446 // the heap size and return with sweeping finished completely.
1447 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1448 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1449 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1450 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001451 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001452 CHECK(HEAP->old_pointer_space()->IsLazySweepingComplete());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001453 int initial_size = static_cast<int>(HEAP->SizeOfObjects());
1454
1455 {
1456 // Allocate objects on several different old-space pages so that
1457 // lazy sweeping kicks in for subsequent GC runs.
1458 AlwaysAllocateScope always_allocate;
1459 int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1460 for (int i = 1; i <= 100; i++) {
1461 HEAP->AllocateFixedArray(8192, TENURED)->ToObjectChecked();
1462 CHECK_EQ(initial_size + i * filler_size,
1463 static_cast<int>(HEAP->SizeOfObjects()));
1464 }
1465 }
1466
1467 // The heap size should go back to initial size after a full GC, even
1468 // though sweeping didn't finish yet.
1469 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001470
1471 // Normally sweeping would not be complete here, but no guarantees.
1472
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001473 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1474
1475 // Advancing the sweeper step-wise should not change the heap size.
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00001476 while (!HEAP->old_pointer_space()->IsLazySweepingComplete()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001477 HEAP->old_pointer_space()->AdvanceSweeper(KB);
1478 CHECK_EQ(initial_size, static_cast<int>(HEAP->SizeOfObjects()));
1479 }
1480}
1481
1482
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001483TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1484 InitializeVM();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001485 HEAP->EnsureHeapIsIterable();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001486 intptr_t size_of_objects_1 = HEAP->SizeOfObjects();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001487 HeapIterator iterator(HEAP);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001488 intptr_t size_of_objects_2 = 0;
1489 for (HeapObject* obj = iterator.next();
1490 obj != NULL;
1491 obj = iterator.next()) {
ulan@chromium.org56c14af2012-09-20 12:51:09 +00001492 if (!obj->IsFreeSpace()) {
1493 size_of_objects_2 += obj->Size();
1494 }
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001495 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001496 // Delta must be within 5% of the larger result.
1497 // TODO(gc): Tighten this up by distinguishing between byte
1498 // arrays that are real and those that merely mark free space
1499 // on the heap.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001500 if (size_of_objects_1 > size_of_objects_2) {
1501 intptr_t delta = size_of_objects_1 - size_of_objects_2;
1502 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1503 "Iterator: %" V8_PTR_PREFIX "d, "
1504 "delta: %" V8_PTR_PREFIX "d\n",
1505 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001506 CHECK_GT(size_of_objects_1 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001507 } else {
1508 intptr_t delta = size_of_objects_2 - size_of_objects_1;
1509 PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1510 "Iterator: %" V8_PTR_PREFIX "d, "
1511 "delta: %" V8_PTR_PREFIX "d\n",
1512 size_of_objects_1, size_of_objects_2, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001513 CHECK_GT(size_of_objects_2 / 20, delta);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001514 }
1515}
whesse@chromium.org023421e2010-12-21 12:19:12 +00001516
1517
danno@chromium.orgc612e022011-11-10 11:38:15 +00001518static void FillUpNewSpace(NewSpace* new_space) {
1519 // Fill up new space to the point that it is completely full. Make sure
1520 // that the scavenger does not undo the filling.
1521 v8::HandleScope scope;
1522 AlwaysAllocateScope always_allocate;
1523 intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001524 intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
danno@chromium.orgc612e022011-11-10 11:38:15 +00001525 for (intptr_t i = 0; i < number_of_fillers; i++) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001526 CHECK(HEAP->InNewSpace(*FACTORY->NewFixedArray(32, NOT_TENURED)));
danno@chromium.orgc612e022011-11-10 11:38:15 +00001527 }
1528}
1529
1530
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001531TEST(GrowAndShrinkNewSpace) {
1532 InitializeVM();
1533 NewSpace* new_space = HEAP->new_space();
1534
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001535 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1536 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001537 // The max size cannot exceed the reserved size, since semispaces must be
1538 // always within the reserved space. We can't test new space growing and
1539 // shrinking if the reserved size is the same as the minimum (initial) size.
1540 return;
1541 }
1542
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001543 // Explicitly growing should double the space capacity.
1544 intptr_t old_capacity, new_capacity;
1545 old_capacity = new_space->Capacity();
1546 new_space->Grow();
1547 new_capacity = new_space->Capacity();
1548 CHECK(2 * old_capacity == new_capacity);
1549
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001550 old_capacity = new_space->Capacity();
danno@chromium.orgc612e022011-11-10 11:38:15 +00001551 FillUpNewSpace(new_space);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001552 new_capacity = new_space->Capacity();
1553 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001554
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001555 // Explicitly shrinking should not affect space capacity.
1556 old_capacity = new_space->Capacity();
1557 new_space->Shrink();
1558 new_capacity = new_space->Capacity();
1559 CHECK(old_capacity == new_capacity);
1560
1561 // Let the scavenger empty the new space.
1562 HEAP->CollectGarbage(NEW_SPACE);
1563 CHECK_LE(new_space->Size(), old_capacity);
1564
1565 // Explicitly shrinking should halve the space capacity.
1566 old_capacity = new_space->Capacity();
1567 new_space->Shrink();
1568 new_capacity = new_space->Capacity();
1569 CHECK(old_capacity == 2 * new_capacity);
1570
1571 // Consecutive shrinking should not affect space capacity.
1572 old_capacity = new_space->Capacity();
1573 new_space->Shrink();
1574 new_space->Shrink();
1575 new_space->Shrink();
1576 new_capacity = new_space->Capacity();
1577 CHECK(old_capacity == new_capacity);
whesse@chromium.org023421e2010-12-21 12:19:12 +00001578}
danno@chromium.orgc612e022011-11-10 11:38:15 +00001579
1580
1581TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1582 InitializeVM();
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001583
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001584 if (HEAP->ReservedSemiSpaceSize() == HEAP->InitialSemiSpaceSize() ||
1585 HEAP->MaxSemiSpaceSize() == HEAP->InitialSemiSpaceSize()) {
danno@chromium.org1044a4d2012-04-30 12:34:39 +00001586 // The max size cannot exceed the reserved size, since semispaces must be
1587 // always within the reserved space. We can't test new space growing and
1588 // shrinking if the reserved size is the same as the minimum (initial) size.
1589 return;
1590 }
1591
danno@chromium.orgc612e022011-11-10 11:38:15 +00001592 v8::HandleScope scope;
1593 NewSpace* new_space = HEAP->new_space();
1594 intptr_t old_capacity, new_capacity;
1595 old_capacity = new_space->Capacity();
1596 new_space->Grow();
1597 new_capacity = new_space->Capacity();
1598 CHECK(2 * old_capacity == new_capacity);
1599 FillUpNewSpace(new_space);
1600 HEAP->CollectAllAvailableGarbage();
1601 new_capacity = new_space->Capacity();
1602 CHECK(old_capacity == new_capacity);
1603}
svenpanne@chromium.orgecb9dd62011-12-01 08:22:35 +00001604
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001605
1606static int NumberOfGlobalObjects() {
1607 int count = 0;
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00001608 HeapIterator iterator(HEAP);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001609 for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1610 if (obj->IsGlobalObject()) count++;
1611 }
1612 return count;
1613}
1614
1615
1616// Test that we don't embed maps from foreign contexts into
1617// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001618TEST(LeakNativeContextViaMap) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001619 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001620 v8::HandleScope outer_scope;
1621 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1622 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1623 ctx1->Enter();
1624
1625 HEAP->CollectAllAvailableGarbage();
1626 CHECK_EQ(4, NumberOfGlobalObjects());
1627
1628 {
1629 v8::HandleScope inner_scope;
1630 CompileRun("var v = {x: 42}");
1631 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1632 ctx2->Enter();
1633 ctx2->Global()->Set(v8_str("o"), v);
1634 v8::Local<v8::Value> res = CompileRun(
1635 "function f() { return o.x; }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001636 "for (var i = 0; i < 10; ++i) f();"
1637 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001638 "f();");
1639 CHECK_EQ(42, res->Int32Value());
1640 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1641 ctx2->Exit();
1642 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001643 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001644 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001645 }
1646 HEAP->CollectAllAvailableGarbage();
1647 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001648 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001649 HEAP->CollectAllAvailableGarbage();
1650 CHECK_EQ(0, NumberOfGlobalObjects());
1651}
1652
1653
1654// Test that we don't embed functions from foreign contexts into
1655// optimized code.
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001656TEST(LeakNativeContextViaFunction) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001657 i::FLAG_allow_natives_syntax = true;
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001658 v8::HandleScope outer_scope;
1659 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1660 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1661 ctx1->Enter();
1662
1663 HEAP->CollectAllAvailableGarbage();
1664 CHECK_EQ(4, NumberOfGlobalObjects());
1665
1666 {
1667 v8::HandleScope inner_scope;
1668 CompileRun("var v = function() { return 42; }");
1669 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1670 ctx2->Enter();
1671 ctx2->Global()->Set(v8_str("o"), v);
1672 v8::Local<v8::Value> res = CompileRun(
1673 "function f(x) { return x(); }"
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001674 "for (var i = 0; i < 10; ++i) f(o);"
1675 "%OptimizeFunctionOnNextCall(f);"
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001676 "f(o);");
1677 CHECK_EQ(42, res->Int32Value());
1678 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1679 ctx2->Exit();
1680 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001681 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001682 v8::V8::ContextDisposedNotification();
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001683 }
1684 HEAP->CollectAllAvailableGarbage();
1685 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001686 ctx2.Dispose(ctx2->GetIsolate());
ricow@chromium.org7ad65222011-12-19 12:13:11 +00001687 HEAP->CollectAllAvailableGarbage();
1688 CHECK_EQ(0, NumberOfGlobalObjects());
1689}
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001690
1691
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001692TEST(LeakNativeContextViaMapKeyed) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001693 i::FLAG_allow_natives_syntax = true;
1694 v8::HandleScope outer_scope;
1695 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1696 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1697 ctx1->Enter();
1698
1699 HEAP->CollectAllAvailableGarbage();
1700 CHECK_EQ(4, NumberOfGlobalObjects());
1701
1702 {
1703 v8::HandleScope inner_scope;
1704 CompileRun("var v = [42, 43]");
1705 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1706 ctx2->Enter();
1707 ctx2->Global()->Set(v8_str("o"), v);
1708 v8::Local<v8::Value> res = CompileRun(
1709 "function f() { return o[0]; }"
1710 "for (var i = 0; i < 10; ++i) f();"
1711 "%OptimizeFunctionOnNextCall(f);"
1712 "f();");
1713 CHECK_EQ(42, res->Int32Value());
1714 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1715 ctx2->Exit();
1716 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001717 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001718 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001719 }
1720 HEAP->CollectAllAvailableGarbage();
1721 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001722 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001723 HEAP->CollectAllAvailableGarbage();
1724 CHECK_EQ(0, NumberOfGlobalObjects());
1725}
1726
1727
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001728TEST(LeakNativeContextViaMapProto) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001729 i::FLAG_allow_natives_syntax = true;
1730 v8::HandleScope outer_scope;
1731 v8::Persistent<v8::Context> ctx1 = v8::Context::New();
1732 v8::Persistent<v8::Context> ctx2 = v8::Context::New();
1733 ctx1->Enter();
1734
1735 HEAP->CollectAllAvailableGarbage();
1736 CHECK_EQ(4, NumberOfGlobalObjects());
1737
1738 {
1739 v8::HandleScope inner_scope;
1740 CompileRun("var v = { y: 42}");
1741 v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1742 ctx2->Enter();
1743 ctx2->Global()->Set(v8_str("o"), v);
1744 v8::Local<v8::Value> res = CompileRun(
1745 "function f() {"
1746 " var p = {x: 42};"
1747 " p.__proto__ = o;"
1748 " return p.x;"
1749 "}"
1750 "for (var i = 0; i < 10; ++i) f();"
1751 "%OptimizeFunctionOnNextCall(f);"
1752 "f();");
1753 CHECK_EQ(42, res->Int32Value());
1754 ctx2->Global()->Set(v8_str("o"), v8::Int32::New(0));
1755 ctx2->Exit();
1756 ctx1->Exit();
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001757 ctx1.Dispose(ctx1->GetIsolate());
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001758 v8::V8::ContextDisposedNotification();
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001759 }
1760 HEAP->CollectAllAvailableGarbage();
1761 CHECK_EQ(2, NumberOfGlobalObjects());
mvstanton@chromium.orgd16d8532013-01-25 13:29:10 +00001762 ctx2.Dispose(ctx2->GetIsolate());
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00001763 HEAP->CollectAllAvailableGarbage();
1764 CHECK_EQ(0, NumberOfGlobalObjects());
1765}
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001766
1767
1768TEST(InstanceOfStubWriteBarrier) {
1769 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001770#ifdef VERIFY_HEAP
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001771 i::FLAG_verify_heap = true;
1772#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001773
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001774 InitializeVM();
1775 if (!i::V8::UseCrankshaft()) return;
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001776 if (i::FLAG_force_marking_deque_overflows) return;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001777 v8::HandleScope outer_scope;
1778
1779 {
1780 v8::HandleScope scope;
1781 CompileRun(
1782 "function foo () { }"
1783 "function mkbar () { return new (new Function(\"\")) (); }"
1784 "function f (x) { return (x instanceof foo); }"
1785 "function g () { f(mkbar()); }"
1786 "f(new foo()); f(new foo());"
1787 "%OptimizeFunctionOnNextCall(f);"
1788 "f(new foo()); g();");
1789 }
1790
1791 IncrementalMarking* marking = HEAP->incremental_marking();
1792 marking->Abort();
1793 marking->Start();
1794
1795 Handle<JSFunction> f =
1796 v8::Utils::OpenHandle(
1797 *v8::Handle<v8::Function>::Cast(
1798 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1799
1800 CHECK(f->IsOptimized());
1801
1802 while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1803 !marking->IsStopped()) {
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001804 // Discard any pending GC requests otherwise we will get GC when we enter
1805 // code below.
1806 marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001807 }
1808
1809 CHECK(marking->IsMarking());
1810
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001811 {
1812 v8::HandleScope scope;
1813 v8::Handle<v8::Object> global = v8::Context::GetCurrent()->Global();
1814 v8::Handle<v8::Function> g =
1815 v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1816 g->Call(global, 0, NULL);
1817 }
1818
1819 HEAP->incremental_marking()->set_should_hurry(true);
1820 HEAP->CollectGarbage(OLD_POINTER_SPACE);
1821}
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001822
1823
1824TEST(PrototypeTransitionClearing) {
1825 InitializeVM();
1826 v8::HandleScope scope;
1827
1828 CompileRun(
1829 "var base = {};"
1830 "var live = [];"
1831 "for (var i = 0; i < 10; i++) {"
1832 " var object = {};"
1833 " var prototype = {};"
1834 " object.__proto__ = prototype;"
1835 " if (i >= 3) live.push(object, prototype);"
1836 "}");
1837
1838 Handle<JSObject> baseObject =
1839 v8::Utils::OpenHandle(
1840 *v8::Handle<v8::Object>::Cast(
1841 v8::Context::GetCurrent()->Global()->Get(v8_str("base"))));
1842
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001843 // Verify that only dead prototype transitions are cleared.
1844 CHECK_EQ(10, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001845 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
ulan@chromium.orgf6a0c412012-06-15 12:31:06 +00001846 const int transitions = 10 - 3;
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001847 CHECK_EQ(transitions, baseObject->map()->NumberOfProtoTransitions());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001848
1849 // Verify that prototype transitions array was compacted.
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001850 FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001851 for (int i = 0; i < transitions; i++) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001852 int j = Map::kProtoTransitionHeaderSize +
1853 i * Map::kProtoTransitionElementsPerEntry;
1854 CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001855 Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
1856 CHECK(proto->IsTheHole() || proto->IsJSObject());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001857 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001858
1859 // Make sure next prototype is placed on an old-space evacuation candidate.
1860 Handle<JSObject> prototype;
1861 PagedSpace* space = HEAP->old_pointer_space();
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001862 {
1863 AlwaysAllocateScope always_allocate;
1864 SimulateFullSpace(space);
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001865 prototype = FACTORY->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00001866 }
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001867
1868 // Add a prototype on an evacuation candidate and verify that transition
1869 // clearing correctly records slots in prototype transition array.
1870 i::FLAG_always_compact = true;
1871 Handle<Map> map(baseObject->map());
danno@chromium.org81cac2b2012-07-10 11:28:27 +00001872 CHECK(!space->LastPage()->Contains(
1873 map->GetPrototypeTransitions()->address()));
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001874 CHECK(space->LastPage()->Contains(prototype->address()));
1875 baseObject->SetPrototype(*prototype, false)->ToObjectChecked();
1876 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
1877 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
1878 CHECK(map->GetPrototypeTransition(*prototype)->IsMap());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00001879}
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001880
1881
1882TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
1883 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001884#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001885 i::FLAG_verify_heap = true;
1886#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001887
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001888 InitializeVM();
1889 if (!i::V8::UseCrankshaft()) return;
1890 v8::HandleScope outer_scope;
1891
1892 {
1893 v8::HandleScope scope;
1894 CompileRun(
1895 "function f () {"
1896 " var s = 0;"
1897 " for (var i = 0; i < 100; i++) s += i;"
1898 " return s;"
1899 "}"
1900 "f(); f();"
1901 "%OptimizeFunctionOnNextCall(f);"
1902 "f();");
1903 }
1904 Handle<JSFunction> f =
1905 v8::Utils::OpenHandle(
1906 *v8::Handle<v8::Function>::Cast(
1907 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1908 CHECK(f->IsOptimized());
1909
1910 IncrementalMarking* marking = HEAP->incremental_marking();
1911 marking->Abort();
1912 marking->Start();
1913
1914 // The following two calls will increment HEAP->global_ic_age().
1915 const int kLongIdlePauseInMs = 1000;
1916 v8::V8::ContextDisposedNotification();
1917 v8::V8::IdleNotification(kLongIdlePauseInMs);
1918
1919 while (!marking->IsStopped() && !marking->IsComplete()) {
1920 marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1921 }
danno@chromium.org2c26cb12012-05-03 09:06:43 +00001922 if (!marking->IsStopped() || marking->should_hurry()) {
1923 // We don't normally finish a GC via Step(), we normally finish by
1924 // setting the stack guard and then do the final steps in the stack
1925 // guard interrupt. But here we didn't ask for that, and there is no
1926 // JS code running to trigger the interrupt, so we explicitly finalize
1927 // here.
1928 HEAP->CollectAllGarbage(Heap::kNoGCFlags,
1929 "Test finalizing incremental mark-sweep");
1930 }
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001931
1932 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1933 CHECK_EQ(0, f->shared()->opt_count());
1934 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1935}
1936
1937
1938TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
1939 i::FLAG_allow_natives_syntax = true;
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001940#ifdef VERIFY_HEAP
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001941 i::FLAG_verify_heap = true;
1942#endif
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00001943
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001944 InitializeVM();
1945 if (!i::V8::UseCrankshaft()) return;
1946 v8::HandleScope outer_scope;
1947
1948 {
1949 v8::HandleScope scope;
1950 CompileRun(
1951 "function f () {"
1952 " var s = 0;"
1953 " for (var i = 0; i < 100; i++) s += i;"
1954 " return s;"
1955 "}"
1956 "f(); f();"
1957 "%OptimizeFunctionOnNextCall(f);"
1958 "f();");
1959 }
1960 Handle<JSFunction> f =
1961 v8::Utils::OpenHandle(
1962 *v8::Handle<v8::Function>::Cast(
1963 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
1964 CHECK(f->IsOptimized());
1965
1966 HEAP->incremental_marking()->Abort();
1967
1968 // The following two calls will increment HEAP->global_ic_age().
1969 // Since incremental marking is off, IdleNotification will do full GC.
1970 const int kLongIdlePauseInMs = 1000;
1971 v8::V8::ContextDisposedNotification();
1972 v8::V8::IdleNotification(kLongIdlePauseInMs);
1973
1974 CHECK_EQ(HEAP->global_ic_age(), f->shared()->ic_age());
1975 CHECK_EQ(0, f->shared()->opt_count());
1976 CHECK_EQ(0, f->shared()->code()->profiler_ticks());
1977}
1978
1979
1980// Test that HAllocateObject will always return an object in new-space.
1981TEST(OptimizedAllocationAlwaysInNewSpace) {
1982 i::FLAG_allow_natives_syntax = true;
1983 InitializeVM();
1984 if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00001985 if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001986 v8::HandleScope scope;
1987
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00001988 SimulateFullSpace(HEAP->new_space());
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00001989 AlwaysAllocateScope always_allocate;
1990 v8::Local<v8::Value> res = CompileRun(
1991 "function c(x) {"
1992 " this.x = x;"
1993 " for (var i = 0; i < 32; i++) {"
1994 " this['x' + i] = x;"
1995 " }"
1996 "}"
1997 "function f(x) { return new c(x); };"
1998 "f(1); f(2); f(3);"
1999 "%OptimizeFunctionOnNextCall(f);"
2000 "f(4);");
2001 CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
2002
2003 Handle<JSObject> o =
2004 v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2005
2006 CHECK(HEAP->InNewSpace(*o));
2007}
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002008
2009
2010static int CountMapTransitions(Map* map) {
yangguo@chromium.org99aa4902012-07-06 16:21:55 +00002011 return map->transitions()->number_of_transitions();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002012}
2013
2014
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002015// Test that map transitions are cleared and maps are collected with
2016// incremental marking as well.
2017TEST(Regress1465) {
2018 i::FLAG_allow_natives_syntax = true;
2019 i::FLAG_trace_incremental_marking = true;
2020 InitializeVM();
2021 v8::HandleScope scope;
2022 static const int transitions_count = 256;
2023
2024 {
2025 AlwaysAllocateScope always_allocate;
2026 for (int i = 0; i < transitions_count; i++) {
2027 EmbeddedVector<char, 64> buffer;
2028 OS::SNPrintF(buffer, "var o = new Object; o.prop%d = %d;", i, i);
2029 CompileRun(buffer.start());
2030 }
2031 CompileRun("var root = new Object;");
2032 }
2033
2034 Handle<JSObject> root =
2035 v8::Utils::OpenHandle(
2036 *v8::Handle<v8::Object>::Cast(
2037 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2038
2039 // Count number of live transitions before marking.
2040 int transitions_before = CountMapTransitions(root->map());
2041 CompileRun("%DebugPrint(root);");
2042 CHECK_EQ(transitions_count, transitions_before);
2043
2044 SimulateIncrementalMarking();
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002045 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org5f0b8ea2012-05-16 12:37:04 +00002046
2047 // Count number of live transitions after marking. Note that one transition
2048 // is left, because 'o' still holds an instance of one transition target.
2049 int transitions_after = CountMapTransitions(root->map());
2050 CompileRun("%DebugPrint(root);");
2051 CHECK_EQ(1, transitions_after);
2052}
verwaest@chromium.org37141392012-05-31 13:27:02 +00002053
2054
2055TEST(Regress2143a) {
2056 i::FLAG_collect_maps = true;
2057 i::FLAG_incremental_marking = true;
2058 InitializeVM();
2059 v8::HandleScope scope;
2060
2061 // Prepare a map transition from the root object together with a yet
2062 // untransitioned root object.
2063 CompileRun("var root = new Object;"
2064 "root.foo = 0;"
2065 "root = new Object;");
2066
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002067 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002068
2069 // Compile a StoreIC that performs the prepared map transition. This
2070 // will restart incremental marking and should make sure the root is
2071 // marked grey again.
2072 CompileRun("function f(o) {"
2073 " o.foo = 0;"
2074 "}"
2075 "f(new Object);"
2076 "f(root);");
2077
2078 // This bug only triggers with aggressive IC clearing.
2079 HEAP->AgeInlineCaches();
2080
2081 // Explicitly request GC to perform final marking step and sweeping.
2082 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002083
2084 Handle<JSObject> root =
2085 v8::Utils::OpenHandle(
2086 *v8::Handle<v8::Object>::Cast(
2087 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2088
2089 // The root object should be in a sane state.
2090 CHECK(root->IsJSObject());
2091 CHECK(root->map()->IsMap());
2092}
2093
2094
2095TEST(Regress2143b) {
2096 i::FLAG_collect_maps = true;
2097 i::FLAG_incremental_marking = true;
2098 i::FLAG_allow_natives_syntax = true;
2099 InitializeVM();
2100 v8::HandleScope scope;
2101
2102 // Prepare a map transition from the root object together with a yet
2103 // untransitioned root object.
2104 CompileRun("var root = new Object;"
2105 "root.foo = 0;"
2106 "root = new Object;");
2107
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002108 SimulateIncrementalMarking();
verwaest@chromium.org37141392012-05-31 13:27:02 +00002109
2110 // Compile an optimized LStoreNamedField that performs the prepared
2111 // map transition. This will restart incremental marking and should
2112 // make sure the root is marked grey again.
2113 CompileRun("function f(o) {"
2114 " o.foo = 0;"
2115 "}"
2116 "f(new Object);"
2117 "f(new Object);"
2118 "%OptimizeFunctionOnNextCall(f);"
2119 "f(root);"
2120 "%DeoptimizeFunction(f);");
2121
2122 // This bug only triggers with aggressive IC clearing.
2123 HEAP->AgeInlineCaches();
2124
2125 // Explicitly request GC to perform final marking step and sweeping.
2126 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
verwaest@chromium.org37141392012-05-31 13:27:02 +00002127
2128 Handle<JSObject> root =
2129 v8::Utils::OpenHandle(
2130 *v8::Handle<v8::Object>::Cast(
2131 v8::Context::GetCurrent()->Global()->Get(v8_str("root"))));
2132
2133 // The root object should be in a sane state.
2134 CHECK(root->IsJSObject());
2135 CHECK(root->map()->IsMap());
2136}
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002137
2138
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002139TEST(ReleaseOverReservedPages) {
2140 i::FLAG_trace_gc = true;
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002141 // The optimizer can allocate stuff, messing up the test.
2142 i::FLAG_crankshaft = false;
2143 i::FLAG_always_opt = false;
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002144 InitializeVM();
2145 v8::HandleScope scope;
2146 static const int number_of_test_pages = 20;
2147
2148 // Prepare many pages with low live-bytes count.
2149 PagedSpace* old_pointer_space = HEAP->old_pointer_space();
2150 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2151 for (int i = 0; i < number_of_test_pages; i++) {
2152 AlwaysAllocateScope always_allocate;
2153 SimulateFullSpace(old_pointer_space);
2154 FACTORY->NewFixedArray(1, TENURED);
2155 }
2156 CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2157
2158 // Triggering one GC will cause a lot of garbage to be discovered but
2159 // even spread across all allocated pages.
2160 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
jkummerow@chromium.org5323a9c2012-12-10 19:00:50 +00002161 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002162
2163 // Triggering subsequent GCs should cause at least half of the pages
2164 // to be released to the OS after at most two cycles.
2165 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
2166 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2167 HEAP->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
2168 CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
2169
ulan@chromium.org56c14af2012-09-20 12:51:09 +00002170 // Triggering a last-resort GC should cause all pages to be released to the
2171 // OS so that other processes can seize the memory. If we get a failure here
2172 // where there are 2 pages left instead of 1, then we should increase the
2173 // size of the first page a little in SizeOfFirstPage in spaces.cc. The
2174 // first page should be small in order to reduce memory used when the VM
2175 // boots, but if the 20 small arrays don't fit on the first page then that's
2176 // an indication that it is too small.
yangguo@chromium.orgde0db002012-06-22 13:44:28 +00002177 HEAP->CollectAllAvailableGarbage("triggered really hard");
2178 CHECK_EQ(1, old_pointer_space->CountTotalPages());
2179}
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002180
2181
2182TEST(Regress2237) {
2183 InitializeVM();
2184 v8::HandleScope scope;
2185 Handle<String> slice(HEAP->empty_string());
2186
2187 {
2188 // Generate a parent that lives in new-space.
2189 v8::HandleScope inner_scope;
2190 const char* c = "This text is long enough to trigger sliced strings.";
2191 Handle<String> s = FACTORY->NewStringFromAscii(CStrVector(c));
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002192 CHECK(s->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002193 CHECK(HEAP->InNewSpace(*s));
2194
2195 // Generate a sliced string that is based on the above parent and
2196 // lives in old-space.
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002197 SimulateFullSpace(HEAP->new_space());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002198 AlwaysAllocateScope always_allocate;
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +00002199 Handle<String> t = FACTORY->NewProperSubString(s, 5, 35);
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002200 CHECK(t->IsSlicedString());
2201 CHECK(!HEAP->InNewSpace(*t));
2202 *slice.location() = *t.location();
2203 }
2204
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002205 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002206 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002207 CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
yangguo@chromium.org304cc332012-07-24 07:59:48 +00002208}
ulan@chromium.orgea52b5f2012-07-30 13:05:33 +00002209
2210
2211#ifdef OBJECT_PRINT
2212TEST(PrintSharedFunctionInfo) {
2213 InitializeVM();
2214 v8::HandleScope scope;
2215 const char* source = "f = function() { return 987654321; }\n"
2216 "g = function() { return 123456789; }\n";
2217 CompileRun(source);
2218 Handle<JSFunction> g =
2219 v8::Utils::OpenHandle(
2220 *v8::Handle<v8::Function>::Cast(
2221 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2222
2223 AssertNoAllocation no_alloc;
2224 g->shared()->PrintLn();
2225}
2226#endif // OBJECT_PRINT
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002227
2228
2229TEST(Regress2211) {
2230 InitializeVM();
2231 v8::HandleScope scope;
2232
2233 v8::Handle<v8::String> value = v8_str("val string");
2234 Smi* hash = Smi::FromInt(321);
2235 Heap* heap = Isolate::Current()->heap();
2236
2237 for (int i = 0; i < 2; i++) {
2238 // Store identity hash first and common hidden property second.
2239 v8::Handle<v8::Object> obj = v8::Object::New();
2240 Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
2241 CHECK(internal_obj->HasFastProperties());
2242
2243 // In the first iteration, set hidden value first and identity hash second.
2244 // In the second iteration, reverse the order.
2245 if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
2246 MaybeObject* maybe_obj = internal_obj->SetIdentityHash(hash,
2247 ALLOW_CREATION);
2248 CHECK(!maybe_obj->IsFailure());
2249 if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
2250
2251 // Check values.
2252 CHECK_EQ(hash,
2253 internal_obj->GetHiddenProperty(heap->identity_hash_symbol()));
2254 CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
2255
2256 // Check size.
2257 DescriptorArray* descriptors = internal_obj->map()->instance_descriptors();
2258 ObjectHashTable* hashtable = ObjectHashTable::cast(
2259 internal_obj->FastPropertyAt(descriptors->GetFieldIndex(0)));
2260 // HashTable header (5) and 4 initial entries (8).
2261 CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
2262 }
2263}
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002264
2265
2266TEST(IncrementalMarkingClearsTypeFeedbackCells) {
2267 if (i::FLAG_always_opt) return;
2268 InitializeVM();
2269 v8::HandleScope scope;
2270 v8::Local<v8::Value> fun1, fun2;
2271
2272 {
2273 LocalContext env;
2274 CompileRun("function fun() {};");
2275 fun1 = env->Global()->Get(v8_str("fun"));
2276 }
2277
2278 {
2279 LocalContext env;
2280 CompileRun("function fun() {};");
2281 fun2 = env->Global()->Get(v8_str("fun"));
2282 }
2283
2284 // Prepare function f that contains type feedback for closures
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002285 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002286 v8::Context::GetCurrent()->Global()->Set(v8_str("fun1"), fun1);
2287 v8::Context::GetCurrent()->Global()->Set(v8_str("fun2"), fun2);
2288 CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
2289 Handle<JSFunction> f =
2290 v8::Utils::OpenHandle(
2291 *v8::Handle<v8::Function>::Cast(
2292 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2293 Handle<TypeFeedbackCells> cells(TypeFeedbackInfo::cast(
2294 f->shared()->code()->type_feedback_info())->type_feedback_cells());
2295
2296 CHECK_EQ(2, cells->CellCount());
2297 CHECK(cells->Cell(0)->value()->IsJSFunction());
2298 CHECK(cells->Cell(1)->value()->IsJSFunction());
2299
2300 SimulateIncrementalMarking();
2301 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2302
2303 CHECK_EQ(2, cells->CellCount());
2304 CHECK(cells->Cell(0)->value()->IsTheHole());
2305 CHECK(cells->Cell(1)->value()->IsTheHole());
2306}
2307
2308
2309static Code* FindFirstIC(Code* code, Code::Kind kind) {
2310 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
2311 RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
2312 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID) |
2313 RelocInfo::ModeMask(RelocInfo::CODE_TARGET_CONTEXT);
2314 for (RelocIterator it(code, mask); !it.done(); it.next()) {
2315 RelocInfo* info = it.rinfo();
2316 Code* target = Code::GetCodeFromTargetAddress(info->target_address());
2317 if (target->is_inline_cache_stub() && target->kind() == kind) {
2318 return target;
2319 }
2320 }
2321 return NULL;
2322}
2323
2324
2325TEST(IncrementalMarkingPreservesMonomorhpicIC) {
2326 if (i::FLAG_always_opt) return;
2327 InitializeVM();
2328 v8::HandleScope scope;
2329
2330 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002331 // originating from the same native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002332 CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
2333 "function f(o) { return o.x; } f(obj); f(obj);");
2334 Handle<JSFunction> f =
2335 v8::Utils::OpenHandle(
2336 *v8::Handle<v8::Function>::Cast(
2337 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2338
2339 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2340 CHECK(ic_before->ic_state() == MONOMORPHIC);
2341
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002342 SimulateIncrementalMarking();
2343 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2344
2345 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2346 CHECK(ic_after->ic_state() == MONOMORPHIC);
2347}
2348
2349
2350TEST(IncrementalMarkingClearsMonomorhpicIC) {
2351 if (i::FLAG_always_opt) return;
2352 InitializeVM();
2353 v8::HandleScope scope;
2354 v8::Local<v8::Value> obj1;
2355
2356 {
2357 LocalContext env;
2358 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2359 obj1 = env->Global()->Get(v8_str("obj"));
2360 }
2361
2362 // Prepare function f that contains a monomorphic IC for object
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002363 // originating from a different native context.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002364 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2365 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
2366 Handle<JSFunction> f =
2367 v8::Utils::OpenHandle(
2368 *v8::Handle<v8::Function>::Cast(
2369 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2370
2371 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2372 CHECK(ic_before->ic_state() == MONOMORPHIC);
2373
2374 // Fire context dispose notification.
2375 v8::V8::ContextDisposedNotification();
2376 SimulateIncrementalMarking();
2377 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2378
2379 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2380 CHECK(ic_after->ic_state() == UNINITIALIZED);
2381}
2382
2383
2384TEST(IncrementalMarkingClearsPolymorhpicIC) {
2385 if (i::FLAG_always_opt) return;
2386 InitializeVM();
2387 v8::HandleScope scope;
2388 v8::Local<v8::Value> obj1, obj2;
2389
2390 {
2391 LocalContext env;
2392 CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
2393 obj1 = env->Global()->Get(v8_str("obj"));
2394 }
2395
2396 {
2397 LocalContext env;
2398 CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
2399 obj2 = env->Global()->Get(v8_str("obj"));
2400 }
2401
2402 // Prepare function f that contains a polymorphic IC for objects
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00002403 // originating from two different native contexts.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002404 v8::Context::GetCurrent()->Global()->Set(v8_str("obj1"), obj1);
2405 v8::Context::GetCurrent()->Global()->Set(v8_str("obj2"), obj2);
2406 CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
2407 Handle<JSFunction> f =
2408 v8::Utils::OpenHandle(
2409 *v8::Handle<v8::Function>::Cast(
2410 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2411
2412 Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2413 CHECK(ic_before->ic_state() == MEGAMORPHIC);
2414
2415 // Fire context dispose notification.
2416 v8::V8::ContextDisposedNotification();
2417 SimulateIncrementalMarking();
2418 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2419
2420 Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
2421 CHECK(ic_after->ic_state() == UNINITIALIZED);
2422}
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002423
2424
2425class SourceResource: public v8::String::ExternalAsciiStringResource {
2426 public:
2427 explicit SourceResource(const char* data)
2428 : data_(data), length_(strlen(data)) { }
2429
2430 virtual void Dispose() {
2431 i::DeleteArray(data_);
2432 data_ = NULL;
2433 }
2434
2435 const char* data() const { return data_; }
2436
2437 size_t length() const { return length_; }
2438
2439 bool IsDisposed() { return data_ == NULL; }
2440
2441 private:
2442 const char* data_;
2443 size_t length_;
2444};
2445
2446
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002447void ReleaseStackTraceDataTest(const char* source) {
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002448 // Test that the data retained by the Error.stack accessor is released
2449 // after the first time the accessor is fired. We use external string
2450 // to check whether the data is being released since the external string
2451 // resource's callback is fired when the external string is GC'ed.
2452 InitializeVM();
2453 v8::HandleScope scope;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002454 SourceResource* resource = new SourceResource(i::StrDup(source));
2455 {
2456 v8::HandleScope scope;
2457 v8::Handle<v8::String> source_string = v8::String::NewExternal(resource);
2458 v8::Script::Compile(source_string)->Run();
2459 CHECK(!resource->IsDisposed());
2460 }
2461 HEAP->CollectAllAvailableGarbage();
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002462
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002463 // External source has been released.
2464 CHECK(resource->IsDisposed());
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00002465 delete resource;
2466}
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002467
2468
yangguo@chromium.orgeeb44b62012-11-13 13:56:09 +00002469TEST(ReleaseStackTraceData) {
2470 static const char* source1 = "var error = null; "
2471 /* Normal Error */ "try { "
2472 " throw new Error(); "
2473 "} catch (e) { "
2474 " error = e; "
2475 "} ";
2476 static const char* source2 = "var error = null; "
2477 /* Stack overflow */ "try { "
2478 " (function f() { f(); })(); "
2479 "} catch (e) { "
2480 " error = e; "
2481 "} ";
2482 ReleaseStackTraceDataTest(source1);
2483 ReleaseStackTraceDataTest(source2);
2484}
2485
2486
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002487TEST(Regression144230) {
2488 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002489 Isolate* isolate = Isolate::Current();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002490 v8::HandleScope scope;
2491
2492 // First make sure that the uninitialized CallIC stub is on a single page
2493 // that will later be selected as an evacuation candidate.
2494 {
2495 v8::HandleScope inner_scope;
2496 AlwaysAllocateScope always_allocate;
2497 SimulateFullSpace(HEAP->code_space());
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002498 isolate->stub_cache()->ComputeCallInitialize(9, RelocInfo::CODE_TARGET);
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002499 }
2500
2501 // Second compile a CallIC and execute it once so that it gets patched to
2502 // the pre-monomorphic stub. These code objects are on yet another page.
2503 {
2504 v8::HandleScope inner_scope;
2505 AlwaysAllocateScope always_allocate;
2506 SimulateFullSpace(HEAP->code_space());
2507 CompileRun("var o = { f:function(a,b,c,d,e,f,g,h,i) {}};"
2508 "function call() { o.f(1,2,3,4,5,6,7,8,9); };"
2509 "call();");
2510 }
2511
2512 // Third we fill up the last page of the code space so that it does not get
2513 // chosen as an evacuation candidate.
2514 {
2515 v8::HandleScope inner_scope;
2516 AlwaysAllocateScope always_allocate;
2517 CompileRun("for (var i = 0; i < 2000; i++) {"
2518 " eval('function f' + i + '() { return ' + i +'; };' +"
2519 " 'f' + i + '();');"
2520 "}");
2521 }
2522 HEAP->CollectAllGarbage(Heap::kNoGCFlags);
2523
2524 // Fourth is the tricky part. Make sure the code containing the CallIC is
2525 // visited first without clearing the IC. The shared function info is then
2526 // visited later, causing the CallIC to be cleared.
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002527 Handle<String> name = FACTORY->LookupUtf8Symbol("call");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002528 Handle<GlobalObject> global(isolate->context()->global_object());
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002529 MaybeObject* maybe_call = global->GetProperty(*name);
2530 JSFunction* call = JSFunction::cast(maybe_call->ToObjectChecked());
2531 USE(global->SetProperty(*name, Smi::FromInt(0), NONE, kNonStrictMode));
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002532 isolate->compilation_cache()->Clear();
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002533 call->shared()->set_ic_age(HEAP->global_ic_age() + 1);
2534 Handle<Object> call_code(call->code());
2535 Handle<Object> call_function(call);
2536
2537 // Now we are ready to mess up the heap.
2538 HEAP->CollectAllGarbage(Heap::kReduceMemoryFootprintMask);
2539
2540 // Either heap verification caught the problem already or we go kaboom once
2541 // the CallIC is executed the next time.
2542 USE(global->SetProperty(*name, *call_function, NONE, kNonStrictMode));
2543 CompileRun("call();");
2544}
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002545
2546
2547TEST(Regress159140) {
2548 i::FLAG_allow_natives_syntax = true;
2549 i::FLAG_flush_code_incrementally = true;
2550 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002551 Isolate* isolate = Isolate::Current();
2552 Heap* heap = isolate->heap();
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002553 v8::HandleScope scope;
2554
2555 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002556 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002557
2558 // Prepare several closures that are all eligible for code flushing
2559 // because all reachable ones are not optimized. Make sure that the
2560 // optimized code object is directly reachable through a handle so
2561 // that it is marked black during incremental marking.
2562 Handle<Code> code;
2563 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002564 HandleScope inner_scope(isolate);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002565 CompileRun("function h(x) {}"
2566 "function mkClosure() {"
2567 " return function(x) { return x + 1; };"
2568 "}"
2569 "var f = mkClosure();"
2570 "var g = mkClosure();"
2571 "f(1); f(2);"
2572 "g(1); g(2);"
2573 "h(1); h(2);"
2574 "%OptimizeFunctionOnNextCall(f); f(3);"
2575 "%OptimizeFunctionOnNextCall(h); h(3);");
2576
2577 Handle<JSFunction> f =
2578 v8::Utils::OpenHandle(
2579 *v8::Handle<v8::Function>::Cast(
2580 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2581 CHECK(f->is_compiled());
2582 CompileRun("f = null;");
2583
2584 Handle<JSFunction> g =
2585 v8::Utils::OpenHandle(
2586 *v8::Handle<v8::Function>::Cast(
2587 v8::Context::GetCurrent()->Global()->Get(v8_str("g"))));
2588 CHECK(g->is_compiled());
2589 const int kAgingThreshold = 6;
2590 for (int i = 0; i < kAgingThreshold; i++) {
2591 g->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2592 }
2593
2594 code = inner_scope.CloseAndEscape(Handle<Code>(f->code()));
2595 }
2596
2597 // Simulate incremental marking so that the functions are enqueued as
2598 // code flushing candidates. Then optimize one function. Finally
2599 // finish the GC to complete code flushing.
2600 SimulateIncrementalMarking();
2601 CompileRun("%OptimizeFunctionOnNextCall(g); g(3);");
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002602 heap->CollectAllGarbage(Heap::kNoGCFlags);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00002603
2604 // Unoptimized code is missing and the deoptimizer will go ballistic.
2605 CompileRun("g('bozo');");
2606}
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002607
2608
2609TEST(Regress165495) {
2610 i::FLAG_allow_natives_syntax = true;
2611 i::FLAG_flush_code_incrementally = true;
2612 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002613 Isolate* isolate = Isolate::Current();
2614 Heap* heap = isolate->heap();
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002615 v8::HandleScope scope;
2616
2617 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002618 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002619
2620 // Prepare an optimized closure that the optimized code map will get
2621 // populated. Then age the unoptimized code to trigger code flushing
2622 // but make sure the optimized code is unreachable.
2623 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002624 HandleScope inner_scope(isolate);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002625 CompileRun("function mkClosure() {"
2626 " return function(x) { return x + 1; };"
2627 "}"
2628 "var f = mkClosure();"
2629 "f(1); f(2);"
2630 "%OptimizeFunctionOnNextCall(f); f(3);");
2631
2632 Handle<JSFunction> f =
2633 v8::Utils::OpenHandle(
2634 *v8::Handle<v8::Function>::Cast(
2635 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2636 CHECK(f->is_compiled());
2637 const int kAgingThreshold = 6;
2638 for (int i = 0; i < kAgingThreshold; i++) {
2639 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2640 }
2641
2642 CompileRun("f = null;");
2643 }
2644
2645 // Simulate incremental marking so that unoptimized code is flushed
2646 // even though it still is cached in the optimized code map.
2647 SimulateIncrementalMarking();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002648 heap->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002649
2650 // Make a new closure that will get code installed from the code map.
2651 // Unoptimized code is missing and the deoptimizer will go ballistic.
2652 CompileRun("var g = mkClosure(); g('bozo');");
2653}
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002654
2655
2656TEST(Regress169209) {
mmassi@chromium.org2f0efde2013-02-06 14:12:58 +00002657 i::FLAG_stress_compaction = false;
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002658 i::FLAG_allow_natives_syntax = true;
2659 i::FLAG_flush_code_incrementally = true;
2660 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002661 Isolate* isolate = Isolate::Current();
2662 Heap* heap = isolate->heap();
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002663 v8::HandleScope scope;
2664
2665 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002666 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002667
2668 // Prepare a shared function info eligible for code flushing for which
2669 // the unoptimized code will be replaced during optimization.
2670 Handle<SharedFunctionInfo> shared1;
2671 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002672 HandleScope inner_scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002673 CompileRun("function f() { return 'foobar'; }"
2674 "function g(x) { if (x) f(); }"
2675 "f();"
2676 "g(false);"
2677 "g(false);");
2678
2679 Handle<JSFunction> f =
2680 v8::Utils::OpenHandle(
2681 *v8::Handle<v8::Function>::Cast(
2682 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2683 CHECK(f->is_compiled());
2684 const int kAgingThreshold = 6;
2685 for (int i = 0; i < kAgingThreshold; i++) {
2686 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2687 }
2688
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002689 shared1 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002690 }
2691
2692 // Prepare a shared function info eligible for code flushing that will
2693 // represent the dangling tail of the candidate list.
2694 Handle<SharedFunctionInfo> shared2;
2695 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002696 HandleScope inner_scope(isolate);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002697 CompileRun("function flushMe() { return 0; }"
2698 "flushMe(1);");
2699
2700 Handle<JSFunction> f =
2701 v8::Utils::OpenHandle(
2702 *v8::Handle<v8::Function>::Cast(
2703 v8::Context::GetCurrent()->Global()->Get(v8_str("flushMe"))));
2704 CHECK(f->is_compiled());
2705 const int kAgingThreshold = 6;
2706 for (int i = 0; i < kAgingThreshold; i++) {
2707 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2708 }
2709
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002710 shared2 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002711 }
2712
2713 // Simulate incremental marking and collect code flushing candidates.
2714 SimulateIncrementalMarking();
2715 CHECK(shared1->code()->gc_metadata() != NULL);
2716
2717 // Optimize function and make sure the unoptimized code is replaced.
2718#ifdef DEBUG
2719 FLAG_stop_at = "f";
2720#endif
2721 CompileRun("%OptimizeFunctionOnNextCall(g);"
2722 "g(false);");
2723
2724 // Finish garbage collection cycle.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002725 heap->CollectAllGarbage(Heap::kNoGCFlags);
yangguo@chromium.org9768bf12013-01-11 14:51:07 +00002726 CHECK(shared1->code()->gc_metadata() == NULL);
2727}
yangguo@chromium.org28381b42013-01-21 14:39:38 +00002728
2729
2730// Helper function that simulates a fill new-space in the heap.
2731static inline void AllocateAllButNBytes(v8::internal::NewSpace* space,
2732 int extra_bytes) {
2733 int space_remaining = static_cast<int>(
2734 *space->allocation_limit_address() - *space->allocation_top_address());
2735 CHECK(space_remaining >= extra_bytes);
2736 int new_linear_size = space_remaining - extra_bytes;
2737 v8::internal::MaybeObject* maybe = space->AllocateRaw(new_linear_size);
2738 v8::internal::FreeListNode* node = v8::internal::FreeListNode::cast(maybe);
2739 node->set_size(space->heap(), new_linear_size);
2740}
2741
2742
2743TEST(Regress169928) {
2744 i::FLAG_allow_natives_syntax = true;
2745 i::FLAG_crankshaft = false;
2746 InitializeVM();
2747 v8::HandleScope scope;
2748
2749 // Some flags turn Scavenge collections into Mark-sweep collections
2750 // and hence are incompatible with this test case.
2751 if (FLAG_gc_global || FLAG_stress_compaction) return;
2752
2753 // Prepare the environment
2754 CompileRun("function fastliteralcase(literal, value) {"
2755 " literal[0] = value;"
2756 " return literal;"
2757 "}"
2758 "function get_standard_literal() {"
2759 " var literal = [1, 2, 3];"
2760 " return literal;"
2761 "}"
2762 "obj = fastliteralcase(get_standard_literal(), 1);"
2763 "obj = fastliteralcase(get_standard_literal(), 1.5);"
2764 "obj = fastliteralcase(get_standard_literal(), 2);");
2765
2766 // prepare the heap
2767 v8::Local<v8::String> mote_code_string =
2768 v8_str("fastliteralcase(mote, 2.5);");
2769
2770 v8::Local<v8::String> array_name = v8_str("mote");
2771 v8::Context::GetCurrent()->Global()->Set(array_name, v8::Int32::New(0));
2772
2773 // First make sure we flip spaces
2774 HEAP->CollectGarbage(NEW_SPACE);
2775
2776 // Allocate the object.
2777 Handle<FixedArray> array_data = FACTORY->NewFixedArray(2, NOT_TENURED);
2778 array_data->set(0, Smi::FromInt(1));
2779 array_data->set(1, Smi::FromInt(2));
2780
2781 AllocateAllButNBytes(HEAP->new_space(),
2782 JSArray::kSize + AllocationSiteInfo::kSize +
2783 kPointerSize);
2784
2785 Handle<JSArray> array = FACTORY->NewJSArrayWithElements(array_data,
2786 FAST_SMI_ELEMENTS,
2787 NOT_TENURED);
2788
2789 CHECK_EQ(Smi::FromInt(2), array->length());
2790 CHECK(array->HasFastSmiOrObjectElements());
2791
2792 // We need filler the size of AllocationSiteInfo object, plus an extra
2793 // fill pointer value.
2794 MaybeObject* maybe_object = HEAP->AllocateRaw(
2795 AllocationSiteInfo::kSize + kPointerSize, NEW_SPACE, OLD_POINTER_SPACE);
2796 Object* obj = NULL;
2797 CHECK(maybe_object->ToObject(&obj));
2798 Address addr_obj = reinterpret_cast<Address>(
2799 reinterpret_cast<byte*>(obj - kHeapObjectTag));
2800 HEAP->CreateFillerObjectAt(addr_obj,
2801 AllocationSiteInfo::kSize + kPointerSize);
2802
2803 // Give the array a name, making sure not to allocate strings.
2804 v8::Handle<v8::Object> array_obj = v8::Utils::ToLocal(array);
2805 v8::Context::GetCurrent()->Global()->Set(array_name, array_obj);
2806
2807 // This should crash with a protection violation if we are running a build
2808 // with the bug.
2809 AlwaysAllocateScope aa_scope;
2810 v8::Script::Compile(mote_code_string)->Run();
2811}
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002812
2813
2814TEST(Regress168801) {
2815 i::FLAG_always_compact = true;
2816 i::FLAG_cache_optimized_code = false;
2817 i::FLAG_allow_natives_syntax = true;
2818 i::FLAG_flush_code_incrementally = true;
2819 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002820 Isolate* isolate = Isolate::Current();
2821 Heap* heap = isolate->heap();
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002822 v8::HandleScope scope;
2823
2824 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002825 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002826
2827 // Ensure the code ends up on an evacuation candidate.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002828 SimulateFullSpace(heap->code_space());
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002829
2830 // Prepare an unoptimized function that is eligible for code flushing.
2831 Handle<JSFunction> function;
2832 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002833 HandleScope inner_scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002834 CompileRun("function mkClosure() {"
2835 " return function(x) { return x + 1; };"
2836 "}"
2837 "var f = mkClosure();"
2838 "f(1); f(2);");
2839
2840 Handle<JSFunction> f =
2841 v8::Utils::OpenHandle(
2842 *v8::Handle<v8::Function>::Cast(
2843 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2844 CHECK(f->is_compiled());
2845 const int kAgingThreshold = 6;
2846 for (int i = 0; i < kAgingThreshold; i++) {
2847 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2848 }
2849
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002850 function = inner_scope.CloseAndEscape(handle(*f, isolate));
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002851 }
2852
2853 // Simulate incremental marking so that unoptimized function is enqueued as a
2854 // candidate for code flushing. The shared function info however will not be
2855 // explicitly enqueued.
2856 SimulateIncrementalMarking();
2857
2858 // Now optimize the function so that it is taken off the candidate list.
2859 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002860 HandleScope inner_scope(isolate);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002861 CompileRun("%OptimizeFunctionOnNextCall(f); f(3);");
2862 }
2863
2864 // This cycle will bust the heap and subsequent cycles will go ballistic.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002865 heap->CollectAllGarbage(Heap::kNoGCFlags);
2866 heap->CollectAllGarbage(Heap::kNoGCFlags);
mvstanton@chromium.orgc47dff52013-01-23 16:28:41 +00002867}
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002868
2869
2870TEST(Regress173458) {
2871 i::FLAG_always_compact = true;
2872 i::FLAG_cache_optimized_code = false;
2873 i::FLAG_allow_natives_syntax = true;
2874 i::FLAG_flush_code_incrementally = true;
2875 InitializeVM();
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002876 Isolate* isolate = Isolate::Current();
2877 Heap* heap = isolate->heap();
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002878 v8::HandleScope scope;
2879
2880 // Perform one initial GC to enable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002881 heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002882
2883 // Ensure the code ends up on an evacuation candidate.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002884 SimulateFullSpace(heap->code_space());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002885
2886 // Prepare an unoptimized function that is eligible for code flushing.
2887 Handle<JSFunction> function;
2888 {
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002889 HandleScope inner_scope(isolate);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002890 CompileRun("function mkClosure() {"
2891 " return function(x) { return x + 1; };"
2892 "}"
2893 "var f = mkClosure();"
2894 "f(1); f(2);");
2895
2896 Handle<JSFunction> f =
2897 v8::Utils::OpenHandle(
2898 *v8::Handle<v8::Function>::Cast(
2899 v8::Context::GetCurrent()->Global()->Get(v8_str("f"))));
2900 CHECK(f->is_compiled());
2901 const int kAgingThreshold = 6;
2902 for (int i = 0; i < kAgingThreshold; i++) {
2903 f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
2904 }
2905
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002906 function = inner_scope.CloseAndEscape(handle(*f, isolate));
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002907 }
2908
2909 // Simulate incremental marking so that unoptimized function is enqueued as a
2910 // candidate for code flushing. The shared function info however will not be
2911 // explicitly enqueued.
2912 SimulateIncrementalMarking();
2913
2914 // Now enable the debugger which in turn will disable code flushing.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002915 CHECK(isolate->debug()->Load());
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002916
2917 // This cycle will bust the heap and subsequent cycles will go ballistic.
yangguo@chromium.orgc03a1922013-02-19 13:55:47 +00002918 heap->CollectAllGarbage(Heap::kNoGCFlags);
2919 heap->CollectAllGarbage(Heap::kNoGCFlags);
hpayer@chromium.org7c3372b2013-02-13 17:26:04 +00002920}