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