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