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