Upstream version 9.38.207.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 = (RoundDown(available, Page::kPageSize) /
1689       FixedArray::SizeFor(32)) - 1;
1690   for (intptr_t i = 0; i < number_of_fillers; i++) {
1691     CHECK(heap->InNewSpace(*factory->NewFixedArray(32, NOT_TENURED)));
1692   }
1693 }
1694
1695
1696 TEST(GrowAndShrinkNewSpace) {
1697   CcTest::InitializeVM();
1698   Heap* heap = CcTest::heap();
1699   NewSpace* new_space = heap->new_space();
1700
1701   if (heap->ReservedSemiSpaceSize() == heap->InitialSemiSpaceSize() ||
1702       heap->MaxSemiSpaceSize() == heap->InitialSemiSpaceSize()) {
1703     // The max size cannot exceed the reserved size, since semispaces must be
1704     // always within the reserved space.  We can't test new space growing and
1705     // shrinking if the reserved size is the same as the minimum (initial) size.
1706     return;
1707   }
1708
1709   // Explicitly growing should double the space capacity.
1710   intptr_t old_capacity, new_capacity;
1711   old_capacity = new_space->Capacity();
1712   new_space->Grow();
1713   new_capacity = new_space->Capacity();
1714   CHECK(2 * old_capacity == new_capacity);
1715
1716   old_capacity = new_space->Capacity();
1717   new_space->Grow();
1718   new_capacity = new_space->Capacity();
1719   CHECK(2 * old_capacity == new_capacity);
1720
1721   old_capacity = new_space->Capacity();
1722   FillUpNewSpace(new_space);
1723   new_capacity = new_space->Capacity();
1724   CHECK(old_capacity == new_capacity);
1725
1726   // Explicitly shrinking should not affect space capacity.
1727   old_capacity = new_space->Capacity();
1728   new_space->Shrink();
1729   new_capacity = new_space->Capacity();
1730   CHECK(old_capacity == new_capacity);
1731
1732   // Let the scavenger empty the new space.
1733   heap->CollectGarbage(NEW_SPACE);
1734   CHECK_LE(new_space->Size(), old_capacity);
1735
1736   // Explicitly shrinking should halve the space capacity.
1737   old_capacity = new_space->Capacity();
1738   new_space->Shrink();
1739   new_capacity = new_space->Capacity();
1740   CHECK(old_capacity >= 2 * new_capacity);
1741
1742   // Consecutive shrinking should not affect space capacity.
1743   old_capacity = new_space->Capacity();
1744   new_space->Shrink();
1745   new_space->Shrink();
1746   new_space->Shrink();
1747   new_capacity = new_space->Capacity();
1748   CHECK(old_capacity == new_capacity);
1749 }
1750
1751
1752 TEST(CollectingAllAvailableGarbageShrinksNewSpace) {
1753   CcTest::InitializeVM();
1754   Heap* heap = CcTest::heap();
1755   if (heap->ReservedSemiSpaceSize() == heap->InitialSemiSpaceSize() ||
1756       heap->MaxSemiSpaceSize() == heap->InitialSemiSpaceSize()) {
1757     // The max size cannot exceed the reserved size, since semispaces must be
1758     // always within the reserved space.  We can't test new space growing and
1759     // shrinking if the reserved size is the same as the minimum (initial) size.
1760     return;
1761   }
1762
1763   v8::HandleScope scope(CcTest::isolate());
1764   NewSpace* new_space = heap->new_space();
1765   intptr_t old_capacity, new_capacity;
1766   old_capacity = new_space->Capacity();
1767   new_space->Grow();
1768   new_capacity = new_space->Capacity();
1769   CHECK(2 * old_capacity == new_capacity);
1770   FillUpNewSpace(new_space);
1771   heap->CollectAllAvailableGarbage();
1772   new_capacity = new_space->Capacity();
1773   CHECK(old_capacity == new_capacity);
1774 }
1775
1776
1777 static int NumberOfGlobalObjects() {
1778   int count = 0;
1779   HeapIterator iterator(CcTest::heap());
1780   for (HeapObject* obj = iterator.next(); obj != NULL; obj = iterator.next()) {
1781     if (obj->IsGlobalObject()) count++;
1782   }
1783   return count;
1784 }
1785
1786
1787 // Test that we don't embed maps from foreign contexts into
1788 // optimized code.
1789 TEST(LeakNativeContextViaMap) {
1790   i::FLAG_allow_natives_syntax = true;
1791   v8::Isolate* isolate = CcTest::isolate();
1792   v8::HandleScope outer_scope(isolate);
1793   v8::Persistent<v8::Context> ctx1p;
1794   v8::Persistent<v8::Context> ctx2p;
1795   {
1796     v8::HandleScope scope(isolate);
1797     ctx1p.Reset(isolate, v8::Context::New(isolate));
1798     ctx2p.Reset(isolate, v8::Context::New(isolate));
1799     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
1800   }
1801
1802   CcTest::heap()->CollectAllAvailableGarbage();
1803   CHECK_EQ(4, NumberOfGlobalObjects());
1804
1805   {
1806     v8::HandleScope inner_scope(isolate);
1807     CompileRun("var v = {x: 42}");
1808     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
1809     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
1810     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1811     ctx2->Enter();
1812     ctx2->Global()->Set(v8_str("o"), v);
1813     v8::Local<v8::Value> res = CompileRun(
1814         "function f() { return o.x; }"
1815         "for (var i = 0; i < 10; ++i) f();"
1816         "%OptimizeFunctionOnNextCall(f);"
1817         "f();");
1818     CHECK_EQ(42, res->Int32Value());
1819     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(isolate, 0));
1820     ctx2->Exit();
1821     v8::Local<v8::Context>::New(isolate, ctx1)->Exit();
1822     ctx1p.Reset();
1823     isolate->ContextDisposedNotification();
1824   }
1825   CcTest::heap()->CollectAllAvailableGarbage();
1826   CHECK_EQ(2, NumberOfGlobalObjects());
1827   ctx2p.Reset();
1828   CcTest::heap()->CollectAllAvailableGarbage();
1829   CHECK_EQ(0, NumberOfGlobalObjects());
1830 }
1831
1832
1833 // Test that we don't embed functions from foreign contexts into
1834 // optimized code.
1835 TEST(LeakNativeContextViaFunction) {
1836   i::FLAG_allow_natives_syntax = true;
1837   v8::Isolate* isolate = CcTest::isolate();
1838   v8::HandleScope outer_scope(isolate);
1839   v8::Persistent<v8::Context> ctx1p;
1840   v8::Persistent<v8::Context> ctx2p;
1841   {
1842     v8::HandleScope scope(isolate);
1843     ctx1p.Reset(isolate, v8::Context::New(isolate));
1844     ctx2p.Reset(isolate, v8::Context::New(isolate));
1845     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
1846   }
1847
1848   CcTest::heap()->CollectAllAvailableGarbage();
1849   CHECK_EQ(4, NumberOfGlobalObjects());
1850
1851   {
1852     v8::HandleScope inner_scope(isolate);
1853     CompileRun("var v = function() { return 42; }");
1854     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
1855     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
1856     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1857     ctx2->Enter();
1858     ctx2->Global()->Set(v8_str("o"), v);
1859     v8::Local<v8::Value> res = CompileRun(
1860         "function f(x) { return x(); }"
1861         "for (var i = 0; i < 10; ++i) f(o);"
1862         "%OptimizeFunctionOnNextCall(f);"
1863         "f(o);");
1864     CHECK_EQ(42, res->Int32Value());
1865     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(isolate, 0));
1866     ctx2->Exit();
1867     ctx1->Exit();
1868     ctx1p.Reset();
1869     isolate->ContextDisposedNotification();
1870   }
1871   CcTest::heap()->CollectAllAvailableGarbage();
1872   CHECK_EQ(2, NumberOfGlobalObjects());
1873   ctx2p.Reset();
1874   CcTest::heap()->CollectAllAvailableGarbage();
1875   CHECK_EQ(0, NumberOfGlobalObjects());
1876 }
1877
1878
1879 TEST(LeakNativeContextViaMapKeyed) {
1880   i::FLAG_allow_natives_syntax = true;
1881   v8::Isolate* isolate = CcTest::isolate();
1882   v8::HandleScope outer_scope(isolate);
1883   v8::Persistent<v8::Context> ctx1p;
1884   v8::Persistent<v8::Context> ctx2p;
1885   {
1886     v8::HandleScope scope(isolate);
1887     ctx1p.Reset(isolate, v8::Context::New(isolate));
1888     ctx2p.Reset(isolate, v8::Context::New(isolate));
1889     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
1890   }
1891
1892   CcTest::heap()->CollectAllAvailableGarbage();
1893   CHECK_EQ(4, NumberOfGlobalObjects());
1894
1895   {
1896     v8::HandleScope inner_scope(isolate);
1897     CompileRun("var v = [42, 43]");
1898     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
1899     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
1900     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1901     ctx2->Enter();
1902     ctx2->Global()->Set(v8_str("o"), v);
1903     v8::Local<v8::Value> res = CompileRun(
1904         "function f() { return o[0]; }"
1905         "for (var i = 0; i < 10; ++i) f();"
1906         "%OptimizeFunctionOnNextCall(f);"
1907         "f();");
1908     CHECK_EQ(42, res->Int32Value());
1909     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(isolate, 0));
1910     ctx2->Exit();
1911     ctx1->Exit();
1912     ctx1p.Reset();
1913     isolate->ContextDisposedNotification();
1914   }
1915   CcTest::heap()->CollectAllAvailableGarbage();
1916   CHECK_EQ(2, NumberOfGlobalObjects());
1917   ctx2p.Reset();
1918   CcTest::heap()->CollectAllAvailableGarbage();
1919   CHECK_EQ(0, NumberOfGlobalObjects());
1920 }
1921
1922
1923 TEST(LeakNativeContextViaMapProto) {
1924   i::FLAG_allow_natives_syntax = true;
1925   v8::Isolate* isolate = CcTest::isolate();
1926   v8::HandleScope outer_scope(isolate);
1927   v8::Persistent<v8::Context> ctx1p;
1928   v8::Persistent<v8::Context> ctx2p;
1929   {
1930     v8::HandleScope scope(isolate);
1931     ctx1p.Reset(isolate, v8::Context::New(isolate));
1932     ctx2p.Reset(isolate, v8::Context::New(isolate));
1933     v8::Local<v8::Context>::New(isolate, ctx1p)->Enter();
1934   }
1935
1936   CcTest::heap()->CollectAllAvailableGarbage();
1937   CHECK_EQ(4, NumberOfGlobalObjects());
1938
1939   {
1940     v8::HandleScope inner_scope(isolate);
1941     CompileRun("var v = { y: 42}");
1942     v8::Local<v8::Context> ctx1 = v8::Local<v8::Context>::New(isolate, ctx1p);
1943     v8::Local<v8::Context> ctx2 = v8::Local<v8::Context>::New(isolate, ctx2p);
1944     v8::Local<v8::Value> v = ctx1->Global()->Get(v8_str("v"));
1945     ctx2->Enter();
1946     ctx2->Global()->Set(v8_str("o"), v);
1947     v8::Local<v8::Value> res = CompileRun(
1948         "function f() {"
1949         "  var p = {x: 42};"
1950         "  p.__proto__ = o;"
1951         "  return p.x;"
1952         "}"
1953         "for (var i = 0; i < 10; ++i) f();"
1954         "%OptimizeFunctionOnNextCall(f);"
1955         "f();");
1956     CHECK_EQ(42, res->Int32Value());
1957     ctx2->Global()->Set(v8_str("o"), v8::Int32::New(isolate, 0));
1958     ctx2->Exit();
1959     ctx1->Exit();
1960     ctx1p.Reset();
1961     isolate->ContextDisposedNotification();
1962   }
1963   CcTest::heap()->CollectAllAvailableGarbage();
1964   CHECK_EQ(2, NumberOfGlobalObjects());
1965   ctx2p.Reset();
1966   CcTest::heap()->CollectAllAvailableGarbage();
1967   CHECK_EQ(0, NumberOfGlobalObjects());
1968 }
1969
1970
1971 TEST(InstanceOfStubWriteBarrier) {
1972   i::FLAG_allow_natives_syntax = true;
1973 #ifdef VERIFY_HEAP
1974   i::FLAG_verify_heap = true;
1975 #endif
1976
1977   CcTest::InitializeVM();
1978   if (!CcTest::i_isolate()->use_crankshaft()) return;
1979   if (i::FLAG_force_marking_deque_overflows) return;
1980   v8::HandleScope outer_scope(CcTest::isolate());
1981
1982   {
1983     v8::HandleScope scope(CcTest::isolate());
1984     CompileRun(
1985         "function foo () { }"
1986         "function mkbar () { return new (new Function(\"\")) (); }"
1987         "function f (x) { return (x instanceof foo); }"
1988         "function g () { f(mkbar()); }"
1989         "f(new foo()); f(new foo());"
1990         "%OptimizeFunctionOnNextCall(f);"
1991         "f(new foo()); g();");
1992   }
1993
1994   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
1995   marking->Abort();
1996   marking->Start();
1997
1998   Handle<JSFunction> f =
1999       v8::Utils::OpenHandle(
2000           *v8::Handle<v8::Function>::Cast(
2001               CcTest::global()->Get(v8_str("f"))));
2002
2003   CHECK(f->IsOptimized());
2004
2005   while (!Marking::IsBlack(Marking::MarkBitFrom(f->code())) &&
2006          !marking->IsStopped()) {
2007     // Discard any pending GC requests otherwise we will get GC when we enter
2008     // code below.
2009     marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
2010   }
2011
2012   CHECK(marking->IsMarking());
2013
2014   {
2015     v8::HandleScope scope(CcTest::isolate());
2016     v8::Handle<v8::Object> global = CcTest::global();
2017     v8::Handle<v8::Function> g =
2018         v8::Handle<v8::Function>::Cast(global->Get(v8_str("g")));
2019     g->Call(global, 0, NULL);
2020   }
2021
2022   CcTest::heap()->incremental_marking()->set_should_hurry(true);
2023   CcTest::heap()->CollectGarbage(OLD_POINTER_SPACE);
2024 }
2025
2026
2027 TEST(PrototypeTransitionClearing) {
2028   if (FLAG_never_compact) return;
2029   CcTest::InitializeVM();
2030   Isolate* isolate = CcTest::i_isolate();
2031   Factory* factory = isolate->factory();
2032   v8::HandleScope scope(CcTest::isolate());
2033
2034   CompileRun("var base = {};");
2035   Handle<JSObject> baseObject =
2036       v8::Utils::OpenHandle(
2037           *v8::Handle<v8::Object>::Cast(
2038               CcTest::global()->Get(v8_str("base"))));
2039   int initialTransitions = baseObject->map()->NumberOfProtoTransitions();
2040
2041   CompileRun(
2042       "var live = [];"
2043       "for (var i = 0; i < 10; i++) {"
2044       "  var object = {};"
2045       "  var prototype = {};"
2046       "  object.__proto__ = prototype;"
2047       "  if (i >= 3) live.push(object, prototype);"
2048       "}");
2049
2050   // Verify that only dead prototype transitions are cleared.
2051   CHECK_EQ(initialTransitions + 10,
2052       baseObject->map()->NumberOfProtoTransitions());
2053   CcTest::heap()->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
2054   const int transitions = 10 - 3;
2055   CHECK_EQ(initialTransitions + transitions,
2056       baseObject->map()->NumberOfProtoTransitions());
2057
2058   // Verify that prototype transitions array was compacted.
2059   FixedArray* trans = baseObject->map()->GetPrototypeTransitions();
2060   for (int i = initialTransitions; i < initialTransitions + transitions; i++) {
2061     int j = Map::kProtoTransitionHeaderSize +
2062         i * Map::kProtoTransitionElementsPerEntry;
2063     CHECK(trans->get(j + Map::kProtoTransitionMapOffset)->IsMap());
2064     Object* proto = trans->get(j + Map::kProtoTransitionPrototypeOffset);
2065     CHECK(proto->IsJSObject());
2066   }
2067
2068   // Make sure next prototype is placed on an old-space evacuation candidate.
2069   Handle<JSObject> prototype;
2070   PagedSpace* space = CcTest::heap()->old_pointer_space();
2071   {
2072     AlwaysAllocateScope always_allocate(isolate);
2073     SimulateFullSpace(space);
2074     prototype = factory->NewJSArray(32 * KB, FAST_HOLEY_ELEMENTS, TENURED);
2075   }
2076
2077   // Add a prototype on an evacuation candidate and verify that transition
2078   // clearing correctly records slots in prototype transition array.
2079   i::FLAG_always_compact = true;
2080   Handle<Map> map(baseObject->map());
2081   CHECK(!space->LastPage()->Contains(
2082       map->GetPrototypeTransitions()->address()));
2083   CHECK(space->LastPage()->Contains(prototype->address()));
2084 }
2085
2086
2087 TEST(ResetSharedFunctionInfoCountersDuringIncrementalMarking) {
2088   i::FLAG_stress_compaction = false;
2089   i::FLAG_allow_natives_syntax = true;
2090 #ifdef VERIFY_HEAP
2091   i::FLAG_verify_heap = true;
2092 #endif
2093
2094   CcTest::InitializeVM();
2095   if (!CcTest::i_isolate()->use_crankshaft()) return;
2096   v8::HandleScope outer_scope(CcTest::isolate());
2097
2098   {
2099     v8::HandleScope scope(CcTest::isolate());
2100     CompileRun(
2101         "function f () {"
2102         "  var s = 0;"
2103         "  for (var i = 0; i < 100; i++)  s += i;"
2104         "  return s;"
2105         "}"
2106         "f(); f();"
2107         "%OptimizeFunctionOnNextCall(f);"
2108         "f();");
2109   }
2110   Handle<JSFunction> f =
2111       v8::Utils::OpenHandle(
2112           *v8::Handle<v8::Function>::Cast(
2113               CcTest::global()->Get(v8_str("f"))));
2114   CHECK(f->IsOptimized());
2115
2116   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
2117   marking->Abort();
2118   marking->Start();
2119
2120   // The following two calls will increment CcTest::heap()->global_ic_age().
2121   const int kLongIdlePauseInMs = 1000;
2122   CcTest::isolate()->ContextDisposedNotification();
2123   CcTest::isolate()->IdleNotification(kLongIdlePauseInMs);
2124
2125   while (!marking->IsStopped() && !marking->IsComplete()) {
2126     marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
2127   }
2128   if (!marking->IsStopped() || marking->should_hurry()) {
2129     // We don't normally finish a GC via Step(), we normally finish by
2130     // setting the stack guard and then do the final steps in the stack
2131     // guard interrupt.  But here we didn't ask for that, and there is no
2132     // JS code running to trigger the interrupt, so we explicitly finalize
2133     // here.
2134     CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags,
2135                             "Test finalizing incremental mark-sweep");
2136   }
2137
2138   CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age());
2139   CHECK_EQ(0, f->shared()->opt_count());
2140   CHECK_EQ(0, f->shared()->code()->profiler_ticks());
2141 }
2142
2143
2144 TEST(ResetSharedFunctionInfoCountersDuringMarkSweep) {
2145   i::FLAG_stress_compaction = false;
2146   i::FLAG_allow_natives_syntax = true;
2147 #ifdef VERIFY_HEAP
2148   i::FLAG_verify_heap = true;
2149 #endif
2150
2151   CcTest::InitializeVM();
2152   if (!CcTest::i_isolate()->use_crankshaft()) return;
2153   v8::HandleScope outer_scope(CcTest::isolate());
2154
2155   {
2156     v8::HandleScope scope(CcTest::isolate());
2157     CompileRun(
2158         "function f () {"
2159         "  var s = 0;"
2160         "  for (var i = 0; i < 100; i++)  s += i;"
2161         "  return s;"
2162         "}"
2163         "f(); f();"
2164         "%OptimizeFunctionOnNextCall(f);"
2165         "f();");
2166   }
2167   Handle<JSFunction> f =
2168       v8::Utils::OpenHandle(
2169           *v8::Handle<v8::Function>::Cast(
2170               CcTest::global()->Get(v8_str("f"))));
2171   CHECK(f->IsOptimized());
2172
2173   CcTest::heap()->incremental_marking()->Abort();
2174
2175   // The following two calls will increment CcTest::heap()->global_ic_age().
2176   // Since incremental marking is off, IdleNotification will do full GC.
2177   const int kLongIdlePauseInMs = 1000;
2178   CcTest::isolate()->ContextDisposedNotification();
2179   CcTest::isolate()->IdleNotification(kLongIdlePauseInMs);
2180
2181   CHECK_EQ(CcTest::heap()->global_ic_age(), f->shared()->ic_age());
2182   CHECK_EQ(0, f->shared()->opt_count());
2183   CHECK_EQ(0, f->shared()->code()->profiler_ticks());
2184 }
2185
2186
2187 // Test that HAllocateObject will always return an object in new-space.
2188 TEST(OptimizedAllocationAlwaysInNewSpace) {
2189   i::FLAG_allow_natives_syntax = true;
2190   CcTest::InitializeVM();
2191   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2192   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2193   v8::HandleScope scope(CcTest::isolate());
2194
2195   SimulateFullSpace(CcTest::heap()->new_space());
2196   AlwaysAllocateScope always_allocate(CcTest::i_isolate());
2197   v8::Local<v8::Value> res = CompileRun(
2198       "function c(x) {"
2199       "  this.x = x;"
2200       "  for (var i = 0; i < 32; i++) {"
2201       "    this['x' + i] = x;"
2202       "  }"
2203       "}"
2204       "function f(x) { return new c(x); };"
2205       "f(1); f(2); f(3);"
2206       "%OptimizeFunctionOnNextCall(f);"
2207       "f(4);");
2208   CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
2209
2210   Handle<JSObject> o =
2211       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2212
2213   CHECK(CcTest::heap()->InNewSpace(*o));
2214 }
2215
2216
2217 TEST(OptimizedPretenuringAllocationFolding) {
2218   i::FLAG_allow_natives_syntax = true;
2219   i::FLAG_expose_gc = true;
2220   CcTest::InitializeVM();
2221   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2222   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2223   v8::HandleScope scope(CcTest::isolate());
2224
2225   // Grow new space unitl maximum capacity reached.
2226   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2227     CcTest::heap()->new_space()->Grow();
2228   }
2229
2230   i::ScopedVector<char> source(1024);
2231   i::SNPrintF(
2232       source,
2233       "var number_elements = %d;"
2234       "var elements = new Array();"
2235       "function f() {"
2236       "  for (var i = 0; i < number_elements; i++) {"
2237       "    elements[i] = [[{}], [1.1]];"
2238       "  }"
2239       "  return elements[number_elements-1]"
2240       "};"
2241       "f(); gc();"
2242       "f(); f();"
2243       "%%OptimizeFunctionOnNextCall(f);"
2244       "f();",
2245       AllocationSite::kPretenureMinimumCreated);
2246
2247   v8::Local<v8::Value> res = CompileRun(source.start());
2248
2249   v8::Local<v8::Value> int_array = v8::Object::Cast(*res)->Get(v8_str("0"));
2250   Handle<JSObject> int_array_handle =
2251       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array));
2252   v8::Local<v8::Value> double_array = v8::Object::Cast(*res)->Get(v8_str("1"));
2253   Handle<JSObject> double_array_handle =
2254       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array));
2255
2256   Handle<JSObject> o =
2257       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2258   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2259   CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle));
2260   CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle->elements()));
2261   CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle));
2262   CHECK(CcTest::heap()->InOldDataSpace(double_array_handle->elements()));
2263 }
2264
2265
2266 TEST(OptimizedPretenuringObjectArrayLiterals) {
2267   i::FLAG_allow_natives_syntax = true;
2268   i::FLAG_expose_gc = true;
2269   CcTest::InitializeVM();
2270   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2271   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2272   v8::HandleScope scope(CcTest::isolate());
2273
2274   // Grow new space unitl maximum capacity reached.
2275   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2276     CcTest::heap()->new_space()->Grow();
2277   }
2278
2279   i::ScopedVector<char> source(1024);
2280   i::SNPrintF(
2281       source,
2282       "var number_elements = %d;"
2283       "var elements = new Array(number_elements);"
2284       "function f() {"
2285       "  for (var i = 0; i < number_elements; i++) {"
2286       "    elements[i] = [{}, {}, {}];"
2287       "  }"
2288       "  return elements[number_elements - 1];"
2289       "};"
2290       "f(); gc();"
2291       "f(); f();"
2292       "%%OptimizeFunctionOnNextCall(f);"
2293       "f();",
2294       AllocationSite::kPretenureMinimumCreated);
2295
2296   v8::Local<v8::Value> res = CompileRun(source.start());
2297
2298   Handle<JSObject> o =
2299       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2300
2301   CHECK(CcTest::heap()->InOldPointerSpace(o->elements()));
2302   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2303 }
2304
2305
2306 TEST(OptimizedPretenuringMixedInObjectProperties) {
2307   i::FLAG_allow_natives_syntax = true;
2308   i::FLAG_expose_gc = true;
2309   CcTest::InitializeVM();
2310   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2311   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2312   v8::HandleScope scope(CcTest::isolate());
2313
2314   // Grow new space unitl maximum capacity reached.
2315   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2316     CcTest::heap()->new_space()->Grow();
2317   }
2318
2319
2320   i::ScopedVector<char> source(1024);
2321   i::SNPrintF(
2322       source,
2323       "var number_elements = %d;"
2324       "var elements = new Array(number_elements);"
2325       "function f() {"
2326       "  for (var i = 0; i < number_elements; i++) {"
2327       "    elements[i] = {a: {c: 2.2, d: {}}, b: 1.1};"
2328       "  }"
2329       "  return elements[number_elements - 1];"
2330       "};"
2331       "f(); gc();"
2332       "f(); f();"
2333       "%%OptimizeFunctionOnNextCall(f);"
2334       "f();",
2335       AllocationSite::kPretenureMinimumCreated);
2336
2337   v8::Local<v8::Value> res = CompileRun(source.start());
2338
2339   Handle<JSObject> o =
2340       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2341
2342   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2343   FieldIndex idx1 = FieldIndex::ForPropertyIndex(o->map(), 0);
2344   FieldIndex idx2 = FieldIndex::ForPropertyIndex(o->map(), 1);
2345   CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(idx1)));
2346   CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2)));
2347
2348   JSObject* inner_object =
2349       reinterpret_cast<JSObject*>(o->RawFastPropertyAt(idx1));
2350   CHECK(CcTest::heap()->InOldPointerSpace(inner_object));
2351   CHECK(CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1)));
2352   CHECK(CcTest::heap()->InOldPointerSpace(
2353       inner_object->RawFastPropertyAt(idx2)));
2354 }
2355
2356
2357 TEST(OptimizedPretenuringDoubleArrayProperties) {
2358   i::FLAG_allow_natives_syntax = true;
2359   i::FLAG_expose_gc = true;
2360   CcTest::InitializeVM();
2361   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2362   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2363   v8::HandleScope scope(CcTest::isolate());
2364
2365   // Grow new space unitl maximum capacity reached.
2366   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2367     CcTest::heap()->new_space()->Grow();
2368   }
2369
2370   i::ScopedVector<char> source(1024);
2371   i::SNPrintF(
2372       source,
2373       "var number_elements = %d;"
2374       "var elements = new Array(number_elements);"
2375       "function f() {"
2376       "  for (var i = 0; i < number_elements; i++) {"
2377       "    elements[i] = {a: 1.1, b: 2.2};"
2378       "  }"
2379       "  return elements[i - 1];"
2380       "};"
2381       "f(); gc();"
2382       "f(); f();"
2383       "%%OptimizeFunctionOnNextCall(f);"
2384       "f();",
2385       AllocationSite::kPretenureMinimumCreated);
2386
2387   v8::Local<v8::Value> res = CompileRun(source.start());
2388
2389   Handle<JSObject> o =
2390       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2391
2392   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2393   CHECK(CcTest::heap()->InOldDataSpace(o->properties()));
2394 }
2395
2396
2397 TEST(OptimizedPretenuringdoubleArrayLiterals) {
2398   i::FLAG_allow_natives_syntax = true;
2399   i::FLAG_expose_gc = true;
2400   CcTest::InitializeVM();
2401   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2402   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2403   v8::HandleScope scope(CcTest::isolate());
2404
2405   // Grow new space unitl maximum capacity reached.
2406   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2407     CcTest::heap()->new_space()->Grow();
2408   }
2409
2410   i::ScopedVector<char> source(1024);
2411   i::SNPrintF(
2412       source,
2413       "var number_elements = %d;"
2414       "var elements = new Array(number_elements);"
2415       "function f() {"
2416       "  for (var i = 0; i < number_elements; i++) {"
2417       "    elements[i] = [1.1, 2.2, 3.3];"
2418       "  }"
2419       "  return elements[number_elements - 1];"
2420       "};"
2421       "f(); gc();"
2422       "f(); f();"
2423       "%%OptimizeFunctionOnNextCall(f);"
2424       "f();",
2425       AllocationSite::kPretenureMinimumCreated);
2426
2427   v8::Local<v8::Value> res = CompileRun(source.start());
2428
2429   Handle<JSObject> o =
2430       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2431
2432   CHECK(CcTest::heap()->InOldDataSpace(o->elements()));
2433   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2434 }
2435
2436
2437 TEST(OptimizedPretenuringNestedMixedArrayLiterals) {
2438   i::FLAG_allow_natives_syntax = true;
2439   i::FLAG_expose_gc = true;
2440   CcTest::InitializeVM();
2441   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2442   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2443   v8::HandleScope scope(CcTest::isolate());
2444
2445   // Grow new space unitl maximum capacity reached.
2446   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2447     CcTest::heap()->new_space()->Grow();
2448   }
2449
2450   i::ScopedVector<char> source(1024);
2451   i::SNPrintF(
2452       source,
2453       "var number_elements = 100;"
2454       "var elements = new Array(number_elements);"
2455       "function f() {"
2456       "  for (var i = 0; i < number_elements; i++) {"
2457       "    elements[i] = [[{}, {}, {}], [1.1, 2.2, 3.3]];"
2458       "  }"
2459       "  return elements[number_elements - 1];"
2460       "};"
2461       "f(); gc();"
2462       "f(); f();"
2463       "%%OptimizeFunctionOnNextCall(f);"
2464       "f();");
2465
2466   v8::Local<v8::Value> res = CompileRun(source.start());
2467
2468   v8::Local<v8::Value> int_array = v8::Object::Cast(*res)->Get(v8_str("0"));
2469   Handle<JSObject> int_array_handle =
2470       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array));
2471   v8::Local<v8::Value> double_array = v8::Object::Cast(*res)->Get(v8_str("1"));
2472   Handle<JSObject> double_array_handle =
2473       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array));
2474
2475   Handle<JSObject> o =
2476       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2477   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2478   CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle));
2479   CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle->elements()));
2480   CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle));
2481   CHECK(CcTest::heap()->InOldDataSpace(double_array_handle->elements()));
2482 }
2483
2484
2485 TEST(OptimizedPretenuringNestedObjectLiterals) {
2486   i::FLAG_allow_natives_syntax = true;
2487   i::FLAG_expose_gc = true;
2488   CcTest::InitializeVM();
2489   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2490   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2491   v8::HandleScope scope(CcTest::isolate());
2492
2493   // Grow new space unitl maximum capacity reached.
2494   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2495     CcTest::heap()->new_space()->Grow();
2496   }
2497
2498   i::ScopedVector<char> source(1024);
2499   i::SNPrintF(
2500       source,
2501       "var number_elements = %d;"
2502       "var elements = new Array(number_elements);"
2503       "function f() {"
2504       "  for (var i = 0; i < number_elements; i++) {"
2505       "    elements[i] = [[{}, {}, {}],[{}, {}, {}]];"
2506       "  }"
2507       "  return elements[number_elements - 1];"
2508       "};"
2509       "f(); gc();"
2510       "f(); f();"
2511       "%%OptimizeFunctionOnNextCall(f);"
2512       "f();",
2513       AllocationSite::kPretenureMinimumCreated);
2514
2515   v8::Local<v8::Value> res = CompileRun(source.start());
2516
2517   v8::Local<v8::Value> int_array_1 = v8::Object::Cast(*res)->Get(v8_str("0"));
2518   Handle<JSObject> int_array_handle_1 =
2519       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array_1));
2520   v8::Local<v8::Value> int_array_2 = v8::Object::Cast(*res)->Get(v8_str("1"));
2521   Handle<JSObject> int_array_handle_2 =
2522       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(int_array_2));
2523
2524   Handle<JSObject> o =
2525       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2526   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2527   CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle_1));
2528   CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle_1->elements()));
2529   CHECK(CcTest::heap()->InOldPointerSpace(*int_array_handle_2));
2530   CHECK(CcTest::heap()->InOldPointerSpace(int_array_handle_2->elements()));
2531 }
2532
2533
2534 TEST(OptimizedPretenuringNestedDoubleLiterals) {
2535   i::FLAG_allow_natives_syntax = true;
2536   i::FLAG_expose_gc = true;
2537   CcTest::InitializeVM();
2538   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2539   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2540   v8::HandleScope scope(CcTest::isolate());
2541
2542   // Grow new space unitl maximum capacity reached.
2543   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2544     CcTest::heap()->new_space()->Grow();
2545   }
2546
2547   i::ScopedVector<char> source(1024);
2548   i::SNPrintF(
2549       source,
2550       "var number_elements = %d;"
2551       "var elements = new Array(number_elements);"
2552       "function f() {"
2553       "  for (var i = 0; i < number_elements; i++) {"
2554       "    elements[i] = [[1.1, 1.2, 1.3],[2.1, 2.2, 2.3]];"
2555       "  }"
2556       "  return elements[number_elements - 1];"
2557       "};"
2558       "f(); gc();"
2559       "f(); f();"
2560       "%%OptimizeFunctionOnNextCall(f);"
2561       "f();",
2562       AllocationSite::kPretenureMinimumCreated);
2563
2564   v8::Local<v8::Value> res = CompileRun(source.start());
2565
2566   v8::Local<v8::Value> double_array_1 =
2567       v8::Object::Cast(*res)->Get(v8_str("0"));
2568   Handle<JSObject> double_array_handle_1 =
2569       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array_1));
2570   v8::Local<v8::Value> double_array_2 =
2571       v8::Object::Cast(*res)->Get(v8_str("1"));
2572   Handle<JSObject> double_array_handle_2 =
2573       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(double_array_2));
2574
2575   Handle<JSObject> o =
2576       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2577   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2578   CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle_1));
2579   CHECK(CcTest::heap()->InOldDataSpace(double_array_handle_1->elements()));
2580   CHECK(CcTest::heap()->InOldPointerSpace(*double_array_handle_2));
2581   CHECK(CcTest::heap()->InOldDataSpace(double_array_handle_2->elements()));
2582 }
2583
2584
2585 // Make sure pretenuring feedback is gathered for constructed objects as well
2586 // as for literals.
2587 TEST(OptimizedPretenuringConstructorCalls) {
2588   if (!i::FLAG_pretenuring_call_new) {
2589     // FLAG_pretenuring_call_new needs to be synced with the snapshot.
2590     return;
2591   }
2592   i::FLAG_allow_natives_syntax = true;
2593   i::FLAG_expose_gc = true;
2594   CcTest::InitializeVM();
2595   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2596   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2597   v8::HandleScope scope(CcTest::isolate());
2598
2599   // Grow new space unitl maximum capacity reached.
2600   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2601     CcTest::heap()->new_space()->Grow();
2602   }
2603
2604   i::ScopedVector<char> source(1024);
2605   // Call new is doing slack tracking for the first
2606   // JSFunction::kGenerousAllocationCount allocations, and we can't find
2607   // mementos during that time.
2608   i::SNPrintF(
2609       source,
2610       "var number_elements = %d;"
2611       "var elements = new Array(number_elements);"
2612       "function foo() {"
2613       "  this.a = 3;"
2614       "  this.b = {};"
2615       "}"
2616       "function f() {"
2617       "  for (var i = 0; i < number_elements; i++) {"
2618       "    elements[i] = new foo();"
2619       "  }"
2620       "  return elements[number_elements - 1];"
2621       "};"
2622       "f(); gc();"
2623       "f(); f();"
2624       "%%OptimizeFunctionOnNextCall(f);"
2625       "f();",
2626       AllocationSite::kPretenureMinimumCreated +
2627       JSFunction::kGenerousAllocationCount);
2628
2629   v8::Local<v8::Value> res = CompileRun(source.start());
2630
2631   Handle<JSObject> o =
2632       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2633
2634   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2635 }
2636
2637
2638 TEST(OptimizedPretenuringCallNew) {
2639   if (!i::FLAG_pretenuring_call_new) {
2640     // FLAG_pretenuring_call_new needs to be synced with the snapshot.
2641     return;
2642   }
2643   i::FLAG_allow_natives_syntax = true;
2644   i::FLAG_expose_gc = true;
2645   CcTest::InitializeVM();
2646   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2647   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2648   v8::HandleScope scope(CcTest::isolate());
2649
2650   // Grow new space unitl maximum capacity reached.
2651   while (!CcTest::heap()->new_space()->IsAtMaximumCapacity()) {
2652     CcTest::heap()->new_space()->Grow();
2653   }
2654
2655   i::ScopedVector<char> source(1024);
2656   // Call new is doing slack tracking for the first
2657   // JSFunction::kGenerousAllocationCount allocations, and we can't find
2658   // mementos during that time.
2659   i::SNPrintF(
2660       source,
2661       "var number_elements = %d;"
2662       "var elements = new Array(number_elements);"
2663       "function g() { this.a = 0; }"
2664       "function f() {"
2665       "  for (var i = 0; i < number_elements; i++) {"
2666       "    elements[i] = new g();"
2667       "  }"
2668       "  return elements[number_elements - 1];"
2669       "};"
2670       "f(); gc();"
2671       "f(); f();"
2672       "%%OptimizeFunctionOnNextCall(f);"
2673       "f();",
2674       AllocationSite::kPretenureMinimumCreated +
2675       JSFunction::kGenerousAllocationCount);
2676
2677   v8::Local<v8::Value> res = CompileRun(source.start());
2678
2679   Handle<JSObject> o =
2680       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2681   CHECK(CcTest::heap()->InOldPointerSpace(*o));
2682 }
2683
2684
2685 // Test regular array literals allocation.
2686 TEST(OptimizedAllocationArrayLiterals) {
2687   i::FLAG_allow_natives_syntax = true;
2688   CcTest::InitializeVM();
2689   if (!CcTest::i_isolate()->use_crankshaft() || i::FLAG_always_opt) return;
2690   if (i::FLAG_gc_global || i::FLAG_stress_compaction) return;
2691   v8::HandleScope scope(CcTest::isolate());
2692
2693   v8::Local<v8::Value> res = CompileRun(
2694       "function f() {"
2695       "  var numbers = new Array(1, 2, 3);"
2696       "  numbers[0] = 3.14;"
2697       "  return numbers;"
2698       "};"
2699       "f(); f(); f();"
2700       "%OptimizeFunctionOnNextCall(f);"
2701       "f();");
2702   CHECK_EQ(static_cast<int>(3.14),
2703            v8::Object::Cast(*res)->Get(v8_str("0"))->Int32Value());
2704
2705   Handle<JSObject> o =
2706       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
2707
2708   CHECK(CcTest::heap()->InNewSpace(o->elements()));
2709 }
2710
2711
2712 static int CountMapTransitions(Map* map) {
2713   return map->transitions()->number_of_transitions();
2714 }
2715
2716
2717 // Test that map transitions are cleared and maps are collected with
2718 // incremental marking as well.
2719 TEST(Regress1465) {
2720   i::FLAG_stress_compaction = false;
2721   i::FLAG_allow_natives_syntax = true;
2722   i::FLAG_trace_incremental_marking = true;
2723   CcTest::InitializeVM();
2724   v8::HandleScope scope(CcTest::isolate());
2725   static const int transitions_count = 256;
2726
2727   CompileRun("function F() {}");
2728   {
2729     AlwaysAllocateScope always_allocate(CcTest::i_isolate());
2730     for (int i = 0; i < transitions_count; i++) {
2731       EmbeddedVector<char, 64> buffer;
2732       SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i);
2733       CompileRun(buffer.start());
2734     }
2735     CompileRun("var root = new F;");
2736   }
2737
2738   Handle<JSObject> root =
2739       v8::Utils::OpenHandle(
2740           *v8::Handle<v8::Object>::Cast(
2741               CcTest::global()->Get(v8_str("root"))));
2742
2743   // Count number of live transitions before marking.
2744   int transitions_before = CountMapTransitions(root->map());
2745   CompileRun("%DebugPrint(root);");
2746   CHECK_EQ(transitions_count, transitions_before);
2747
2748   SimulateIncrementalMarking(CcTest::heap());
2749   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
2750
2751   // Count number of live transitions after marking.  Note that one transition
2752   // is left, because 'o' still holds an instance of one transition target.
2753   int transitions_after = CountMapTransitions(root->map());
2754   CompileRun("%DebugPrint(root);");
2755   CHECK_EQ(1, transitions_after);
2756 }
2757
2758
2759 #ifdef DEBUG
2760 static void AddTransitions(int transitions_count) {
2761   AlwaysAllocateScope always_allocate(CcTest::i_isolate());
2762   for (int i = 0; i < transitions_count; i++) {
2763     EmbeddedVector<char, 64> buffer;
2764     SNPrintF(buffer, "var o = new F; o.prop%d = %d;", i, i);
2765     CompileRun(buffer.start());
2766   }
2767 }
2768
2769
2770 static Handle<JSObject> GetByName(const char* name) {
2771   return v8::Utils::OpenHandle(
2772       *v8::Handle<v8::Object>::Cast(
2773           CcTest::global()->Get(v8_str(name))));
2774 }
2775
2776
2777 static void AddPropertyTo(
2778     int gc_count, Handle<JSObject> object, const char* property_name) {
2779   Isolate* isolate = CcTest::i_isolate();
2780   Factory* factory = isolate->factory();
2781   Handle<String> prop_name = factory->InternalizeUtf8String(property_name);
2782   Handle<Smi> twenty_three(Smi::FromInt(23), isolate);
2783   i::FLAG_gc_interval = gc_count;
2784   i::FLAG_gc_global = true;
2785   CcTest::heap()->set_allocation_timeout(gc_count);
2786   JSReceiver::SetProperty(object, prop_name, twenty_three, SLOPPY).Check();
2787 }
2788
2789
2790 TEST(TransitionArrayShrinksDuringAllocToZero) {
2791   i::FLAG_stress_compaction = false;
2792   i::FLAG_allow_natives_syntax = true;
2793   CcTest::InitializeVM();
2794   v8::HandleScope scope(CcTest::isolate());
2795   static const int transitions_count = 10;
2796   CompileRun("function F() { }");
2797   AddTransitions(transitions_count);
2798   CompileRun("var root = new F;");
2799   Handle<JSObject> root = GetByName("root");
2800
2801   // Count number of live transitions before marking.
2802   int transitions_before = CountMapTransitions(root->map());
2803   CHECK_EQ(transitions_count, transitions_before);
2804
2805   // Get rid of o
2806   CompileRun("o = new F;"
2807              "root = new F");
2808   root = GetByName("root");
2809   AddPropertyTo(2, root, "funny");
2810
2811   // Count number of live transitions after marking.  Note that one transition
2812   // is left, because 'o' still holds an instance of one transition target.
2813   int transitions_after = CountMapTransitions(
2814       Map::cast(root->map()->GetBackPointer()));
2815   CHECK_EQ(1, transitions_after);
2816 }
2817
2818
2819 TEST(TransitionArrayShrinksDuringAllocToOne) {
2820   i::FLAG_stress_compaction = false;
2821   i::FLAG_allow_natives_syntax = true;
2822   CcTest::InitializeVM();
2823   v8::HandleScope scope(CcTest::isolate());
2824   static const int transitions_count = 10;
2825   CompileRun("function F() {}");
2826   AddTransitions(transitions_count);
2827   CompileRun("var root = new F;");
2828   Handle<JSObject> root = GetByName("root");
2829
2830   // Count number of live transitions before marking.
2831   int transitions_before = CountMapTransitions(root->map());
2832   CHECK_EQ(transitions_count, transitions_before);
2833
2834   root = GetByName("root");
2835   AddPropertyTo(2, root, "funny");
2836
2837   // Count number of live transitions after marking.  Note that one transition
2838   // is left, because 'o' still holds an instance of one transition target.
2839   int transitions_after = CountMapTransitions(
2840       Map::cast(root->map()->GetBackPointer()));
2841   CHECK_EQ(2, transitions_after);
2842 }
2843
2844
2845 TEST(TransitionArrayShrinksDuringAllocToOnePropertyFound) {
2846   i::FLAG_stress_compaction = false;
2847   i::FLAG_allow_natives_syntax = true;
2848   CcTest::InitializeVM();
2849   v8::HandleScope scope(CcTest::isolate());
2850   static const int transitions_count = 10;
2851   CompileRun("function F() {}");
2852   AddTransitions(transitions_count);
2853   CompileRun("var root = new F;");
2854   Handle<JSObject> root = GetByName("root");
2855
2856   // Count number of live transitions before marking.
2857   int transitions_before = CountMapTransitions(root->map());
2858   CHECK_EQ(transitions_count, transitions_before);
2859
2860   root = GetByName("root");
2861   AddPropertyTo(0, root, "prop9");
2862
2863   // Count number of live transitions after marking.  Note that one transition
2864   // is left, because 'o' still holds an instance of one transition target.
2865   int transitions_after = CountMapTransitions(
2866       Map::cast(root->map()->GetBackPointer()));
2867   CHECK_EQ(1, transitions_after);
2868 }
2869
2870
2871 TEST(TransitionArraySimpleToFull) {
2872   i::FLAG_stress_compaction = false;
2873   i::FLAG_allow_natives_syntax = true;
2874   CcTest::InitializeVM();
2875   v8::HandleScope scope(CcTest::isolate());
2876   static const int transitions_count = 1;
2877   CompileRun("function F() {}");
2878   AddTransitions(transitions_count);
2879   CompileRun("var root = new F;");
2880   Handle<JSObject> root = GetByName("root");
2881
2882   // Count number of live transitions before marking.
2883   int transitions_before = CountMapTransitions(root->map());
2884   CHECK_EQ(transitions_count, transitions_before);
2885
2886   CompileRun("o = new F;"
2887              "root = new F");
2888   root = GetByName("root");
2889   DCHECK(root->map()->transitions()->IsSimpleTransition());
2890   AddPropertyTo(2, root, "happy");
2891
2892   // Count number of live transitions after marking.  Note that one transition
2893   // is left, because 'o' still holds an instance of one transition target.
2894   int transitions_after = CountMapTransitions(
2895       Map::cast(root->map()->GetBackPointer()));
2896   CHECK_EQ(1, transitions_after);
2897 }
2898 #endif  // DEBUG
2899
2900
2901 TEST(Regress2143a) {
2902   i::FLAG_collect_maps = true;
2903   i::FLAG_incremental_marking = true;
2904   CcTest::InitializeVM();
2905   v8::HandleScope scope(CcTest::isolate());
2906
2907   // Prepare a map transition from the root object together with a yet
2908   // untransitioned root object.
2909   CompileRun("var root = new Object;"
2910              "root.foo = 0;"
2911              "root = new Object;");
2912
2913   SimulateIncrementalMarking(CcTest::heap());
2914
2915   // Compile a StoreIC that performs the prepared map transition. This
2916   // will restart incremental marking and should make sure the root is
2917   // marked grey again.
2918   CompileRun("function f(o) {"
2919              "  o.foo = 0;"
2920              "}"
2921              "f(new Object);"
2922              "f(root);");
2923
2924   // This bug only triggers with aggressive IC clearing.
2925   CcTest::heap()->AgeInlineCaches();
2926
2927   // Explicitly request GC to perform final marking step and sweeping.
2928   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
2929
2930   Handle<JSObject> root =
2931       v8::Utils::OpenHandle(
2932           *v8::Handle<v8::Object>::Cast(
2933               CcTest::global()->Get(v8_str("root"))));
2934
2935   // The root object should be in a sane state.
2936   CHECK(root->IsJSObject());
2937   CHECK(root->map()->IsMap());
2938 }
2939
2940
2941 TEST(Regress2143b) {
2942   i::FLAG_collect_maps = true;
2943   i::FLAG_incremental_marking = true;
2944   i::FLAG_allow_natives_syntax = true;
2945   CcTest::InitializeVM();
2946   v8::HandleScope scope(CcTest::isolate());
2947
2948   // Prepare a map transition from the root object together with a yet
2949   // untransitioned root object.
2950   CompileRun("var root = new Object;"
2951              "root.foo = 0;"
2952              "root = new Object;");
2953
2954   SimulateIncrementalMarking(CcTest::heap());
2955
2956   // Compile an optimized LStoreNamedField that performs the prepared
2957   // map transition. This will restart incremental marking and should
2958   // make sure the root is marked grey again.
2959   CompileRun("function f(o) {"
2960              "  o.foo = 0;"
2961              "}"
2962              "f(new Object);"
2963              "f(new Object);"
2964              "%OptimizeFunctionOnNextCall(f);"
2965              "f(root);"
2966              "%DeoptimizeFunction(f);");
2967
2968   // This bug only triggers with aggressive IC clearing.
2969   CcTest::heap()->AgeInlineCaches();
2970
2971   // Explicitly request GC to perform final marking step and sweeping.
2972   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
2973
2974   Handle<JSObject> root =
2975       v8::Utils::OpenHandle(
2976           *v8::Handle<v8::Object>::Cast(
2977               CcTest::global()->Get(v8_str("root"))));
2978
2979   // The root object should be in a sane state.
2980   CHECK(root->IsJSObject());
2981   CHECK(root->map()->IsMap());
2982 }
2983
2984
2985 TEST(ReleaseOverReservedPages) {
2986   if (FLAG_never_compact) return;
2987   i::FLAG_trace_gc = true;
2988   // The optimizer can allocate stuff, messing up the test.
2989   i::FLAG_crankshaft = false;
2990   i::FLAG_always_opt = false;
2991   CcTest::InitializeVM();
2992   Isolate* isolate = CcTest::i_isolate();
2993   Factory* factory = isolate->factory();
2994   Heap* heap = isolate->heap();
2995   v8::HandleScope scope(CcTest::isolate());
2996   static const int number_of_test_pages = 20;
2997
2998   // Prepare many pages with low live-bytes count.
2999   PagedSpace* old_pointer_space = heap->old_pointer_space();
3000   CHECK_EQ(1, old_pointer_space->CountTotalPages());
3001   for (int i = 0; i < number_of_test_pages; i++) {
3002     AlwaysAllocateScope always_allocate(isolate);
3003     SimulateFullSpace(old_pointer_space);
3004     factory->NewFixedArray(1, TENURED);
3005   }
3006   CHECK_EQ(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
3007
3008   // Triggering one GC will cause a lot of garbage to be discovered but
3009   // even spread across all allocated pages.
3010   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask,
3011                           "triggered for preparation");
3012   CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
3013
3014   // Triggering subsequent GCs should cause at least half of the pages
3015   // to be released to the OS after at most two cycles.
3016   heap->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 1");
3017   CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages());
3018   heap->CollectAllGarbage(Heap::kNoGCFlags, "triggered by test 2");
3019   CHECK_GE(number_of_test_pages + 1, old_pointer_space->CountTotalPages() * 2);
3020
3021   // Triggering a last-resort GC should cause all pages to be released to the
3022   // OS so that other processes can seize the memory.  If we get a failure here
3023   // where there are 2 pages left instead of 1, then we should increase the
3024   // size of the first page a little in SizeOfFirstPage in spaces.cc.  The
3025   // first page should be small in order to reduce memory used when the VM
3026   // boots, but if the 20 small arrays don't fit on the first page then that's
3027   // an indication that it is too small.
3028   heap->CollectAllAvailableGarbage("triggered really hard");
3029   CHECK_EQ(1, old_pointer_space->CountTotalPages());
3030 }
3031
3032
3033 TEST(Regress2237) {
3034   i::FLAG_stress_compaction = false;
3035   CcTest::InitializeVM();
3036   Isolate* isolate = CcTest::i_isolate();
3037   Factory* factory = isolate->factory();
3038   v8::HandleScope scope(CcTest::isolate());
3039   Handle<String> slice(CcTest::heap()->empty_string());
3040
3041   {
3042     // Generate a parent that lives in new-space.
3043     v8::HandleScope inner_scope(CcTest::isolate());
3044     const char* c = "This text is long enough to trigger sliced strings.";
3045     Handle<String> s = factory->NewStringFromAsciiChecked(c);
3046     CHECK(s->IsSeqOneByteString());
3047     CHECK(CcTest::heap()->InNewSpace(*s));
3048
3049     // Generate a sliced string that is based on the above parent and
3050     // lives in old-space.
3051     SimulateFullSpace(CcTest::heap()->new_space());
3052     AlwaysAllocateScope always_allocate(isolate);
3053     Handle<String> t = factory->NewProperSubString(s, 5, 35);
3054     CHECK(t->IsSlicedString());
3055     CHECK(!CcTest::heap()->InNewSpace(*t));
3056     *slice.location() = *t.location();
3057   }
3058
3059   CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
3060   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
3061   CHECK(SlicedString::cast(*slice)->parent()->IsSeqOneByteString());
3062 }
3063
3064
3065 #ifdef OBJECT_PRINT
3066 TEST(PrintSharedFunctionInfo) {
3067   CcTest::InitializeVM();
3068   v8::HandleScope scope(CcTest::isolate());
3069   const char* source = "f = function() { return 987654321; }\n"
3070                        "g = function() { return 123456789; }\n";
3071   CompileRun(source);
3072   Handle<JSFunction> g =
3073       v8::Utils::OpenHandle(
3074           *v8::Handle<v8::Function>::Cast(
3075               CcTest::global()->Get(v8_str("g"))));
3076
3077   OFStream os(stdout);
3078   g->shared()->Print(os);
3079   os << endl;
3080 }
3081 #endif  // OBJECT_PRINT
3082
3083
3084 TEST(Regress2211) {
3085   CcTest::InitializeVM();
3086   v8::HandleScope scope(CcTest::isolate());
3087
3088   v8::Handle<v8::String> value = v8_str("val string");
3089   Smi* hash = Smi::FromInt(321);
3090   Factory* factory = CcTest::i_isolate()->factory();
3091
3092   for (int i = 0; i < 2; i++) {
3093     // Store identity hash first and common hidden property second.
3094     v8::Handle<v8::Object> obj = v8::Object::New(CcTest::isolate());
3095     Handle<JSObject> internal_obj = v8::Utils::OpenHandle(*obj);
3096     CHECK(internal_obj->HasFastProperties());
3097
3098     // In the first iteration, set hidden value first and identity hash second.
3099     // In the second iteration, reverse the order.
3100     if (i == 0) obj->SetHiddenValue(v8_str("key string"), value);
3101     JSObject::SetIdentityHash(internal_obj, handle(hash, CcTest::i_isolate()));
3102     if (i == 1) obj->SetHiddenValue(v8_str("key string"), value);
3103
3104     // Check values.
3105     CHECK_EQ(hash,
3106              internal_obj->GetHiddenProperty(factory->identity_hash_string()));
3107     CHECK(value->Equals(obj->GetHiddenValue(v8_str("key string"))));
3108
3109     // Check size.
3110     FieldIndex index = FieldIndex::ForDescriptor(internal_obj->map(), 0);
3111     ObjectHashTable* hashtable = ObjectHashTable::cast(
3112         internal_obj->RawFastPropertyAt(index));
3113     // HashTable header (5) and 4 initial entries (8).
3114     CHECK_LE(hashtable->SizeFor(hashtable->length()), 13 * kPointerSize);
3115   }
3116 }
3117
3118
3119 TEST(IncrementalMarkingClearsTypeFeedbackInfo) {
3120   if (i::FLAG_always_opt) return;
3121   CcTest::InitializeVM();
3122   v8::HandleScope scope(CcTest::isolate());
3123   v8::Local<v8::Value> fun1, fun2;
3124
3125   {
3126     LocalContext env;
3127     CompileRun("function fun() {};");
3128     fun1 = env->Global()->Get(v8_str("fun"));
3129   }
3130
3131   {
3132     LocalContext env;
3133     CompileRun("function fun() {};");
3134     fun2 = env->Global()->Get(v8_str("fun"));
3135   }
3136
3137   // Prepare function f that contains type feedback for closures
3138   // originating from two different native contexts.
3139   CcTest::global()->Set(v8_str("fun1"), fun1);
3140   CcTest::global()->Set(v8_str("fun2"), fun2);
3141   CompileRun("function f(a, b) { a(); b(); } f(fun1, fun2);");
3142
3143   Handle<JSFunction> f =
3144       v8::Utils::OpenHandle(
3145           *v8::Handle<v8::Function>::Cast(
3146               CcTest::global()->Get(v8_str("f"))));
3147
3148   Handle<FixedArray> feedback_vector(f->shared()->feedback_vector());
3149
3150   int expected_length = FLAG_vector_ics ? 4 : 2;
3151   CHECK_EQ(expected_length, feedback_vector->length());
3152   for (int i = 0; i < expected_length; i++) {
3153     if ((i % 2) == 1) {
3154       CHECK(feedback_vector->get(i)->IsJSFunction());
3155     }
3156   }
3157
3158   SimulateIncrementalMarking(CcTest::heap());
3159   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
3160
3161   CHECK_EQ(expected_length, feedback_vector->length());
3162   for (int i = 0; i < expected_length; i++) {
3163     CHECK_EQ(feedback_vector->get(i),
3164              *TypeFeedbackInfo::UninitializedSentinel(CcTest::i_isolate()));
3165   }
3166 }
3167
3168
3169 static Code* FindFirstIC(Code* code, Code::Kind kind) {
3170   int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
3171              RelocInfo::ModeMask(RelocInfo::CONSTRUCT_CALL) |
3172              RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID);
3173   for (RelocIterator it(code, mask); !it.done(); it.next()) {
3174     RelocInfo* info = it.rinfo();
3175     Code* target = Code::GetCodeFromTargetAddress(info->target_address());
3176     if (target->is_inline_cache_stub() && target->kind() == kind) {
3177       return target;
3178     }
3179   }
3180   return NULL;
3181 }
3182
3183
3184 TEST(IncrementalMarkingPreservesMonomorphicIC) {
3185   if (i::FLAG_always_opt) return;
3186   CcTest::InitializeVM();
3187   v8::HandleScope scope(CcTest::isolate());
3188
3189   // Prepare function f that contains a monomorphic IC for object
3190   // originating from the same native context.
3191   CompileRun("function fun() { this.x = 1; }; var obj = new fun();"
3192              "function f(o) { return o.x; } f(obj); f(obj);");
3193   Handle<JSFunction> f =
3194       v8::Utils::OpenHandle(
3195           *v8::Handle<v8::Function>::Cast(
3196               CcTest::global()->Get(v8_str("f"))));
3197
3198   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
3199   CHECK(ic_before->ic_state() == MONOMORPHIC);
3200
3201   SimulateIncrementalMarking(CcTest::heap());
3202   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
3203
3204   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
3205   CHECK(ic_after->ic_state() == MONOMORPHIC);
3206 }
3207
3208
3209 TEST(IncrementalMarkingClearsMonomorphicIC) {
3210   if (i::FLAG_always_opt) return;
3211   CcTest::InitializeVM();
3212   v8::HandleScope scope(CcTest::isolate());
3213   v8::Local<v8::Value> obj1;
3214
3215   {
3216     LocalContext env;
3217     CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
3218     obj1 = env->Global()->Get(v8_str("obj"));
3219   }
3220
3221   // Prepare function f that contains a monomorphic IC for object
3222   // originating from a different native context.
3223   CcTest::global()->Set(v8_str("obj1"), obj1);
3224   CompileRun("function f(o) { return o.x; } f(obj1); f(obj1);");
3225   Handle<JSFunction> f =
3226       v8::Utils::OpenHandle(
3227           *v8::Handle<v8::Function>::Cast(
3228               CcTest::global()->Get(v8_str("f"))));
3229
3230   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
3231   CHECK(ic_before->ic_state() == MONOMORPHIC);
3232
3233   // Fire context dispose notification.
3234   CcTest::isolate()->ContextDisposedNotification();
3235   SimulateIncrementalMarking(CcTest::heap());
3236   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
3237
3238   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
3239   CHECK(IC::IsCleared(ic_after));
3240 }
3241
3242
3243 TEST(IncrementalMarkingClearsPolymorphicIC) {
3244   if (i::FLAG_always_opt) return;
3245   CcTest::InitializeVM();
3246   v8::HandleScope scope(CcTest::isolate());
3247   v8::Local<v8::Value> obj1, obj2;
3248
3249   {
3250     LocalContext env;
3251     CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
3252     obj1 = env->Global()->Get(v8_str("obj"));
3253   }
3254
3255   {
3256     LocalContext env;
3257     CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
3258     obj2 = env->Global()->Get(v8_str("obj"));
3259   }
3260
3261   // Prepare function f that contains a polymorphic IC for objects
3262   // originating from two different native contexts.
3263   CcTest::global()->Set(v8_str("obj1"), obj1);
3264   CcTest::global()->Set(v8_str("obj2"), obj2);
3265   CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
3266   Handle<JSFunction> f =
3267       v8::Utils::OpenHandle(
3268           *v8::Handle<v8::Function>::Cast(
3269               CcTest::global()->Get(v8_str("f"))));
3270
3271   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
3272   CHECK(ic_before->ic_state() == POLYMORPHIC);
3273
3274   // Fire context dispose notification.
3275   CcTest::isolate()->ContextDisposedNotification();
3276   SimulateIncrementalMarking(CcTest::heap());
3277   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
3278
3279   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
3280   CHECK(IC::IsCleared(ic_after));
3281 }
3282
3283
3284 class SourceResource: public v8::String::ExternalAsciiStringResource {
3285  public:
3286   explicit SourceResource(const char* data)
3287     : data_(data), length_(strlen(data)) { }
3288
3289   virtual void Dispose() {
3290     i::DeleteArray(data_);
3291     data_ = NULL;
3292   }
3293
3294   const char* data() const { return data_; }
3295
3296   size_t length() const { return length_; }
3297
3298   bool IsDisposed() { return data_ == NULL; }
3299
3300  private:
3301   const char* data_;
3302   size_t length_;
3303 };
3304
3305
3306 void ReleaseStackTraceDataTest(const char* source, const char* accessor) {
3307   // Test that the data retained by the Error.stack accessor is released
3308   // after the first time the accessor is fired.  We use external string
3309   // to check whether the data is being released since the external string
3310   // resource's callback is fired when the external string is GC'ed.
3311   v8::HandleScope scope(CcTest::isolate());
3312   SourceResource* resource = new SourceResource(i::StrDup(source));
3313   {
3314     v8::HandleScope scope(CcTest::isolate());
3315     v8::Handle<v8::String> source_string =
3316         v8::String::NewExternal(CcTest::isolate(), resource);
3317     CcTest::heap()->CollectAllAvailableGarbage();
3318     v8::Script::Compile(source_string)->Run();
3319     CHECK(!resource->IsDisposed());
3320   }
3321   // CcTest::heap()->CollectAllAvailableGarbage();
3322   CHECK(!resource->IsDisposed());
3323
3324   CompileRun(accessor);
3325   CcTest::heap()->CollectAllAvailableGarbage();
3326
3327   // External source has been released.
3328   CHECK(resource->IsDisposed());
3329   delete resource;
3330 }
3331
3332
3333 TEST(ReleaseStackTraceData) {
3334   if (i::FLAG_always_opt) {
3335     // TODO(ulan): Remove this once the memory leak via code_next_link is fixed.
3336     // See: https://codereview.chromium.org/181833004/
3337     return;
3338   }
3339   FLAG_use_ic = false;  // ICs retain objects.
3340   FLAG_concurrent_recompilation = false;
3341   CcTest::InitializeVM();
3342   static const char* source1 = "var error = null;            "
3343   /* Normal Error */           "try {                        "
3344                                "  throw new Error();         "
3345                                "} catch (e) {                "
3346                                "  error = e;                 "
3347                                "}                            ";
3348   static const char* source2 = "var error = null;            "
3349   /* Stack overflow */         "try {                        "
3350                                "  (function f() { f(); })(); "
3351                                "} catch (e) {                "
3352                                "  error = e;                 "
3353                                "}                            ";
3354   static const char* source3 = "var error = null;            "
3355   /* Normal Error */           "try {                        "
3356   /* as prototype */           "  throw new Error();         "
3357                                "} catch (e) {                "
3358                                "  error = {};                "
3359                                "  error.__proto__ = e;       "
3360                                "}                            ";
3361   static const char* source4 = "var error = null;            "
3362   /* Stack overflow */         "try {                        "
3363   /* as prototype   */         "  (function f() { f(); })(); "
3364                                "} catch (e) {                "
3365                                "  error = {};                "
3366                                "  error.__proto__ = e;       "
3367                                "}                            ";
3368   static const char* getter = "error.stack";
3369   static const char* setter = "error.stack = 0";
3370
3371   ReleaseStackTraceDataTest(source1, setter);
3372   ReleaseStackTraceDataTest(source2, setter);
3373   // We do not test source3 and source4 with setter, since the setter is
3374   // supposed to (untypically) write to the receiver, not the holder.  This is
3375   // to emulate the behavior of a data property.
3376
3377   ReleaseStackTraceDataTest(source1, getter);
3378   ReleaseStackTraceDataTest(source2, getter);
3379   ReleaseStackTraceDataTest(source3, getter);
3380   ReleaseStackTraceDataTest(source4, getter);
3381 }
3382
3383
3384 TEST(Regress159140) {
3385   i::FLAG_allow_natives_syntax = true;
3386   i::FLAG_flush_code_incrementally = true;
3387   CcTest::InitializeVM();
3388   Isolate* isolate = CcTest::i_isolate();
3389   Heap* heap = isolate->heap();
3390   HandleScope scope(isolate);
3391
3392   // Perform one initial GC to enable code flushing.
3393   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3394
3395   // Prepare several closures that are all eligible for code flushing
3396   // because all reachable ones are not optimized. Make sure that the
3397   // optimized code object is directly reachable through a handle so
3398   // that it is marked black during incremental marking.
3399   Handle<Code> code;
3400   {
3401     HandleScope inner_scope(isolate);
3402     CompileRun("function h(x) {}"
3403                "function mkClosure() {"
3404                "  return function(x) { return x + 1; };"
3405                "}"
3406                "var f = mkClosure();"
3407                "var g = mkClosure();"
3408                "f(1); f(2);"
3409                "g(1); g(2);"
3410                "h(1); h(2);"
3411                "%OptimizeFunctionOnNextCall(f); f(3);"
3412                "%OptimizeFunctionOnNextCall(h); h(3);");
3413
3414     Handle<JSFunction> f =
3415         v8::Utils::OpenHandle(
3416             *v8::Handle<v8::Function>::Cast(
3417                 CcTest::global()->Get(v8_str("f"))));
3418     CHECK(f->is_compiled());
3419     CompileRun("f = null;");
3420
3421     Handle<JSFunction> g =
3422         v8::Utils::OpenHandle(
3423             *v8::Handle<v8::Function>::Cast(
3424                 CcTest::global()->Get(v8_str("g"))));
3425     CHECK(g->is_compiled());
3426     const int kAgingThreshold = 6;
3427     for (int i = 0; i < kAgingThreshold; i++) {
3428       g->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3429     }
3430
3431     code = inner_scope.CloseAndEscape(Handle<Code>(f->code()));
3432   }
3433
3434   // Simulate incremental marking so that the functions are enqueued as
3435   // code flushing candidates. Then optimize one function. Finally
3436   // finish the GC to complete code flushing.
3437   SimulateIncrementalMarking(heap);
3438   CompileRun("%OptimizeFunctionOnNextCall(g); g(3);");
3439   heap->CollectAllGarbage(Heap::kNoGCFlags);
3440
3441   // Unoptimized code is missing and the deoptimizer will go ballistic.
3442   CompileRun("g('bozo');");
3443 }
3444
3445
3446 TEST(Regress165495) {
3447   i::FLAG_allow_natives_syntax = true;
3448   i::FLAG_flush_code_incrementally = true;
3449   CcTest::InitializeVM();
3450   Isolate* isolate = CcTest::i_isolate();
3451   Heap* heap = isolate->heap();
3452   HandleScope scope(isolate);
3453
3454   // Perform one initial GC to enable code flushing.
3455   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3456
3457   // Prepare an optimized closure that the optimized code map will get
3458   // populated. Then age the unoptimized code to trigger code flushing
3459   // but make sure the optimized code is unreachable.
3460   {
3461     HandleScope inner_scope(isolate);
3462     CompileRun("function mkClosure() {"
3463                "  return function(x) { return x + 1; };"
3464                "}"
3465                "var f = mkClosure();"
3466                "f(1); f(2);"
3467                "%OptimizeFunctionOnNextCall(f); f(3);");
3468
3469     Handle<JSFunction> f =
3470         v8::Utils::OpenHandle(
3471             *v8::Handle<v8::Function>::Cast(
3472                 CcTest::global()->Get(v8_str("f"))));
3473     CHECK(f->is_compiled());
3474     const int kAgingThreshold = 6;
3475     for (int i = 0; i < kAgingThreshold; i++) {
3476       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3477     }
3478
3479     CompileRun("f = null;");
3480   }
3481
3482   // Simulate incremental marking so that unoptimized code is flushed
3483   // even though it still is cached in the optimized code map.
3484   SimulateIncrementalMarking(heap);
3485   heap->CollectAllGarbage(Heap::kNoGCFlags);
3486
3487   // Make a new closure that will get code installed from the code map.
3488   // Unoptimized code is missing and the deoptimizer will go ballistic.
3489   CompileRun("var g = mkClosure(); g('bozo');");
3490 }
3491
3492
3493 TEST(Regress169209) {
3494   i::FLAG_stress_compaction = false;
3495   i::FLAG_allow_natives_syntax = true;
3496   i::FLAG_flush_code_incrementally = true;
3497
3498   CcTest::InitializeVM();
3499   Isolate* isolate = CcTest::i_isolate();
3500   Heap* heap = isolate->heap();
3501   HandleScope scope(isolate);
3502
3503   // Perform one initial GC to enable code flushing.
3504   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3505
3506   // Prepare a shared function info eligible for code flushing for which
3507   // the unoptimized code will be replaced during optimization.
3508   Handle<SharedFunctionInfo> shared1;
3509   {
3510     HandleScope inner_scope(isolate);
3511     CompileRun("function f() { return 'foobar'; }"
3512                "function g(x) { if (x) f(); }"
3513                "f();"
3514                "g(false);"
3515                "g(false);");
3516
3517     Handle<JSFunction> f =
3518         v8::Utils::OpenHandle(
3519             *v8::Handle<v8::Function>::Cast(
3520                 CcTest::global()->Get(v8_str("f"))));
3521     CHECK(f->is_compiled());
3522     const int kAgingThreshold = 6;
3523     for (int i = 0; i < kAgingThreshold; i++) {
3524       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3525     }
3526
3527     shared1 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
3528   }
3529
3530   // Prepare a shared function info eligible for code flushing that will
3531   // represent the dangling tail of the candidate list.
3532   Handle<SharedFunctionInfo> shared2;
3533   {
3534     HandleScope inner_scope(isolate);
3535     CompileRun("function flushMe() { return 0; }"
3536                "flushMe(1);");
3537
3538     Handle<JSFunction> f =
3539         v8::Utils::OpenHandle(
3540             *v8::Handle<v8::Function>::Cast(
3541                 CcTest::global()->Get(v8_str("flushMe"))));
3542     CHECK(f->is_compiled());
3543     const int kAgingThreshold = 6;
3544     for (int i = 0; i < kAgingThreshold; i++) {
3545       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3546     }
3547
3548     shared2 = inner_scope.CloseAndEscape(handle(f->shared(), isolate));
3549   }
3550
3551   // Simulate incremental marking and collect code flushing candidates.
3552   SimulateIncrementalMarking(heap);
3553   CHECK(shared1->code()->gc_metadata() != NULL);
3554
3555   // Optimize function and make sure the unoptimized code is replaced.
3556 #ifdef DEBUG
3557   FLAG_stop_at = "f";
3558 #endif
3559   CompileRun("%OptimizeFunctionOnNextCall(g);"
3560              "g(false);");
3561
3562   // Finish garbage collection cycle.
3563   heap->CollectAllGarbage(Heap::kNoGCFlags);
3564   CHECK(shared1->code()->gc_metadata() == NULL);
3565 }
3566
3567
3568 // Helper function that simulates a fill new-space in the heap.
3569 static inline void AllocateAllButNBytes(v8::internal::NewSpace* space,
3570                                         int extra_bytes) {
3571   int space_remaining = static_cast<int>(
3572       *space->allocation_limit_address() - *space->allocation_top_address());
3573   CHECK(space_remaining >= extra_bytes);
3574   int new_linear_size = space_remaining - extra_bytes;
3575   v8::internal::AllocationResult allocation =
3576       space->AllocateRaw(new_linear_size);
3577   v8::internal::FreeListNode* node =
3578       v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
3579   node->set_size(space->heap(), new_linear_size);
3580 }
3581
3582
3583 TEST(Regress169928) {
3584   i::FLAG_allow_natives_syntax = true;
3585   i::FLAG_crankshaft = false;
3586   CcTest::InitializeVM();
3587   Isolate* isolate = CcTest::i_isolate();
3588   Factory* factory = isolate->factory();
3589   v8::HandleScope scope(CcTest::isolate());
3590
3591   // Some flags turn Scavenge collections into Mark-sweep collections
3592   // and hence are incompatible with this test case.
3593   if (FLAG_gc_global || FLAG_stress_compaction) return;
3594
3595   // Prepare the environment
3596   CompileRun("function fastliteralcase(literal, value) {"
3597              "    literal[0] = value;"
3598              "    return literal;"
3599              "}"
3600              "function get_standard_literal() {"
3601              "    var literal = [1, 2, 3];"
3602              "    return literal;"
3603              "}"
3604              "obj = fastliteralcase(get_standard_literal(), 1);"
3605              "obj = fastliteralcase(get_standard_literal(), 1.5);"
3606              "obj = fastliteralcase(get_standard_literal(), 2);");
3607
3608   // prepare the heap
3609   v8::Local<v8::String> mote_code_string =
3610       v8_str("fastliteralcase(mote, 2.5);");
3611
3612   v8::Local<v8::String> array_name = v8_str("mote");
3613   CcTest::global()->Set(array_name, v8::Int32::New(CcTest::isolate(), 0));
3614
3615   // First make sure we flip spaces
3616   CcTest::heap()->CollectGarbage(NEW_SPACE);
3617
3618   // Allocate the object.
3619   Handle<FixedArray> array_data = factory->NewFixedArray(2, NOT_TENURED);
3620   array_data->set(0, Smi::FromInt(1));
3621   array_data->set(1, Smi::FromInt(2));
3622
3623   AllocateAllButNBytes(CcTest::heap()->new_space(),
3624                        JSArray::kSize + AllocationMemento::kSize +
3625                        kPointerSize);
3626
3627   Handle<JSArray> array = factory->NewJSArrayWithElements(array_data,
3628                                                           FAST_SMI_ELEMENTS,
3629                                                           NOT_TENURED);
3630
3631   CHECK_EQ(Smi::FromInt(2), array->length());
3632   CHECK(array->HasFastSmiOrObjectElements());
3633
3634   // We need filler the size of AllocationMemento object, plus an extra
3635   // fill pointer value.
3636   HeapObject* obj = NULL;
3637   AllocationResult allocation = CcTest::heap()->new_space()->AllocateRaw(
3638       AllocationMemento::kSize + kPointerSize);
3639   CHECK(allocation.To(&obj));
3640   Address addr_obj = obj->address();
3641   CcTest::heap()->CreateFillerObjectAt(
3642       addr_obj, AllocationMemento::kSize + kPointerSize);
3643
3644   // Give the array a name, making sure not to allocate strings.
3645   v8::Handle<v8::Object> array_obj = v8::Utils::ToLocal(array);
3646   CcTest::global()->Set(array_name, array_obj);
3647
3648   // This should crash with a protection violation if we are running a build
3649   // with the bug.
3650   AlwaysAllocateScope aa_scope(isolate);
3651   v8::Script::Compile(mote_code_string)->Run();
3652 }
3653
3654
3655 TEST(Regress168801) {
3656   if (i::FLAG_never_compact) return;
3657   i::FLAG_always_compact = true;
3658   i::FLAG_cache_optimized_code = false;
3659   i::FLAG_allow_natives_syntax = true;
3660   i::FLAG_flush_code_incrementally = true;
3661   CcTest::InitializeVM();
3662   Isolate* isolate = CcTest::i_isolate();
3663   Heap* heap = isolate->heap();
3664   HandleScope scope(isolate);
3665
3666   // Perform one initial GC to enable code flushing.
3667   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3668
3669   // Ensure the code ends up on an evacuation candidate.
3670   SimulateFullSpace(heap->code_space());
3671
3672   // Prepare an unoptimized function that is eligible for code flushing.
3673   Handle<JSFunction> function;
3674   {
3675     HandleScope inner_scope(isolate);
3676     CompileRun("function mkClosure() {"
3677                "  return function(x) { return x + 1; };"
3678                "}"
3679                "var f = mkClosure();"
3680                "f(1); f(2);");
3681
3682     Handle<JSFunction> f =
3683         v8::Utils::OpenHandle(
3684             *v8::Handle<v8::Function>::Cast(
3685                 CcTest::global()->Get(v8_str("f"))));
3686     CHECK(f->is_compiled());
3687     const int kAgingThreshold = 6;
3688     for (int i = 0; i < kAgingThreshold; i++) {
3689       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3690     }
3691
3692     function = inner_scope.CloseAndEscape(handle(*f, isolate));
3693   }
3694
3695   // Simulate incremental marking so that unoptimized function is enqueued as a
3696   // candidate for code flushing. The shared function info however will not be
3697   // explicitly enqueued.
3698   SimulateIncrementalMarking(heap);
3699
3700   // Now optimize the function so that it is taken off the candidate list.
3701   {
3702     HandleScope inner_scope(isolate);
3703     CompileRun("%OptimizeFunctionOnNextCall(f); f(3);");
3704   }
3705
3706   // This cycle will bust the heap and subsequent cycles will go ballistic.
3707   heap->CollectAllGarbage(Heap::kNoGCFlags);
3708   heap->CollectAllGarbage(Heap::kNoGCFlags);
3709 }
3710
3711
3712 TEST(Regress173458) {
3713   if (i::FLAG_never_compact) return;
3714   i::FLAG_always_compact = true;
3715   i::FLAG_cache_optimized_code = false;
3716   i::FLAG_allow_natives_syntax = true;
3717   i::FLAG_flush_code_incrementally = true;
3718   CcTest::InitializeVM();
3719   Isolate* isolate = CcTest::i_isolate();
3720   Heap* heap = isolate->heap();
3721   HandleScope scope(isolate);
3722
3723   // Perform one initial GC to enable code flushing.
3724   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3725
3726   // Ensure the code ends up on an evacuation candidate.
3727   SimulateFullSpace(heap->code_space());
3728
3729   // Prepare an unoptimized function that is eligible for code flushing.
3730   Handle<JSFunction> function;
3731   {
3732     HandleScope inner_scope(isolate);
3733     CompileRun("function mkClosure() {"
3734                "  return function(x) { return x + 1; };"
3735                "}"
3736                "var f = mkClosure();"
3737                "f(1); f(2);");
3738
3739     Handle<JSFunction> f =
3740         v8::Utils::OpenHandle(
3741             *v8::Handle<v8::Function>::Cast(
3742                 CcTest::global()->Get(v8_str("f"))));
3743     CHECK(f->is_compiled());
3744     const int kAgingThreshold = 6;
3745     for (int i = 0; i < kAgingThreshold; i++) {
3746       f->shared()->code()->MakeOlder(static_cast<MarkingParity>(i % 2));
3747     }
3748
3749     function = inner_scope.CloseAndEscape(handle(*f, isolate));
3750   }
3751
3752   // Simulate incremental marking so that unoptimized function is enqueued as a
3753   // candidate for code flushing. The shared function info however will not be
3754   // explicitly enqueued.
3755   SimulateIncrementalMarking(heap);
3756
3757   // Now enable the debugger which in turn will disable code flushing.
3758   CHECK(isolate->debug()->Load());
3759
3760   // This cycle will bust the heap and subsequent cycles will go ballistic.
3761   heap->CollectAllGarbage(Heap::kNoGCFlags);
3762   heap->CollectAllGarbage(Heap::kNoGCFlags);
3763 }
3764
3765
3766 class DummyVisitor : public ObjectVisitor {
3767  public:
3768   void VisitPointers(Object** start, Object** end) { }
3769 };
3770
3771
3772 TEST(DeferredHandles) {
3773   CcTest::InitializeVM();
3774   Isolate* isolate = CcTest::i_isolate();
3775   Heap* heap = isolate->heap();
3776   v8::HandleScope scope(reinterpret_cast<v8::Isolate*>(isolate));
3777   HandleScopeData* data = isolate->handle_scope_data();
3778   Handle<Object> init(heap->empty_string(), isolate);
3779   while (data->next < data->limit) {
3780     Handle<Object> obj(heap->empty_string(), isolate);
3781   }
3782   // An entire block of handles has been filled.
3783   // Next handle would require a new block.
3784   DCHECK(data->next == data->limit);
3785
3786   DeferredHandleScope deferred(isolate);
3787   DummyVisitor visitor;
3788   isolate->handle_scope_implementer()->Iterate(&visitor);
3789   delete deferred.Detach();
3790 }
3791
3792
3793 TEST(IncrementalMarkingStepMakesBigProgressWithLargeObjects) {
3794   CcTest::InitializeVM();
3795   v8::HandleScope scope(CcTest::isolate());
3796   CompileRun("function f(n) {"
3797              "    var a = new Array(n);"
3798              "    for (var i = 0; i < n; i += 100) a[i] = i;"
3799              "};"
3800              "f(10 * 1024 * 1024);");
3801   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
3802   if (marking->IsStopped()) marking->Start();
3803   // This big step should be sufficient to mark the whole array.
3804   marking->Step(100 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
3805   DCHECK(marking->IsComplete());
3806 }
3807
3808
3809 TEST(DisableInlineAllocation) {
3810   i::FLAG_allow_natives_syntax = true;
3811   CcTest::InitializeVM();
3812   v8::HandleScope scope(CcTest::isolate());
3813   CompileRun("function test() {"
3814              "  var x = [];"
3815              "  for (var i = 0; i < 10; i++) {"
3816              "    x[i] = [ {}, [1,2,3], [1,x,3] ];"
3817              "  }"
3818              "}"
3819              "function run() {"
3820              "  %OptimizeFunctionOnNextCall(test);"
3821              "  test();"
3822              "  %DeoptimizeFunction(test);"
3823              "}");
3824
3825   // Warm-up with inline allocation enabled.
3826   CompileRun("test(); test(); run();");
3827
3828   // Run test with inline allocation disabled.
3829   CcTest::heap()->DisableInlineAllocation();
3830   CompileRun("run()");
3831
3832   // Run test with inline allocation re-enabled.
3833   CcTest::heap()->EnableInlineAllocation();
3834   CompileRun("run()");
3835 }
3836
3837
3838 static int AllocationSitesCount(Heap* heap) {
3839   int count = 0;
3840   for (Object* site = heap->allocation_sites_list();
3841        !(site->IsUndefined());
3842        site = AllocationSite::cast(site)->weak_next()) {
3843     count++;
3844   }
3845   return count;
3846 }
3847
3848
3849 TEST(EnsureAllocationSiteDependentCodesProcessed) {
3850   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
3851   i::FLAG_allow_natives_syntax = true;
3852   CcTest::InitializeVM();
3853   Isolate* isolate = CcTest::i_isolate();
3854   v8::internal::Heap* heap = CcTest::heap();
3855   GlobalHandles* global_handles = isolate->global_handles();
3856
3857   if (!isolate->use_crankshaft()) return;
3858
3859   // The allocation site at the head of the list is ours.
3860   Handle<AllocationSite> site;
3861   {
3862     LocalContext context;
3863     v8::HandleScope scope(context->GetIsolate());
3864
3865     int count = AllocationSitesCount(heap);
3866     CompileRun("var bar = function() { return (new Array()); };"
3867                "var a = bar();"
3868                "bar();"
3869                "bar();");
3870
3871     // One allocation site should have been created.
3872     int new_count = AllocationSitesCount(heap);
3873     CHECK_EQ(new_count, (count + 1));
3874     site = Handle<AllocationSite>::cast(
3875         global_handles->Create(
3876             AllocationSite::cast(heap->allocation_sites_list())));
3877
3878     CompileRun("%OptimizeFunctionOnNextCall(bar); bar();");
3879
3880     DependentCode::GroupStartIndexes starts(site->dependent_code());
3881     CHECK_GE(starts.number_of_entries(), 1);
3882     int index = starts.at(DependentCode::kAllocationSiteTransitionChangedGroup);
3883     CHECK(site->dependent_code()->is_code_at(index));
3884     Code* function_bar = site->dependent_code()->code_at(index);
3885     Handle<JSFunction> bar_handle =
3886         v8::Utils::OpenHandle(
3887             *v8::Handle<v8::Function>::Cast(
3888                 CcTest::global()->Get(v8_str("bar"))));
3889     CHECK_EQ(bar_handle->code(), function_bar);
3890   }
3891
3892   // Now make sure that a gc should get rid of the function, even though we
3893   // still have the allocation site alive.
3894   for (int i = 0; i < 4; i++) {
3895     heap->CollectAllGarbage(Heap::kNoGCFlags);
3896   }
3897
3898   // The site still exists because of our global handle, but the code is no
3899   // longer referred to by dependent_code().
3900   DependentCode::GroupStartIndexes starts(site->dependent_code());
3901   int index = starts.at(DependentCode::kAllocationSiteTransitionChangedGroup);
3902   CHECK(!(site->dependent_code()->is_code_at(index)));
3903 }
3904
3905
3906 TEST(CellsInOptimizedCodeAreWeak) {
3907   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
3908   i::FLAG_weak_embedded_objects_in_optimized_code = true;
3909   i::FLAG_allow_natives_syntax = true;
3910   CcTest::InitializeVM();
3911   Isolate* isolate = CcTest::i_isolate();
3912   v8::internal::Heap* heap = CcTest::heap();
3913
3914   if (!isolate->use_crankshaft()) return;
3915   HandleScope outer_scope(heap->isolate());
3916   Handle<Code> code;
3917   {
3918     LocalContext context;
3919     HandleScope scope(heap->isolate());
3920
3921     CompileRun("bar = (function() {"
3922                "  function bar() {"
3923                "    return foo(1);"
3924                "  };"
3925                "  var foo = function(x) { with (x) { return 1 + x; } };"
3926                "  bar(foo);"
3927                "  bar(foo);"
3928                "  bar(foo);"
3929                "  %OptimizeFunctionOnNextCall(bar);"
3930                "  bar(foo);"
3931                "  return bar;})();");
3932
3933     Handle<JSFunction> bar =
3934         v8::Utils::OpenHandle(
3935             *v8::Handle<v8::Function>::Cast(
3936                 CcTest::global()->Get(v8_str("bar"))));
3937     code = scope.CloseAndEscape(Handle<Code>(bar->code()));
3938   }
3939
3940   // Now make sure that a gc should get rid of the function
3941   for (int i = 0; i < 4; i++) {
3942     heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3943   }
3944
3945   DCHECK(code->marked_for_deoptimization());
3946 }
3947
3948
3949 TEST(ObjectsInOptimizedCodeAreWeak) {
3950   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
3951   i::FLAG_weak_embedded_objects_in_optimized_code = true;
3952   i::FLAG_allow_natives_syntax = true;
3953   CcTest::InitializeVM();
3954   Isolate* isolate = CcTest::i_isolate();
3955   v8::internal::Heap* heap = CcTest::heap();
3956
3957   if (!isolate->use_crankshaft()) return;
3958   HandleScope outer_scope(heap->isolate());
3959   Handle<Code> code;
3960   {
3961     LocalContext context;
3962     HandleScope scope(heap->isolate());
3963
3964     CompileRun("function bar() {"
3965                "  return foo(1);"
3966                "};"
3967                "function foo(x) { with (x) { return 1 + x; } };"
3968                "bar();"
3969                "bar();"
3970                "bar();"
3971                "%OptimizeFunctionOnNextCall(bar);"
3972                "bar();");
3973
3974     Handle<JSFunction> bar =
3975         v8::Utils::OpenHandle(
3976             *v8::Handle<v8::Function>::Cast(
3977                 CcTest::global()->Get(v8_str("bar"))));
3978     code = scope.CloseAndEscape(Handle<Code>(bar->code()));
3979   }
3980
3981   // Now make sure that a gc should get rid of the function
3982   for (int i = 0; i < 4; i++) {
3983     heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
3984   }
3985
3986   DCHECK(code->marked_for_deoptimization());
3987 }
3988
3989
3990 TEST(NoWeakHashTableLeakWithIncrementalMarking) {
3991   if (i::FLAG_always_opt || !i::FLAG_crankshaft) return;
3992   if (!i::FLAG_incremental_marking) return;
3993   i::FLAG_weak_embedded_objects_in_optimized_code = true;
3994   i::FLAG_allow_natives_syntax = true;
3995   i::FLAG_compilation_cache = false;
3996   CcTest::InitializeVM();
3997   Isolate* isolate = CcTest::i_isolate();
3998   v8::internal::Heap* heap = CcTest::heap();
3999
4000   if (!isolate->use_crankshaft()) return;
4001   HandleScope outer_scope(heap->isolate());
4002   for (int i = 0; i < 3; i++) {
4003     SimulateIncrementalMarking(heap);
4004     {
4005       LocalContext context;
4006       HandleScope scope(heap->isolate());
4007       EmbeddedVector<char, 256> source;
4008       SNPrintF(source,
4009                "function bar%d() {"
4010                "  return foo%d(1);"
4011                "};"
4012                "function foo%d(x) { with (x) { return 1 + x; } };"
4013                "bar%d();"
4014                "bar%d();"
4015                "bar%d();"
4016                "%%OptimizeFunctionOnNextCall(bar%d);"
4017                "bar%d();", i, i, i, i, i, i, i, i);
4018       CompileRun(source.start());
4019     }
4020     heap->CollectAllGarbage(i::Heap::kNoGCFlags);
4021   }
4022   int elements = 0;
4023   if (heap->weak_object_to_code_table()->IsHashTable()) {
4024     WeakHashTable* t = WeakHashTable::cast(heap->weak_object_to_code_table());
4025     elements = t->NumberOfElements();
4026   }
4027   CHECK_EQ(0, elements);
4028 }
4029
4030
4031 static Handle<JSFunction> OptimizeDummyFunction(const char* name) {
4032   EmbeddedVector<char, 256> source;
4033   SNPrintF(source,
4034           "function %s() { return 0; }"
4035           "%s(); %s();"
4036           "%%OptimizeFunctionOnNextCall(%s);"
4037           "%s();", name, name, name, name, name);
4038   CompileRun(source.start());
4039   Handle<JSFunction> fun =
4040       v8::Utils::OpenHandle(
4041           *v8::Handle<v8::Function>::Cast(
4042               CcTest::global()->Get(v8_str(name))));
4043   return fun;
4044 }
4045
4046
4047 static int GetCodeChainLength(Code* code) {
4048   int result = 0;
4049   while (code->next_code_link()->IsCode()) {
4050     result++;
4051     code = Code::cast(code->next_code_link());
4052   }
4053   return result;
4054 }
4055
4056
4057 TEST(NextCodeLinkIsWeak) {
4058   i::FLAG_allow_natives_syntax = true;
4059   CcTest::InitializeVM();
4060   Isolate* isolate = CcTest::i_isolate();
4061   v8::internal::Heap* heap = CcTest::heap();
4062
4063   if (!isolate->use_crankshaft()) return;
4064   HandleScope outer_scope(heap->isolate());
4065   Handle<Code> code;
4066   heap->CollectAllAvailableGarbage();
4067   int code_chain_length_before, code_chain_length_after;
4068   {
4069     HandleScope scope(heap->isolate());
4070     Handle<JSFunction> mortal = OptimizeDummyFunction("mortal");
4071     Handle<JSFunction> immortal = OptimizeDummyFunction("immortal");
4072     CHECK_EQ(immortal->code()->next_code_link(), mortal->code());
4073     code_chain_length_before = GetCodeChainLength(immortal->code());
4074     // Keep the immortal code and let the mortal code die.
4075     code = scope.CloseAndEscape(Handle<Code>(immortal->code()));
4076     CompileRun("mortal = null; immortal = null;");
4077   }
4078   heap->CollectAllAvailableGarbage();
4079   // Now mortal code should be dead.
4080   code_chain_length_after = GetCodeChainLength(*code);
4081   CHECK_EQ(code_chain_length_before - 1, code_chain_length_after);
4082 }
4083
4084
4085 static Handle<Code> DummyOptimizedCode(Isolate* isolate) {
4086   i::byte buffer[i::Assembler::kMinimalBufferSize];
4087   MacroAssembler masm(isolate, buffer, sizeof(buffer));
4088   CodeDesc desc;
4089   masm.Push(isolate->factory()->undefined_value());
4090   masm.Drop(1);
4091   masm.GetCode(&desc);
4092   Handle<Object> undefined(isolate->heap()->undefined_value(), isolate);
4093   Handle<Code> code = isolate->factory()->NewCode(
4094       desc, Code::ComputeFlags(Code::OPTIMIZED_FUNCTION), undefined);
4095   CHECK(code->IsCode());
4096   return code;
4097 }
4098
4099
4100 TEST(NextCodeLinkIsWeak2) {
4101   i::FLAG_allow_natives_syntax = true;
4102   CcTest::InitializeVM();
4103   Isolate* isolate = CcTest::i_isolate();
4104   v8::internal::Heap* heap = CcTest::heap();
4105
4106   if (!isolate->use_crankshaft()) return;
4107   HandleScope outer_scope(heap->isolate());
4108   heap->CollectAllAvailableGarbage();
4109   Handle<Context> context(Context::cast(heap->native_contexts_list()), isolate);
4110   Handle<Code> new_head;
4111   Handle<Object> old_head(context->get(Context::OPTIMIZED_CODE_LIST), isolate);
4112   {
4113     HandleScope scope(heap->isolate());
4114     Handle<Code> immortal = DummyOptimizedCode(isolate);
4115     Handle<Code> mortal = DummyOptimizedCode(isolate);
4116     mortal->set_next_code_link(*old_head);
4117     immortal->set_next_code_link(*mortal);
4118     context->set(Context::OPTIMIZED_CODE_LIST, *immortal);
4119     new_head = scope.CloseAndEscape(immortal);
4120   }
4121   heap->CollectAllAvailableGarbage();
4122   // Now mortal code should be dead.
4123   CHECK_EQ(*old_head, new_head->next_code_link());
4124 }
4125
4126
4127 static bool weak_ic_cleared = false;
4128
4129 static void ClearWeakIC(const v8::WeakCallbackData<v8::Object, void>& data) {
4130   printf("clear weak is called\n");
4131   weak_ic_cleared = true;
4132   v8::Persistent<v8::Value>* p =
4133       reinterpret_cast<v8::Persistent<v8::Value>*>(data.GetParameter());
4134   CHECK(p->IsNearDeath());
4135   p->Reset();
4136 }
4137
4138
4139 // Checks that the value returned by execution of the source is weak.
4140 void CheckWeakness(const char* source) {
4141   i::FLAG_stress_compaction = false;
4142   CcTest::InitializeVM();
4143   v8::Isolate* isolate = CcTest::isolate();
4144   v8::HandleScope scope(isolate);
4145   v8::Persistent<v8::Object> garbage;
4146   {
4147     v8::HandleScope scope(isolate);
4148     garbage.Reset(isolate, CompileRun(source)->ToObject());
4149   }
4150   weak_ic_cleared = false;
4151   garbage.SetWeak(static_cast<void*>(&garbage), &ClearWeakIC);
4152   Heap* heap = CcTest::i_isolate()->heap();
4153   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
4154   CHECK(weak_ic_cleared);
4155 }
4156
4157
4158 // Each of the following "weak IC" tests creates an IC that embeds a map with
4159 // the prototype pointing to _proto_ and checks that the _proto_ dies on GC.
4160 TEST(WeakMapInMonomorphicLoadIC) {
4161   CheckWeakness("function loadIC(obj) {"
4162                 "  return obj.name;"
4163                 "}"
4164                 " (function() {"
4165                 "   var proto = {'name' : 'weak'};"
4166                 "   var obj = Object.create(proto);"
4167                 "   loadIC(obj);"
4168                 "   loadIC(obj);"
4169                 "   loadIC(obj);"
4170                 "   return proto;"
4171                 " })();");
4172 }
4173
4174
4175 TEST(WeakMapInMonomorphicKeyedLoadIC) {
4176   CheckWeakness("function keyedLoadIC(obj, field) {"
4177                 "  return obj[field];"
4178                 "}"
4179                 " (function() {"
4180                 "   var proto = {'name' : 'weak'};"
4181                 "   var obj = Object.create(proto);"
4182                 "   keyedLoadIC(obj, 'name');"
4183                 "   keyedLoadIC(obj, 'name');"
4184                 "   keyedLoadIC(obj, 'name');"
4185                 "   return proto;"
4186                 " })();");
4187 }
4188
4189
4190 TEST(WeakMapInMonomorphicStoreIC) {
4191   CheckWeakness("function storeIC(obj, value) {"
4192                 "  obj.name = value;"
4193                 "}"
4194                 " (function() {"
4195                 "   var proto = {'name' : 'weak'};"
4196                 "   var obj = Object.create(proto);"
4197                 "   storeIC(obj, 'x');"
4198                 "   storeIC(obj, 'x');"
4199                 "   storeIC(obj, 'x');"
4200                 "   return proto;"
4201                 " })();");
4202 }
4203
4204
4205 TEST(WeakMapInMonomorphicKeyedStoreIC) {
4206   CheckWeakness("function keyedStoreIC(obj, field, value) {"
4207                 "  obj[field] = value;"
4208                 "}"
4209                 " (function() {"
4210                 "   var proto = {'name' : 'weak'};"
4211                 "   var obj = Object.create(proto);"
4212                 "   keyedStoreIC(obj, 'x');"
4213                 "   keyedStoreIC(obj, 'x');"
4214                 "   keyedStoreIC(obj, 'x');"
4215                 "   return proto;"
4216                 " })();");
4217 }
4218
4219
4220 TEST(WeakMapInMonomorphicCompareNilIC) {
4221   CheckWeakness("function compareNilIC(obj) {"
4222                 "  return obj == null;"
4223                 "}"
4224                 " (function() {"
4225                 "   var proto = {'name' : 'weak'};"
4226                 "   var obj = Object.create(proto);"
4227                 "   compareNilIC(obj);"
4228                 "   compareNilIC(obj);"
4229                 "   compareNilIC(obj);"
4230                 "   return proto;"
4231                 " })();");
4232 }
4233
4234
4235 #ifdef DEBUG
4236 TEST(AddInstructionChangesNewSpacePromotion) {
4237   i::FLAG_allow_natives_syntax = true;
4238   i::FLAG_expose_gc = true;
4239   i::FLAG_stress_compaction = true;
4240   i::FLAG_gc_interval = 1000;
4241   CcTest::InitializeVM();
4242   if (!i::FLAG_allocation_site_pretenuring) return;
4243   v8::HandleScope scope(CcTest::isolate());
4244   Isolate* isolate = CcTest::i_isolate();
4245   Heap* heap = isolate->heap();
4246
4247   CompileRun(
4248       "function add(a, b) {"
4249       "  return a + b;"
4250       "}"
4251       "add(1, 2);"
4252       "add(\"a\", \"b\");"
4253       "var oldSpaceObject;"
4254       "gc();"
4255       "function crash(x) {"
4256       "  var object = {a: null, b: null};"
4257       "  var result = add(1.5, x | 0);"
4258       "  object.a = result;"
4259       "  oldSpaceObject = object;"
4260       "  return object;"
4261       "}"
4262       "crash(1);"
4263       "crash(1);"
4264       "%OptimizeFunctionOnNextCall(crash);"
4265       "crash(1);");
4266
4267   v8::Handle<v8::Object> global = CcTest::global();
4268     v8::Handle<v8::Function> g =
4269         v8::Handle<v8::Function>::Cast(global->Get(v8_str("crash")));
4270   v8::Handle<v8::Value> args1[] = { v8_num(1) };
4271   heap->DisableInlineAllocation();
4272   heap->set_allocation_timeout(1);
4273   g->Call(global, 1, args1);
4274   heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
4275 }
4276
4277
4278 void OnFatalErrorExpectOOM(const char* location, const char* message) {
4279   // Exit with 0 if the location matches our expectation.
4280   exit(strcmp(location, "CALL_AND_RETRY_LAST"));
4281 }
4282
4283
4284 TEST(CEntryStubOOM) {
4285   i::FLAG_allow_natives_syntax = true;
4286   CcTest::InitializeVM();
4287   v8::HandleScope scope(CcTest::isolate());
4288   v8::V8::SetFatalErrorHandler(OnFatalErrorExpectOOM);
4289
4290   v8::Handle<v8::Value> result = CompileRun(
4291       "%SetFlags('--gc-interval=1');"
4292       "var a = [];"
4293       "a.__proto__ = [];"
4294       "a.unshift(1)");
4295
4296   CHECK(result->IsNumber());
4297 }
4298
4299 #endif  // DEBUG
4300
4301
4302 static void InterruptCallback357137(v8::Isolate* isolate, void* data) { }
4303
4304
4305 static void RequestInterrupt(const v8::FunctionCallbackInfo<v8::Value>& args) {
4306   CcTest::isolate()->RequestInterrupt(&InterruptCallback357137, NULL);
4307 }
4308
4309
4310 TEST(Regress357137) {
4311   CcTest::InitializeVM();
4312   v8::Isolate* isolate = CcTest::isolate();
4313   v8::HandleScope hscope(isolate);
4314   v8::Handle<v8::ObjectTemplate> global =v8::ObjectTemplate::New(isolate);
4315   global->Set(v8::String::NewFromUtf8(isolate, "interrupt"),
4316               v8::FunctionTemplate::New(isolate, RequestInterrupt));
4317   v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
4318   DCHECK(!context.IsEmpty());
4319   v8::Context::Scope cscope(context);
4320
4321   v8::Local<v8::Value> result = CompileRun(
4322       "var locals = '';"
4323       "for (var i = 0; i < 512; i++) locals += 'var v' + i + '= 42;';"
4324       "eval('function f() {' + locals + 'return function() { return v0; }; }');"
4325       "interrupt();"  // This triggers a fake stack overflow in f.
4326       "f()()");
4327   CHECK_EQ(42.0, result->ToNumber()->Value());
4328 }
4329
4330
4331 TEST(ArrayShiftSweeping) {
4332   i::FLAG_expose_gc = true;
4333   CcTest::InitializeVM();
4334   v8::HandleScope scope(CcTest::isolate());
4335   Isolate* isolate = CcTest::i_isolate();
4336   Heap* heap = isolate->heap();
4337
4338   v8::Local<v8::Value> result = CompileRun(
4339       "var array = new Array(40000);"
4340       "var tmp = new Array(100000);"
4341       "array[0] = 10;"
4342       "gc();"
4343       "gc();"
4344       "array.shift();"
4345       "array;");
4346
4347   Handle<JSObject> o =
4348       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(result));
4349   CHECK(heap->InOldPointerSpace(o->elements()));
4350   CHECK(heap->InOldPointerSpace(*o));
4351   Page* page = Page::FromAddress(o->elements()->address());
4352   CHECK(page->parallel_sweeping() <= MemoryChunk::SWEEPING_FINALIZE ||
4353         Marking::IsBlack(Marking::MarkBitFrom(o->elements())));
4354 }
4355
4356
4357 TEST(PromotionQueue) {
4358   i::FLAG_expose_gc = true;
4359   i::FLAG_max_semi_space_size = 2;
4360   CcTest::InitializeVM();
4361   v8::HandleScope scope(CcTest::isolate());
4362   Isolate* isolate = CcTest::i_isolate();
4363   Heap* heap = isolate->heap();
4364   NewSpace* new_space = heap->new_space();
4365
4366   // In this test we will try to overwrite the promotion queue which is at the
4367   // end of to-space. To actually make that possible, we need at least two
4368   // semi-space pages and take advantage of fragementation.
4369   // (1) Grow semi-space to two pages.
4370   // (2) Create a few small long living objects and call the scavenger to
4371   // move them to the other semi-space.
4372   // (3) Create a huge object, i.e., remainder of first semi-space page and
4373   // create another huge object which should be of maximum allocatable memory
4374   // size of the second semi-space page.
4375   // (4) Call the scavenger again.
4376   // What will happen is: the scavenger will promote the objects created in (2)
4377   // and will create promotion queue entries at the end of the second
4378   // semi-space page during the next scavenge when it promotes the objects to
4379   // the old generation. The first allocation of (3) will fill up the first
4380   // semi-space page. The second allocation in (3) will not fit into the first
4381   // semi-space page, but it will overwrite the promotion queue which are in
4382   // the second semi-space page. If the right guards are in place, the promotion
4383   // queue will be evacuated in that case.
4384
4385   // Grow the semi-space to two pages to make semi-space copy overwrite the
4386   // promotion queue, which will be at the end of the second page.
4387   intptr_t old_capacity = new_space->Capacity();
4388   new_space->Grow();
4389   CHECK(new_space->IsAtMaximumCapacity());
4390   CHECK(2 * old_capacity == new_space->Capacity());
4391
4392   // Call the scavenger two times to get an empty new space
4393   heap->CollectGarbage(NEW_SPACE);
4394   heap->CollectGarbage(NEW_SPACE);
4395
4396   // First create a few objects which will survive a scavenge, and will get
4397   // promoted to the old generation later on. These objects will create
4398   // promotion queue entries at the end of the second semi-space page.
4399   const int number_handles = 12;
4400   Handle<FixedArray> handles[number_handles];
4401   for (int i = 0; i < number_handles; i++) {
4402     handles[i] = isolate->factory()->NewFixedArray(1, NOT_TENURED);
4403   }
4404   heap->CollectGarbage(NEW_SPACE);
4405
4406   // Create the first huge object which will exactly fit the first semi-space
4407   // page.
4408   int new_linear_size = static_cast<int>(
4409       *heap->new_space()->allocation_limit_address() -
4410           *heap->new_space()->allocation_top_address());
4411   int length = new_linear_size / kPointerSize - FixedArray::kHeaderSize;
4412   Handle<FixedArray> first =
4413     isolate->factory()->NewFixedArray(length, NOT_TENURED);
4414   CHECK(heap->InNewSpace(*first));
4415
4416   // Create the second huge object of maximum allocatable second semi-space
4417   // page size.
4418   new_linear_size = static_cast<int>(
4419       *heap->new_space()->allocation_limit_address() -
4420           *heap->new_space()->allocation_top_address());
4421   length = Page::kMaxRegularHeapObjectSize / kPointerSize -
4422       FixedArray::kHeaderSize;
4423   Handle<FixedArray> second =
4424       isolate->factory()->NewFixedArray(length, NOT_TENURED);
4425   CHECK(heap->InNewSpace(*second));
4426
4427   // This scavenge will corrupt memory if the promotion queue is not evacuated.
4428   heap->CollectGarbage(NEW_SPACE);
4429 }
4430
4431
4432 TEST(Regress388880) {
4433   i::FLAG_expose_gc = true;
4434   CcTest::InitializeVM();
4435   v8::HandleScope scope(CcTest::isolate());
4436   Isolate* isolate = CcTest::i_isolate();
4437   Factory* factory = isolate->factory();
4438   Heap* heap = isolate->heap();
4439
4440   Handle<Map> map1 = Map::Create(isolate->object_function(), 1);
4441   Handle<Map> map2 =
4442       Map::CopyWithField(map1, factory->NewStringFromStaticAscii("foo"),
4443                          HeapType::Any(isolate), NONE, Representation::Tagged(),
4444                          OMIT_TRANSITION).ToHandleChecked();
4445
4446   int desired_offset = Page::kPageSize - map1->instance_size();
4447
4448   // Allocate fixed array in old pointer space so, that object allocated
4449   // afterwards would end at the end of the page.
4450   {
4451     SimulateFullSpace(heap->old_pointer_space());
4452     int padding_size = desired_offset - Page::kObjectStartOffset;
4453     int padding_array_length =
4454         (padding_size - FixedArray::kHeaderSize) / kPointerSize;
4455
4456     Handle<FixedArray> temp2 =
4457         factory->NewFixedArray(padding_array_length, TENURED);
4458     Page* page = Page::FromAddress(temp2->address());
4459     CHECK_EQ(Page::kObjectStartOffset, page->Offset(temp2->address()));
4460   }
4461
4462   Handle<JSObject> o = factory->NewJSObjectFromMap(map1, TENURED, false);
4463   o->set_properties(*factory->empty_fixed_array());
4464
4465   // Ensure that the object allocated where we need it.
4466   Page* page = Page::FromAddress(o->address());
4467   CHECK_EQ(desired_offset, page->Offset(o->address()));
4468
4469   // Now we have an object right at the end of the page.
4470
4471   // Enable incremental marking to trigger actions in Heap::AdjustLiveBytes()
4472   // that would cause crash.
4473   IncrementalMarking* marking = CcTest::heap()->incremental_marking();
4474   marking->Abort();
4475   marking->Start();
4476   CHECK(marking->IsMarking());
4477
4478   // Now everything is set up for crashing in JSObject::MigrateFastToFast()
4479   // when it calls heap->AdjustLiveBytes(...).
4480   JSObject::MigrateToMap(o, map2);
4481 }
4482
4483
4484 TEST(RegressStoreBufferMapUpdate) {
4485   CcTest::InitializeVM();
4486   v8::HandleScope scope(CcTest::isolate());
4487   Isolate* isolate = CcTest::i_isolate();
4488   Factory* factory = isolate->factory();
4489   Heap* heap = isolate->heap();
4490
4491   // This test checks that we do not treat instance size field of the map
4492   // as a heap pointer when processing the store buffer.
4493
4494   Handle<Map> map1 = Map::Create(isolate->object_function(), 1);
4495
4496   // Allocate a throw-away object.
4497   factory->NewFixedArray(1, NOT_TENURED);
4498
4499   // Allocate a new-space object that will be moved by the GC (because
4500   // the throw-away object will die).
4501   Handle<FixedArray> object_to_move = factory->NewFixedArray(1, NOT_TENURED);
4502
4503   // Record the address before the GC.
4504   Object* object_to_move_address = *object_to_move;
4505
4506   // Smash the new space pointer to the moving object into the instance size
4507   // field of the map. The idea is to trick the GC into updating this pointer
4508   // when the object moves. This would be wrong because instance size should
4509   // not be treated as a heap pointer.
4510   *(reinterpret_cast<Object**>(map1->address() + Map::kInstanceSizeOffset)) =
4511       object_to_move_address;
4512
4513   // Make sure we scan the map's page on scavenge.
4514   Page* page = Page::FromAddress(map1->address());
4515   page->set_scan_on_scavenge(true);
4516
4517   heap->CollectGarbage(NEW_SPACE);
4518
4519   // Check the object has really moved.
4520   CHECK(*object_to_move != object_to_move_address);
4521
4522   // Now check that we have not updated the instance size field of the map.
4523   CHECK_EQ(object_to_move_address,
4524            *(reinterpret_cast<Object**>(map1->address() +
4525                                         Map::kInstanceSizeOffset)));
4526 }
4527
4528
4529 #ifdef DEBUG
4530 TEST(PathTracer) {
4531   CcTest::InitializeVM();
4532   v8::HandleScope scope(CcTest::isolate());
4533
4534   v8::Local<v8::Value> result = CompileRun("'abc'");
4535   Handle<Object> o = v8::Utils::OpenHandle(*result);
4536   CcTest::i_isolate()->heap()->TracePathToObject(*o);
4537 }
4538 #endif  // DEBUG