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