bb54b0a8ee7526edece8e2756e960a666886bf35
[platform/framework/web/crosswalk.git] / src / v8 / test / cctest / test-heap.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 //     * Redistributions of source code must retain the above copyright
7 //       notice, this list of conditions and the following disclaimer.
8 //     * Redistributions in binary form must reproduce the above
9 //       copyright notice, this list of conditions and the following
10 //       disclaimer in the documentation and/or other materials provided
11 //       with the distribution.
12 //     * Neither the name of Google Inc. nor the names of its
13 //       contributors may be used to endorse or promote products derived
14 //       from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include <stdlib.h>
29 #include <utility>
30
31 #include "src/v8.h"
32
33 #include "src/compilation-cache.h"
34 #include "src/execution.h"
35 #include "src/factory.h"
36 #include "src/global-handles.h"
37 #include "src/macro-assembler.h"
38 #include "src/stub-cache.h"
39 #include "test/cctest/cctest.h"
40
41 using namespace v8::internal;
42
43 // Go through all incremental marking steps in one swoop.
44 static void SimulateIncrementalMarking() {
45   MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector();
46   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
47   if (collector->IsConcurrentSweepingInProgress()) {
48     collector->WaitUntilSweepingCompleted();
49   }
50   CHECK(marking->IsMarking() || marking->IsStopped());
51   if (marking->IsStopped()) {
52     marking->Start();
53   }
54   CHECK(marking->IsMarking());
55   while (!marking->IsComplete()) {
56     marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
57   }
58   CHECK(marking->IsComplete());
59 }
60
61
62 static void CheckMap(Map* map, int type, int instance_size) {
63   CHECK(map->IsHeapObject());
64 #ifdef DEBUG
65   CHECK(CcTest::heap()->Contains(map));
66 #endif
67   CHECK_EQ(CcTest::heap()->meta_map(), map->map());
68   CHECK_EQ(type, map->instance_type());
69   CHECK_EQ(instance_size, map->instance_size());
70 }
71
72
73 TEST(HeapMaps) {
74   CcTest::InitializeVM();
75   Heap* heap = CcTest::heap();
76   CheckMap(heap->meta_map(), MAP_TYPE, Map::kSize);
77   CheckMap(heap->heap_number_map(), HEAP_NUMBER_TYPE, HeapNumber::kSize);
78   CheckMap(heap->fixed_array_map(), FIXED_ARRAY_TYPE, kVariableSizeSentinel);
79   CheckMap(heap->string_map(), STRING_TYPE, kVariableSizeSentinel);
80 }
81
82
83 static void CheckOddball(Isolate* isolate, Object* obj, const char* string) {
84   CHECK(obj->IsOddball());
85   Handle<Object> handle(obj, isolate);
86   Object* print_string =
87       *Execution::ToString(isolate, handle).ToHandleChecked();
88   CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
89 }
90
91
92 static void CheckSmi(Isolate* isolate, int value, const char* string) {
93   Handle<Object> handle(Smi::FromInt(value), isolate);
94   Object* print_string =
95       *Execution::ToString(isolate, handle).ToHandleChecked();
96   CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
97 }
98
99
100 static void CheckNumber(Isolate* isolate, double value, const char* string) {
101   Handle<Object> number = isolate->factory()->NewNumber(value);
102   CHECK(number->IsNumber());
103   Handle<Object> print_string =
104       Execution::ToString(isolate, number).ToHandleChecked();
105   CHECK(String::cast(*print_string)->IsUtf8EqualTo(CStrVector(string)));
106 }
107
108
109 static void CheckFindCodeObject(Isolate* isolate) {
110   // Test FindCodeObject
111 #define __ assm.
112
113   Assembler assm(isolate, NULL, 0);
114
115   __ nop();  // supported on all architectures
116
117   CodeDesc desc;
118   assm.GetCode(&desc);
119   Handle<Code> code = isolate->factory()->NewCode(
120       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
121   CHECK(code->IsCode());
122
123   HeapObject* obj = HeapObject::cast(*code);
124   Address obj_addr = obj->address();
125
126   for (int i = 0; i < obj->Size(); i += kPointerSize) {
127     Object* found = isolate->FindCodeObject(obj_addr + i);
128     CHECK_EQ(*code, found);
129   }
130
131   Handle<Code> copy = isolate->factory()->NewCode(
132       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
133   HeapObject* obj_copy = HeapObject::cast(*copy);
134   Object* not_right = isolate->FindCodeObject(obj_copy->address() +
135                                               obj_copy->Size() / 2);
136   CHECK(not_right != *code);
137 }
138
139
140 TEST(HandleNull) {
141   CcTest::InitializeVM();
142   Isolate* isolate = CcTest::i_isolate();
143   HandleScope outer_scope(isolate);
144   LocalContext context;
145   Handle<Object> n(reinterpret_cast<Object*>(NULL), isolate);
146   CHECK(!n.is_null());
147 }
148
149
150 TEST(HeapObjects) {
151   CcTest::InitializeVM();
152   Isolate* isolate = CcTest::i_isolate();
153   Factory* factory = isolate->factory();
154   Heap* heap = isolate->heap();
155
156   HandleScope sc(isolate);
157   Handle<Object> value = factory->NewNumber(1.000123);
158   CHECK(value->IsHeapNumber());
159   CHECK(value->IsNumber());
160   CHECK_EQ(1.000123, value->Number());
161
162   value = factory->NewNumber(1.0);
163   CHECK(value->IsSmi());
164   CHECK(value->IsNumber());
165   CHECK_EQ(1.0, value->Number());
166
167   value = factory->NewNumberFromInt(1024);
168   CHECK(value->IsSmi());
169   CHECK(value->IsNumber());
170   CHECK_EQ(1024.0, value->Number());
171
172   value = factory->NewNumberFromInt(Smi::kMinValue);
173   CHECK(value->IsSmi());
174   CHECK(value->IsNumber());
175   CHECK_EQ(Smi::kMinValue, Handle<Smi>::cast(value)->value());
176
177   value = factory->NewNumberFromInt(Smi::kMaxValue);
178   CHECK(value->IsSmi());
179   CHECK(value->IsNumber());
180   CHECK_EQ(Smi::kMaxValue, Handle<Smi>::cast(value)->value());
181
182 #if !defined(V8_TARGET_ARCH_X64) && !defined(V8_TARGET_ARCH_ARM64)
183   // TODO(lrn): We need a NumberFromIntptr function in order to test this.
184   value = factory->NewNumberFromInt(Smi::kMinValue - 1);
185   CHECK(value->IsHeapNumber());
186   CHECK(value->IsNumber());
187   CHECK_EQ(static_cast<double>(Smi::kMinValue - 1), value->Number());
188 #endif
189
190   value = factory->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
191   CHECK(value->IsHeapNumber());
192   CHECK(value->IsNumber());
193   CHECK_EQ(static_cast<double>(static_cast<uint32_t>(Smi::kMaxValue) + 1),
194            value->Number());
195
196   value = factory->NewNumberFromUint(static_cast<uint32_t>(1) << 31);
197   CHECK(value->IsHeapNumber());
198   CHECK(value->IsNumber());
199   CHECK_EQ(static_cast<double>(static_cast<uint32_t>(1) << 31),
200            value->Number());
201
202   // nan oddball checks
203   CHECK(factory->nan_value()->IsNumber());
204   CHECK(std::isnan(factory->nan_value()->Number()));
205
206   Handle<String> s = factory->NewStringFromStaticAscii("fisk hest ");
207   CHECK(s->IsString());
208   CHECK_EQ(10, s->length());
209
210   Handle<String> object_string = Handle<String>::cast(factory->Object_string());
211   Handle<GlobalObject> global(CcTest::i_isolate()->context()->global_object());
212   CHECK(JSReceiver::HasOwnProperty(global, object_string));
213
214   // Check ToString for oddballs
215   CheckOddball(isolate, heap->true_value(), "true");
216   CheckOddball(isolate, heap->false_value(), "false");
217   CheckOddball(isolate, heap->null_value(), "null");
218   CheckOddball(isolate, heap->undefined_value(), "undefined");
219
220   // Check ToString for Smis
221   CheckSmi(isolate, 0, "0");
222   CheckSmi(isolate, 42, "42");
223   CheckSmi(isolate, -42, "-42");
224
225   // Check ToString for Numbers
226   CheckNumber(isolate, 1.1, "1.1");
227
228   CheckFindCodeObject(isolate);
229 }
230
231
232 TEST(Tagging) {
233   CcTest::InitializeVM();
234   int request = 24;
235   CHECK_EQ(request, static_cast<int>(OBJECT_POINTER_ALIGN(request)));
236   CHECK(Smi::FromInt(42)->IsSmi());
237   CHECK(Smi::FromInt(Smi::kMinValue)->IsSmi());
238   CHECK(Smi::FromInt(Smi::kMaxValue)->IsSmi());
239 }
240
241
242 TEST(GarbageCollection) {
243   CcTest::InitializeVM();
244   Isolate* isolate = CcTest::i_isolate();
245   Heap* heap = isolate->heap();
246   Factory* factory = isolate->factory();
247
248   HandleScope sc(isolate);
249   // Check GC.
250   heap->CollectGarbage(NEW_SPACE);
251
252   Handle<GlobalObject> global(CcTest::i_isolate()->context()->global_object());
253   Handle<String> name = factory->InternalizeUtf8String("theFunction");
254   Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
255   Handle<String> prop_namex = factory->InternalizeUtf8String("theSlotx");
256   Handle<String> obj_name = factory->InternalizeUtf8String("theObject");
257   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
258   Handle<Smi> twenty_four(Smi::FromInt(24), isolate);
259
260   {
261     HandleScope inner_scope(isolate);
262     // Allocate a function and keep it in global object's property.
263     Handle<JSFunction> function = factory->NewFunction(name);
264     JSReceiver::SetProperty(global, name, function, NONE, SLOPPY).Check();
265     // Allocate an object.  Unrooted after leaving the scope.
266     Handle<JSObject> obj = factory->NewJSObject(function);
267     JSReceiver::SetProperty(
268         obj, prop_name, twenty_three, NONE, SLOPPY).Check();
269     JSReceiver::SetProperty(
270         obj, prop_namex, twenty_four, NONE, SLOPPY).Check();
271
272     CHECK_EQ(Smi::FromInt(23),
273              *Object::GetProperty(obj, prop_name).ToHandleChecked());
274     CHECK_EQ(Smi::FromInt(24),
275              *Object::GetProperty(obj, prop_namex).ToHandleChecked());
276   }
277
278   heap->CollectGarbage(NEW_SPACE);
279
280   // Function should be alive.
281   CHECK(JSReceiver::HasOwnProperty(global, name));
282   // Check function is retained.
283   Handle<Object> func_value =
284       Object::GetProperty(global, name).ToHandleChecked();
285   CHECK(func_value->IsJSFunction());
286   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
287
288   {
289     HandleScope inner_scope(isolate);
290     // Allocate another object, make it reachable from global.
291     Handle<JSObject> obj = factory->NewJSObject(function);
292     JSReceiver::SetProperty(global, obj_name, obj, NONE, SLOPPY).Check();
293     JSReceiver::SetProperty(
294         obj, prop_name, twenty_three, NONE, SLOPPY).Check();
295   }
296
297   // After gc, it should survive.
298   heap->CollectGarbage(NEW_SPACE);
299
300   CHECK(JSReceiver::HasOwnProperty(global, obj_name));
301   Handle<Object> obj =
302       Object::GetProperty(global, obj_name).ToHandleChecked();
303   CHECK(obj->IsJSObject());
304   CHECK_EQ(Smi::FromInt(23),
305            *Object::GetProperty(obj, prop_name).ToHandleChecked());
306 }
307
308
309 static void VerifyStringAllocation(Isolate* isolate, const char* string) {
310   HandleScope scope(isolate);
311   Handle<String> s = isolate->factory()->NewStringFromUtf8(
312       CStrVector(string)).ToHandleChecked();
313   CHECK_EQ(StrLength(string), s->length());
314   for (int index = 0; index < s->length(); index++) {
315     CHECK_EQ(static_cast<uint16_t>(string[index]), s->Get(index));
316   }
317 }
318
319
320 TEST(String) {
321   CcTest::InitializeVM();
322   Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
323
324   VerifyStringAllocation(isolate, "a");
325   VerifyStringAllocation(isolate, "ab");
326   VerifyStringAllocation(isolate, "abc");
327   VerifyStringAllocation(isolate, "abcd");
328   VerifyStringAllocation(isolate, "fiskerdrengen er paa havet");
329 }
330
331
332 TEST(LocalHandles) {
333   CcTest::InitializeVM();
334   Isolate* isolate = CcTest::i_isolate();
335   Factory* factory = isolate->factory();
336
337   v8::HandleScope scope(CcTest::isolate());
338   const char* name = "Kasper the spunky";
339   Handle<String> string = factory->NewStringFromAsciiChecked(name);
340   CHECK_EQ(StrLength(name), string->length());
341 }
342
343
344 TEST(GlobalHandles) {
345   CcTest::InitializeVM();
346   Isolate* isolate = CcTest::i_isolate();
347   Heap* heap = isolate->heap();
348   Factory* factory = isolate->factory();
349   GlobalHandles* global_handles = isolate->global_handles();
350
351   Handle<Object> h1;
352   Handle<Object> h2;
353   Handle<Object> h3;
354   Handle<Object> h4;
355
356   {
357     HandleScope scope(isolate);
358
359     Handle<Object> i = factory->NewStringFromStaticAscii("fisk");
360     Handle<Object> u = factory->NewNumber(1.12344);
361
362     h1 = global_handles->Create(*i);
363     h2 = global_handles->Create(*u);
364     h3 = global_handles->Create(*i);
365     h4 = global_handles->Create(*u);
366   }
367
368   // after gc, it should survive
369   heap->CollectGarbage(NEW_SPACE);
370
371   CHECK((*h1)->IsString());
372   CHECK((*h2)->IsHeapNumber());
373   CHECK((*h3)->IsString());
374   CHECK((*h4)->IsHeapNumber());
375
376   CHECK_EQ(*h3, *h1);
377   GlobalHandles::Destroy(h1.location());
378   GlobalHandles::Destroy(h3.location());
379
380   CHECK_EQ(*h4, *h2);
381   GlobalHandles::Destroy(h2.location());
382   GlobalHandles::Destroy(h4.location());
383 }
384
385
386 static bool WeakPointerCleared = false;
387
388 static void TestWeakGlobalHandleCallback(
389     const v8::WeakCallbackData<v8::Value, void>& data) {
390   std::pair<v8::Persistent<v8::Value>*, int>* p =
391       reinterpret_cast<std::pair<v8::Persistent<v8::Value>*, int>*>(
392           data.GetParameter());
393   if (p->second == 1234) WeakPointerCleared = true;
394   p->first->Reset();
395 }
396
397
398 TEST(WeakGlobalHandlesScavenge) {
399   i::FLAG_stress_compaction = false;
400   CcTest::InitializeVM();
401   Isolate* isolate = CcTest::i_isolate();
402   Heap* heap = isolate->heap();
403   Factory* factory = isolate->factory();
404   GlobalHandles* global_handles = isolate->global_handles();
405
406   WeakPointerCleared = false;
407
408   Handle<Object> h1;
409   Handle<Object> h2;
410
411   {
412     HandleScope scope(isolate);
413
414     Handle<Object> i = factory->NewStringFromStaticAscii("fisk");
415     Handle<Object> u = factory->NewNumber(1.12344);
416
417     h1 = global_handles->Create(*i);
418     h2 = global_handles->Create(*u);
419   }
420
421   std::pair<Handle<Object>*, int> handle_and_id(&h2, 1234);
422   GlobalHandles::MakeWeak(h2.location(),
423                           reinterpret_cast<void*>(&handle_and_id),
424                           &TestWeakGlobalHandleCallback);
425
426   // Scavenge treats weak pointers as normal roots.
427   heap->CollectGarbage(NEW_SPACE);
428
429   CHECK((*h1)->IsString());
430   CHECK((*h2)->IsHeapNumber());
431
432   CHECK(!WeakPointerCleared);
433   CHECK(!global_handles->IsNearDeath(h2.location()));
434   CHECK(!global_handles->IsNearDeath(h1.location()));
435
436   GlobalHandles::Destroy(h1.location());
437   GlobalHandles::Destroy(h2.location());
438 }
439
440
441 TEST(WeakGlobalHandlesMark) {
442   CcTest::InitializeVM();
443   Isolate* isolate = CcTest::i_isolate();
444   Heap* heap = isolate->heap();
445   Factory* factory = isolate->factory();
446   GlobalHandles* global_handles = isolate->global_handles();
447
448   WeakPointerCleared = false;
449
450   Handle<Object> h1;
451   Handle<Object> h2;
452
453   {
454     HandleScope scope(isolate);
455
456     Handle<Object> i = factory->NewStringFromStaticAscii("fisk");
457     Handle<Object> u = factory->NewNumber(1.12344);
458
459     h1 = global_handles->Create(*i);
460     h2 = global_handles->Create(*u);
461   }
462
463   // Make sure the objects are promoted.
464   heap->CollectGarbage(OLD_POINTER_SPACE);
465   heap->CollectGarbage(NEW_SPACE);
466   CHECK(!heap->InNewSpace(*h1) && !heap->InNewSpace(*h2));
467
468   std::pair<Handle<Object>*, int> handle_and_id(&h2, 1234);
469   GlobalHandles::MakeWeak(h2.location(),
470                           reinterpret_cast<void*>(&handle_and_id),
471                           &TestWeakGlobalHandleCallback);
472   CHECK(!GlobalHandles::IsNearDeath(h1.location()));
473   CHECK(!GlobalHandles::IsNearDeath(h2.location()));
474
475   // Incremental marking potentially marked handles before they turned weak.
476   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
477
478   CHECK((*h1)->IsString());
479
480   CHECK(WeakPointerCleared);
481   CHECK(!GlobalHandles::IsNearDeath(h1.location()));
482
483   GlobalHandles::Destroy(h1.location());
484 }
485
486
487 TEST(DeleteWeakGlobalHandle) {
488   i::FLAG_stress_compaction = false;
489   CcTest::InitializeVM();
490   Isolate* isolate = CcTest::i_isolate();
491   Heap* heap = isolate->heap();
492   Factory* factory = isolate->factory();
493   GlobalHandles* global_handles = isolate->global_handles();
494
495   WeakPointerCleared = false;
496
497   Handle<Object> h;
498
499   {
500     HandleScope scope(isolate);
501
502     Handle<Object> i = factory->NewStringFromStaticAscii("fisk");
503     h = global_handles->Create(*i);
504   }
505
506   std::pair<Handle<Object>*, int> handle_and_id(&h, 1234);
507   GlobalHandles::MakeWeak(h.location(),
508                           reinterpret_cast<void*>(&handle_and_id),
509                           &TestWeakGlobalHandleCallback);
510
511   // Scanvenge does not recognize weak reference.
512   heap->CollectGarbage(NEW_SPACE);
513
514   CHECK(!WeakPointerCleared);
515
516   // Mark-compact treats weak reference properly.
517   heap->CollectGarbage(OLD_POINTER_SPACE);
518
519   CHECK(WeakPointerCleared);
520 }
521
522
523 static const char* not_so_random_string_table[] = {
524   "abstract",
525   "boolean",
526   "break",
527   "byte",
528   "case",
529   "catch",
530   "char",
531   "class",
532   "const",
533   "continue",
534   "debugger",
535   "default",
536   "delete",
537   "do",
538   "double",
539   "else",
540   "enum",
541   "export",
542   "extends",
543   "false",
544   "final",
545   "finally",
546   "float",
547   "for",
548   "function",
549   "goto",
550   "if",
551   "implements",
552   "import",
553   "in",
554   "instanceof",
555   "int",
556   "interface",
557   "long",
558   "native",
559   "new",
560   "null",
561   "package",
562   "private",
563   "protected",
564   "public",
565   "return",
566   "short",
567   "static",
568   "super",
569   "switch",
570   "synchronized",
571   "this",
572   "throw",
573   "throws",
574   "transient",
575   "true",
576   "try",
577   "typeof",
578   "var",
579   "void",
580   "volatile",
581   "while",
582   "with",
583   0
584 };
585
586
587 static void CheckInternalizedStrings(const char** strings) {
588   Isolate* isolate = CcTest::i_isolate();
589   Factory* factory = isolate->factory();
590   for (const char* string = *strings; *strings != 0; string = *strings++) {
591     HandleScope scope(isolate);
592     Handle<String> a =
593         isolate->factory()->InternalizeUtf8String(CStrVector(string));
594     // InternalizeUtf8String may return a failure if a GC is needed.
595     CHECK(a->IsInternalizedString());
596     Handle<String> b = factory->InternalizeUtf8String(string);
597     CHECK_EQ(*b, *a);
598     CHECK(b->IsUtf8EqualTo(CStrVector(string)));
599     b = isolate->factory()->InternalizeUtf8String(CStrVector(string));
600     CHECK_EQ(*b, *a);
601     CHECK(b->IsUtf8EqualTo(CStrVector(string)));
602   }
603 }
604
605
606 TEST(StringTable) {
607   CcTest::InitializeVM();
608
609   v8::HandleScope sc(CcTest::isolate());
610   CheckInternalizedStrings(not_so_random_string_table);
611   CheckInternalizedStrings(not_so_random_string_table);
612 }
613
614
615 TEST(FunctionAllocation) {
616   CcTest::InitializeVM();
617   Isolate* isolate = CcTest::i_isolate();
618   Factory* factory = isolate->factory();
619
620   v8::HandleScope sc(CcTest::isolate());
621   Handle<String> name = factory->InternalizeUtf8String("theFunction");
622   Handle<JSFunction> function = factory->NewFunction(name);
623
624   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
625   Handle<Smi> twenty_four(Smi::FromInt(24), isolate);
626
627   Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
628   Handle<JSObject> obj = factory->NewJSObject(function);
629   JSReceiver::SetProperty(obj, prop_name, twenty_three, NONE, SLOPPY).Check();
630   CHECK_EQ(Smi::FromInt(23),
631            *Object::GetProperty(obj, prop_name).ToHandleChecked());
632   // Check that we can add properties to function objects.
633   JSReceiver::SetProperty(
634       function, prop_name, twenty_four, NONE, SLOPPY).Check();
635   CHECK_EQ(Smi::FromInt(24),
636            *Object::GetProperty(function, prop_name).ToHandleChecked());
637 }
638
639
640 TEST(ObjectProperties) {
641   CcTest::InitializeVM();
642   Isolate* isolate = CcTest::i_isolate();
643   Factory* factory = isolate->factory();
644
645   v8::HandleScope sc(CcTest::isolate());
646   Handle<String> object_string(String::cast(CcTest::heap()->Object_string()));
647   Handle<Object> object = Object::GetProperty(
648       CcTest::i_isolate()->global_object(), object_string).ToHandleChecked();
649   Handle<JSFunction> constructor = Handle<JSFunction>::cast(object);
650   Handle<JSObject> obj = factory->NewJSObject(constructor);
651   Handle<String> first = factory->InternalizeUtf8String("first");
652   Handle<String> second = factory->InternalizeUtf8String("second");
653
654   Handle<Smi> one(Smi::FromInt(1), isolate);
655   Handle<Smi> two(Smi::FromInt(2), isolate);
656
657   // check for empty
658   CHECK(!JSReceiver::HasOwnProperty(obj, first));
659
660   // add first
661   JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check();
662   CHECK(JSReceiver::HasOwnProperty(obj, first));
663
664   // delete first
665   JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check();
666   CHECK(!JSReceiver::HasOwnProperty(obj, first));
667
668   // add first and then second
669   JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check();
670   JSReceiver::SetProperty(obj, second, two, NONE, SLOPPY).Check();
671   CHECK(JSReceiver::HasOwnProperty(obj, first));
672   CHECK(JSReceiver::HasOwnProperty(obj, second));
673
674   // delete first and then second
675   JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check();
676   CHECK(JSReceiver::HasOwnProperty(obj, second));
677   JSReceiver::DeleteProperty(obj, second, JSReceiver::NORMAL_DELETION).Check();
678   CHECK(!JSReceiver::HasOwnProperty(obj, first));
679   CHECK(!JSReceiver::HasOwnProperty(obj, second));
680
681   // add first and then second
682   JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check();
683   JSReceiver::SetProperty(obj, second, two, NONE, SLOPPY).Check();
684   CHECK(JSReceiver::HasOwnProperty(obj, first));
685   CHECK(JSReceiver::HasOwnProperty(obj, second));
686
687   // delete second and then first
688   JSReceiver::DeleteProperty(obj, second, JSReceiver::NORMAL_DELETION).Check();
689   CHECK(JSReceiver::HasOwnProperty(obj, first));
690   JSReceiver::DeleteProperty(obj, first, JSReceiver::NORMAL_DELETION).Check();
691   CHECK(!JSReceiver::HasOwnProperty(obj, first));
692   CHECK(!JSReceiver::HasOwnProperty(obj, second));
693
694   // check string and internalized string match
695   const char* string1 = "fisk";
696   Handle<String> s1 = factory->NewStringFromAsciiChecked(string1);
697   JSReceiver::SetProperty(obj, s1, one, NONE, SLOPPY).Check();
698   Handle<String> s1_string = factory->InternalizeUtf8String(string1);
699   CHECK(JSReceiver::HasOwnProperty(obj, s1_string));
700
701   // check internalized string and string match
702   const char* string2 = "fugl";
703   Handle<String> s2_string = factory->InternalizeUtf8String(string2);
704   JSReceiver::SetProperty(obj, s2_string, one, NONE, SLOPPY).Check();
705   Handle<String> s2 = factory->NewStringFromAsciiChecked(string2);
706   CHECK(JSReceiver::HasOwnProperty(obj, s2));
707 }
708
709
710 TEST(JSObjectMaps) {
711   CcTest::InitializeVM();
712   Isolate* isolate = CcTest::i_isolate();
713   Factory* factory = isolate->factory();
714
715   v8::HandleScope sc(CcTest::isolate());
716   Handle<String> name = factory->InternalizeUtf8String("theFunction");
717   Handle<JSFunction> function = factory->NewFunction(name);
718
719   Handle<String> prop_name = factory->InternalizeUtf8String("theSlot");
720   Handle<JSObject> obj = factory->NewJSObject(function);
721   Handle<Map> initial_map(function->initial_map());
722
723   // Set a propery
724   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
725   JSReceiver::SetProperty(obj, prop_name, twenty_three, NONE, SLOPPY).Check();
726   CHECK_EQ(Smi::FromInt(23),
727            *Object::GetProperty(obj, prop_name).ToHandleChecked());
728
729   // Check the map has changed
730   CHECK(*initial_map != obj->map());
731 }
732
733
734 TEST(JSArray) {
735   CcTest::InitializeVM();
736   Isolate* isolate = CcTest::i_isolate();
737   Factory* factory = isolate->factory();
738
739   v8::HandleScope sc(CcTest::isolate());
740   Handle<String> name = factory->InternalizeUtf8String("Array");
741   Handle<Object> fun_obj = Object::GetProperty(
742       CcTest::i_isolate()->global_object(), name).ToHandleChecked();
743   Handle<JSFunction> function = Handle<JSFunction>::cast(fun_obj);
744
745   // Allocate the object.
746   Handle<Object> element;
747   Handle<JSObject> object = factory->NewJSObject(function);
748   Handle<JSArray> array = Handle<JSArray>::cast(object);
749   // We just initialized the VM, no heap allocation failure yet.
750   JSArray::Initialize(array, 0);
751
752   // Set array length to 0.
753   JSArray::SetElementsLength(array, handle(Smi::FromInt(0), isolate)).Check();
754   CHECK_EQ(Smi::FromInt(0), array->length());
755   // Must be in fast mode.
756   CHECK(array->HasFastSmiOrObjectElements());
757
758   // array[length] = name.
759   JSReceiver::SetElement(array, 0, name, NONE, SLOPPY).Check();
760   CHECK_EQ(Smi::FromInt(1), array->length());
761   element = i::Object::GetElement(isolate, array, 0).ToHandleChecked();
762   CHECK_EQ(*element, *name);
763
764   // Set array length with larger than smi value.
765   Handle<Object> length =
766       factory->NewNumberFromUint(static_cast<uint32_t>(Smi::kMaxValue) + 1);
767   JSArray::SetElementsLength(array, length).Check();
768
769   uint32_t int_length = 0;
770   CHECK(length->ToArrayIndex(&int_length));
771   CHECK_EQ(*length, array->length());
772   CHECK(array->HasDictionaryElements());  // Must be in slow mode.
773
774   // array[length] = name.
775   JSReceiver::SetElement(array, int_length, name, NONE, SLOPPY).Check();
776   uint32_t new_int_length = 0;
777   CHECK(array->length()->ToArrayIndex(&new_int_length));
778   CHECK_EQ(static_cast<double>(int_length), new_int_length - 1);
779   element = Object::GetElement(isolate, array, int_length).ToHandleChecked();
780   CHECK_EQ(*element, *name);
781   element = Object::GetElement(isolate, array, 0).ToHandleChecked();
782   CHECK_EQ(*element, *name);
783 }
784
785
786 TEST(JSObjectCopy) {
787   CcTest::InitializeVM();
788   Isolate* isolate = CcTest::i_isolate();
789   Factory* factory = isolate->factory();
790
791   v8::HandleScope sc(CcTest::isolate());
792   Handle<String> object_string(String::cast(CcTest::heap()->Object_string()));
793   Handle<Object> object = Object::GetProperty(
794       CcTest::i_isolate()->global_object(), object_string).ToHandleChecked();
795   Handle<JSFunction> constructor = Handle<JSFunction>::cast(object);
796   Handle<JSObject> obj = factory->NewJSObject(constructor);
797   Handle<String> first = factory->InternalizeUtf8String("first");
798   Handle<String> second = factory->InternalizeUtf8String("second");
799
800   Handle<Smi> one(Smi::FromInt(1), isolate);
801   Handle<Smi> two(Smi::FromInt(2), isolate);
802
803   JSReceiver::SetProperty(obj, first, one, NONE, SLOPPY).Check();
804   JSReceiver::SetProperty(obj, second, two, NONE, SLOPPY).Check();
805
806   JSReceiver::SetElement(obj, 0, first, NONE, SLOPPY).Check();
807   JSReceiver::SetElement(obj, 1, second, NONE, SLOPPY).Check();
808
809   // Make the clone.
810   Handle<Object> value1, value2;
811   Handle<JSObject> clone = factory->CopyJSObject(obj);
812   CHECK(!clone.is_identical_to(obj));
813
814   value1 = Object::GetElement(isolate, obj, 0).ToHandleChecked();
815   value2 = Object::GetElement(isolate, clone, 0).ToHandleChecked();
816   CHECK_EQ(*value1, *value2);
817   value1 = Object::GetElement(isolate, obj, 1).ToHandleChecked();
818   value2 = Object::GetElement(isolate, clone, 1).ToHandleChecked();
819   CHECK_EQ(*value1, *value2);
820
821   value1 = Object::GetProperty(obj, first).ToHandleChecked();
822   value2 = Object::GetProperty(clone, first).ToHandleChecked();
823   CHECK_EQ(*value1, *value2);
824   value1 = Object::GetProperty(obj, second).ToHandleChecked();
825   value2 = Object::GetProperty(clone, second).ToHandleChecked();
826   CHECK_EQ(*value1, *value2);
827
828   // Flip the values.
829   JSReceiver::SetProperty(clone, first, two, NONE, SLOPPY).Check();
830   JSReceiver::SetProperty(clone, second, one, NONE, SLOPPY).Check();
831
832   JSReceiver::SetElement(clone, 0, second, NONE, SLOPPY).Check();
833   JSReceiver::SetElement(clone, 1, first, NONE, SLOPPY).Check();
834
835   value1 = Object::GetElement(isolate, obj, 1).ToHandleChecked();
836   value2 = Object::GetElement(isolate, clone, 0).ToHandleChecked();
837   CHECK_EQ(*value1, *value2);
838   value1 = Object::GetElement(isolate, obj, 0).ToHandleChecked();
839   value2 = Object::GetElement(isolate, clone, 1).ToHandleChecked();
840   CHECK_EQ(*value1, *value2);
841
842   value1 = Object::GetProperty(obj, second).ToHandleChecked();
843   value2 = Object::GetProperty(clone, first).ToHandleChecked();
844   CHECK_EQ(*value1, *value2);
845   value1 = Object::GetProperty(obj, first).ToHandleChecked();
846   value2 = Object::GetProperty(clone, second).ToHandleChecked();
847   CHECK_EQ(*value1, *value2);
848 }
849
850
851 TEST(StringAllocation) {
852   CcTest::InitializeVM();
853   Isolate* isolate = CcTest::i_isolate();
854   Factory* factory = isolate->factory();
855
856   const unsigned char chars[] = { 0xe5, 0xa4, 0xa7 };
857   for (int length = 0; length < 100; length++) {
858     v8::HandleScope scope(CcTest::isolate());
859     char* non_ascii = NewArray<char>(3 * length + 1);
860     char* ascii = NewArray<char>(length + 1);
861     non_ascii[3 * length] = 0;
862     ascii[length] = 0;
863     for (int i = 0; i < length; i++) {
864       ascii[i] = 'a';
865       non_ascii[3 * i] = chars[0];
866       non_ascii[3 * i + 1] = chars[1];
867       non_ascii[3 * i + 2] = chars[2];
868     }
869     Handle<String> non_ascii_sym =
870         factory->InternalizeUtf8String(
871             Vector<const char>(non_ascii, 3 * length));
872     CHECK_EQ(length, non_ascii_sym->length());
873     Handle<String> ascii_sym =
874         factory->InternalizeOneByteString(OneByteVector(ascii, length));
875     CHECK_EQ(length, ascii_sym->length());
876     Handle<String> non_ascii_str = factory->NewStringFromUtf8(
877         Vector<const char>(non_ascii, 3 * length)).ToHandleChecked();
878     non_ascii_str->Hash();
879     CHECK_EQ(length, non_ascii_str->length());
880     Handle<String> ascii_str = factory->NewStringFromUtf8(
881         Vector<const char>(ascii, length)).ToHandleChecked();
882     ascii_str->Hash();
883     CHECK_EQ(length, ascii_str->length());
884     DeleteArray(non_ascii);
885     DeleteArray(ascii);
886   }
887 }
888
889
890 static int ObjectsFoundInHeap(Heap* heap, Handle<Object> objs[], int size) {
891   // Count the number of objects found in the heap.
892   int found_count = 0;
893   HeapIterator iterator(heap);
894   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
895     for (int i = 0; i < size; i++) {
896       if (*objs[i] == obj) {
897         found_count++;
898       }
899     }
900   }
901   return found_count;
902 }
903
904
905 TEST(Iteration) {
906   CcTest::InitializeVM();
907   Isolate* isolate = CcTest::i_isolate();
908   Factory* factory = isolate->factory();
909   v8::HandleScope scope(CcTest::isolate());
910
911   // Array of objects to scan haep for.
912   const int objs_count = 6;
913   Handle<Object> objs[objs_count];
914   int next_objs_index = 0;
915
916   // Allocate a JS array to OLD_POINTER_SPACE and NEW_SPACE
917   objs[next_objs_index++] = factory->NewJSArray(10);
918   objs[next_objs_index++] = factory->NewJSArray(10,
919                                                 FAST_HOLEY_ELEMENTS,
920                                                 TENURED);
921
922   // Allocate a small string to OLD_DATA_SPACE and NEW_SPACE
923   objs[next_objs_index++] =
924       factory->NewStringFromStaticAscii("abcdefghij");
925   objs[next_objs_index++] =
926       factory->NewStringFromStaticAscii("abcdefghij", TENURED);
927
928   // Allocate a large string (for large object space).
929   int large_size = Page::kMaxRegularHeapObjectSize + 1;
930   char* str = new char[large_size];
931   for (int i = 0; i < large_size - 1; ++i) str[i] = 'a';
932   str[large_size - 1] = '\0';
933   objs[next_objs_index++] = factory->NewStringFromAsciiChecked(str, TENURED);
934   delete[] str;
935
936   // Add a Map object to look for.
937   objs[next_objs_index++] = Handle<Map>(HeapObject::cast(*objs[0])->map());
938
939   CHECK_EQ(objs_count, next_objs_index);
940   CHECK_EQ(objs_count, ObjectsFoundInHeap(CcTest::heap(), objs, objs_count));
941 }
942
943
944 TEST(EmptyHandleEscapeFrom) {
945   CcTest::InitializeVM();
946
947   v8::HandleScope scope(CcTest::isolate());
948   Handle<JSObject> runaway;
949
950   {
951       v8::EscapableHandleScope nested(CcTest::isolate());
952       Handle<JSObject> empty;
953       runaway = empty.EscapeFrom(&nested);
954   }
955
956   CHECK(runaway.is_null());
957 }
958
959
960 static int LenFromSize(int size) {
961   return (size - FixedArray::kHeaderSize) / kPointerSize;
962 }
963
964
965 TEST(Regression39128) {
966   // Test case for crbug.com/39128.
967   CcTest::InitializeVM();
968   Isolate* isolate = CcTest::i_isolate();
969   TestHeap* heap = CcTest::test_heap();
970
971   // Increase the chance of 'bump-the-pointer' allocation in old space.
972   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
973
974   v8::HandleScope scope(CcTest::isolate());
975
976   // The plan: create JSObject which references objects in new space.
977   // Then clone this object (forcing it to go into old space) and check
978   // that region dirty marks are updated correctly.
979
980   // Step 1: prepare a map for the object.  We add 1 inobject property to it.
981   Handle<JSFunction> object_ctor(
982       CcTest::i_isolate()->native_context()->object_function());
983   CHECK(object_ctor->has_initial_map());
984   // Create a map with single inobject property.
985   Handle<Map> my_map = Map::Create(object_ctor, 1);
986   int n_properties = my_map->inobject_properties();
987   CHECK_GT(n_properties, 0);
988
989   int object_size = my_map->instance_size();
990
991   // Step 2: allocate a lot of objects so to almost fill new space: we need
992   // just enough room to allocate JSObject and thus fill the newspace.
993
994   int allocation_amount = Min(FixedArray::kMaxSize,
995                               Page::kMaxRegularHeapObjectSize + kPointerSize);
996   int allocation_len = LenFromSize(allocation_amount);
997   NewSpace* new_space = heap->new_space();
998   Address* top_addr = new_space->allocation_top_address();
999   Address* limit_addr = new_space->allocation_limit_address();
1000   while ((*limit_addr - *top_addr) > allocation_amount) {
1001     CHECK(!heap->always_allocate());
1002     Object* array = heap->AllocateFixedArray(allocation_len).ToObjectChecked();
1003     CHECK(new_space->Contains(array));
1004   }
1005
1006   // Step 3: now allocate fixed array and JSObject to fill the whole new space.
1007   int to_fill = static_cast<int>(*limit_addr - *top_addr - object_size);
1008   int fixed_array_len = LenFromSize(to_fill);
1009   CHECK(fixed_array_len < FixedArray::kMaxLength);
1010
1011   CHECK(!heap->always_allocate());
1012   Object* array = heap->AllocateFixedArray(fixed_array_len).ToObjectChecked();
1013   CHECK(new_space->Contains(array));
1014
1015   Object* object = heap->AllocateJSObjectFromMap(*my_map).ToObjectChecked();
1016   CHECK(new_space->Contains(object));
1017   JSObject* jsobject = JSObject::cast(object);
1018   CHECK_EQ(0, FixedArray::cast(jsobject->elements())->length());
1019   CHECK_EQ(0, jsobject->properties()->length());
1020   // Create a reference to object in new space in jsobject.
1021   FieldIndex index = FieldIndex::ForInObjectOffset(
1022       JSObject::kHeaderSize - kPointerSize);
1023   jsobject->FastPropertyAtPut(index, array);
1024
1025   CHECK_EQ(0, static_cast<int>(*limit_addr - *top_addr));
1026
1027   // Step 4: clone jsobject, but force always allocate first to create a clone
1028   // in old pointer space.
1029   Address old_pointer_space_top = heap->old_pointer_space()->top();
1030   AlwaysAllocateScope aa_scope(isolate);
1031   Object* clone_obj = heap->CopyJSObject(jsobject).ToObjectChecked();
1032   JSObject* clone = JSObject::cast(clone_obj);
1033   if (clone->address() != old_pointer_space_top) {
1034     // Alas, got allocated from free list, we cannot do checks.
1035     return;
1036   }
1037   CHECK(heap->old_pointer_space()->Contains(clone->address()));
1038 }
1039
1040
1041 TEST(TestCodeFlushing) {
1042   // If we do not flush code this test is invalid.
1043   if (!FLAG_flush_code) return;
1044   i::FLAG_allow_natives_syntax = true;
1045   i::FLAG_optimize_for_size = false;
1046   CcTest::InitializeVM();
1047   Isolate* isolate = CcTest::i_isolate();
1048   Factory* factory = isolate->factory();
1049   v8::HandleScope scope(CcTest::isolate());
1050   const char* source = "function foo() {"
1051                        "  var x = 42;"
1052                        "  var y = 42;"
1053                        "  var z = x + y;"
1054                        "};"
1055                        "foo()";
1056   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
1057
1058   // This compile will add the code to the compilation cache.
1059   { v8::HandleScope scope(CcTest::isolate());
1060     CompileRun(source);
1061   }
1062
1063   // Check function is compiled.
1064   Handle<Object> func_value = Object::GetProperty(
1065       CcTest::i_isolate()->global_object(), foo_name).ToHandleChecked();
1066   CHECK(func_value->IsJSFunction());
1067   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
1068   CHECK(function->shared()->is_compiled());
1069
1070   // The code will survive at least two GCs.
1071   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1072   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1073   CHECK(function->shared()->is_compiled());
1074
1075   // Simulate several GCs that use full marking.
1076   const int kAgingThreshold = 6;
1077   for (int i = 0; i < kAgingThreshold; i++) {
1078     CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1079   }
1080
1081   // foo should no longer be in the compilation cache
1082   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1083   CHECK(!function->is_compiled() || function->IsOptimized());
1084   // Call foo to get it recompiled.
1085   CompileRun("foo()");
1086   CHECK(function->shared()->is_compiled());
1087   CHECK(function->is_compiled());
1088 }
1089
1090
1091 TEST(TestCodeFlushingPreAged) {
1092   // If we do not flush code this test is invalid.
1093   if (!FLAG_flush_code) return;
1094   i::FLAG_allow_natives_syntax = true;
1095   i::FLAG_optimize_for_size = true;
1096   CcTest::InitializeVM();
1097   Isolate* isolate = CcTest::i_isolate();
1098   Factory* factory = isolate->factory();
1099   v8::HandleScope scope(CcTest::isolate());
1100   const char* source = "function foo() {"
1101                        "  var x = 42;"
1102                        "  var y = 42;"
1103                        "  var z = x + y;"
1104                        "};"
1105                        "foo()";
1106   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
1107
1108   // Compile foo, but don't run it.
1109   { v8::HandleScope scope(CcTest::isolate());
1110     CompileRun(source);
1111   }
1112
1113   // Check function is compiled.
1114   Handle<Object> func_value =
1115       Object::GetProperty(isolate->global_object(), foo_name).ToHandleChecked();
1116   CHECK(func_value->IsJSFunction());
1117   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
1118   CHECK(function->shared()->is_compiled());
1119
1120   // The code has been run so will survive at least one GC.
1121   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1122   CHECK(function->shared()->is_compiled());
1123
1124   // The code was only run once, so it should be pre-aged and collected on the
1125   // next GC.
1126   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1127   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1128
1129   // Execute the function again twice, and ensure it is reset to the young age.
1130   { v8::HandleScope scope(CcTest::isolate());
1131     CompileRun("foo();"
1132                "foo();");
1133   }
1134
1135   // The code will survive at least two GC now that it is young again.
1136   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1137   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1138   CHECK(function->shared()->is_compiled());
1139
1140   // Simulate several GCs that use full marking.
1141   const int kAgingThreshold = 6;
1142   for (int i = 0; i < kAgingThreshold; i++) {
1143     CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1144   }
1145
1146   // foo should no longer be in the compilation cache
1147   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1148   CHECK(!function->is_compiled() || function->IsOptimized());
1149   // Call foo to get it recompiled.
1150   CompileRun("foo()");
1151   CHECK(function->shared()->is_compiled());
1152   CHECK(function->is_compiled());
1153 }
1154
1155
1156 TEST(TestCodeFlushingIncremental) {
1157   // If we do not flush code this test is invalid.
1158   if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1159   i::FLAG_allow_natives_syntax = true;
1160   i::FLAG_optimize_for_size = false;
1161   CcTest::InitializeVM();
1162   Isolate* isolate = CcTest::i_isolate();
1163   Factory* factory = isolate->factory();
1164   v8::HandleScope scope(CcTest::isolate());
1165   const char* source = "function foo() {"
1166                        "  var x = 42;"
1167                        "  var y = 42;"
1168                        "  var z = x + y;"
1169                        "};"
1170                        "foo()";
1171   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
1172
1173   // This compile will add the code to the compilation cache.
1174   { v8::HandleScope scope(CcTest::isolate());
1175     CompileRun(source);
1176   }
1177
1178   // Check function is compiled.
1179   Handle<Object> func_value =
1180       Object::GetProperty(isolate->global_object(), foo_name).ToHandleChecked();
1181   CHECK(func_value->IsJSFunction());
1182   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
1183   CHECK(function->shared()->is_compiled());
1184
1185   // The code will survive at least two GCs.
1186   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1187   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1188   CHECK(function->shared()->is_compiled());
1189
1190   // Simulate several GCs that use incremental marking.
1191   const int kAgingThreshold = 6;
1192   for (int i = 0; i < kAgingThreshold; i++) {
1193     SimulateIncrementalMarking();
1194     CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1195   }
1196   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1197   CHECK(!function->is_compiled() || function->IsOptimized());
1198
1199   // This compile will compile the function again.
1200   { v8::HandleScope scope(CcTest::isolate());
1201     CompileRun("foo();");
1202   }
1203
1204   // Simulate several GCs that use incremental marking but make sure
1205   // the loop breaks once the function is enqueued as a candidate.
1206   for (int i = 0; i < kAgingThreshold; i++) {
1207     SimulateIncrementalMarking();
1208     if (!function->next_function_link()->IsUndefined()) break;
1209     CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1210   }
1211
1212   // Force optimization while incremental marking is active and while
1213   // the function is enqueued as a candidate.
1214   { v8::HandleScope scope(CcTest::isolate());
1215     CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1216   }
1217
1218   // Simulate one final GC to make sure the candidate queue is sane.
1219   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1220   CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1221   CHECK(function->is_compiled() || !function->IsOptimized());
1222 }
1223
1224
1225 TEST(TestCodeFlushingIncrementalScavenge) {
1226   // If we do not flush code this test is invalid.
1227   if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1228   i::FLAG_allow_natives_syntax = true;
1229   i::FLAG_optimize_for_size = false;
1230   CcTest::InitializeVM();
1231   Isolate* isolate = CcTest::i_isolate();
1232   Factory* factory = isolate->factory();
1233   v8::HandleScope scope(CcTest::isolate());
1234   const char* source = "var foo = function() {"
1235                        "  var x = 42;"
1236                        "  var y = 42;"
1237                        "  var z = x + y;"
1238                        "};"
1239                        "foo();"
1240                        "var bar = function() {"
1241                        "  var x = 23;"
1242                        "};"
1243                        "bar();";
1244   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
1245   Handle<String> bar_name = factory->InternalizeUtf8String("bar");
1246
1247   // Perfrom one initial GC to enable code flushing.
1248   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1249
1250   // This compile will add the code to the compilation cache.
1251   { v8::HandleScope scope(CcTest::isolate());
1252     CompileRun(source);
1253   }
1254
1255   // Check functions are compiled.
1256   Handle<Object> func_value =
1257       Object::GetProperty(isolate->global_object(), foo_name).ToHandleChecked();
1258   CHECK(func_value->IsJSFunction());
1259   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
1260   CHECK(function->shared()->is_compiled());
1261   Handle<Object> func_value2 =
1262       Object::GetProperty(isolate->global_object(), bar_name).ToHandleChecked();
1263   CHECK(func_value2->IsJSFunction());
1264   Handle<JSFunction> function2 = Handle<JSFunction>::cast(func_value2);
1265   CHECK(function2->shared()->is_compiled());
1266
1267   // Clear references to functions so that one of them can die.
1268   { v8::HandleScope scope(CcTest::isolate());
1269     CompileRun("foo = 0; bar = 0;");
1270   }
1271
1272   // Bump the code age so that flushing is triggered while the function
1273   // object is still located in new-space.
1274   const int kAgingThreshold = 6;
1275   for (int i = 0; i < kAgingThreshold; i++) {
1276     function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1277     function2->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1278   }
1279
1280   // Simulate incremental marking so that the functions are enqueued as
1281   // code flushing candidates. Then kill one of the functions. Finally
1282   // perform a scavenge while incremental marking is still running.
1283   SimulateIncrementalMarking();
1284   *function2.location() = NULL;
1285   CcTest::heap()->CollectGarbage(NEW_SPACE, "test scavenge while marking");
1286
1287   // Simulate one final GC to make sure the candidate queue is sane.
1288   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1289   CHECK(!function->shared()->is_compiled() || function->IsOptimized());
1290   CHECK(!function->is_compiled() || function->IsOptimized());
1291 }
1292
1293
1294 TEST(TestCodeFlushingIncrementalAbort) {
1295   // If we do not flush code this test is invalid.
1296   if (!FLAG_flush_code || !FLAG_flush_code_incrementally) return;
1297   i::FLAG_allow_natives_syntax = true;
1298   i::FLAG_optimize_for_size = false;
1299   CcTest::InitializeVM();
1300   Isolate* isolate = CcTest::i_isolate();
1301   Factory* factory = isolate->factory();
1302   Heap* heap = isolate->heap();
1303   v8::HandleScope scope(CcTest::isolate());
1304   const char* source = "function foo() {"
1305                        "  var x = 42;"
1306                        "  var y = 42;"
1307                        "  var z = x + y;"
1308                        "};"
1309                        "foo()";
1310   Handle<String> foo_name = factory->InternalizeUtf8String("foo");
1311
1312   // This compile will add the code to the compilation cache.
1313   { v8::HandleScope scope(CcTest::isolate());
1314     CompileRun(source);
1315   }
1316
1317   // Check function is compiled.
1318   Handle<Object> func_value =
1319       Object::GetProperty(isolate->global_object(), foo_name).ToHandleChecked();
1320   CHECK(func_value->IsJSFunction());
1321   Handle<JSFunction> function = Handle<JSFunction>::cast(func_value);
1322   CHECK(function->shared()->is_compiled());
1323
1324   // The code will survive at least two GCs.
1325   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1326   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
1327   CHECK(function->shared()->is_compiled());
1328
1329   // Bump the code age so that flushing is triggered.
1330   const int kAgingThreshold = 6;
1331   for (int i = 0; i < kAgingThreshold; i++) {
1332     function->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
1333   }
1334
1335   // Simulate incremental marking so that the function is enqueued as
1336   // code flushing candidate.
1337   SimulateIncrementalMarking();
1338
1339   // Enable the debugger and add a breakpoint while incremental marking
1340   // is running so that incremental marking aborts and code flushing is
1341   // disabled.
1342   int position = 0;
1343   Handle<Object> breakpoint_object(Smi::FromInt(0), isolate);
1344   isolate->debug()->SetBreakPoint(function, breakpoint_object, &position);
1345   isolate->debug()->ClearAllBreakPoints();
1346
1347   // Force optimization now that code flushing is disabled.
1348   { v8::HandleScope scope(CcTest::isolate());
1349     CompileRun("%OptimizeFunctionOnNextCall(foo); foo();");
1350   }
1351
1352   // Simulate one final GC to make sure the candidate queue is sane.
1353   heap->CollectAllGarbage(Heap::kNoGCFlags);
1354   CHECK(function->shared()->is_compiled() || !function->IsOptimized());
1355   CHECK(function->is_compiled() || !function->IsOptimized());
1356 }
1357
1358
1359 // Count the number of native contexts in the weak list of native contexts.
1360 int CountNativeContexts() {
1361   int count = 0;
1362   Object* object = CcTest::heap()->native_contexts_list();
1363   while (!object->IsUndefined()) {
1364     count++;
1365     object = Context::cast(object)->get(Context::NEXT_CONTEXT_LINK);
1366   }
1367   return count;
1368 }
1369
1370
1371 // Count the number of user functions in the weak list of optimized
1372 // functions attached to a native context.
1373 static int CountOptimizedUserFunctions(v8::Handle<v8::Context> context) {
1374   int count = 0;
1375   Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1376   Object* object = icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST);
1377   while (object->IsJSFunction() && !JSFunction::cast(object)->IsBuiltin()) {
1378     count++;
1379     object = JSFunction::cast(object)->next_function_link();
1380   }
1381   return count;
1382 }
1383
1384
1385 TEST(TestInternalWeakLists) {
1386   v8::V8::Initialize();
1387
1388   // Some flags turn Scavenge collections into Mark-sweep collections
1389   // and hence are incompatible with this test case.
1390   if (FLAG_gc_global || FLAG_stress_compaction) return;
1391
1392   static const int kNumTestContexts = 10;
1393
1394   Isolate* isolate = CcTest::i_isolate();
1395   Heap* heap = isolate->heap();
1396   HandleScope scope(isolate);
1397   v8::Handle<v8::Context> ctx[kNumTestContexts];
1398
1399   CHECK_EQ(0, CountNativeContexts());
1400
1401   // Create a number of global contests which gets linked together.
1402   for (int i = 0; i < kNumTestContexts; i++) {
1403     ctx[i] = v8::Context::New(CcTest::isolate());
1404
1405     // Collect garbage that might have been created by one of the
1406     // installed extensions.
1407     isolate->compilation_cache()->Clear();
1408     heap->CollectAllGarbage(Heap::kNoGCFlags);
1409
1410     bool opt = (FLAG_always_opt && isolate->use_crankshaft());
1411
1412     CHECK_EQ(i + 1, CountNativeContexts());
1413
1414     ctx[i]->Enter();
1415
1416     // Create a handle scope so no function objects get stuch in the outer
1417     // handle scope
1418     HandleScope scope(isolate);
1419     const char* source = "function f1() { };"
1420                          "function f2() { };"
1421                          "function f3() { };"
1422                          "function f4() { };"
1423                          "function f5() { };";
1424     CompileRun(source);
1425     CHECK_EQ(0, CountOptimizedUserFunctions(ctx[i]));
1426     CompileRun("f1()");
1427     CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[i]));
1428     CompileRun("f2()");
1429     CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1430     CompileRun("f3()");
1431     CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1432     CompileRun("f4()");
1433     CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1434     CompileRun("f5()");
1435     CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1436
1437     // Remove function f1, and
1438     CompileRun("f1=null");
1439
1440     // Scavenge treats these references as strong.
1441     for (int j = 0; j < 10; j++) {
1442       CcTest::heap()->CollectGarbage(NEW_SPACE);
1443       CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[i]));
1444     }
1445
1446     // Mark compact handles the weak references.
1447     isolate->compilation_cache()->Clear();
1448     heap->CollectAllGarbage(Heap::kNoGCFlags);
1449     CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1450
1451     // Get rid of f3 and f5 in the same way.
1452     CompileRun("f3=null");
1453     for (int j = 0; j < 10; j++) {
1454       CcTest::heap()->CollectGarbage(NEW_SPACE);
1455       CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[i]));
1456     }
1457     CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1458     CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1459     CompileRun("f5=null");
1460     for (int j = 0; j < 10; j++) {
1461       CcTest::heap()->CollectGarbage(NEW_SPACE);
1462       CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[i]));
1463     }
1464     CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1465     CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[i]));
1466
1467     ctx[i]->Exit();
1468   }
1469
1470   // Force compilation cache cleanup.
1471   CcTest::heap()->NotifyContextDisposed();
1472   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1473
1474   // Dispose the native contexts one by one.
1475   for (int i = 0; i < kNumTestContexts; i++) {
1476     // TODO(dcarney): is there a better way to do this?
1477     i::Object** unsafe = reinterpret_cast<i::Object**>(*ctx[i]);
1478     *unsafe = CcTest::heap()->undefined_value();
1479     ctx[i].Clear();
1480
1481     // Scavenge treats these references as strong.
1482     for (int j = 0; j < 10; j++) {
1483       CcTest::heap()->CollectGarbage(i::NEW_SPACE);
1484       CHECK_EQ(kNumTestContexts - i, CountNativeContexts());
1485     }
1486
1487     // Mark compact handles the weak references.
1488     CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1489     CHECK_EQ(kNumTestContexts - i - 1, CountNativeContexts());
1490   }
1491
1492   CHECK_EQ(0, CountNativeContexts());
1493 }
1494
1495
1496 // Count the number of native contexts in the weak list of native contexts
1497 // causing a GC after the specified number of elements.
1498 static int CountNativeContextsWithGC(Isolate* isolate, int n) {
1499   Heap* heap = isolate->heap();
1500   int count = 0;
1501   Handle<Object> object(heap->native_contexts_list(), isolate);
1502   while (!object->IsUndefined()) {
1503     count++;
1504     if (count == n) heap->CollectAllGarbage(Heap::kNoGCFlags);
1505     object =
1506         Handle<Object>(Context::cast(*object)->get(Context::NEXT_CONTEXT_LINK),
1507                        isolate);
1508   }
1509   return count;
1510 }
1511
1512
1513 // Count the number of user functions in the weak list of optimized
1514 // functions attached to a native context causing a GC after the
1515 // specified number of elements.
1516 static int CountOptimizedUserFunctionsWithGC(v8::Handle<v8::Context> context,
1517                                              int n) {
1518   int count = 0;
1519   Handle<Context> icontext = v8::Utils::OpenHandle(*context);
1520   Isolate* isolate = icontext->GetIsolate();
1521   Handle<Object> object(icontext->get(Context::OPTIMIZED_FUNCTIONS_LIST),
1522                         isolate);
1523   while (object->IsJSFunction() &&
1524          !Handle<JSFunction>::cast(object)->IsBuiltin()) {
1525     count++;
1526     if (count == n) isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
1527     object = Handle<Object>(
1528         Object::cast(JSFunction::cast(*object)->next_function_link()),
1529         isolate);
1530   }
1531   return count;
1532 }
1533
1534
1535 TEST(TestInternalWeakListsTraverseWithGC) {
1536   v8::V8::Initialize();
1537   Isolate* isolate = CcTest::i_isolate();
1538
1539   static const int kNumTestContexts = 10;
1540
1541   HandleScope scope(isolate);
1542   v8::Handle<v8::Context> ctx[kNumTestContexts];
1543
1544   CHECK_EQ(0, CountNativeContexts());
1545
1546   // Create an number of contexts and check the length of the weak list both
1547   // with and without GCs while iterating the list.
1548   for (int i = 0; i < kNumTestContexts; i++) {
1549     ctx[i] = v8::Context::New(CcTest::isolate());
1550     CHECK_EQ(i + 1, CountNativeContexts());
1551     CHECK_EQ(i + 1, CountNativeContextsWithGC(isolate, i / 2 + 1));
1552   }
1553
1554   bool opt = (FLAG_always_opt && isolate->use_crankshaft());
1555
1556   // Compile a number of functions the length of the weak list of optimized
1557   // functions both with and without GCs while iterating the list.
1558   ctx[0]->Enter();
1559   const char* source = "function f1() { };"
1560                        "function f2() { };"
1561                        "function f3() { };"
1562                        "function f4() { };"
1563                        "function f5() { };";
1564   CompileRun(source);
1565   CHECK_EQ(0, CountOptimizedUserFunctions(ctx[0]));
1566   CompileRun("f1()");
1567   CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctions(ctx[0]));
1568   CHECK_EQ(opt ? 1 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1569   CompileRun("f2()");
1570   CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctions(ctx[0]));
1571   CHECK_EQ(opt ? 2 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1572   CompileRun("f3()");
1573   CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctions(ctx[0]));
1574   CHECK_EQ(opt ? 3 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 1));
1575   CompileRun("f4()");
1576   CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctions(ctx[0]));
1577   CHECK_EQ(opt ? 4 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 2));
1578   CompileRun("f5()");
1579   CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctions(ctx[0]));
1580   CHECK_EQ(opt ? 5 : 0, CountOptimizedUserFunctionsWithGC(ctx[0], 4));
1581
1582   ctx[0]->Exit();
1583 }
1584
1585
1586 TEST(TestSizeOfObjects) {
1587   v8::V8::Initialize();
1588
1589   // Get initial heap size after several full GCs, which will stabilize
1590   // the heap size and return with sweeping finished completely.
1591   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1592   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1593   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1594   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1595   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1596   MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector();
1597   if (collector->IsConcurrentSweepingInProgress()) {
1598     collector->WaitUntilSweepingCompleted();
1599   }
1600   int initial_size = static_cast<int>(CcTest::heap()->SizeOfObjects());
1601
1602   {
1603     // Allocate objects on several different old-space pages so that
1604     // concurrent sweeper threads will be busy sweeping the old space on
1605     // subsequent GC runs.
1606     AlwaysAllocateScope always_allocate(CcTest::i_isolate());
1607     int filler_size = static_cast<int>(FixedArray::SizeFor(8192));
1608     for (int i = 1; i <= 100; i++) {
1609       CcTest::test_heap()->AllocateFixedArray(8192, TENURED).ToObjectChecked();
1610       CHECK_EQ(initial_size + i * filler_size,
1611                static_cast<int>(CcTest::heap()->SizeOfObjects()));
1612     }
1613   }
1614
1615   // The heap size should go back to initial size after a full GC, even
1616   // though sweeping didn't finish yet.
1617   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
1618
1619   // Normally sweeping would not be complete here, but no guarantees.
1620
1621   CHECK_EQ(initial_size, static_cast<int>(CcTest::heap()->SizeOfObjects()));
1622
1623   // Waiting for sweeper threads should not change heap size.
1624   if (collector->IsConcurrentSweepingInProgress()) {
1625     collector->WaitUntilSweepingCompleted();
1626   }
1627   CHECK_EQ(initial_size, static_cast<int>(CcTest::heap()->SizeOfObjects()));
1628 }
1629
1630
1631 TEST(TestSizeOfObjectsVsHeapIteratorPrecision) {
1632   CcTest::InitializeVM();
1633   HeapIterator iterator(CcTest::heap());
1634   intptr_t size_of_objects_1 = CcTest::heap()->SizeOfObjects();
1635   intptr_t size_of_objects_2 = 0;
1636   for (HeapObject* obj = iterator.next();
1637        obj != NULL;
1638        obj = iterator.next()) {
1639     if (!obj->IsFreeSpace()) {
1640       size_of_objects_2 += obj->Size();
1641     }
1642   }
1643   // Delta must be within 5% of the larger result.
1644   // TODO(gc): Tighten this up by distinguishing between byte
1645   // arrays that are real and those that merely mark free space
1646   // on the heap.
1647   if (size_of_objects_1 > size_of_objects_2) {
1648     intptr_t delta = size_of_objects_1 - size_of_objects_2;
1649     PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1650            "Iterator: %" V8_PTR_PREFIX "d, "
1651            "delta: %" V8_PTR_PREFIX "d\n",
1652            size_of_objects_1, size_of_objects_2, delta);
1653     CHECK_GT(size_of_objects_1 / 20, delta);
1654   } else {
1655     intptr_t delta = size_of_objects_2 - size_of_objects_1;
1656     PrintF("Heap::SizeOfObjects: %" V8_PTR_PREFIX "d, "
1657            "Iterator: %" V8_PTR_PREFIX "d, "
1658            "delta: %" V8_PTR_PREFIX "d\n",
1659            size_of_objects_1, size_of_objects_2, delta);
1660     CHECK_GT(size_of_objects_2 / 20, delta);
1661   }
1662 }
1663
1664
1665 static void FillUpNewSpace(NewSpace* new_space) {
1666   // Fill up new space to the point that it is completely full. Make sure
1667   // that the scavenger does not undo the filling.
1668   Heap* heap = new_space->heap();
1669   Isolate* isolate = heap->isolate();
1670   Factory* factory = isolate->factory();
1671   HandleScope scope(isolate);
1672   AlwaysAllocateScope always_allocate(isolate);
1673   intptr_t available = new_space->EffectiveCapacity() - new_space->Size();
1674   intptr_t number_of_fillers = (available / FixedArray::SizeFor(32)) - 1;
1675   for (intptr_t i = 0; i < number_of_fillers; i++) {
1676     CHECK(heap->InNewSpace(*factory->NewFixedArray(32, NOT_TENURED)));
1677   }
1678 }
1679
1680
1681 TEST(GrowAndShrinkNewSpace) {
1682   CcTest::InitializeVM();
1683   Heap* heap = CcTest::heap();
1684   NewSpace* new_space = heap->new_space();
1685
1686   if (heap->ReservedSemiSpaceSize() == heap->InitialSemiSpaceSize() ||
1687       heap->MaxSemiSpaceSize() == heap->InitialSemiSpaceSize()) {
1688     // The max size cannot exceed the reserved size, since semispaces must be
1689     // always within the reserved space.  We can't test new space growing and
1690     // shrinking if the reserved size is the same as the minimum (initial) size.
1691     return;
1692   }
1693
1694   // Explicitly growing should double the space capacity.
1695   intptr_t old_capacity, new_capacity;
1696   old_capacity = new_space->Capacity();
1697   new_space->Grow();
1698   new_capacity = new_space->Capacity();
1699   CHECK(2 * old_capacity == new_capacity);
1700
1701   old_capacity = new_space->Capacity();
1702   FillUpNewSpace(new_space);
1703   new_capacity = new_space->Capacity();
1704   CHECK(old_capacity == new_capacity);
1705
1706   // Explicitly shrinking should not affect space capacity.
1707   old_capacity = new_space->Capacity();
1708   new_space->Shrink();
1709   new_capacity = new_space->Capacity();
1710   CHECK(old_capacity == new_capacity);
1711
1712   // Let the scavenger empty the new space.
1713   heap->CollectGarbage(NEW_SPACE);
1714   CHECK_LE(new_space->Size(), old_capacity);
1715
1716   // Explicitly shrinking should halve the space capacity.
1717   old_capacity = new_space->Capacity();
1718   new_space->Shrink();
1719   new_capacity = new_space->Capacity();
1720   CHECK(old_capacity == 2 * new_capacity);
1721
1722   // Consecutive shrinking should not affect space capacity.
1723   old_capacity = new_space->Capacity();
1724   new_space->Shrink();
1725   new_space->Shrink();
1726   new_space->Shrink();
1727   new_capacity = new_space->Capacity();
1728   CHECK(old_capacity == new_capacity);
1729 }
1730
1731
1732 TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1733   CcTest::InitializeVM();
1734   Heap* heap = CcTest::heap();
1735   if (heap->ReservedSemiSpaceSize() == heap->InitialSemiSpaceSize() ||
1736       heap->MaxSemiSpaceSize() == heap->InitialSemiSpaceSize()) {
1737     // The max size cannot exceed the reserved size, since semispaces must be
1738     // always within the reserved space.  We can't test new space growing and
1739     // shrinking if the reserved size is the same as the minimum (initial) size.
1740     return;
1741   }
1742
1743   v8::HandleScope scope(CcTest::isolate());
1744   NewSpace* new_space = heap->new_space();
1745   intptr_t old_capacity, new_capacity;
1746   old_capacity = new_space->Capacity();
1747   new_space->Grow();
1748   new_capacity = new_space->Capacity();
1749   CHECK(2 * old_capacity == new_capacity);
1750   FillUpNewSpace(new_space);
1751   heap->CollectAllAvailableGarbage();
1752   new_capacity = new_space->Capacity();
1753   CHECK(old_capacity == new_capacity);
1754 }
1755
1756
1757 static int NumberOfGlobalObjects() {
1758   int count = 0;
1759   HeapIterator iterator(CcTest::heap());
1760   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1761     if (obj->IsGlobalObject()) count++;
1762   }
1763   return count;
1764 }
1765
1766
1767 // Test that we don't embed maps from foreign contexts into
1768 // optimized code.
1769 TEST(LeakNativeContextViaMap) {
1770   i::FLAG_allow_natives_syntax = true;
1771   v8::Isolate* isolate = CcTest::isolate();
1772   v8::HandleScope outer_scope(isolate);
1773   v8::Persistent<v8::Context> ctx1p;
1774   v8::Persistent<v8::Context> ctx2p;
1775   {
1776     v8::HandleScope scope(isolate);
1777     ctx1p.Reset(isolate, v8::Context::New(isolate));
1778     ctx2p.Reset(isolate, v8::Context::New(isolate));
1779     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
1780   }
1781
1782   CcTest::heap()->CollectAllAvailableGarbage();
1783   CHECK_EQ(4, NumberOfGlobalObjects());
1784
1785   {
1786     v8::HandleScope inner_scope(isolate);
1787     CompileRun("var v = {x: 42}");
1788     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
1789     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
1790     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1791     ctx2->Enter();
1792     ctx2->Global()->Set(v8_str("o"), v);
1793     v8::Local<v8::Value> res = CompileRun(
1794         "function f() { return o.x; }"
1795         "for (var i = 0; i < 10; ++i) f();"
1796         "%OptimizeFunctionOnNextCall(f);"
1797         "f();");
1798     CHECK_EQ(42, res->Int32Value());
1799     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(isolate, 0));
1800     ctx2->Exit();
1801     v8::Local<v8::Context>::New(isolate, ctx1)->Exit();
1802     ctx1p.Reset();
1803     v8::V8::ContextDisposedNotification();
1804   }
1805   CcTest::heap()->CollectAllAvailableGarbage();
1806   CHECK_EQ(2, NumberOfGlobalObjects());
1807   ctx2p.Reset();
1808   CcTest::heap()->CollectAllAvailableGarbage();
1809   CHECK_EQ(0, NumberOfGlobalObjects());
1810 }
1811
1812
1813 // Test that we don't embed functions from foreign contexts into
1814 // optimized code.
1815 TEST(LeakNativeContextViaFunction) {
1816   i::FLAG_allow_natives_syntax = true;
1817   v8::Isolate* isolate = CcTest::isolate();
1818   v8::HandleScope outer_scope(isolate);
1819   v8::Persistent<v8::Context> ctx1p;
1820   v8::Persistent<v8::Context> ctx2p;
1821   {
1822     v8::HandleScope scope(isolate);
1823     ctx1p.Reset(isolate, v8::Context::New(isolate));
1824     ctx2p.Reset(isolate, v8::Context::New(isolate));
1825     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
1826   }
1827
1828   CcTest::heap()->CollectAllAvailableGarbage();
1829   CHECK_EQ(4, NumberOfGlobalObjects());
1830
1831   {
1832     v8::HandleScope inner_scope(isolate);
1833     CompileRun("var v = function() { return 42; }");
1834     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
1835     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
1836     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1837     ctx2->Enter();
1838     ctx2->Global()->Set(v8_str("o"), v);
1839     v8::Local<v8::Value> res = CompileRun(
1840         "function f(x) { return x(); }"
1841         "for (var i = 0; i < 10; ++i) f(o);"
1842         "%OptimizeFunctionOnNextCall(f);"
1843         "f(o);");
1844     CHECK_EQ(42, res->Int32Value());
1845     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(isolate, 0));
1846     ctx2->Exit();
1847     ctx1->Exit();
1848     ctx1p.Reset();
1849     v8::V8::ContextDisposedNotification();
1850   }
1851   CcTest::heap()->CollectAllAvailableGarbage();
1852   CHECK_EQ(2, NumberOfGlobalObjects());
1853   ctx2p.Reset();
1854   CcTest::heap()->CollectAllAvailableGarbage();
1855   CHECK_EQ(0, NumberOfGlobalObjects());
1856 }
1857
1858
1859 TEST(LeakNativeContextViaMapKeyed) {
1860   i::FLAG_allow_natives_syntax = true;
1861   v8::Isolate* isolate = CcTest::isolate();
1862   v8::HandleScope outer_scope(isolate);
1863   v8::Persistent<v8::Context> ctx1p;
1864   v8::Persistent<v8::Context> ctx2p;
1865   {
1866     v8::HandleScope scope(isolate);
1867     ctx1p.Reset(isolate, v8::Context::New(isolate));
1868     ctx2p.Reset(isolate, v8::Context::New(isolate));
1869     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
1870   }
1871
1872   CcTest::heap()->CollectAllAvailableGarbage();
1873   CHECK_EQ(4, NumberOfGlobalObjects());
1874
1875   {
1876     v8::HandleScope inner_scope(isolate);
1877     CompileRun("var v = [42, 43]");
1878     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
1879     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
1880     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1881     ctx2->Enter();
1882     ctx2->Global()->Set(v8_str("o"), v);
1883     v8::Local<v8::Value> res = CompileRun(
1884         "function f() { return o[0]; }"
1885         "for (var i = 0; i < 10; ++i) f();"
1886         "%OptimizeFunctionOnNextCall(f);"
1887         "f();");
1888     CHECK_EQ(42, res->Int32Value());
1889     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(isolate, 0));
1890     ctx2->Exit();
1891     ctx1->Exit();
1892     ctx1p.Reset();
1893     v8::V8::ContextDisposedNotification();
1894   }
1895   CcTest::heap()->CollectAllAvailableGarbage();
1896   CHECK_EQ(2, NumberOfGlobalObjects());
1897   ctx2p.Reset();
1898   CcTest::heap()->CollectAllAvailableGarbage();
1899   CHECK_EQ(0, NumberOfGlobalObjects());
1900 }
1901
1902
1903 TEST(LeakNativeContextViaMapProto) {
1904   i::FLAG_allow_natives_syntax = true;
1905   v8::Isolate* isolate = CcTest::isolate();
1906   v8::HandleScope outer_scope(isolate);
1907   v8::Persistent<v8::Context> ctx1p;
1908   v8::Persistent<v8::Context> ctx2p;
1909   {
1910     v8::HandleScope scope(isolate);
1911     ctx1p.Reset(isolate, v8::Context::New(isolate));
1912     ctx2p.Reset(isolate, v8::Context::New(isolate));
1913     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
1914   }
1915
1916   CcTest::heap()->CollectAllAvailableGarbage();
1917   CHECK_EQ(4, NumberOfGlobalObjects());
1918
1919   {
1920     v8::HandleScope inner_scope(isolate);
1921     CompileRun("var v = { y: 42}");
1922     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
1923     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
1924     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1925     ctx2->Enter();
1926     ctx2->Global()->Set(v8_str("o"), v);
1927     v8::Local<v8::Value> res = CompileRun(
1928         "function f() {"
1929         "  var p = {x: 42};"
1930         "  p.__proto__ = o;"
1931         "  return p.x;"
1932         "}"
1933         "for (var i = 0; i < 10; ++i) f();"
1934         "%OptimizeFunctionOnNextCall(f);"
1935         "f();");
1936     CHECK_EQ(42, res->Int32Value());
1937     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(isolate, 0));
1938     ctx2->Exit();
1939     ctx1->Exit();
1940     ctx1p.Reset();
1941     v8::V8::ContextDisposedNotification();
1942   }
1943   CcTest::heap()->CollectAllAvailableGarbage();
1944   CHECK_EQ(2, NumberOfGlobalObjects());
1945   ctx2p.Reset();
1946   CcTest::heap()->CollectAllAvailableGarbage();
1947   CHECK_EQ(0, NumberOfGlobalObjects());
1948 }
1949
1950
1951 TEST(InstanceOfStubWriteBarrier) {
1952   i::FLAG_allow_natives_syntax = true;
1953 #ifdef VERIFY_HEAP
1954   i::FLAG_verify_heap = true;
1955 #endif
1956
1957   CcTest::InitializeVM();
1958   if (!CcTest::i_isolate()->use_crankshaft()) return;
1959   if (i::FLAG_force_marking_deque_overflows) return;
1960   v8::HandleScope outer_scope(CcTest::isolate());
1961
1962   {
1963     v8::HandleScope scope(CcTest::isolate());
1964     CompileRun(
1965         "function foo () { }"
1966         "function mkbar () { return new (new Function(\"\")) (); }"
1967         "function f (x) { return (x instanceof foo); }"
1968         "function g () { f(mkbar()); }"
1969         "f(new foo()); f(new foo());"
1970         "%OptimizeFunctionOnNextCall(f);"
1971         "f(new foo()); g();");
1972   }
1973
1974   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
1975   marking->Abort();
1976   marking->Start();
1977
1978   Handle<JSFunction> f =
1979       v8::Utils::OpenHandle(
1980           *v8::Handle<v8::Function>::Cast(
1981               CcTest::global()->Get(v8_str("f"))));
1982
1983   CHECK(f->IsOptimized());
1984
1985   while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
1986          !marking->IsStopped()) {
1987     // Discard any pending GC requests otherwise we will get GC when we enter
1988     // code below.
1989     marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
1990   }
1991
1992   CHECK(marking->IsMarking());
1993
1994   {
1995     v8::HandleScope scope(CcTest::isolate());
1996     v8::Handle<v8::Object> global = CcTest::global();
1997     v8::Handle<v8::Function> g =
1998         v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
1999     g->Call(global, 0, NULL);
2000   }
2001
2002   CcTest::heap()->incremental_marking()->set_should_hurry(true);
2003   CcTest::heap()->CollectGarbage(OLD_POINTER_SPACE);
2004 }
2005
2006
2007 TEST(PrototypeTransitionClearing) {
2008   if (FLAG_never_compact) return;
2009   CcTest::InitializeVM();
2010   Isolate* isolate = CcTest::i_isolate();
2011   Factory* factory = isolate->factory();
2012   v8::HandleScope scope(CcTest::isolate());
2013
2014   CompileRun("var base = {};");
2015   Handle<JSObject> baseObject =
2016       v8::Utils::OpenHandle(
2017           *v8::Handle<v8::Object>::Cast(
2018               CcTest::global()->Get(v8_str("base"))));
2019   int initialTransitions = baseObject->map()->NumberOfProtoTransitions();
2020
2021   CompileRun(
2022       "var live = [];"
2023       "for (var i = 0; i < 10; i++) {"
2024       "  var object = {};"
2025       "  var prototype = {};"
2026       "  object.__proto__ = prototype;"
2027       "  if (i >= 3) live.push(object, prototype);"
2028       "}");
2029
2030   // Verify that only dead prototype transitions are cleared.
2031   CHECK_EQ(initialTransitions + 10,
2032       baseObject->map()->NumberOfProtoTransitions());
2033   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
2034   const int transitions = 10 - 3;
2035   CHECK_EQ(initialTransitions + transitions,
2036       baseObject->map()->NumberOfProtoTransitions());
2037
2038   // Verify that prototype transitions array was compacted.
2039   FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
2040   for (int i = initialTransitions; i < initialTransitions + transitions; i++) {
2041     int j = Map::kProtoTransitionHeaderSize +
2042         i * Map::kProtoTransitionElementsPerEntry;
2043     CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
2044     Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
2045     CHECK(proto->IsJSObject());
2046   }
2047
2048   // Make sure next prototype is placed on an old-space evacuation candidate.
2049   Handle<JSObject> prototype;
2050   PagedSpace* space = CcTest::heap()->old_pointer_space();
2051   {
2052     AlwaysAllocateScope always_allocate(isolate);
2053     SimulateFullSpace(space);
2054     prototype = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
2055   }
2056
2057   // Add a prototype on an evacuation candidate and verify that transition
2058   // clearing correctly records slots in prototype transition array.
2059   i::FLAG_always_compact = true;
2060   Handle<Map> map(baseObject->map());
2061   CHECK(!space->LastPage()->Contains(
2062       map->GetPrototypeTransitions()->address()));
2063   CHECK(space->LastPage()->Contains(prototype->address()));
2064 }
2065
2066
2067 TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
2068   i::FLAG_stress_compaction = false;
2069   i::FLAG_allow_natives_syntax = true;
2070 #ifdef VERIFY_HEAP
2071   i::FLAG_verify_heap = true;
2072 #endif
2073
2074   CcTest::InitializeVM();
2075   if (!CcTest::i_isolate()->use_crankshaft()) return;
2076   v8::HandleScope outer_scope(CcTest::isolate());
2077
2078   {
2079     v8::HandleScope scope(CcTest::isolate());
2080     CompileRun(
2081         "function f () {"
2082         "  var s = 0;"
2083         "  for (var i = 0; i < 100; i++)  s += i;"
2084         "  return s;"
2085         "}"
2086         "f(); f();"
2087         "%OptimizeFunctionOnNextCall(f);"
2088         "f();");
2089   }
2090   Handle<JSFunction> f =
2091       v8::Utils::OpenHandle(
2092           *v8::Handle<v8::Function>::Cast(
2093               CcTest::global()->Get(v8_str("f"))));
2094   CHECK(f->IsOptimized());
2095
2096   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
2097   marking->Abort();
2098   marking->Start();
2099
2100   // The following two calls will increment CcTest::heap()->global_ic_age().
2101   const int kLongIdlePauseInMs = 1000;
2102   v8::V8::ContextDisposedNotification();
2103   v8::V8::IdleNotification(kLongIdlePauseInMs);
2104
2105   while (!marking->IsStopped() && !marking->IsComplete()) {
2106     marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
2107   }
2108   if (!marking->IsStopped() || marking->should_hurry()) {
2109     // We don't normally finish a GC via Step(), we normally finish by
2110     // setting the stack guard and then do the final steps in the stack
2111     // guard interrupt.  But here we didn't ask for that, and there is no
2112     // JS code running to trigger the interrupt, so we explicitly finalize
2113     // here.
2114     CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags,
2115                             "Test finalizing incremental mark-sweep");
2116   }
2117
2118   CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age());
2119   CHECK_EQ(0, f->shared()->opt_count());
2120   CHECK_EQ(0, f->shared()->code()->profiler_ticks());
2121 }
2122
2123
2124 TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
2125   i::FLAG_stress_compaction = false;
2126   i::FLAG_allow_natives_syntax = true;
2127 #ifdef VERIFY_HEAP
2128   i::FLAG_verify_heap = true;
2129 #endif
2130
2131   CcTest::InitializeVM();
2132   if (!CcTest::i_isolate()->use_crankshaft()) return;
2133   v8::HandleScope outer_scope(CcTest::isolate());
2134
2135   {
2136     v8::HandleScope scope(CcTest::isolate());
2137     CompileRun(
2138         "function f () {"
2139         "  var s = 0;"
2140         "  for (var i = 0; i < 100; i++)  s += i;"
2141         "  return s;"
2142         "}"
2143         "f(); f();"
2144         "%OptimizeFunctionOnNextCall(f);"
2145         "f();");
2146   }
2147   Handle<JSFunction> f =
2148       v8::Utils::OpenHandle(
2149           *v8::Handle<v8::Function>::Cast(
2150               CcTest::global()->Get(v8_str("f"))));
2151   CHECK(f->IsOptimized());
2152
2153   CcTest::heap()->incremental_marking()->Abort();
2154
2155   // The following two calls will increment CcTest::heap()->global_ic_age().
2156   // Since incremental marking is off, IdleNotification will do full GC.
2157   const int kLongIdlePauseInMs = 1000;
2158   v8::V8::ContextDisposedNotification();
2159   v8::V8::IdleNotification(kLongIdlePauseInMs);
2160
2161   CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age());
2162   CHECK_EQ(0, f->shared()->opt_count());
2163   CHECK_EQ(0, f->shared()->code()->profiler_ticks());
2164 }
2165
2166
2167 // Test that HAllocateObject will always return an object in new-space.
2168 TEST(OptimizedAllocationAlwaysInNewSpace) {
2169   i::FLAG_allow_natives_syntax = true;
2170   CcTest::InitializeVM();
2171   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2172   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2173   v8::HandleScope scope(CcTest::isolate());
2174
2175   SimulateFullSpace(CcTest::heap()->new_space());
2176   AlwaysAllocateScope always_allocate(CcTest::i_isolate());
2177   v8::Local<v8::Value> res = CompileRun(
2178       "function c(x) {"
2179       "  this.x = x;"
2180       "  for (var i = 0; i < 32; i++) {"
2181       "    this['x' + i] = x;"
2182       "  }"
2183       "}"
2184       "function f(x) { return new c(x); };"
2185       "f(1); f(2); f(3);"
2186       "%OptimizeFunctionOnNextCall(f);"
2187       "f(4);");
2188   CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
2189
2190   Handle<JSObject> o =
2191       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2192
2193   CHECK(CcTest::heap()->InNewSpace(*o));
2194 }
2195
2196
2197 TEST(OptimizedPretenuringAllocationFolding) {
2198   i::FLAG_allow_natives_syntax = true;
2199   i::FLAG_expose_gc = true;
2200   CcTest::InitializeVM();
2201   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2202   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2203   v8::HandleScope scope(CcTest::isolate());
2204
2205   // Grow new space unitl maximum capacity reached.
2206   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2207     CcTest::heap()->new_space()->Grow();
2208   }
2209
2210   i::ScopedVector<char> source(1024);
2211   i::SNPrintF(
2212       source,
2213       "var number_elements = %d;"
2214       "var elements = new Array();"
2215       "function f() {"
2216       "  for (var i = 0; i < number_elements; i++) {"
2217       "    elements[i] = [[{}], [1.1]];"
2218       "  }"
2219       "  return elements[number_elements-1]"
2220       "};"
2221       "f(); gc();"
2222       "f(); f();"
2223       "%%OptimizeFunctionOnNextCall(f);"
2224       "f();",
2225       AllocationSite::kPretenureMinimumCreated);
2226
2227   v8::Local<v8::Value> res = CompileRun(source.start());
2228
2229   v8::Local<v8::Value> int_array = v8::Object::Cast(*res)->Get(v8_str("0"));
2230   Handle<JSObject> int_array_handle =
2231       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array));
2232   v8::Local<v8::Value> double_array = v8::Object::Cast(*res)->Get(v8_str("1"));
2233   Handle<JSObject> double_array_handle =
2234       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array));
2235
2236   Handle<JSObject> o =
2237       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2238   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2239   CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle));
2240   CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle->elements()));
2241   CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle));
2242   CHECK(CcTest::heap()->InOldDataSpace(double_array_handle->elements()));
2243 }
2244
2245
2246 TEST(OptimizedPretenuringObjectArrayLiterals) {
2247   i::FLAG_allow_natives_syntax = true;
2248   i::FLAG_expose_gc = true;
2249   CcTest::InitializeVM();
2250   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2251   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2252   v8::HandleScope scope(CcTest::isolate());
2253
2254   // Grow new space unitl maximum capacity reached.
2255   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2256     CcTest::heap()->new_space()->Grow();
2257   }
2258
2259   i::ScopedVector<char> source(1024);
2260   i::SNPrintF(
2261       source,
2262       "var number_elements = %d;"
2263       "var elements = new Array(number_elements);"
2264       "function f() {"
2265       "  for (var i = 0; i < number_elements; i++) {"
2266       "    elements[i] = [{}, {}, {}];"
2267       "  }"
2268       "  return elements[number_elements - 1];"
2269       "};"
2270       "f(); gc();"
2271       "f(); f();"
2272       "%%OptimizeFunctionOnNextCall(f);"
2273       "f();",
2274       AllocationSite::kPretenureMinimumCreated);
2275
2276   v8::Local<v8::Value> res = CompileRun(source.start());
2277
2278   Handle<JSObject> o =
2279       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2280
2281   CHECK(CcTest::heap()->InOldPointerSpace(o->elements()));
2282   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2283 }
2284
2285
2286 TEST(OptimizedPretenuringMixedInObjectProperties) {
2287   i::FLAG_allow_natives_syntax = true;
2288   i::FLAG_expose_gc = true;
2289   CcTest::InitializeVM();
2290   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2291   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2292   v8::HandleScope scope(CcTest::isolate());
2293
2294   // Grow new space unitl maximum capacity reached.
2295   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2296     CcTest::heap()->new_space()->Grow();
2297   }
2298
2299
2300   i::ScopedVector<char> source(1024);
2301   i::SNPrintF(
2302       source,
2303       "var number_elements = %d;"
2304       "var elements = new Array(number_elements);"
2305       "function f() {"
2306       "  for (var i = 0; i < number_elements; i++) {"
2307       "    elements[i] = {a: {c: 2.2, d: {}}, b: 1.1};"
2308       "  }"
2309       "  return elements[number_elements - 1];"
2310       "};"
2311       "f(); gc();"
2312       "f(); f();"
2313       "%%OptimizeFunctionOnNextCall(f);"
2314       "f();",
2315       AllocationSite::kPretenureMinimumCreated);
2316
2317   v8::Local<v8::Value> res = CompileRun(source.start());
2318
2319   Handle<JSObject> o =
2320       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2321
2322   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2323   FieldIndex idx1 = FieldIndex::ForPropertyIndex(o->map(), 0);
2324   FieldIndex idx2 = FieldIndex::ForPropertyIndex(o->map(), 1);
2325   CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(idx1)));
2326   CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2)));
2327
2328   JSObject* inner_object =
2329       reinterpret_cast<JSObject*>(o->RawFastPropertyAt(idx1));
2330   CHECK(CcTest::heap()->InOldPointerSpace(inner_object));
2331   CHECK(CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1)));
2332   CHECK(CcTest::heap()->InOldPointerSpace(
2333       inner_object->RawFastPropertyAt(idx2)));
2334 }
2335
2336
2337 TEST(OptimizedPretenuringDoubleArrayProperties) {
2338   i::FLAG_allow_natives_syntax = true;
2339   i::FLAG_expose_gc = true;
2340   CcTest::InitializeVM();
2341   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2342   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2343   v8::HandleScope scope(CcTest::isolate());
2344
2345   // Grow new space unitl maximum capacity reached.
2346   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2347     CcTest::heap()->new_space()->Grow();
2348   }
2349
2350   i::ScopedVector<char> source(1024);
2351   i::SNPrintF(
2352       source,
2353       "var number_elements = %d;"
2354       "var elements = new Array(number_elements);"
2355       "function f() {"
2356       "  for (var i = 0; i < number_elements; i++) {"
2357       "    elements[i] = {a: 1.1, b: 2.2};"
2358       "  }"
2359       "  return elements[i - 1];"
2360       "};"
2361       "f(); gc();"
2362       "f(); f();"
2363       "%%OptimizeFunctionOnNextCall(f);"
2364       "f();",
2365       AllocationSite::kPretenureMinimumCreated);
2366
2367   v8::Local<v8::Value> res = CompileRun(source.start());
2368
2369   Handle<JSObject> o =
2370       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2371
2372   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2373   CHECK(CcTest::heap()->InOldDataSpace(o->properties()));
2374 }
2375
2376
2377 TEST(OptimizedPretenuringdoubleArrayLiterals) {
2378   i::FLAG_allow_natives_syntax = true;
2379   i::FLAG_expose_gc = true;
2380   CcTest::InitializeVM();
2381   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2382   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2383   v8::HandleScope scope(CcTest::isolate());
2384
2385   // Grow new space unitl maximum capacity reached.
2386   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2387     CcTest::heap()->new_space()->Grow();
2388   }
2389
2390   i::ScopedVector<char> source(1024);
2391   i::SNPrintF(
2392       source,
2393       "var number_elements = %d;"
2394       "var elements = new Array(number_elements);"
2395       "function f() {"
2396       "  for (var i = 0; i < number_elements; i++) {"
2397       "    elements[i] = [1.1, 2.2, 3.3];"
2398       "  }"
2399       "  return elements[number_elements - 1];"
2400       "};"
2401       "f(); gc();"
2402       "f(); f();"
2403       "%%OptimizeFunctionOnNextCall(f);"
2404       "f();",
2405       AllocationSite::kPretenureMinimumCreated);
2406
2407   v8::Local<v8::Value> res = CompileRun(source.start());
2408
2409   Handle<JSObject> o =
2410       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2411
2412   CHECK(CcTest::heap()->InOldDataSpace(o->elements()));
2413   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2414 }
2415
2416
2417 TEST(OptimizedPretenuringNestedMixedArrayLiterals) {
2418   i::FLAG_allow_natives_syntax = true;
2419   i::FLAG_expose_gc = true;
2420   CcTest::InitializeVM();
2421   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2422   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2423   v8::HandleScope scope(CcTest::isolate());
2424
2425   // Grow new space unitl maximum capacity reached.
2426   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2427     CcTest::heap()->new_space()->Grow();
2428   }
2429
2430   i::ScopedVector<char> source(1024);
2431   i::SNPrintF(
2432       source,
2433       "var number_elements = 100;"
2434       "var elements = new Array(number_elements);"
2435       "function f() {"
2436       "  for (var i = 0; i < number_elements; i++) {"
2437       "    elements[i] = [[{}, {}, {}], [1.1, 2.2, 3.3]];"
2438       "  }"
2439       "  return elements[number_elements - 1];"
2440       "};"
2441       "f(); gc();"
2442       "f(); f();"
2443       "%%OptimizeFunctionOnNextCall(f);"
2444       "f();");
2445
2446   v8::Local<v8::Value> res = CompileRun(source.start());
2447
2448   v8::Local<v8::Value> int_array = v8::Object::Cast(*res)->Get(v8_str("0"));
2449   Handle<JSObject> int_array_handle =
2450       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array));
2451   v8::Local<v8::Value> double_array = v8::Object::Cast(*res)->Get(v8_str("1"));
2452   Handle<JSObject> double_array_handle =
2453       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array));
2454
2455   Handle<JSObject> o =
2456       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2457   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2458   CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle));
2459   CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle->elements()));
2460   CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle));
2461   CHECK(CcTest::heap()->InOldDataSpace(double_array_handle->elements()));
2462 }
2463
2464
2465 TEST(OptimizedPretenuringNestedObjectLiterals) {
2466   i::FLAG_allow_natives_syntax = true;
2467   i::FLAG_expose_gc = true;
2468   CcTest::InitializeVM();
2469   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2470   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2471   v8::HandleScope scope(CcTest::isolate());
2472
2473   // Grow new space unitl maximum capacity reached.
2474   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2475     CcTest::heap()->new_space()->Grow();
2476   }
2477
2478   i::ScopedVector<char> source(1024);
2479   i::SNPrintF(
2480       source,
2481       "var number_elements = %d;"
2482       "var elements = new Array(number_elements);"
2483       "function f() {"
2484       "  for (var i = 0; i < number_elements; i++) {"
2485       "    elements[i] = [[{}, {}, {}],[{}, {}, {}]];"
2486       "  }"
2487       "  return elements[number_elements - 1];"
2488       "};"
2489       "f(); gc();"
2490       "f(); f();"
2491       "%%OptimizeFunctionOnNextCall(f);"
2492       "f();",
2493       AllocationSite::kPretenureMinimumCreated);
2494
2495   v8::Local<v8::Value> res = CompileRun(source.start());
2496
2497   v8::Local<v8::Value> int_array_1 = v8::Object::Cast(*res)->Get(v8_str("0"));
2498   Handle<JSObject> int_array_handle_1 =
2499       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array_1));
2500   v8::Local<v8::Value> int_array_2 = v8::Object::Cast(*res)->Get(v8_str("1"));
2501   Handle<JSObject> int_array_handle_2 =
2502       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array_2));
2503
2504   Handle<JSObject> o =
2505       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2506   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2507   CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle_1));
2508   CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle_1->elements()));
2509   CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle_2));
2510   CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle_2->elements()));
2511 }
2512
2513
2514 TEST(OptimizedPretenuringNestedDoubleLiterals) {
2515   i::FLAG_allow_natives_syntax = true;
2516   i::FLAG_expose_gc = true;
2517   CcTest::InitializeVM();
2518   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2519   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2520   v8::HandleScope scope(CcTest::isolate());
2521
2522   // Grow new space unitl maximum capacity reached.
2523   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2524     CcTest::heap()->new_space()->Grow();
2525   }
2526
2527   i::ScopedVector<char> source(1024);
2528   i::SNPrintF(
2529       source,
2530       "var number_elements = %d;"
2531       "var elements = new Array(number_elements);"
2532       "function f() {"
2533       "  for (var i = 0; i < number_elements; i++) {"
2534       "    elements[i] = [[1.1, 1.2, 1.3],[2.1, 2.2, 2.3]];"
2535       "  }"
2536       "  return elements[number_elements - 1];"
2537       "};"
2538       "f(); gc();"
2539       "f(); f();"
2540       "%%OptimizeFunctionOnNextCall(f);"
2541       "f();",
2542       AllocationSite::kPretenureMinimumCreated);
2543
2544   v8::Local<v8::Value> res = CompileRun(source.start());
2545
2546   v8::Local<v8::Value> double_array_1 =
2547       v8::Object::Cast(*res)->Get(v8_str("0"));
2548   Handle<JSObject> double_array_handle_1 =
2549       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array_1));
2550   v8::Local<v8::Value> double_array_2 =
2551       v8::Object::Cast(*res)->Get(v8_str("1"));
2552   Handle<JSObject> double_array_handle_2 =
2553       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array_2));
2554
2555   Handle<JSObject> o =
2556       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2557   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2558   CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle_1));
2559   CHECK(CcTest::heap()->InOldDataSpace(double_array_handle_1->elements()));
2560   CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle_2));
2561   CHECK(CcTest::heap()->InOldDataSpace(double_array_handle_2->elements()));
2562 }
2563
2564
2565 // Make sure pretenuring feedback is gathered for constructed objects as well
2566 // as for literals.
2567 TEST(OptimizedPretenuringConstructorCalls) {
2568   if (!i::FLAG_pretenuring_call_new) {
2569     // FLAG_pretenuring_call_new needs to be synced with the snapshot.
2570     return;
2571   }
2572   i::FLAG_allow_natives_syntax = true;
2573   i::FLAG_expose_gc = true;
2574   CcTest::InitializeVM();
2575   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2576   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2577   v8::HandleScope scope(CcTest::isolate());
2578
2579   // Grow new space unitl maximum capacity reached.
2580   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2581     CcTest::heap()->new_space()->Grow();
2582   }
2583
2584   i::ScopedVector<char> source(1024);
2585   // Call new is doing slack tracking for the first
2586   // JSFunction::kGenerousAllocationCount allocations, and we can't find
2587   // mementos during that time.
2588   i::SNPrintF(
2589       source,
2590       "var number_elements = %d;"
2591       "var elements = new Array(number_elements);"
2592       "function foo() {"
2593       "  this.a = 3;"
2594       "  this.b = {};"
2595       "}"
2596       "function f() {"
2597       "  for (var i = 0; i < number_elements; i++) {"
2598       "    elements[i] = new foo();"
2599       "  }"
2600       "  return elements[number_elements - 1];"
2601       "};"
2602       "f(); gc();"
2603       "f(); f();"
2604       "%%OptimizeFunctionOnNextCall(f);"
2605       "f();",
2606       AllocationSite::kPretenureMinimumCreated +
2607       JSFunction::kGenerousAllocationCount);
2608
2609   v8::Local<v8::Value> res = CompileRun(source.start());
2610
2611   Handle<JSObject> o =
2612       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2613
2614   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2615 }
2616
2617
2618 TEST(OptimizedPretenuringCallNew) {
2619   if (!i::FLAG_pretenuring_call_new) {
2620     // FLAG_pretenuring_call_new needs to be synced with the snapshot.
2621     return;
2622   }
2623   i::FLAG_allow_natives_syntax = true;
2624   i::FLAG_expose_gc = true;
2625   CcTest::InitializeVM();
2626   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2627   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2628   v8::HandleScope scope(CcTest::isolate());
2629
2630   // Grow new space unitl maximum capacity reached.
2631   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2632     CcTest::heap()->new_space()->Grow();
2633   }
2634
2635   i::ScopedVector<char> source(1024);
2636   // Call new is doing slack tracking for the first
2637   // JSFunction::kGenerousAllocationCount allocations, and we can't find
2638   // mementos during that time.
2639   i::SNPrintF(
2640       source,
2641       "var number_elements = %d;"
2642       "var elements = new Array(number_elements);"
2643       "function g() { this.a = 0; }"
2644       "function f() {"
2645       "  for (var i = 0; i < number_elements; i++) {"
2646       "    elements[i] = new g();"
2647       "  }"
2648       "  return elements[number_elements - 1];"
2649       "};"
2650       "f(); gc();"
2651       "f(); f();"
2652       "%%OptimizeFunctionOnNextCall(f);"
2653       "f();",
2654       AllocationSite::kPretenureMinimumCreated +
2655       JSFunction::kGenerousAllocationCount);
2656
2657   v8::Local<v8::Value> res = CompileRun(source.start());
2658
2659   Handle<JSObject> o =
2660       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2661   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2662 }
2663
2664
2665 // Test regular array literals allocation.
2666 TEST(OptimizedAllocationArrayLiterals) {
2667   i::FLAG_allow_natives_syntax = true;
2668   CcTest::InitializeVM();
2669   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2670   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2671   v8::HandleScope scope(CcTest::isolate());
2672
2673   v8::Local<v8::Value> res = CompileRun(
2674       "function f() {"
2675       "  var numbers = new Array(1, 2, 3);"
2676       "  numbers[0] = 3.14;"
2677       "  return numbers;"
2678       "};"
2679       "f(); f(); f();"
2680       "%OptimizeFunctionOnNextCall(f);"
2681       "f();");
2682   CHECK_EQ(static_cast<int>(3.14),
2683            v8::Object::Cast(*res)->Get(v8_str("0"))->Int32Value());
2684
2685   Handle<JSObject> o =
2686       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2687
2688   CHECK(CcTest::heap()->InNewSpace(o->elements()));
2689 }
2690
2691
2692 static int CountMapTransitions(Map* map) {
2693   return map->transitions()->number_of_transitions();
2694 }
2695
2696
2697 // Test that map transitions are cleared and maps are collected with
2698 // incremental marking as well.
2699 TEST(Regress1465) {
2700   i::FLAG_stress_compaction = false;
2701   i::FLAG_allow_natives_syntax = true;
2702   i::FLAG_trace_incremental_marking = true;
2703   CcTest::InitializeVM();
2704   v8::HandleScope scope(CcTest::isolate());
2705   static const int transitions_count = 256;
2706
2707   CompileRun("function F() {}");
2708   {
2709     AlwaysAllocateScope always_allocate(CcTest::i_isolate());
2710     for (int i = 0; i < transitions_count; i++) {
2711       EmbeddedVector<char, 64> buffer;
2712       SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i);
2713       CompileRun(buffer.start());
2714     }
2715     CompileRun("var root = new F;");
2716   }
2717
2718   Handle<JSObject> root =
2719       v8::Utils::OpenHandle(
2720           *v8::Handle<v8::Object>::Cast(
2721               CcTest::global()->Get(v8_str("root"))));
2722
2723   // Count number of live transitions before marking.
2724   int transitions_before = CountMapTransitions(root->map());
2725   CompileRun("%DebugPrint(root);");
2726   CHECK_EQ(transitions_count, transitions_before);
2727
2728   SimulateIncrementalMarking();
2729   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
2730
2731   // Count number of live transitions after marking.  Note that one transition
2732   // is left, because 'o' still holds an instance of one transition target.
2733   int transitions_after = CountMapTransitions(root->map());
2734   CompileRun("%DebugPrint(root);");
2735   CHECK_EQ(1, transitions_after);
2736 }
2737
2738
2739 #ifdef DEBUG
2740 static void AddTransitions(int transitions_count) {
2741   AlwaysAllocateScope always_allocate(CcTest::i_isolate());
2742   for (int i = 0; i < transitions_count; i++) {
2743     EmbeddedVector<char, 64> buffer;
2744     SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i);
2745     CompileRun(buffer.start());
2746   }
2747 }
2748
2749
2750 static Handle<JSObject> GetByName(const char* name) {
2751   return v8::Utils::OpenHandle(
2752       *v8::Handle<v8::Object>::Cast(
2753           CcTest::global()->Get(v8_str(name))));
2754 }
2755
2756
2757 static void AddPropertyTo(
2758     int gc_count, Handle<JSObject> object, const char* property_name) {
2759   Isolate* isolate = CcTest::i_isolate();
2760   Factory* factory = isolate->factory();
2761   Handle<String> prop_name = factory->InternalizeUtf8String(property_name);
2762   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
2763   i::FLAG_gc_interval = gc_count;
2764   i::FLAG_gc_global = true;
2765   CcTest::heap()->set_allocation_timeout(gc_count);
2766   JSReceiver::SetProperty(
2767       object, prop_name, twenty_three, NONE, SLOPPY).Check();
2768 }
2769
2770
2771 TEST(TransitionArrayShrinksDuringAllocToZero) {
2772   i::FLAG_stress_compaction = false;
2773   i::FLAG_allow_natives_syntax = true;
2774   CcTest::InitializeVM();
2775   v8::HandleScope scope(CcTest::isolate());
2776   static const int transitions_count = 10;
2777   CompileRun("function F() { }");
2778   AddTransitions(transitions_count);
2779   CompileRun("var root = new F;");
2780   Handle<JSObject> root = GetByName("root");
2781
2782   // Count number of live transitions before marking.
2783   int transitions_before = CountMapTransitions(root->map());
2784   CHECK_EQ(transitions_count, transitions_before);
2785
2786   // Get rid of o
2787   CompileRun("o = new F;"
2788              "root = new F");
2789   root = GetByName("root");
2790   AddPropertyTo(2, root, "funny");
2791
2792   // Count number of live transitions after marking.  Note that one transition
2793   // is left, because 'o' still holds an instance of one transition target.
2794   int transitions_after = CountMapTransitions(
2795       Map::cast(root->map()->GetBackPointer()));
2796   CHECK_EQ(1, transitions_after);
2797 }
2798
2799
2800 TEST(TransitionArrayShrinksDuringAllocToOne) {
2801   i::FLAG_stress_compaction = false;
2802   i::FLAG_allow_natives_syntax = true;
2803   CcTest::InitializeVM();
2804   v8::HandleScope scope(CcTest::isolate());
2805   static const int transitions_count = 10;
2806   CompileRun("function F() {}");
2807   AddTransitions(transitions_count);
2808   CompileRun("var root = new F;");
2809   Handle<JSObject> root = GetByName("root");
2810
2811   // Count number of live transitions before marking.
2812   int transitions_before = CountMapTransitions(root->map());
2813   CHECK_EQ(transitions_count, transitions_before);
2814
2815   root = GetByName("root");
2816   AddPropertyTo(2, root, "funny");
2817
2818   // Count number of live transitions after marking.  Note that one transition
2819   // is left, because 'o' still holds an instance of one transition target.
2820   int transitions_after = CountMapTransitions(
2821       Map::cast(root->map()->GetBackPointer()));
2822   CHECK_EQ(2, transitions_after);
2823 }
2824
2825
2826 TEST(TransitionArrayShrinksDuringAllocToOnePropertyFound) {
2827   i::FLAG_stress_compaction = false;
2828   i::FLAG_allow_natives_syntax = true;
2829   CcTest::InitializeVM();
2830   v8::HandleScope scope(CcTest::isolate());
2831   static const int transitions_count = 10;
2832   CompileRun("function F() {}");
2833   AddTransitions(transitions_count);
2834   CompileRun("var root = new F;");
2835   Handle<JSObject> root = GetByName("root");
2836
2837   // Count number of live transitions before marking.
2838   int transitions_before = CountMapTransitions(root->map());
2839   CHECK_EQ(transitions_count, transitions_before);
2840
2841   root = GetByName("root");
2842   AddPropertyTo(0, root, "prop9");
2843
2844   // Count number of live transitions after marking.  Note that one transition
2845   // is left, because 'o' still holds an instance of one transition target.
2846   int transitions_after = CountMapTransitions(
2847       Map::cast(root->map()->GetBackPointer()));
2848   CHECK_EQ(1, transitions_after);
2849 }
2850
2851
2852 TEST(TransitionArraySimpleToFull) {
2853   i::FLAG_stress_compaction = false;
2854   i::FLAG_allow_natives_syntax = true;
2855   CcTest::InitializeVM();
2856   v8::HandleScope scope(CcTest::isolate());
2857   static const int transitions_count = 1;
2858   CompileRun("function F() {}");
2859   AddTransitions(transitions_count);
2860   CompileRun("var root = new F;");
2861   Handle<JSObject> root = GetByName("root");
2862
2863   // Count number of live transitions before marking.
2864   int transitions_before = CountMapTransitions(root->map());
2865   CHECK_EQ(transitions_count, transitions_before);
2866
2867   CompileRun("o = new F;"
2868              "root = new F");
2869   root = GetByName("root");
2870   ASSERT(root->map()->transitions()->IsSimpleTransition());
2871   AddPropertyTo(2, root, "happy");
2872
2873   // Count number of live transitions after marking.  Note that one transition
2874   // is left, because 'o' still holds an instance of one transition target.
2875   int transitions_after = CountMapTransitions(
2876       Map::cast(root->map()->GetBackPointer()));
2877   CHECK_EQ(1, transitions_after);
2878 }
2879 #endif  // DEBUG
2880
2881
2882 TEST(Regress2143a) {
2883   i::FLAG_collect_maps = true;
2884   i::FLAG_incremental_marking = true;
2885   CcTest::InitializeVM();
2886   v8::HandleScope scope(CcTest::isolate());
2887
2888   // Prepare a map transition from the root object together with a yet
2889   // untransitioned root object.
2890   CompileRun("var root = new Object;"
2891              "root.foo = 0;"
2892              "root = new Object;");
2893
2894   SimulateIncrementalMarking();
2895
2896   // Compile a StoreIC that performs the prepared map transition. This
2897   // will restart incremental marking and should make sure the root is
2898   // marked grey again.
2899   CompileRun("function f(o) {"
2900              "  o.foo = 0;"
2901              "}"
2902              "f(new Object);"
2903              "f(root);");
2904
2905   // This bug only triggers with aggressive IC clearing.
2906   CcTest::heap()->AgeInlineCaches();
2907
2908   // Explicitly request GC to perform final marking step and sweeping.
2909   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
2910
2911   Handle<JSObject> root =
2912       v8::Utils::OpenHandle(
2913           *v8::Handle<v8::Object>::Cast(
2914               CcTest::global()->Get(v8_str("root"))));
2915
2916   // The root object should be in a sane state.
2917   CHECK(root->IsJSObject());
2918   CHECK(root->map()->IsMap());
2919 }
2920
2921
2922 TEST(Regress2143b) {
2923   i::FLAG_collect_maps = true;
2924   i::FLAG_incremental_marking = true;
2925   i::FLAG_allow_natives_syntax = true;
2926   CcTest::InitializeVM();
2927   v8::HandleScope scope(CcTest::isolate());
2928
2929   // Prepare a map transition from the root object together with a yet
2930   // untransitioned root object.
2931   CompileRun("var root = new Object;"
2932              "root.foo = 0;"
2933              "root = new Object;");
2934
2935   SimulateIncrementalMarking();
2936
2937   // Compile an optimized LStoreNamedField that performs the prepared
2938   // map transition. This will restart incremental marking and should
2939   // make sure the root is marked grey again.
2940   CompileRun("function f(o) {"
2941              "  o.foo = 0;"
2942              "}"
2943              "f(new Object);"
2944              "f(new Object);"
2945              "%OptimizeFunctionOnNextCall(f);"
2946              "f(root);"
2947              "%DeoptimizeFunction(f);");
2948
2949   // This bug only triggers with aggressive IC clearing.
2950   CcTest::heap()->AgeInlineCaches();
2951
2952   // Explicitly request GC to perform final marking step and sweeping.
2953   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
2954
2955   Handle<JSObject> root =
2956       v8::Utils::OpenHandle(
2957           *v8::Handle<v8::Object>::Cast(
2958               CcTest::global()->Get(v8_str("root"))));
2959
2960   // The root object should be in a sane state.
2961   CHECK(root->IsJSObject());
2962   CHECK(root->map()->IsMap());
2963 }
2964
2965
2966 TEST(ReleaseOverReservedPages) {
2967   if (FLAG_never_compact) return;
2968   i::FLAG_trace_gc = true;
2969   // The optimizer can allocate stuff, messing up the test.
2970   i::FLAG_crankshaft = false;
2971   i::FLAG_always_opt = false;
2972   CcTest::InitializeVM();
2973   Isolate* isolate = CcTest::i_isolate();
2974   Factory* factory = isolate->factory();
2975   Heap* heap = isolate->heap();
2976   v8::HandleScope scope(CcTest::isolate());
2977   static const int number_of_test_pages = 20;
2978
2979   // Prepare many pages with low live-bytes count.
2980   PagedSpace* old_pointer_space = heap->old_pointer_space();
2981   CHECK_EQ(1, old_pointer_space->CountTotalPages());
2982   for (int i = 0; i < number_of_test_pages; i++) {
2983     AlwaysAllocateScope always_allocate(isolate);
2984     SimulateFullSpace(old_pointer_space);
2985     factory->NewFixedArray(1, TENURED);
2986   }
2987   CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2988
2989   // Triggering one GC will cause a lot of garbage to be discovered but
2990   // even spread across all allocated pages.
2991   heap->CollectAllGarbage(Heap::kNoGCFlags, "triggered for preparation");
2992   CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2993
2994   // Triggering subsequent GCs should cause at least half of the pages
2995   // to be released to the OS after at most two cycles.
2996   heap->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
2997   CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
2998   heap->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
2999   CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
3000
3001   // Triggering a last-resort GC should cause all pages to be released to the
3002   // OS so that other processes can seize the memory.  If we get a failure here
3003   // where there are 2 pages left instead of 1, then we should increase the
3004   // size of the first page a little in SizeOfFirstPage in spaces.cc.  The
3005   // first page should be small in order to reduce memory used when the VM
3006   // boots, but if the 20 small arrays don't fit on the first page then that's
3007   // an indication that it is too small.
3008   heap->CollectAllAvailableGarbage("triggered really hard");
3009   CHECK_EQ(1, old_pointer_space->CountTotalPages());
3010 }
3011
3012
3013 TEST(Regress2237) {
3014   i::FLAG_stress_compaction = false;
3015   CcTest::InitializeVM();
3016   Isolate* isolate = CcTest::i_isolate();
3017   Factory* factory = isolate->factory();
3018   v8::HandleScope scope(CcTest::isolate());
3019   Handle<String> slice(CcTest::heap()->empty_string());
3020
3021   {
3022     // Generate a parent that lives in new-space.
3023     v8::HandleScope inner_scope(CcTest::isolate());
3024     const char* c = "This text is long enough to trigger sliced strings.";
3025     Handle<String> s = factory->NewStringFromAsciiChecked(c);
3026     CHECK(s->IsSeqOneByteString());
3027     CHECK(CcTest::heap()->InNewSpace(*s));
3028
3029     // Generate a sliced string that is based on the above parent and
3030     // lives in old-space.
3031     SimulateFullSpace(CcTest::heap()->new_space());
3032     AlwaysAllocateScope always_allocate(isolate);
3033     Handle<String> t = factory->NewProperSubString(s, 5, 35);
3034     CHECK(t->IsSlicedString());
3035     CHECK(!CcTest::heap()->InNewSpace(*t));
3036     *slice.location() = *t.location();
3037   }
3038
3039   CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
3040   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
3041   CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
3042 }
3043
3044
3045 #ifdef OBJECT_PRINT
3046 TEST(PrintSharedFunctionInfo) {
3047   CcTest::InitializeVM();
3048   v8::HandleScope scope(CcTest::isolate());
3049   const char* source = "f = function() { return 987654321; }\n"
3050                        "g = function() { return 123456789; }\n";
3051   CompileRun(source);
3052   Handle<JSFunction> g =
3053       v8::Utils::OpenHandle(
3054           *v8::Handle<v8::Function>::Cast(
3055               CcTest::global()->Get(v8_str("g"))));
3056
3057   DisallowHeapAllocation no_allocation;
3058   g->shared()->PrintLn();
3059 }
3060 #endif  // OBJECT_PRINT
3061
3062
3063 TEST(Regress2211) {
3064   CcTest::InitializeVM();
3065   v8::HandleScope scope(CcTest::isolate());
3066
3067   v8::Handle<v8::String> value = v8_str("val string");
3068   Smi* hash = Smi::FromInt(321);
3069   Factory* factory = CcTest::i_isolate()->factory();
3070
3071   for (int i = 0; i < 2; i++) {
3072     // Store identity hash first and common hidden property second.
3073     v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
3074     Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
3075     CHECK(internal_obj->HasFastProperties());
3076
3077     // In the first iteration, set hidden value first and identity hash second.
3078     // In the second iteration, reverse the order.
3079     if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
3080     JSObject::SetIdentityHash(internal_obj, handle(hash, CcTest::i_isolate()));
3081     if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
3082
3083     // Check values.
3084     CHECK_EQ(hash,
3085              internal_obj->GetHiddenProperty(factory->identity_hash_string()));
3086     CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
3087
3088     // Check size.
3089     FieldIndex index = FieldIndex::ForDescriptor(internal_obj->map(), 0);
3090     ObjectHashTable* hashtable = ObjectHashTable::cast(
3091         internal_obj->RawFastPropertyAt(index));
3092     // HashTable header (5) and 4 initial entries (8).
3093     CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
3094   }
3095 }
3096
3097
3098 TEST(IncrementalMarkingClearsTypeFeedbackInfo) {
3099   if (i::FLAG_always_opt) return;
3100   CcTest::InitializeVM();
3101   v8::HandleScope scope(CcTest::isolate());
3102   v8::Local<v8::Value> fun1, fun2;
3103
3104   {
3105     LocalContext env;
3106     CompileRun("function fun() {};");
3107     fun1 = env->Global()->Get(v8_str("fun"));
3108   }
3109
3110   {
3111     LocalContext env;
3112     CompileRun("function fun() {};");
3113     fun2 = env->Global()->Get(v8_str("fun"));
3114   }
3115
3116   // Prepare function f that contains type feedback for closures
3117   // originating from two different native contexts.
3118   CcTest::global()->Set(v8_str("fun1"), fun1);
3119   CcTest::global()->Set(v8_str("fun2"), fun2);
3120   CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
3121
3122   Handle<JSFunction> f =
3123       v8::Utils::OpenHandle(
3124           *v8::Handle<v8::Function>::Cast(
3125               CcTest::global()->Get(v8_str("f"))));
3126
3127   Handle<FixedArray> feedback_vector(f->shared()->feedback_vector());
3128
3129   CHECK_EQ(2, feedback_vector->length());
3130   CHECK(feedback_vector->get(0)->IsJSFunction());
3131   CHECK(feedback_vector->get(1)->IsJSFunction());
3132
3133   SimulateIncrementalMarking();
3134   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
3135
3136   CHECK_EQ(2, feedback_vector->length());
3137   CHECK_EQ(feedback_vector->get(0),
3138            *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate()));
3139   CHECK_EQ(feedback_vector->get(1),
3140            *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate()));
3141 }
3142
3143
3144 static Code* FindFirstIC(Code* code, Code::Kind kind) {
3145   int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
3146              RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
3147              RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
3148   for (RelocIterator it(code, mask); !it.done(); it.next()) {
3149     RelocInfo* info = it.rinfo();
3150     Code* target = Code::GetCodeFromTargetAddress(info->target_address());
3151     if (target->is_inline_cache_stub() && target->kind() == kind) {
3152       return target;
3153     }
3154   }
3155   return NULL;
3156 }
3157
3158
3159 TEST(IncrementalMarkingPreservesMonomorphicIC) {
3160   if (i::FLAG_always_opt) return;
3161   CcTest::InitializeVM();
3162   v8::HandleScope scope(CcTest::isolate());
3163
3164   // Prepare function f that contains a monomorphic IC for object
3165   // originating from the same native context.
3166   CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
3167              "function f(o) { return o.x; } f(obj); f(obj);");
3168   Handle<JSFunction> f =
3169       v8::Utils::OpenHandle(
3170           *v8::Handle<v8::Function>::Cast(
3171               CcTest::global()->Get(v8_str("f"))));
3172
3173   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
3174   CHECK(ic_before->ic_state() == MONOMORPHIC);
3175
3176   SimulateIncrementalMarking();
3177   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
3178
3179   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
3180   CHECK(ic_after->ic_state() == MONOMORPHIC);
3181 }
3182
3183
3184 TEST(IncrementalMarkingClearsMonomorphicIC) {
3185   if (i::FLAG_always_opt) return;
3186   CcTest::InitializeVM();
3187   v8::HandleScope scope(CcTest::isolate());
3188   v8::Local<v8::Value> obj1;
3189
3190   {
3191     LocalContext env;
3192     CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
3193     obj1 = env->Global()->Get(v8_str("obj"));
3194   }
3195
3196   // Prepare function f that contains a monomorphic IC for object
3197   // originating from a different native context.
3198   CcTest::global()->Set(v8_str("obj1"), obj1);
3199   CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
3200   Handle<JSFunction> f =
3201       v8::Utils::OpenHandle(
3202           *v8::Handle<v8::Function>::Cast(
3203               CcTest::global()->Get(v8_str("f"))));
3204
3205   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
3206   CHECK(ic_before->ic_state() == MONOMORPHIC);
3207
3208   // Fire context dispose notification.
3209   v8::V8::ContextDisposedNotification();
3210   SimulateIncrementalMarking();
3211   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
3212
3213   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
3214   CHECK(IC::IsCleared(ic_after));
3215 }
3216
3217
3218 TEST(IncrementalMarkingClearsPolymorphicIC) {
3219   if (i::FLAG_always_opt) return;
3220   CcTest::InitializeVM();
3221   v8::HandleScope scope(CcTest::isolate());
3222   v8::Local<v8::Value> obj1, obj2;
3223
3224   {
3225     LocalContext env;
3226     CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
3227     obj1 = env->Global()->Get(v8_str("obj"));
3228   }
3229
3230   {
3231     LocalContext env;
3232     CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
3233     obj2 = env->Global()->Get(v8_str("obj"));
3234   }
3235
3236   // Prepare function f that contains a polymorphic IC for objects
3237   // originating from two different native contexts.
3238   CcTest::global()->Set(v8_str("obj1"), obj1);
3239   CcTest::global()->Set(v8_str("obj2"), obj2);
3240   CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
3241   Handle<JSFunction> f =
3242       v8::Utils::OpenHandle(
3243           *v8::Handle<v8::Function>::Cast(
3244               CcTest::global()->Get(v8_str("f"))));
3245
3246   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
3247   CHECK(ic_before->ic_state() == POLYMORPHIC);
3248
3249   // Fire context dispose notification.
3250   v8::V8::ContextDisposedNotification();
3251   SimulateIncrementalMarking();
3252   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
3253
3254   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
3255   CHECK(IC::IsCleared(ic_after));
3256 }
3257
3258
3259 class SourceResource: public v8::String::ExternalAsciiStringResource {
3260  public:
3261   explicit SourceResource(const char* data)
3262     : data_(data), length_(strlen(data)) { }
3263
3264   virtual void Dispose() {
3265     i::DeleteArray(data_);
3266     data_ = NULL;
3267   }
3268
3269   const char* data() const { return data_; }
3270
3271   size_t length() const { return length_; }
3272
3273   bool IsDisposed() { return data_ == NULL; }
3274
3275  private:
3276   const char* data_;
3277   size_t length_;
3278 };
3279
3280
3281 void ReleaseStackTraceDataTest(const char* source, const char* accessor) {
3282   // Test that the data retained by the Error.stack accessor is released
3283   // after the first time the accessor is fired.  We use external string
3284   // to check whether the data is being released since the external string
3285   // resource's callback is fired when the external string is GC'ed.
3286   v8::HandleScope scope(CcTest::isolate());
3287   SourceResource* resource = new SourceResource(i::StrDup(source));
3288   {
3289     v8::HandleScope scope(CcTest::isolate());
3290     v8::Handle<v8::String> source_string =
3291         v8::String::NewExternal(CcTest::isolate(), resource);
3292     CcTest::heap()->CollectAllAvailableGarbage();
3293     v8::Script::Compile(source_string)->Run();
3294     CHECK(!resource->IsDisposed());
3295   }
3296   // CcTest::heap()->CollectAllAvailableGarbage();
3297   CHECK(!resource->IsDisposed());
3298
3299   CompileRun(accessor);
3300   CcTest::heap()->CollectAllAvailableGarbage();
3301
3302   // External source has been released.
3303   CHECK(resource->IsDisposed());
3304   delete resource;
3305 }
3306
3307
3308 TEST(ReleaseStackTraceData) {
3309   if (i::FLAG_always_opt) {
3310     // TODO(ulan): Remove this once the memory leak via code_next_link is fixed.
3311     // See: https://codereview.chromium.org/181833004/
3312     return;
3313   }
3314   FLAG_use_ic = false;  // ICs retain objects.
3315   FLAG_concurrent_recompilation = false;
3316   CcTest::InitializeVM();
3317   static const char* source1 = "var error = null;            "
3318   /* Normal Error */           "try {                        "
3319                                "  throw new Error();         "
3320                                "} catch (e) {                "
3321                                "  error = e;                 "
3322                                "}                            ";
3323   static const char* source2 = "var error = null;            "
3324   /* Stack overflow */         "try {                        "
3325                                "  (function f() { f(); })(); "
3326                                "} catch (e) {                "
3327                                "  error = e;                 "
3328                                "}                            ";
3329   static const char* source3 = "var error = null;            "
3330   /* Normal Error */           "try {                        "
3331   /* as prototype */           "  throw new Error();         "
3332                                "} catch (e) {                "
3333                                "  error = {};                "
3334                                "  error.__proto__ = e;       "
3335                                "}                            ";
3336   static const char* source4 = "var error = null;            "
3337   /* Stack overflow */         "try {                        "
3338   /* as prototype   */         "  (function f() { f(); })(); "
3339                                "} catch (e) {                "
3340                                "  error = {};                "
3341                                "  error.__proto__ = e;       "
3342                                "}                            ";
3343   static const char* getter = "error.stack";
3344   static const char* setter = "error.stack = 0";
3345
3346   ReleaseStackTraceDataTest(source1, setter);
3347   ReleaseStackTraceDataTest(source2, setter);
3348   // We do not test source3 and source4 with setter, since the setter is
3349   // supposed to (untypically) write to the receiver, not the holder.  This is
3350   // to emulate the behavior of a data property.
3351
3352   ReleaseStackTraceDataTest(source1, getter);
3353   ReleaseStackTraceDataTest(source2, getter);
3354   ReleaseStackTraceDataTest(source3, getter);
3355   ReleaseStackTraceDataTest(source4, getter);
3356 }
3357
3358
3359 TEST(Regress159140) {
3360   i::FLAG_allow_natives_syntax = true;
3361   i::FLAG_flush_code_incrementally = true;
3362   CcTest::InitializeVM();
3363   Isolate* isolate = CcTest::i_isolate();
3364   Heap* heap = isolate->heap();
3365   HandleScope scope(isolate);
3366
3367   // Perform one initial GC to enable code flushing.
3368   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3369
3370   // Prepare several closures that are all eligible for code flushing
3371   // because all reachable ones are not optimized. Make sure that the
3372   // optimized code object is directly reachable through a handle so
3373   // that it is marked black during incremental marking.
3374   Handle<Code> code;
3375   {
3376     HandleScope inner_scope(isolate);
3377     CompileRun("function h(x) {}"
3378                "function mkClosure() {"
3379                "  return function(x) { return x + 1; };"
3380                "}"
3381                "var f = mkClosure();"
3382                "var g = mkClosure();"
3383                "f(1); f(2);"
3384                "g(1); g(2);"
3385                "h(1); h(2);"
3386                "%OptimizeFunctionOnNextCall(f); f(3);"
3387                "%OptimizeFunctionOnNextCall(h); h(3);");
3388
3389     Handle<JSFunction> f =
3390         v8::Utils::OpenHandle(
3391             *v8::Handle<v8::Function>::Cast(
3392                 CcTest::global()->Get(v8_str("f"))));
3393     CHECK(f->is_compiled());
3394     CompileRun("f = null;");
3395
3396     Handle<JSFunction> g =
3397         v8::Utils::OpenHandle(
3398             *v8::Handle<v8::Function>::Cast(
3399                 CcTest::global()->Get(v8_str("g"))));
3400     CHECK(g->is_compiled());
3401     const int kAgingThreshold = 6;
3402     for (int i = 0; i < kAgingThreshold; i++) {
3403       g->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3404     }
3405
3406     code = inner_scope.CloseAndEscape(Handle<Code>(f->code()));
3407   }
3408
3409   // Simulate incremental marking so that the functions are enqueued as
3410   // code flushing candidates. Then optimize one function. Finally
3411   // finish the GC to complete code flushing.
3412   SimulateIncrementalMarking();
3413   CompileRun("%OptimizeFunctionOnNextCall(g); g(3);");
3414   heap->CollectAllGarbage(Heap::kNoGCFlags);
3415
3416   // Unoptimized code is missing and the deoptimizer will go ballistic.
3417   CompileRun("g('bozo');");
3418 }
3419
3420
3421 TEST(Regress165495) {
3422   i::FLAG_allow_natives_syntax = true;
3423   i::FLAG_flush_code_incrementally = true;
3424   CcTest::InitializeVM();
3425   Isolate* isolate = CcTest::i_isolate();
3426   Heap* heap = isolate->heap();
3427   HandleScope scope(isolate);
3428
3429   // Perform one initial GC to enable code flushing.
3430   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3431
3432   // Prepare an optimized closure that the optimized code map will get
3433   // populated. Then age the unoptimized code to trigger code flushing
3434   // but make sure the optimized code is unreachable.
3435   {
3436     HandleScope inner_scope(isolate);
3437     CompileRun("function mkClosure() {"
3438                "  return function(x) { return x + 1; };"
3439                "}"
3440                "var f = mkClosure();"
3441                "f(1); f(2);"
3442                "%OptimizeFunctionOnNextCall(f); f(3);");
3443
3444     Handle<JSFunction> f =
3445         v8::Utils::OpenHandle(
3446             *v8::Handle<v8::Function>::Cast(
3447                 CcTest::global()->Get(v8_str("f"))));
3448     CHECK(f->is_compiled());
3449     const int kAgingThreshold = 6;
3450     for (int i = 0; i < kAgingThreshold; i++) {
3451       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3452     }
3453
3454     CompileRun("f = null;");
3455   }
3456
3457   // Simulate incremental marking so that unoptimized code is flushed
3458   // even though it still is cached in the optimized code map.
3459   SimulateIncrementalMarking();
3460   heap->CollectAllGarbage(Heap::kNoGCFlags);
3461
3462   // Make a new closure that will get code installed from the code map.
3463   // Unoptimized code is missing and the deoptimizer will go ballistic.
3464   CompileRun("var g = mkClosure(); g('bozo');");
3465 }
3466
3467
3468 TEST(Regress169209) {
3469   i::FLAG_stress_compaction = false;
3470   i::FLAG_allow_natives_syntax = true;
3471   i::FLAG_flush_code_incrementally = true;
3472
3473   CcTest::InitializeVM();
3474   Isolate* isolate = CcTest::i_isolate();
3475   Heap* heap = isolate->heap();
3476   HandleScope scope(isolate);
3477
3478   // Perform one initial GC to enable code flushing.
3479   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3480
3481   // Prepare a shared function info eligible for code flushing for which
3482   // the unoptimized code will be replaced during optimization.
3483   Handle<SharedFunctionInfo> shared1;
3484   {
3485     HandleScope inner_scope(isolate);
3486     CompileRun("function f() { return 'foobar'; }"
3487                "function g(x) { if (x) f(); }"
3488                "f();"
3489                "g(false);"
3490                "g(false);");
3491
3492     Handle<JSFunction> f =
3493         v8::Utils::OpenHandle(
3494             *v8::Handle<v8::Function>::Cast(
3495                 CcTest::global()->Get(v8_str("f"))));
3496     CHECK(f->is_compiled());
3497     const int kAgingThreshold = 6;
3498     for (int i = 0; i < kAgingThreshold; i++) {
3499       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3500     }
3501
3502     shared1 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
3503   }
3504
3505   // Prepare a shared function info eligible for code flushing that will
3506   // represent the dangling tail of the candidate list.
3507   Handle<SharedFunctionInfo> shared2;
3508   {
3509     HandleScope inner_scope(isolate);
3510     CompileRun("function flushMe() { return 0; }"
3511                "flushMe(1);");
3512
3513     Handle<JSFunction> f =
3514         v8::Utils::OpenHandle(
3515             *v8::Handle<v8::Function>::Cast(
3516                 CcTest::global()->Get(v8_str("flushMe"))));
3517     CHECK(f->is_compiled());
3518     const int kAgingThreshold = 6;
3519     for (int i = 0; i < kAgingThreshold; i++) {
3520       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3521     }
3522
3523     shared2 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
3524   }
3525
3526   // Simulate incremental marking and collect code flushing candidates.
3527   SimulateIncrementalMarking();
3528   CHECK(shared1->code()->gc_metadata() != NULL);
3529
3530   // Optimize function and make sure the unoptimized code is replaced.
3531 #ifdef DEBUG
3532   FLAG_stop_at = "f";
3533 #endif
3534   CompileRun("%OptimizeFunctionOnNextCall(g);"
3535              "g(false);");
3536
3537   // Finish garbage collection cycle.
3538   heap->CollectAllGarbage(Heap::kNoGCFlags);
3539   CHECK(shared1->code()->gc_metadata() == NULL);
3540 }
3541
3542
3543 // Helper function that simulates a fill new-space in the heap.
3544 static inline void AllocateAllButNBytes(v8::internal::NewSpace* space,
3545                                         int extra_bytes) {
3546   int space_remaining = static_cast<int>(
3547       *space->allocation_limit_address() - *space->allocation_top_address());
3548   CHECK(space_remaining >= extra_bytes);
3549   int new_linear_size = space_remaining - extra_bytes;
3550   v8::internal::AllocationResult allocation =
3551       space->AllocateRaw(new_linear_size);
3552   v8::internal::FreeListNode* node =
3553       v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
3554   node->set_size(space->heap(), new_linear_size);
3555 }
3556
3557
3558 TEST(Regress169928) {
3559   i::FLAG_allow_natives_syntax = true;
3560   i::FLAG_crankshaft = false;
3561   CcTest::InitializeVM();
3562   Isolate* isolate = CcTest::i_isolate();
3563   Factory* factory = isolate->factory();
3564   v8::HandleScope scope(CcTest::isolate());
3565
3566   // Some flags turn Scavenge collections into Mark-sweep collections
3567   // and hence are incompatible with this test case.
3568   if (FLAG_gc_global || FLAG_stress_compaction) return;
3569
3570   // Prepare the environment
3571   CompileRun("function fastliteralcase(literal, value) {"
3572              "    literal[0] = value;"
3573              "    return literal;"
3574              "}"
3575              "function get_standard_literal() {"
3576              "    var literal = [1, 2, 3];"
3577              "    return literal;"
3578              "}"
3579              "obj = fastliteralcase(get_standard_literal(), 1);"
3580              "obj = fastliteralcase(get_standard_literal(), 1.5);"
3581              "obj = fastliteralcase(get_standard_literal(), 2);");
3582
3583   // prepare the heap
3584   v8::Local<v8::String> mote_code_string =
3585       v8_str("fastliteralcase(mote, 2.5);");
3586
3587   v8::Local<v8::String> array_name = v8_str("mote");
3588   CcTest::global()->Set(array_name, v8::Int32::New(CcTest::isolate(), 0));
3589
3590   // First make sure we flip spaces
3591   CcTest::heap()->CollectGarbage(NEW_SPACE);
3592
3593   // Allocate the object.
3594   Handle<FixedArray> array_data = factory->NewFixedArray(2, NOT_TENURED);
3595   array_data->set(0, Smi::FromInt(1));
3596   array_data->set(1, Smi::FromInt(2));
3597
3598   AllocateAllButNBytes(CcTest::heap()->new_space(),
3599                        JSArray::kSize + AllocationMemento::kSize +
3600                        kPointerSize);
3601
3602   Handle<JSArray> array = factory->NewJSArrayWithElements(array_data,
3603                                                           FAST_SMI_ELEMENTS,
3604                                                           NOT_TENURED);
3605
3606   CHECK_EQ(Smi::FromInt(2), array->length());
3607   CHECK(array->HasFastSmiOrObjectElements());
3608
3609   // We need filler the size of AllocationMemento object, plus an extra
3610   // fill pointer value.
3611   HeapObject* obj = NULL;
3612   AllocationResult allocation = CcTest::heap()->new_space()->AllocateRaw(
3613       AllocationMemento::kSize + kPointerSize);
3614   CHECK(allocation.To(&obj));
3615   Address addr_obj = obj->address();
3616   CcTest::heap()->CreateFillerObjectAt(
3617       addr_obj, AllocationMemento::kSize + kPointerSize);
3618
3619   // Give the array a name, making sure not to allocate strings.
3620   v8::Handle<v8::Object> array_obj = v8::Utils::ToLocal(array);
3621   CcTest::global()->Set(array_name, array_obj);
3622
3623   // This should crash with a protection violation if we are running a build
3624   // with the bug.
3625   AlwaysAllocateScope aa_scope(isolate);
3626   v8::Script::Compile(mote_code_string)->Run();
3627 }
3628
3629
3630 TEST(Regress168801) {
3631   if (i::FLAG_never_compact) return;
3632   i::FLAG_always_compact = true;
3633   i::FLAG_cache_optimized_code = false;
3634   i::FLAG_allow_natives_syntax = true;
3635   i::FLAG_flush_code_incrementally = true;
3636   CcTest::InitializeVM();
3637   Isolate* isolate = CcTest::i_isolate();
3638   Heap* heap = isolate->heap();
3639   HandleScope scope(isolate);
3640
3641   // Perform one initial GC to enable code flushing.
3642   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3643
3644   // Ensure the code ends up on an evacuation candidate.
3645   SimulateFullSpace(heap->code_space());
3646
3647   // Prepare an unoptimized function that is eligible for code flushing.
3648   Handle<JSFunction> function;
3649   {
3650     HandleScope inner_scope(isolate);
3651     CompileRun("function mkClosure() {"
3652                "  return function(x) { return x + 1; };"
3653                "}"
3654                "var f = mkClosure();"
3655                "f(1); f(2);");
3656
3657     Handle<JSFunction> f =
3658         v8::Utils::OpenHandle(
3659             *v8::Handle<v8::Function>::Cast(
3660                 CcTest::global()->Get(v8_str("f"))));
3661     CHECK(f->is_compiled());
3662     const int kAgingThreshold = 6;
3663     for (int i = 0; i < kAgingThreshold; i++) {
3664       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3665     }
3666
3667     function = inner_scope.CloseAndEscape(handle(*f, isolate));
3668   }
3669
3670   // Simulate incremental marking so that unoptimized function is enqueued as a
3671   // candidate for code flushing. The shared function info however will not be
3672   // explicitly enqueued.
3673   SimulateIncrementalMarking();
3674
3675   // Now optimize the function so that it is taken off the candidate list.
3676   {
3677     HandleScope inner_scope(isolate);
3678     CompileRun("%OptimizeFunctionOnNextCall(f); f(3);");
3679   }
3680
3681   // This cycle will bust the heap and subsequent cycles will go ballistic.
3682   heap->CollectAllGarbage(Heap::kNoGCFlags);
3683   heap->CollectAllGarbage(Heap::kNoGCFlags);
3684 }
3685
3686
3687 TEST(Regress173458) {
3688   if (i::FLAG_never_compact) return;
3689   i::FLAG_always_compact = true;
3690   i::FLAG_cache_optimized_code = false;
3691   i::FLAG_allow_natives_syntax = true;
3692   i::FLAG_flush_code_incrementally = true;
3693   CcTest::InitializeVM();
3694   Isolate* isolate = CcTest::i_isolate();
3695   Heap* heap = isolate->heap();
3696   HandleScope scope(isolate);
3697
3698   // Perform one initial GC to enable code flushing.
3699   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3700
3701   // Ensure the code ends up on an evacuation candidate.
3702   SimulateFullSpace(heap->code_space());
3703
3704   // Prepare an unoptimized function that is eligible for code flushing.
3705   Handle<JSFunction> function;
3706   {
3707     HandleScope inner_scope(isolate);
3708     CompileRun("function mkClosure() {"
3709                "  return function(x) { return x + 1; };"
3710                "}"
3711                "var f = mkClosure();"
3712                "f(1); f(2);");
3713
3714     Handle<JSFunction> f =
3715         v8::Utils::OpenHandle(
3716             *v8::Handle<v8::Function>::Cast(
3717                 CcTest::global()->Get(v8_str("f"))));
3718     CHECK(f->is_compiled());
3719     const int kAgingThreshold = 6;
3720     for (int i = 0; i < kAgingThreshold; i++) {
3721       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3722     }
3723
3724     function = inner_scope.CloseAndEscape(handle(*f, isolate));
3725   }
3726
3727   // Simulate incremental marking so that unoptimized function is enqueued as a
3728   // candidate for code flushing. The shared function info however will not be
3729   // explicitly enqueued.
3730   SimulateIncrementalMarking();
3731
3732   // Now enable the debugger which in turn will disable code flushing.
3733   CHECK(isolate->debug()->Load());
3734
3735   // This cycle will bust the heap and subsequent cycles will go ballistic.
3736   heap->CollectAllGarbage(Heap::kNoGCFlags);
3737   heap->CollectAllGarbage(Heap::kNoGCFlags);
3738 }
3739
3740
3741 class DummyVisitor : public ObjectVisitor {
3742  public:
3743   void VisitPointers(Object** start, Object** end) { }
3744 };
3745
3746
3747 TEST(DeferredHandles) {
3748   CcTest::InitializeVM();
3749   Isolate* isolate = CcTest::i_isolate();
3750   Heap* heap = isolate->heap();
3751   v8::HandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
3752   HandleScopeData* data = isolate->handle_scope_data();
3753   Handle<Object> init(heap->empty_string(), isolate);
3754   while (data->next < data->limit) {
3755     Handle<Object> obj(heap->empty_string(), isolate);
3756   }
3757   // An entire block of handles has been filled.
3758   // Next handle would require a new block.
3759   ASSERT(data->next == data->limit);
3760
3761   DeferredHandleScope deferred(isolate);
3762   DummyVisitor visitor;
3763   isolate->handle_scope_implementer()->Iterate(&visitor);
3764   delete deferred.Detach();
3765 }
3766
3767
3768 TEST(IncrementalMarkingStepMakesBigProgressWithLargeObjects) {
3769   CcTest::InitializeVM();
3770   v8::HandleScope scope(CcTest::isolate());
3771   CompileRun("function f(n) {"
3772              "    var a = new Array(n);"
3773              "    for (var i = 0; i < n; i += 100) a[i] = i;"
3774              "};"
3775              "f(10 * 1024 * 1024);");
3776   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
3777   if (marking->IsStopped()) marking->Start();
3778   // This big step should be sufficient to mark the whole array.
3779   marking->Step(100 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
3780   ASSERT(marking->IsComplete());
3781 }
3782
3783
3784 TEST(DisableInlineAllocation) {
3785   i::FLAG_allow_natives_syntax = true;
3786   CcTest::InitializeVM();
3787   v8::HandleScope scope(CcTest::isolate());
3788   CompileRun("function test() {"
3789              "  var x = [];"
3790              "  for (var i = 0; i < 10; i++) {"
3791              "    x[i] = [ {}, [1,2,3], [1,x,3] ];"
3792              "  }"
3793              "}"
3794              "function run() {"
3795              "  %OptimizeFunctionOnNextCall(test);"
3796              "  test();"
3797              "  %DeoptimizeFunction(test);"
3798              "}");
3799
3800   // Warm-up with inline allocation enabled.
3801   CompileRun("test(); test(); run();");
3802
3803   // Run test with inline allocation disabled.
3804   CcTest::heap()->DisableInlineAllocation();
3805   CompileRun("run()");
3806
3807   // Run test with inline allocation re-enabled.
3808   CcTest::heap()->EnableInlineAllocation();
3809   CompileRun("run()");
3810 }
3811
3812
3813 static int AllocationSitesCount(Heap* heap) {
3814   int count = 0;
3815   for (Object* site = heap->allocation_sites_list();
3816        !(site->IsUndefined());
3817        site = AllocationSite::cast(site)->weak_next()) {
3818     count++;
3819   }
3820   return count;
3821 }
3822
3823
3824 TEST(EnsureAllocationSiteDependentCodesProcessed) {
3825   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
3826   i::FLAG_allow_natives_syntax = true;
3827   CcTest::InitializeVM();
3828   Isolate* isolate = CcTest::i_isolate();
3829   v8::internal::Heap* heap = CcTest::heap();
3830   GlobalHandles* global_handles = isolate->global_handles();
3831
3832   if (!isolate->use_crankshaft()) return;
3833
3834   // The allocation site at the head of the list is ours.
3835   Handle<AllocationSite> site;
3836   {
3837     LocalContext context;
3838     v8::HandleScope scope(context->GetIsolate());
3839
3840     int count = AllocationSitesCount(heap);
3841     CompileRun("var bar = function() { return (new Array()); };"
3842                "var a = bar();"
3843                "bar();"
3844                "bar();");
3845
3846     // One allocation site should have been created.
3847     int new_count = AllocationSitesCount(heap);
3848     CHECK_EQ(new_count, (count + 1));
3849     site = Handle<AllocationSite>::cast(
3850         global_handles->Create(
3851             AllocationSite::cast(heap->allocation_sites_list())));
3852
3853     CompileRun("%OptimizeFunctionOnNextCall(bar); bar();");
3854
3855     DependentCode::GroupStartIndexes starts(site->dependent_code());
3856     CHECK_GE(starts.number_of_entries(), 1);
3857     int index = starts.at(DependentCode::kAllocationSiteTransitionChangedGroup);
3858     CHECK(site->dependent_code()->is_code_at(index));
3859     Code* function_bar = site->dependent_code()->code_at(index);
3860     Handle<JSFunction> bar_handle =
3861         v8::Utils::OpenHandle(
3862             *v8::Handle<v8::Function>::Cast(
3863                 CcTest::global()->Get(v8_str("bar"))));
3864     CHECK_EQ(bar_handle->code(), function_bar);
3865   }
3866
3867   // Now make sure that a gc should get rid of the function, even though we
3868   // still have the allocation site alive.
3869   for (int i = 0; i < 4; i++) {
3870     heap->CollectAllGarbage(Heap::kNoGCFlags);
3871   }
3872
3873   // The site still exists because of our global handle, but the code is no
3874   // longer referred to by dependent_code().
3875   DependentCode::GroupStartIndexes starts(site->dependent_code());
3876   int index = starts.at(DependentCode::kAllocationSiteTransitionChangedGroup);
3877   CHECK(!(site->dependent_code()->is_code_at(index)));
3878 }
3879
3880
3881 TEST(CellsInOptimizedCodeAreWeak) {
3882   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
3883   i::FLAG_weak_embedded_objects_in_optimized_code = true;
3884   i::FLAG_allow_natives_syntax = true;
3885   CcTest::InitializeVM();
3886   Isolate* isolate = CcTest::i_isolate();
3887   v8::internal::Heap* heap = CcTest::heap();
3888
3889   if (!isolate->use_crankshaft()) return;
3890   HandleScope outer_scope(heap->isolate());
3891   Handle<Code> code;
3892   {
3893     LocalContext context;
3894     HandleScope scope(heap->isolate());
3895
3896     CompileRun("bar = (function() {"
3897                "  function bar() {"
3898                "    return foo(1);"
3899                "  };"
3900                "  var foo = function(x) { with (x) { return 1 + x; } };"
3901                "  bar(foo);"
3902                "  bar(foo);"
3903                "  bar(foo);"
3904                "  %OptimizeFunctionOnNextCall(bar);"
3905                "  bar(foo);"
3906                "  return bar;})();");
3907
3908     Handle<JSFunction> bar =
3909         v8::Utils::OpenHandle(
3910             *v8::Handle<v8::Function>::Cast(
3911                 CcTest::global()->Get(v8_str("bar"))));
3912     code = scope.CloseAndEscape(Handle<Code>(bar->code()));
3913   }
3914
3915   // Now make sure that a gc should get rid of the function
3916   for (int i = 0; i < 4; i++) {
3917     heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3918   }
3919
3920   ASSERT(code->marked_for_deoptimization());
3921 }
3922
3923
3924 TEST(ObjectsInOptimizedCodeAreWeak) {
3925   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
3926   i::FLAG_weak_embedded_objects_in_optimized_code = true;
3927   i::FLAG_allow_natives_syntax = true;
3928   CcTest::InitializeVM();
3929   Isolate* isolate = CcTest::i_isolate();
3930   v8::internal::Heap* heap = CcTest::heap();
3931
3932   if (!isolate->use_crankshaft()) return;
3933   HandleScope outer_scope(heap->isolate());
3934   Handle<Code> code;
3935   {
3936     LocalContext context;
3937     HandleScope scope(heap->isolate());
3938
3939     CompileRun("function bar() {"
3940                "  return foo(1);"
3941                "};"
3942                "function foo(x) { with (x) { return 1 + x; } };"
3943                "bar();"
3944                "bar();"
3945                "bar();"
3946                "%OptimizeFunctionOnNextCall(bar);"
3947                "bar();");
3948
3949     Handle<JSFunction> bar =
3950         v8::Utils::OpenHandle(
3951             *v8::Handle<v8::Function>::Cast(
3952                 CcTest::global()->Get(v8_str("bar"))));
3953     code = scope.CloseAndEscape(Handle<Code>(bar->code()));
3954   }
3955
3956   // Now make sure that a gc should get rid of the function
3957   for (int i = 0; i < 4; i++) {
3958     heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3959   }
3960
3961   ASSERT(code->marked_for_deoptimization());
3962 }
3963
3964
3965 TEST(NoWeakHashTableLeakWithIncrementalMarking) {
3966   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
3967   if (!i::FLAG_incremental_marking) return;
3968   i::FLAG_weak_embedded_objects_in_optimized_code = true;
3969   i::FLAG_allow_natives_syntax = true;
3970   i::FLAG_compilation_cache = false;
3971   CcTest::InitializeVM();
3972   Isolate* isolate = CcTest::i_isolate();
3973   v8::internal::Heap* heap = CcTest::heap();
3974
3975   if (!isolate->use_crankshaft()) return;
3976   HandleScope outer_scope(heap->isolate());
3977   for (int i = 0; i < 3; i++) {
3978     SimulateIncrementalMarking();
3979     {
3980       LocalContext context;
3981       HandleScope scope(heap->isolate());
3982       EmbeddedVector<char, 256> source;
3983       SNPrintF(source,
3984                "function bar%d() {"
3985                "  return foo%d(1);"
3986                "};"
3987                "function foo%d(x) { with (x) { return 1 + x; } };"
3988                "bar%d();"
3989                "bar%d();"
3990                "bar%d();"
3991                "%%OptimizeFunctionOnNextCall(bar%d);"
3992                "bar%d();", i, i, i, i, i, i, i, i);
3993       CompileRun(source.start());
3994     }
3995     heap->CollectAllGarbage(i::Heap::kNoGCFlags);
3996   }
3997   int elements = 0;
3998   if (heap->weak_object_to_code_table()->IsHashTable()) {
3999     WeakHashTable* t = WeakHashTable::cast(heap->weak_object_to_code_table());
4000     elements = t->NumberOfElements();
4001   }
4002   CHECK_EQ(0, elements);
4003 }
4004
4005
4006 static Handle<JSFunction> OptimizeDummyFunction(const char* name) {
4007   EmbeddedVector<char, 256> source;
4008   SNPrintF(source,
4009           "function %s() { return 0; }"
4010           "%s(); %s();"
4011           "%%OptimizeFunctionOnNextCall(%s);"
4012           "%s();", name, name, name, name, name);
4013   CompileRun(source.start());
4014   Handle<JSFunction> fun =
4015       v8::Utils::OpenHandle(
4016           *v8::Handle<v8::Function>::Cast(
4017               CcTest::global()->Get(v8_str(name))));
4018   return fun;
4019 }
4020
4021
4022 static int GetCodeChainLength(Code* code) {
4023   int result = 0;
4024   while (code->next_code_link()->IsCode()) {
4025     result++;
4026     code = Code::cast(code->next_code_link());
4027   }
4028   return result;
4029 }
4030
4031
4032 TEST(NextCodeLinkIsWeak) {
4033   i::FLAG_allow_natives_syntax = true;
4034   CcTest::InitializeVM();
4035   Isolate* isolate = CcTest::i_isolate();
4036   v8::internal::Heap* heap = CcTest::heap();
4037
4038   if (!isolate->use_crankshaft()) return;
4039   HandleScope outer_scope(heap->isolate());
4040   Handle<Code> code;
4041   heap->CollectAllAvailableGarbage();
4042   int code_chain_length_before, code_chain_length_after;
4043   {
4044     HandleScope scope(heap->isolate());
4045     Handle<JSFunction> mortal = OptimizeDummyFunction("mortal");
4046     Handle<JSFunction> immortal = OptimizeDummyFunction("immortal");
4047     CHECK_EQ(immortal->code()->next_code_link(), mortal->code());
4048     code_chain_length_before = GetCodeChainLength(immortal->code());
4049     // Keep the immortal code and let the mortal code die.
4050     code = scope.CloseAndEscape(Handle<Code>(immortal->code()));
4051     CompileRun("mortal = null; immortal = null;");
4052   }
4053   heap->CollectAllAvailableGarbage();
4054   // Now mortal code should be dead.
4055   code_chain_length_after = GetCodeChainLength(*code);
4056   CHECK_EQ(code_chain_length_before - 1, code_chain_length_after);
4057 }
4058
4059
4060 static Handle<Code> DummyOptimizedCode(Isolate* isolate) {
4061   i::byte buffer[i::Assembler::kMinimalBufferSize];
4062   MacroAssembler masm(isolate, buffer, sizeof(buffer));
4063   CodeDesc desc;
4064   masm.Push(isolate->factory()->undefined_value());
4065   masm.Drop(1);
4066   masm.GetCode(&desc);
4067   Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
4068   Handle<Code> code = isolate->factory()->NewCode(
4069       desc, Code::ComputeFlags(Code::OPTIMIZED_FUNCTION), undefined);
4070   CHECK(code->IsCode());
4071   return code;
4072 }
4073
4074
4075 TEST(NextCodeLinkIsWeak2) {
4076   i::FLAG_allow_natives_syntax = true;
4077   CcTest::InitializeVM();
4078   Isolate* isolate = CcTest::i_isolate();
4079   v8::internal::Heap* heap = CcTest::heap();
4080
4081   if (!isolate->use_crankshaft()) return;
4082   HandleScope outer_scope(heap->isolate());
4083   heap->CollectAllAvailableGarbage();
4084   Handle<Context> context(Context::cast(heap->native_contexts_list()), isolate);
4085   Handle<Code> new_head;
4086   Handle<Object> old_head(context->get(Context::OPTIMIZED_CODE_LIST), isolate);
4087   {
4088     HandleScope scope(heap->isolate());
4089     Handle<Code> immortal = DummyOptimizedCode(isolate);
4090     Handle<Code> mortal = DummyOptimizedCode(isolate);
4091     mortal->set_next_code_link(*old_head);
4092     immortal->set_next_code_link(*mortal);
4093     context->set(Context::OPTIMIZED_CODE_LIST, *immortal);
4094     new_head = scope.CloseAndEscape(immortal);
4095   }
4096   heap->CollectAllAvailableGarbage();
4097   // Now mortal code should be dead.
4098   CHECK_EQ(*old_head, new_head->next_code_link());
4099 }
4100
4101
4102 static bool weak_ic_cleared = false;
4103
4104 static void ClearWeakIC(const v8::WeakCallbackData<v8::Object, void>& data) {
4105   printf("clear weak is called\n");
4106   weak_ic_cleared = true;
4107   v8::Persistent<v8::Value>* p =
4108       reinterpret_cast<v8::Persistent<v8::Value>*>(data.GetParameter());
4109   CHECK(p->IsNearDeath());
4110   p->Reset();
4111 }
4112
4113
4114 // Checks that the value returned by execution of the source is weak.
4115 void CheckWeakness(const char* source) {
4116   i::FLAG_stress_compaction = false;
4117   CcTest::InitializeVM();
4118   v8::Isolate* isolate = CcTest::isolate();
4119   v8::HandleScope scope(isolate);
4120   v8::Persistent<v8::Object> garbage;
4121   {
4122     v8::HandleScope scope(isolate);
4123     garbage.Reset(isolate, CompileRun(source)->ToObject());
4124   }
4125   weak_ic_cleared = false;
4126   garbage.SetWeak(static_cast<void*>(&garbage), &ClearWeakIC);
4127   Heap* heap = CcTest::i_isolate()->heap();
4128   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
4129   CHECK(weak_ic_cleared);
4130 }
4131
4132
4133 // Each of the following "weak IC" tests creates an IC that embeds a map with
4134 // the prototype pointing to _proto_ and checks that the _proto_ dies on GC.
4135 TEST(WeakMapInMonomorphicLoadIC) {
4136   CheckWeakness("function loadIC(obj) {"
4137                 "  return obj.name;"
4138                 "}"
4139                 " (function() {"
4140                 "   var proto = {'name' : 'weak'};"
4141                 "   var obj = Object.create(proto);"
4142                 "   loadIC(obj);"
4143                 "   loadIC(obj);"
4144                 "   loadIC(obj);"
4145                 "   return proto;"
4146                 " })();");
4147 }
4148
4149
4150 TEST(WeakMapInMonomorphicKeyedLoadIC) {
4151   CheckWeakness("function keyedLoadIC(obj, field) {"
4152                 "  return obj[field];"
4153                 "}"
4154                 " (function() {"
4155                 "   var proto = {'name' : 'weak'};"
4156                 "   var obj = Object.create(proto);"
4157                 "   keyedLoadIC(obj, 'name');"
4158                 "   keyedLoadIC(obj, 'name');"
4159                 "   keyedLoadIC(obj, 'name');"
4160                 "   return proto;"
4161                 " })();");
4162 }
4163
4164
4165 TEST(WeakMapInMonomorphicStoreIC) {
4166   CheckWeakness("function storeIC(obj, value) {"
4167                 "  obj.name = value;"
4168                 "}"
4169                 " (function() {"
4170                 "   var proto = {'name' : 'weak'};"
4171                 "   var obj = Object.create(proto);"
4172                 "   storeIC(obj, 'x');"
4173                 "   storeIC(obj, 'x');"
4174                 "   storeIC(obj, 'x');"
4175                 "   return proto;"
4176                 " })();");
4177 }
4178
4179
4180 TEST(WeakMapInMonomorphicKeyedStoreIC) {
4181   CheckWeakness("function keyedStoreIC(obj, field, value) {"
4182                 "  obj[field] = value;"
4183                 "}"
4184                 " (function() {"
4185                 "   var proto = {'name' : 'weak'};"
4186                 "   var obj = Object.create(proto);"
4187                 "   keyedStoreIC(obj, 'x');"
4188                 "   keyedStoreIC(obj, 'x');"
4189                 "   keyedStoreIC(obj, 'x');"
4190                 "   return proto;"
4191                 " })();");
4192 }
4193
4194
4195 TEST(WeakMapInMonomorphicCompareNilIC) {
4196   CheckWeakness("function compareNilIC(obj) {"
4197                 "  return obj == null;"
4198                 "}"
4199                 " (function() {"
4200                 "   var proto = {'name' : 'weak'};"
4201                 "   var obj = Object.create(proto);"
4202                 "   compareNilIC(obj);"
4203                 "   compareNilIC(obj);"
4204                 "   compareNilIC(obj);"
4205                 "   return proto;"
4206                 " })();");
4207 }
4208
4209
4210 #ifdef DEBUG
4211 TEST(AddInstructionChangesNewSpacePromotion) {
4212   i::FLAG_allow_natives_syntax = true;
4213   i::FLAG_expose_gc = true;
4214   i::FLAG_stress_compaction = true;
4215   i::FLAG_gc_interval = 1000;
4216   CcTest::InitializeVM();
4217   if (!i::FLAG_allocation_site_pretenuring) return;
4218   v8::HandleScope scope(CcTest::isolate());
4219   Isolate* isolate = CcTest::i_isolate();
4220   Heap* heap = isolate->heap();
4221
4222   CompileRun(
4223       "function add(a, b) {"
4224       "  return a + b;"
4225       "}"
4226       "add(1, 2);"
4227       "add(\"a\", \"b\");"
4228       "var oldSpaceObject;"
4229       "gc();"
4230       "function crash(x) {"
4231       "  var object = {a: null, b: null};"
4232       "  var result = add(1.5, x | 0);"
4233       "  object.a = result;"
4234       "  oldSpaceObject = object;"
4235       "  return object;"
4236       "}"
4237       "crash(1);"
4238       "crash(1);"
4239       "%OptimizeFunctionOnNextCall(crash);"
4240       "crash(1);");
4241
4242   v8::Handle<v8::Object> global = CcTest::global();
4243     v8::Handle<v8::Function> g =
4244         v8::Handle<v8::Function>::Cast(global->Get(v8_str("crash")));
4245   v8::Handle<v8::Value> args1[] = { v8_num(1) };
4246   heap->DisableInlineAllocation();
4247   heap->set_allocation_timeout(1);
4248   g->Call(global, 1, args1);
4249   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
4250 }
4251
4252
4253 void OnFatalErrorExpectOOM(const char* location, const char* message) {
4254   // Exit with 0 if the location matches our expectation.
4255   exit(strcmp(location, "CALL_AND_RETRY_LAST"));
4256 }
4257
4258
4259 TEST(CEntryStubOOM) {
4260   i::FLAG_allow_natives_syntax = true;
4261   CcTest::InitializeVM();
4262   v8::HandleScope scope(CcTest::isolate());
4263   v8::V8::SetFatalErrorHandler(OnFatalErrorExpectOOM);
4264
4265   v8::Handle<v8::Value> result = CompileRun(
4266       "%SetFlags('--gc-interval=1');"
4267       "var a = [];"
4268       "a.__proto__ = [];"
4269       "a.unshift(1)");
4270
4271   CHECK(result->IsNumber());
4272 }
4273
4274 #endif  // DEBUG
4275
4276
4277 static void InterruptCallback357137(v8::Isolate* isolate, void* data) { }
4278
4279
4280 static void RequestInterrupt(const v8::FunctionCallbackInfo<v8::Value>& args) {
4281   CcTest::isolate()->RequestInterrupt(&InterruptCallback357137, NULL);
4282 }
4283
4284
4285 TEST(Regress357137) {
4286   CcTest::InitializeVM();
4287   v8::Isolate* isolate = CcTest::isolate();
4288   v8::HandleScope hscope(isolate);
4289   v8::Handle<v8::ObjectTemplate> global =v8::ObjectTemplate::New(isolate);
4290   global->Set(v8::String::NewFromUtf8(isolate, "interrupt"),
4291               v8::FunctionTemplate::New(isolate, RequestInterrupt));
4292   v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
4293   ASSERT(!context.IsEmpty());
4294   v8::Context::Scope cscope(context);
4295
4296   v8::Local<v8::Value> result = CompileRun(
4297       "var locals = '';"
4298       "for (var i = 0; i < 512; i++) locals += 'var v' + i + '= 42;';"
4299       "eval('function f() {' + locals + 'return function() { return v0; }; }');"
4300       "interrupt();"  // This triggers a fake stack overflow in f.
4301       "f()()");
4302   CHECK_EQ(42.0, result->ToNumber()->Value());
4303 }
4304
4305
4306 TEST(ArrayShiftSweeping) {
4307   i::FLAG_expose_gc = true;
4308   CcTest::InitializeVM();
4309   v8::HandleScope scope(CcTest::isolate());
4310   Isolate* isolate = CcTest::i_isolate();
4311   Heap* heap = isolate->heap();
4312
4313   v8::Local<v8::Value> result = CompileRun(
4314       "var array = new Array(40000);"
4315       "var tmp = new Array(100000);"
4316       "array[0] = 10;"
4317       "gc();"
4318       "array.shift();"
4319       "array;");
4320
4321   Handle<JSObject> o =
4322       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(result));
4323   CHECK(heap->InOldPointerSpace(o->elements()));
4324   CHECK(heap->InOldPointerSpace(*o));
4325   Page* page = Page::FromAddress(o->elements()->address());
4326   CHECK(page->WasSwept() ||
4327         Marking::IsBlack(Marking::MarkBitFrom(o->elements())));
4328 }
4329
4330
4331 #ifdef DEBUG
4332 TEST(PathTracer) {
4333   CcTest::InitializeVM();
4334   v8::HandleScope scope(CcTest::isolate());
4335
4336   v8::Local<v8::Value> result = CompileRun("'abc'");
4337   Handle<Object> o = v8::Utils::OpenHandle(*result);
4338   CcTest::i_isolate()->heap()->TracePathToObject(*o);
4339 }
4340 #endif  // DEBUG