LCOV - code coverage report
Current view: top level - test/cctest - test-inobject-slack-tracking.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 598 602 99.3 %
Date: 2019-04-17 Functions: 67 67 100.0 %

          Line data    Source code
       1             : // Copyright 2015 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include <stdlib.h>
       6             : #include <sstream>
       7             : #include <utility>
       8             : 
       9             : #include "src/api-inl.h"
      10             : #include "src/objects-inl.h"
      11             : #include "src/objects/heap-number-inl.h"
      12             : #include "src/v8.h"
      13             : 
      14             : #include "test/cctest/cctest.h"
      15             : 
      16             : namespace v8 {
      17             : namespace internal {
      18             : namespace test_inobject_slack_tracking {
      19             : 
      20             : static const int kMaxInobjectProperties = JSObject::kMaxInObjectProperties;
      21             : 
      22             : template <typename T>
      23             : static Handle<T> OpenHandle(v8::Local<v8::Value> value) {
      24             :   Handle<Object> obj = v8::Utils::OpenHandle(*value);
      25             :   return Handle<T>::cast(obj);
      26             : }
      27             : 
      28             : 
      29        6860 : static inline v8::Local<v8::Value> Run(v8::Local<v8::Script> script) {
      30             :   v8::Local<v8::Value> result;
      31       20580 :   if (script->Run(v8::Isolate::GetCurrent()->GetCurrentContext())
      32             :           .ToLocal(&result)) {
      33        6860 :     return result;
      34             :   }
      35           0 :   return v8::Local<v8::Value>();
      36             : }
      37             : 
      38             : 
      39             : 
      40             : template <typename T = Object>
      41         965 : Handle<T> GetLexical(const char* name) {
      42             :   Isolate* isolate = CcTest::i_isolate();
      43             :   Factory* factory = isolate->factory();
      44             : 
      45         965 :   Handle<String> str_name = factory->InternalizeUtf8String(name);
      46             :   Handle<ScriptContextTable> script_contexts(
      47        2895 :       isolate->native_context()->script_context_table(), isolate);
      48             : 
      49             :   ScriptContextTable::LookupResult lookup_result;
      50         965 :   if (ScriptContextTable::Lookup(isolate, *script_contexts, *str_name,
      51             :                                  &lookup_result)) {
      52         965 :     Handle<Context> script_context = ScriptContextTable::GetContext(
      53         965 :         isolate, script_contexts, lookup_result.context_index);
      54             : 
      55             :     Handle<Object> result(script_context->get(lookup_result.slot_index),
      56         965 :                           isolate);
      57             :     return Handle<T>::cast(result);
      58             :   }
      59           0 :   return Handle<T>();
      60             : }
      61             : 
      62             : 
      63             : template <typename T = Object>
      64             : Handle<T> GetLexical(const std::string& name) {
      65         535 :   return GetLexical<T>(name.c_str());
      66             : }
      67             : 
      68             : template <typename T>
      69             : static inline Handle<T> RunI(v8::Local<v8::Script> script) {
      70        6850 :   return OpenHandle<T>(Run(script));
      71             : }
      72             : 
      73             : template <typename T>
      74         145 : static inline Handle<T> CompileRunI(const char* script) {
      75         145 :   return OpenHandle<T>(CompileRun(script));
      76             : }
      77             : 
      78       87920 : static Object GetFieldValue(JSObject obj, int property_index) {
      79       87920 :   FieldIndex index = FieldIndex::ForPropertyIndex(obj->map(), property_index);
      80       87920 :   return obj->RawFastPropertyAt(index);
      81             : }
      82             : 
      83         460 : static double GetDoubleFieldValue(JSObject obj, FieldIndex field_index) {
      84         460 :   if (obj->IsUnboxedDoubleField(field_index)) {
      85         460 :     return obj->RawFastDoublePropertyAt(field_index);
      86             :   } else {
      87           0 :     Object value = obj->RawFastPropertyAt(field_index);
      88           0 :     CHECK(value->IsMutableHeapNumber());
      89             :     return MutableHeapNumber::cast(value)->value();
      90             :   }
      91             : }
      92             : 
      93         460 : static double GetDoubleFieldValue(JSObject obj, int property_index) {
      94         460 :   FieldIndex index = FieldIndex::ForPropertyIndex(obj->map(), property_index);
      95         460 :   return GetDoubleFieldValue(obj, index);
      96             : }
      97             : 
      98        7055 : bool IsObjectShrinkable(JSObject obj) {
      99             :   Handle<Map> filler_map =
     100             :       CcTest::i_isolate()->factory()->one_pointer_filler_map();
     101             : 
     102        7055 :   int inobject_properties = obj->map()->GetInObjectProperties();
     103        7055 :   int unused = obj->map()->UnusedPropertyFields();
     104        7055 :   if (unused == 0) return false;
     105             : 
     106       92005 :   for (int i = inobject_properties - unused; i < inobject_properties; i++) {
     107      174000 :     if (*filler_map != GetFieldValue(obj, i)) {
     108             :       return false;
     109             :     }
     110             :   }
     111             :   return true;
     112             : }
     113             : 
     114       26649 : TEST(JSObjectBasic) {
     115             :   // Avoid eventual completion of in-object slack tracking.
     116          10 :   FLAG_always_opt = false;
     117          10 :   CcTest::InitializeVM();
     118          20 :   v8::HandleScope scope(CcTest::isolate());
     119             :   const char* source =
     120             :       "function A() {"
     121             :       "  this.a = 42;"
     122             :       "  this.d = 4.2;"
     123             :       "  this.o = this;"
     124             :       "}";
     125             :   CompileRun(source);
     126             : 
     127          10 :   Handle<JSFunction> func = GetGlobal<JSFunction>("A");
     128             : 
     129             :   // Zero instances were created so far.
     130          10 :   CHECK(!func->has_initial_map());
     131             : 
     132             :   v8::Local<v8::Script> new_A_script = v8_compile("new A();");
     133             : 
     134             :   Handle<JSObject> obj = RunI<JSObject>(new_A_script);
     135             : 
     136          10 :   CHECK(func->has_initial_map());
     137             :   Handle<Map> initial_map(func->initial_map(), func->GetIsolate());
     138             : 
     139             :   // One instance created.
     140          10 :   CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
     141             :            initial_map->construction_counter());
     142          10 :   CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     143             : 
     144             :   // There must be at least some slack.
     145          10 :   CHECK_LT(5, obj->map()->GetInObjectProperties());
     146          10 :   CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj, 0));
     147          10 :   CHECK_EQ(4.2, GetDoubleFieldValue(*obj, 1));
     148          20 :   CHECK_EQ(*obj, GetFieldValue(*obj, 2));
     149          10 :   CHECK(IsObjectShrinkable(*obj));
     150             : 
     151             :   // Create several objects to complete the tracking.
     152         130 :   for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
     153          60 :     CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     154             :     Handle<JSObject> tmp = RunI<JSObject>(new_A_script);
     155         120 :     CHECK_EQ(initial_map->IsInobjectSlackTrackingInProgress(),
     156             :              IsObjectShrinkable(*tmp));
     157             :   }
     158          10 :   CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
     159          10 :   CHECK(!IsObjectShrinkable(*obj));
     160             : 
     161             :   // No slack left.
     162          10 :   CHECK_EQ(3, obj->map()->GetInObjectProperties());
     163          10 : }
     164             : 
     165             : 
     166       26644 : TEST(JSObjectBasicNoInlineNew) {
     167           5 :   FLAG_inline_new = false;
     168           5 :   TestJSObjectBasic();
     169           5 : }
     170             : 
     171             : 
     172       26649 : TEST(JSObjectComplex) {
     173             :   // Avoid eventual completion of in-object slack tracking.
     174          10 :   FLAG_always_opt = false;
     175          10 :   CcTest::InitializeVM();
     176          20 :   v8::HandleScope scope(CcTest::isolate());
     177             :   const char* source =
     178             :       "function A(n) {"
     179             :       "  if (n > 0) this.a = 42;"
     180             :       "  if (n > 1) this.d = 4.2;"
     181             :       "  if (n > 2) this.o1 = this;"
     182             :       "  if (n > 3) this.o2 = this;"
     183             :       "  if (n > 4) this.o3 = this;"
     184             :       "  if (n > 5) this.o4 = this;"
     185             :       "}";
     186             :   CompileRun(source);
     187             : 
     188          10 :   Handle<JSFunction> func = GetGlobal<JSFunction>("A");
     189             : 
     190             :   // Zero instances were created so far.
     191          10 :   CHECK(!func->has_initial_map());
     192             : 
     193          10 :   Handle<JSObject> obj1 = CompileRunI<JSObject>("new A(1);");
     194          10 :   Handle<JSObject> obj3 = CompileRunI<JSObject>("new A(3);");
     195          10 :   Handle<JSObject> obj5 = CompileRunI<JSObject>("new A(5);");
     196             : 
     197          10 :   CHECK(func->has_initial_map());
     198             :   Handle<Map> initial_map(func->initial_map(), func->GetIsolate());
     199             : 
     200             :   // Three instances created.
     201          10 :   CHECK_EQ(Map::kSlackTrackingCounterStart - 3,
     202             :            initial_map->construction_counter());
     203          10 :   CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     204             : 
     205             :   // There must be at least some slack.
     206          10 :   CHECK_LT(5, obj3->map()->GetInObjectProperties());
     207          10 :   CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj3, 0));
     208          10 :   CHECK_EQ(4.2, GetDoubleFieldValue(*obj3, 1));
     209          20 :   CHECK_EQ(*obj3, GetFieldValue(*obj3, 2));
     210          10 :   CHECK(IsObjectShrinkable(*obj1));
     211          10 :   CHECK(IsObjectShrinkable(*obj3));
     212          10 :   CHECK(IsObjectShrinkable(*obj5));
     213             : 
     214             :   // Create several objects to complete the tracking.
     215          90 :   for (int i = 3; i < Map::kGenerousAllocationCount; i++) {
     216          40 :     CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     217             :     CompileRun("new A(3);");
     218             :   }
     219          10 :   CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
     220             : 
     221             :   // obj1 and obj2 stays shrinkable because we don't clear unused fields.
     222          10 :   CHECK(IsObjectShrinkable(*obj1));
     223          10 :   CHECK(IsObjectShrinkable(*obj3));
     224          10 :   CHECK(!IsObjectShrinkable(*obj5));
     225             : 
     226          10 :   CHECK_EQ(5, obj1->map()->GetInObjectProperties());
     227          10 :   CHECK_EQ(4, obj1->map()->UnusedPropertyFields());
     228             : 
     229          10 :   CHECK_EQ(5, obj3->map()->GetInObjectProperties());
     230          10 :   CHECK_EQ(2, obj3->map()->UnusedPropertyFields());
     231             : 
     232          10 :   CHECK_EQ(5, obj5->map()->GetInObjectProperties());
     233          10 :   CHECK_EQ(0, obj5->map()->UnusedPropertyFields());
     234             : 
     235             :   // Since slack tracking is complete, the new objects should not be shrinkable.
     236          10 :   obj1 = CompileRunI<JSObject>("new A(1);");
     237          10 :   obj3 = CompileRunI<JSObject>("new A(3);");
     238          10 :   obj5 = CompileRunI<JSObject>("new A(5);");
     239             : 
     240          10 :   CHECK(!IsObjectShrinkable(*obj1));
     241          10 :   CHECK(!IsObjectShrinkable(*obj3));
     242          10 :   CHECK(!IsObjectShrinkable(*obj5));
     243          10 : }
     244             : 
     245             : 
     246       26644 : TEST(JSObjectComplexNoInlineNew) {
     247           5 :   FLAG_inline_new = false;
     248           5 :   TestJSObjectComplex();
     249           5 : }
     250             : 
     251             : 
     252       26649 : TEST(JSGeneratorObjectBasic) {
     253             :   // Avoid eventual completion of in-object slack tracking.
     254          10 :   FLAG_always_opt = false;
     255          10 :   CcTest::InitializeVM();
     256          20 :   v8::HandleScope scope(CcTest::isolate());
     257             :   const char* source =
     258             :       "function* A() {"
     259             :       "  var i = 0;"
     260             :       "  while(true) {"
     261             :       "    yield i++;"
     262             :       "  }"
     263             :       "};"
     264             :       "function CreateGenerator() {"
     265             :       "  var o = A();"
     266             :       "  o.a = 42;"
     267             :       "  o.d = 4.2;"
     268             :       "  o.o = o;"
     269             :       "  return o;"
     270             :       "}";
     271             :   CompileRun(source);
     272             : 
     273          10 :   Handle<JSFunction> func = GetGlobal<JSFunction>("A");
     274             : 
     275             :   // Zero instances were created so far.
     276          10 :   CHECK(!func->has_initial_map());
     277             : 
     278             :   v8::Local<v8::Script> new_A_script = v8_compile("CreateGenerator();");
     279             : 
     280             :   Handle<JSObject> obj = RunI<JSObject>(new_A_script);
     281             : 
     282          10 :   CHECK(func->has_initial_map());
     283             :   Handle<Map> initial_map(func->initial_map(), func->GetIsolate());
     284             : 
     285             :   // One instance created.
     286          10 :   CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
     287             :            initial_map->construction_counter());
     288          10 :   CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     289             : 
     290             :   // There must be at least some slack.
     291          10 :   CHECK_LT(5, obj->map()->GetInObjectProperties());
     292          10 :   CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj, 0));
     293          10 :   CHECK_EQ(4.2, GetDoubleFieldValue(*obj, 1));
     294          20 :   CHECK_EQ(*obj, GetFieldValue(*obj, 2));
     295          10 :   CHECK(IsObjectShrinkable(*obj));
     296             : 
     297             :   // Create several objects to complete the tracking.
     298         130 :   for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
     299          60 :     CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     300             :     Handle<JSObject> tmp = RunI<JSObject>(new_A_script);
     301         120 :     CHECK_EQ(initial_map->IsInobjectSlackTrackingInProgress(),
     302             :              IsObjectShrinkable(*tmp));
     303             :   }
     304          10 :   CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
     305          10 :   CHECK(!IsObjectShrinkable(*obj));
     306             : 
     307             :   // No slack left.
     308          10 :   CHECK_EQ(3, obj->map()->GetInObjectProperties());
     309          10 : }
     310             : 
     311             : 
     312       26644 : TEST(JSGeneratorObjectBasicNoInlineNew) {
     313           5 :   FLAG_inline_new = false;
     314           5 :   TestJSGeneratorObjectBasic();
     315           5 : }
     316             : 
     317             : 
     318       26649 : TEST(SubclassBasicNoBaseClassInstances) {
     319             :   // Avoid eventual completion of in-object slack tracking.
     320          10 :   FLAG_always_opt = false;
     321          10 :   CcTest::InitializeVM();
     322          20 :   v8::HandleScope scope(CcTest::isolate());
     323             : 
     324             :   // Check that base class' and subclass' slack tracking do not interfere with
     325             :   // each other.
     326             :   // In this test we never create base class instances.
     327             : 
     328             :   const char* source =
     329             :       "'use strict';"
     330             :       "class A {"
     331             :       "  constructor(...args) {"
     332             :       "    this.aa = 42;"
     333             :       "    this.ad = 4.2;"
     334             :       "    this.ao = this;"
     335             :       "  }"
     336             :       "};"
     337             :       "class B extends A {"
     338             :       "  constructor(...args) {"
     339             :       "    super(...args);"
     340             :       "    this.ba = 142;"
     341             :       "    this.bd = 14.2;"
     342             :       "    this.bo = this;"
     343             :       "  }"
     344             :       "};";
     345             :   CompileRun(source);
     346             : 
     347          10 :   Handle<JSFunction> a_func = GetLexical<JSFunction>("A");
     348          10 :   Handle<JSFunction> b_func = GetLexical<JSFunction>("B");
     349             : 
     350             :   // Zero instances were created so far.
     351          10 :   CHECK(!a_func->has_initial_map());
     352          10 :   CHECK(!b_func->has_initial_map());
     353             : 
     354             :   v8::Local<v8::Script> new_B_script = v8_compile("new B();");
     355             : 
     356             :   Handle<JSObject> obj = RunI<JSObject>(new_B_script);
     357             : 
     358          10 :   CHECK(a_func->has_initial_map());
     359             :   Handle<Map> a_initial_map(a_func->initial_map(), a_func->GetIsolate());
     360             : 
     361          10 :   CHECK(b_func->has_initial_map());
     362             :   Handle<Map> b_initial_map(b_func->initial_map(), a_func->GetIsolate());
     363             : 
     364             :   // Zero instances of A created.
     365          10 :   CHECK_EQ(Map::kSlackTrackingCounterStart,
     366             :            a_initial_map->construction_counter());
     367          10 :   CHECK(a_initial_map->IsInobjectSlackTrackingInProgress());
     368             : 
     369             :   // One instance of B created.
     370          10 :   CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
     371             :            b_initial_map->construction_counter());
     372          10 :   CHECK(b_initial_map->IsInobjectSlackTrackingInProgress());
     373             : 
     374             :   // There must be at least some slack.
     375          10 :   CHECK_LT(10, obj->map()->GetInObjectProperties());
     376          10 :   CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj, 0));
     377          10 :   CHECK_EQ(4.2, GetDoubleFieldValue(*obj, 1));
     378          20 :   CHECK_EQ(*obj, GetFieldValue(*obj, 2));
     379          10 :   CHECK_EQ(Smi::FromInt(142), GetFieldValue(*obj, 3));
     380          10 :   CHECK_EQ(14.2, GetDoubleFieldValue(*obj, 4));
     381          20 :   CHECK_EQ(*obj, GetFieldValue(*obj, 5));
     382          10 :   CHECK(IsObjectShrinkable(*obj));
     383             : 
     384             :   // Create several subclass instances to complete the tracking.
     385         130 :   for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
     386          60 :     CHECK(b_initial_map->IsInobjectSlackTrackingInProgress());
     387             :     Handle<JSObject> tmp = RunI<JSObject>(new_B_script);
     388         120 :     CHECK_EQ(b_initial_map->IsInobjectSlackTrackingInProgress(),
     389             :              IsObjectShrinkable(*tmp));
     390             :   }
     391          10 :   CHECK(!b_initial_map->IsInobjectSlackTrackingInProgress());
     392          10 :   CHECK(!IsObjectShrinkable(*obj));
     393             : 
     394             :   // Zero instances of A created.
     395          10 :   CHECK_EQ(Map::kSlackTrackingCounterStart,
     396             :            a_initial_map->construction_counter());
     397          10 :   CHECK(a_initial_map->IsInobjectSlackTrackingInProgress());
     398             : 
     399             :   // No slack left.
     400          10 :   CHECK_EQ(6, obj->map()->GetInObjectProperties());
     401          10 : }
     402             : 
     403             : 
     404       26644 : TEST(SubclassBasicNoBaseClassInstancesNoInlineNew) {
     405           5 :   FLAG_inline_new = false;
     406           5 :   TestSubclassBasicNoBaseClassInstances();
     407           5 : }
     408             : 
     409             : 
     410       26649 : TEST(SubclassBasic) {
     411             :   // Avoid eventual completion of in-object slack tracking.
     412          10 :   FLAG_always_opt = false;
     413          10 :   CcTest::InitializeVM();
     414          20 :   v8::HandleScope scope(CcTest::isolate());
     415             : 
     416             :   // Check that base class' and subclass' slack tracking do not interfere with
     417             :   // each other.
     418             :   // In this test we first create enough base class instances to complete
     419             :   // the slack tracking and then proceed creating subclass instances.
     420             : 
     421             :   const char* source =
     422             :       "'use strict';"
     423             :       "class A {"
     424             :       "  constructor(...args) {"
     425             :       "    this.aa = 42;"
     426             :       "    this.ad = 4.2;"
     427             :       "    this.ao = this;"
     428             :       "  }"
     429             :       "};"
     430             :       "class B extends A {"
     431             :       "  constructor(...args) {"
     432             :       "    super(...args);"
     433             :       "    this.ba = 142;"
     434             :       "    this.bd = 14.2;"
     435             :       "    this.bo = this;"
     436             :       "  }"
     437             :       "};";
     438             :   CompileRun(source);
     439             : 
     440          10 :   Handle<JSFunction> a_func = GetLexical<JSFunction>("A");
     441          10 :   Handle<JSFunction> b_func = GetLexical<JSFunction>("B");
     442             : 
     443             :   // Zero instances were created so far.
     444          10 :   CHECK(!a_func->has_initial_map());
     445          10 :   CHECK(!b_func->has_initial_map());
     446             : 
     447             :   v8::Local<v8::Script> new_A_script = v8_compile("new A();");
     448             :   v8::Local<v8::Script> new_B_script = v8_compile("new B();");
     449             : 
     450             :   Handle<JSObject> a_obj = RunI<JSObject>(new_A_script);
     451             :   Handle<JSObject> b_obj = RunI<JSObject>(new_B_script);
     452             : 
     453          10 :   CHECK(a_func->has_initial_map());
     454             :   Handle<Map> a_initial_map(a_func->initial_map(), a_func->GetIsolate());
     455             : 
     456          10 :   CHECK(b_func->has_initial_map());
     457             :   Handle<Map> b_initial_map(b_func->initial_map(), a_func->GetIsolate());
     458             : 
     459             :   // One instance of a base class created.
     460          10 :   CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
     461             :            a_initial_map->construction_counter());
     462          10 :   CHECK(a_initial_map->IsInobjectSlackTrackingInProgress());
     463             : 
     464             :   // One instance of a subclass created.
     465          10 :   CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
     466             :            b_initial_map->construction_counter());
     467          10 :   CHECK(b_initial_map->IsInobjectSlackTrackingInProgress());
     468             : 
     469             :   // Create several base class instances to complete the tracking.
     470         130 :   for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
     471          60 :     CHECK(a_initial_map->IsInobjectSlackTrackingInProgress());
     472             :     Handle<JSObject> tmp = RunI<JSObject>(new_A_script);
     473         120 :     CHECK_EQ(a_initial_map->IsInobjectSlackTrackingInProgress(),
     474             :              IsObjectShrinkable(*tmp));
     475             :   }
     476          10 :   CHECK(!a_initial_map->IsInobjectSlackTrackingInProgress());
     477          10 :   CHECK(!IsObjectShrinkable(*a_obj));
     478             : 
     479             :   // No slack left.
     480          10 :   CHECK_EQ(3, a_obj->map()->GetInObjectProperties());
     481             : 
     482             :   // There must be at least some slack.
     483          10 :   CHECK_LT(10, b_obj->map()->GetInObjectProperties());
     484          10 :   CHECK_EQ(Smi::FromInt(42), GetFieldValue(*b_obj, 0));
     485          10 :   CHECK_EQ(4.2, GetDoubleFieldValue(*b_obj, 1));
     486          20 :   CHECK_EQ(*b_obj, GetFieldValue(*b_obj, 2));
     487          10 :   CHECK_EQ(Smi::FromInt(142), GetFieldValue(*b_obj, 3));
     488          10 :   CHECK_EQ(14.2, GetDoubleFieldValue(*b_obj, 4));
     489          20 :   CHECK_EQ(*b_obj, GetFieldValue(*b_obj, 5));
     490          10 :   CHECK(IsObjectShrinkable(*b_obj));
     491             : 
     492             :   // Create several subclass instances to complete the tracking.
     493         130 :   for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
     494          60 :     CHECK(b_initial_map->IsInobjectSlackTrackingInProgress());
     495             :     Handle<JSObject> tmp = RunI<JSObject>(new_B_script);
     496         120 :     CHECK_EQ(b_initial_map->IsInobjectSlackTrackingInProgress(),
     497             :              IsObjectShrinkable(*tmp));
     498             :   }
     499          10 :   CHECK(!b_initial_map->IsInobjectSlackTrackingInProgress());
     500          10 :   CHECK(!IsObjectShrinkable(*b_obj));
     501             : 
     502             :   // No slack left.
     503          10 :   CHECK_EQ(6, b_obj->map()->GetInObjectProperties());
     504          10 : }
     505             : 
     506             : 
     507       26644 : TEST(SubclassBasicNoInlineNew) {
     508           5 :   FLAG_inline_new = false;
     509           5 :   TestSubclassBasic();
     510           5 : }
     511             : 
     512             : 
     513             : // Creates class hierarchy of length matching the |hierarchy_desc| length and
     514             : // with the number of fields at i'th level equal to |hierarchy_desc[i]|.
     515          30 : static void CreateClassHierarchy(const std::vector<int>& hierarchy_desc) {
     516          60 :   std::ostringstream os;
     517          30 :   os << "'use strict';\n\n";
     518             : 
     519          30 :   int n = static_cast<int>(hierarchy_desc.size());
     520        1100 :   for (int cur_class = 0; cur_class < n; cur_class++) {
     521         535 :     os << "class A" << cur_class;
     522         535 :     if (cur_class > 0) {
     523        1010 :       os << " extends A" << (cur_class - 1);
     524             :     }
     525             :     os << " {\n"
     526         535 :           "  constructor(...args) {\n";
     527         535 :     if (cur_class > 0) {
     528         505 :       os << "    super(...args);\n";
     529             :     }
     530        1070 :     int fields_count = hierarchy_desc[cur_class];
     531       24915 :     for (int k = 0; k < fields_count; k++) {
     532       36570 :       os << "    this.f" << cur_class << "_" << k << " = " << k << ";\n";
     533             :     }
     534             :     os << "  }\n"
     535         535 :           "};\n\n";
     536             :   }
     537          30 :   CompileRun(os.str().c_str());
     538          30 : }
     539             : 
     540             : 
     541         535 : static std::string GetClassName(int class_index) {
     542        1070 :   std::ostringstream os;
     543         535 :   os << "A" << class_index;
     544         535 :   return os.str();
     545             : }
     546             : 
     547             : 
     548         535 : static v8::Local<v8::Script> GetNewObjectScript(const std::string& class_name) {
     549        1070 :   std::ostringstream os;
     550         535 :   os << "new " << class_name << "();";
     551        1070 :   return v8_compile(os.str().c_str());
     552             : }
     553             : 
     554             : 
     555             : // Test that in-object slack tracking works as expected for first |n| classes
     556             : // in the hierarchy.
     557             : // This test works only for if the total property count is less than maximum
     558             : // in-object properties count.
     559          30 : static void TestClassHierarchy(const std::vector<int>& hierarchy_desc, int n) {
     560             :   int fields_count = 0;
     561        1080 :   for (int cur_class = 0; cur_class < n; cur_class++) {
     562         525 :     std::string class_name = GetClassName(cur_class);
     563        1050 :     int fields_count_at_current_level = hierarchy_desc[cur_class];
     564         525 :     fields_count += fields_count_at_current_level;
     565             : 
     566             :     // This test is not suitable for in-object properties count overflow case.
     567         525 :     CHECK_LT(fields_count, kMaxInobjectProperties);
     568             : 
     569             :     // Create |class_name| objects and check slack tracking.
     570         525 :     v8::Local<v8::Script> new_script = GetNewObjectScript(class_name);
     571             : 
     572             :     Handle<JSFunction> func = GetLexical<JSFunction>(class_name);
     573             : 
     574             :     Handle<JSObject> obj = RunI<JSObject>(new_script);
     575             : 
     576         525 :     CHECK(func->has_initial_map());
     577             :     Handle<Map> initial_map(func->initial_map(), func->GetIsolate());
     578             : 
     579             :     // If the object is slow-mode already, bail out.
     580         525 :     if (obj->map()->is_dictionary_map()) continue;
     581             : 
     582             :     // There must be at least some slack.
     583         525 :     CHECK_LT(fields_count, obj->map()->GetInObjectProperties());
     584             : 
     585             :     // One instance was created.
     586         525 :     CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
     587             :              initial_map->construction_counter());
     588         525 :     CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     589             : 
     590             :     // Create several instances to complete the tracking.
     591        5775 :     for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
     592        3150 :       CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     593             :       Handle<JSObject> tmp = RunI<JSObject>(new_script);
     594        6300 :       CHECK_EQ(initial_map->IsInobjectSlackTrackingInProgress(),
     595             :                IsObjectShrinkable(*tmp));
     596        3150 :       if (!initial_map->IsInobjectSlackTrackingInProgress()) {
     597             :         // Turbofan can force completion of in-object slack tracking.
     598             :         break;
     599             :       }
     600        2625 :       CHECK_EQ(Map::kSlackTrackingCounterStart - i - 1,
     601             :                initial_map->construction_counter());
     602             :     }
     603         525 :     CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
     604         525 :     CHECK(!IsObjectShrinkable(*obj));
     605             : 
     606             :     // No slack left.
     607         525 :     CHECK_EQ(fields_count, obj->map()->GetInObjectProperties());
     608             :   }
     609          30 : }
     610             : 
     611             : 
     612          20 : static void TestSubclassChain(const std::vector<int>& hierarchy_desc) {
     613             :   // Avoid eventual completion of in-object slack tracking.
     614          20 :   FLAG_always_opt = false;
     615          20 :   CcTest::InitializeVM();
     616          40 :   v8::HandleScope scope(CcTest::isolate());
     617             : 
     618          20 :   CreateClassHierarchy(hierarchy_desc);
     619          20 :   TestClassHierarchy(hierarchy_desc, static_cast<int>(hierarchy_desc.size()));
     620          20 : }
     621             : 
     622       26644 : TEST(Subclasses) {
     623             :   std::vector<int> hierarchy_desc;
     624          10 :   hierarchy_desc.push_back(50);
     625          10 :   hierarchy_desc.push_back(128);
     626           5 :   TestSubclassChain(hierarchy_desc);
     627           5 : }
     628             : 
     629       26644 : TEST(LongSubclassChain1) {
     630             :   std::vector<int> hierarchy_desc;
     631          75 :   for (int i = 0; i < 7; i++) {
     632          70 :     hierarchy_desc.push_back(i * 10);
     633             :   }
     634           5 :   TestSubclassChain(hierarchy_desc);
     635           5 : }
     636             : 
     637             : 
     638       26644 : TEST(LongSubclassChain2) {
     639             :   std::vector<int> hierarchy_desc;
     640          10 :   hierarchy_desc.push_back(10);
     641         425 :   for (int i = 0; i < 42; i++) {
     642         420 :     hierarchy_desc.push_back(0);
     643             :   }
     644          10 :   hierarchy_desc.push_back(230);
     645           5 :   TestSubclassChain(hierarchy_desc);
     646           5 : }
     647             : 
     648             : 
     649       26644 : TEST(LongSubclassChain3) {
     650             :   std::vector<int> hierarchy_desc;
     651         425 :   for (int i = 0; i < 42; i++) {
     652         420 :     hierarchy_desc.push_back(5);
     653             :   }
     654           5 :   TestSubclassChain(hierarchy_desc);
     655           5 : }
     656             : 
     657             : 
     658       26644 : TEST(InobjectPropetiesCountOverflowInSubclass) {
     659             :   // Avoid eventual completion of in-object slack tracking.
     660           5 :   FLAG_always_opt = false;
     661           5 :   CcTest::InitializeVM();
     662          10 :   v8::HandleScope scope(CcTest::isolate());
     663             : 
     664             :   std::vector<int> hierarchy_desc;
     665             :   const int kNoOverflowCount = 5;
     666          55 :   for (int i = 0; i < kNoOverflowCount; i++) {
     667          50 :     hierarchy_desc.push_back(50);
     668             :   }
     669             :   // In this class we are going to have properties in the backing store.
     670          10 :   hierarchy_desc.push_back(100);
     671             : 
     672           5 :   CreateClassHierarchy(hierarchy_desc);
     673             : 
     674             :   // For the last class in the hierarchy we need different checks.
     675             :   {
     676             :     int cur_class = kNoOverflowCount;
     677           5 :     std::string class_name = GetClassName(cur_class);
     678             : 
     679             :     // Create |class_name| objects and check slack tracking.
     680           5 :     v8::Local<v8::Script> new_script = GetNewObjectScript(class_name);
     681             : 
     682             :     Handle<JSFunction> func = GetLexical<JSFunction>(class_name);
     683             : 
     684             :     Handle<JSObject> obj = RunI<JSObject>(new_script);
     685             : 
     686           5 :     CHECK(func->has_initial_map());
     687             :     Handle<Map> initial_map(func->initial_map(), func->GetIsolate());
     688             : 
     689             :     // There must be no slack left.
     690           5 :     CHECK_EQ(JSObject::kMaxInstanceSize, obj->map()->instance_size());
     691           5 :     CHECK_EQ(kMaxInobjectProperties, obj->map()->GetInObjectProperties());
     692             : 
     693             :     // One instance was created.
     694           5 :     CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
     695             :              initial_map->construction_counter());
     696           5 :     CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     697             : 
     698             :     // Create several instances to complete the tracking.
     699          65 :     for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
     700          30 :       CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     701             :       Handle<JSObject> tmp = RunI<JSObject>(new_script);
     702          30 :       CHECK(!IsObjectShrinkable(*tmp));
     703             :     }
     704           5 :     CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
     705           5 :     CHECK(!IsObjectShrinkable(*obj));
     706             : 
     707             :     // No slack left.
     708           5 :     CHECK_EQ(kMaxInobjectProperties, obj->map()->GetInObjectProperties());
     709             :   }
     710             : 
     711             :   // The other classes in the hierarchy are not affected.
     712           5 :   TestClassHierarchy(hierarchy_desc, kNoOverflowCount);
     713           5 : }
     714             : 
     715          35 : static void CheckExpectedProperties(int expected, std::ostringstream& os) {
     716             :   Handle<HeapObject> obj = Handle<HeapObject>::cast(
     717          35 :       v8::Utils::OpenHandle(*CompileRun(os.str().c_str())));
     718          35 :   CHECK_EQ(expected, obj->map()->GetInObjectProperties());
     719          35 : }
     720             : 
     721       26644 : TEST(ObjectLiteralPropertyBackingStoreSize) {
     722          10 :   v8::HandleScope scope(CcTest::isolate());
     723           5 :   LocalContext env;
     724             : 
     725          10 :   std::ostringstream os;
     726             : 
     727             :   // An index key does not require space in the property backing store.
     728             :   os << "(function() {\n"
     729             :         "  function f() {\n"
     730             :         "    var o = {\n"
     731             :         "      '-1': 42,\n"  // Allocate for non-index key.
     732             :         "      1: 42,\n"     // Do not allocate for index key.
     733             :         "      '2': 42\n"    // Do not allocate for index key.
     734             :         "    };\n"
     735             :         "    return o;\n"
     736             :         "  }\n"
     737             :         "\n"
     738             :         "  return f();\n"
     739           5 :         "} )();";
     740           5 :   CheckExpectedProperties(1, os);
     741             : 
     742             :   // Avoid over-/under-allocation for computed property names.
     743             :   os << "(function() {\n"
     744             :         "  'use strict';\n"
     745             :         "  function f(x) {\n"
     746             :         "    var o = {\n"
     747             :         "      1: 42,\n"    // Do not allocate for index key.
     748             :         "      '2': 42,\n"  // Do not allocate for index key.
     749             :         "      [x]: 42,\n"  // Allocate for property with computed name.
     750             :         "      3: 42,\n"    // Do not allocate for index key.
     751             :         "      '4': 42\n"   // Do not allocate for index key.
     752             :         "    };\n"
     753             :         "    return o;\n"
     754             :         "  }\n"
     755             :         "\n"
     756             :         "  var x = 'hello'\n"
     757             :         "\n"
     758             :         "  return f(x);\n"
     759           5 :         "} )();";
     760           5 :   CheckExpectedProperties(1, os);
     761             : 
     762             :   // Conversion to index key.
     763             :   os << "(function() {\n"
     764             :         "  function f(x) {\n"
     765             :         "    var o = {\n"
     766             :         "      1: 42,\n"       // Do not allocate for index key.
     767             :         "      '2': 42,\n"     // Do not allocate for index key.
     768             :         "      [x]: 42,\n"     // Allocate for property with computed name.
     769             :         "      3: 42,\n"       // Do not allocate for index key.
     770             :         "      get 12() {}\n"  // Do not allocate for index key.
     771             :         "    };\n"
     772             :         "    return o;\n"
     773             :         "  }\n"
     774             :         "\n"
     775             :         "  var x = 'hello'\n"
     776             :         "\n"
     777             :         "  return f(x);\n"
     778           5 :         "} )();";
     779           5 :   CheckExpectedProperties(1, os);
     780             : 
     781             :   os << "(function() {\n"
     782             :         "  function f() {\n"
     783             :         "    var o = {};\n"
     784             :         "    return o;\n"
     785             :         "  }\n"
     786             :         "\n"
     787             :         "  return f();\n"
     788           5 :         "} )();";
     789             :   // Empty objects have slack for 4 properties.
     790           5 :   CheckExpectedProperties(4, os);
     791             : 
     792             :   os << "(function() {\n"
     793             :         "  function f(x) {\n"
     794             :         "    var o = {\n"
     795             :         "      a: 42,\n"    // Allocate for constant property.
     796             :         "      [x]: 42,\n"  // Allocate for property with computed name.
     797             :         "      b: 42\n"     // Allocate for constant property.
     798             :         "    };\n"
     799             :         "    return o;\n"
     800             :         "  }\n"
     801             :         "\n"
     802             :         "  var x = 'hello'\n"
     803             :         "\n"
     804             :         "  return f(x);\n"
     805           5 :         "} )();";
     806           5 :   CheckExpectedProperties(3, os);
     807             : 
     808             :   os << "(function() {\n"
     809             :         "  function f(x) {\n"
     810             :         "    var o = {\n"
     811             :         "      a: 42,\n"          // Allocate for constant property.
     812             :         "      __proto__: 42,\n"  // Do not allocate for __proto__.
     813             :         "      [x]: 42\n"         // Allocate for property with computed name.
     814             :         "    };\n"
     815             :         "    return o;\n"
     816             :         "  }\n"
     817             :         "\n"
     818             :         "  var x = 'hello'\n"
     819             :         "\n"
     820             :         "  return f(x);\n"
     821           5 :         "} )();";
     822             :   // __proto__ is not allocated in the backing store.
     823           5 :   CheckExpectedProperties(2, os);
     824             : 
     825             :   os << "(function() {\n"
     826             :         "  function f(x) {\n"
     827             :         "    var o = {\n"
     828             :         "      a: 42,\n"         // Allocate for constant property.
     829             :         "      [x]: 42,\n"       // Allocate for property with computed name.
     830             :         "      __proto__: 42\n"  // Do not allocate for __proto__.
     831             :         "    };\n"
     832             :         "    return o;\n"
     833             :         "  }\n"
     834             :         "\n"
     835             :         "  var x = 'hello'\n"
     836             :         "\n"
     837             :         "  return f(x);\n"
     838           5 :         "} )();";
     839           5 :   CheckExpectedProperties(2, os);
     840           5 : }
     841             : 
     842       26644 : TEST(SlowModeSubclass) {
     843             :   // Avoid eventual completion of in-object slack tracking.
     844           5 :   FLAG_always_opt = false;
     845           5 :   CcTest::InitializeVM();
     846          10 :   v8::HandleScope scope(CcTest::isolate());
     847             : 
     848             :   std::vector<int> hierarchy_desc;
     849             :   const int kNoOverflowCount = 5;
     850          55 :   for (int i = 0; i < kNoOverflowCount; i++) {
     851          50 :     hierarchy_desc.push_back(50);
     852             :   }
     853             :   // This class should go dictionary mode.
     854          10 :   hierarchy_desc.push_back(1000);
     855             : 
     856           5 :   CreateClassHierarchy(hierarchy_desc);
     857             : 
     858             :   // For the last class in the hierarchy we need different checks.
     859             :   {
     860             :     int cur_class = kNoOverflowCount;
     861           5 :     std::string class_name = GetClassName(cur_class);
     862             : 
     863             :     // Create |class_name| objects and check slack tracking.
     864           5 :     v8::Local<v8::Script> new_script = GetNewObjectScript(class_name);
     865             : 
     866             :     Handle<JSFunction> func = GetLexical<JSFunction>(class_name);
     867             : 
     868             :     Handle<JSObject> obj = RunI<JSObject>(new_script);
     869             : 
     870           5 :     CHECK(func->has_initial_map());
     871             :     Handle<Map> initial_map(func->initial_map(), func->GetIsolate());
     872             : 
     873             :     // Object should go dictionary mode.
     874           5 :     CHECK_EQ(JSObject::kHeaderSize, obj->map()->instance_size());
     875           5 :     CHECK(obj->map()->is_dictionary_map());
     876             : 
     877             :     // One instance was created.
     878           5 :     CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
     879             :              initial_map->construction_counter());
     880           5 :     CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     881             : 
     882             :     // Create several instances to complete the tracking.
     883          65 :     for (int i = 1; i < Map::kGenerousAllocationCount; i++) {
     884          30 :       CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     885             :       Handle<JSObject> tmp = RunI<JSObject>(new_script);
     886          30 :       CHECK(!IsObjectShrinkable(*tmp));
     887             :     }
     888           5 :     CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
     889           5 :     CHECK(!IsObjectShrinkable(*obj));
     890             : 
     891             :     // Object should stay in dictionary mode.
     892           5 :     CHECK_EQ(JSObject::kHeaderSize, obj->map()->instance_size());
     893           5 :     CHECK(obj->map()->is_dictionary_map());
     894             :   }
     895             : 
     896             :   // The other classes in the hierarchy are not affected.
     897           5 :   TestClassHierarchy(hierarchy_desc, kNoOverflowCount);
     898           5 : }
     899             : 
     900             : 
     901         390 : static void TestSubclassBuiltin(const char* subclass_name,
     902             :                                 InstanceType instance_type,
     903             :                                 const char* builtin_name,
     904             :                                 const char* ctor_arguments = "",
     905             :                                 int builtin_properties_count = 0) {
     906             :   {
     907         780 :     std::ostringstream os;
     908             :     os << "'use strict';\n"
     909             :           "class "
     910         780 :        << subclass_name << " extends " << builtin_name
     911             :        << " {\n"
     912             :           "  constructor(...args) {\n"
     913             :           "    super(...args);\n"
     914             :           "    this.a = 42;\n"
     915             :           "    this.d = 4.2;\n"
     916             :           "    this.o = this;\n"
     917             :           "  }\n"
     918         390 :           "};\n";
     919         390 :     CompileRun(os.str().c_str());
     920             :   }
     921             : 
     922         390 :   Handle<JSFunction> func = GetLexical<JSFunction>(subclass_name);
     923             : 
     924             :   // Zero instances were created so far.
     925         390 :   CHECK(!func->has_initial_map());
     926             : 
     927             :   v8::Local<v8::Script> new_script;
     928             :   {
     929         780 :     std::ostringstream os;
     930         780 :     os << "new " << subclass_name << "(" << ctor_arguments << ");";
     931         390 :     new_script = v8_compile(os.str().c_str());
     932             :   }
     933             : 
     934             :   RunI<JSObject>(new_script);
     935             : 
     936         390 :   CHECK(func->has_initial_map());
     937             :   Handle<Map> initial_map(func->initial_map(), func->GetIsolate());
     938             : 
     939         390 :   CHECK_EQ(instance_type, initial_map->instance_type());
     940             : 
     941             :   // One instance of a subclass created.
     942         390 :   CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
     943             :            initial_map->construction_counter());
     944         390 :   CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     945             : 
     946             :   // Create two instances in order to ensure that |obj|.o is a data field
     947             :   // in case of Function subclassing.
     948             :   Handle<JSObject> obj = RunI<JSObject>(new_script);
     949             : 
     950             :   // Two instances of a subclass created.
     951         390 :   CHECK_EQ(Map::kSlackTrackingCounterStart - 2,
     952             :            initial_map->construction_counter());
     953         390 :   CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     954             : 
     955             :   // There must be at least some slack.
     956         390 :   CHECK_LT(builtin_properties_count + 5, obj->map()->GetInObjectProperties());
     957         390 :   CHECK_EQ(Smi::FromInt(42), GetFieldValue(*obj, builtin_properties_count + 0));
     958         780 :   CHECK_EQ(4.2, GetDoubleFieldValue(*obj, builtin_properties_count + 1));
     959        1170 :   CHECK_EQ(*obj, GetFieldValue(*obj, builtin_properties_count + 2));
     960         390 :   CHECK(IsObjectShrinkable(*obj));
     961             : 
     962             :   // Create several subclass instances to complete the tracking.
     963        4290 :   for (int i = 2; i < Map::kGenerousAllocationCount; i++) {
     964        1950 :     CHECK(initial_map->IsInobjectSlackTrackingInProgress());
     965             :     Handle<JSObject> tmp = RunI<JSObject>(new_script);
     966        3900 :     CHECK_EQ(initial_map->IsInobjectSlackTrackingInProgress(),
     967             :              IsObjectShrinkable(*tmp));
     968             :   }
     969         390 :   CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
     970         390 :   CHECK(!IsObjectShrinkable(*obj));
     971             : 
     972             :   // No slack left.
     973         390 :   CHECK_EQ(builtin_properties_count + 3, obj->map()->GetInObjectProperties());
     974             : 
     975         390 :   CHECK_EQ(instance_type, obj->map()->instance_type());
     976         390 : }
     977             : 
     978             : 
     979       26649 : TEST(SubclassObjectBuiltin) {
     980             :   // Avoid eventual completion of in-object slack tracking.
     981          10 :   FLAG_always_opt = false;
     982          10 :   CcTest::InitializeVM();
     983          20 :   v8::HandleScope scope(CcTest::isolate());
     984             : 
     985          10 :   TestSubclassBuiltin("A1", JS_OBJECT_TYPE, "Object", "true");
     986          10 :   TestSubclassBuiltin("A2", JS_OBJECT_TYPE, "Object", "42");
     987          10 :   TestSubclassBuiltin("A3", JS_OBJECT_TYPE, "Object", "'some string'");
     988          10 : }
     989             : 
     990             : 
     991       26644 : TEST(SubclassObjectBuiltinNoInlineNew) {
     992           5 :   FLAG_inline_new = false;
     993           5 :   TestSubclassObjectBuiltin();
     994           5 : }
     995             : 
     996             : 
     997       26649 : TEST(SubclassFunctionBuiltin) {
     998             :   // Avoid eventual completion of in-object slack tracking.
     999          10 :   FLAG_always_opt = false;
    1000          10 :   CcTest::InitializeVM();
    1001          20 :   v8::HandleScope scope(CcTest::isolate());
    1002             : 
    1003          10 :   TestSubclassBuiltin("A1", JS_FUNCTION_TYPE, "Function", "'return 153;'");
    1004          10 :   TestSubclassBuiltin("A2", JS_FUNCTION_TYPE, "Function", "'this.a = 44;'");
    1005          10 : }
    1006             : 
    1007             : 
    1008       26644 : TEST(SubclassFunctionBuiltinNoInlineNew) {
    1009           5 :   FLAG_inline_new = false;
    1010           5 :   TestSubclassFunctionBuiltin();
    1011           5 : }
    1012             : 
    1013             : 
    1014       26649 : TEST(SubclassBooleanBuiltin) {
    1015             :   // Avoid eventual completion of in-object slack tracking.
    1016          10 :   FLAG_always_opt = false;
    1017          10 :   CcTest::InitializeVM();
    1018          20 :   v8::HandleScope scope(CcTest::isolate());
    1019             : 
    1020          10 :   TestSubclassBuiltin("A1", JS_VALUE_TYPE, "Boolean", "true");
    1021          10 :   TestSubclassBuiltin("A2", JS_VALUE_TYPE, "Boolean", "false");
    1022          10 : }
    1023             : 
    1024             : 
    1025       26644 : TEST(SubclassBooleanBuiltinNoInlineNew) {
    1026           5 :   FLAG_inline_new = false;
    1027           5 :   TestSubclassBooleanBuiltin();
    1028           5 : }
    1029             : 
    1030             : 
    1031       26649 : TEST(SubclassErrorBuiltin) {
    1032             :   // Avoid eventual completion of in-object slack tracking.
    1033          10 :   FLAG_always_opt = false;
    1034          10 :   CcTest::InitializeVM();
    1035          20 :   v8::HandleScope scope(CcTest::isolate());
    1036             : 
    1037             :   const int first_field = 2;
    1038          10 :   TestSubclassBuiltin("A1", JS_ERROR_TYPE, "Error", "'err'", first_field);
    1039          10 :   TestSubclassBuiltin("A2", JS_ERROR_TYPE, "EvalError", "'err'", first_field);
    1040          10 :   TestSubclassBuiltin("A3", JS_ERROR_TYPE, "RangeError", "'err'", first_field);
    1041             :   TestSubclassBuiltin("A4", JS_ERROR_TYPE, "ReferenceError", "'err'",
    1042          10 :                       first_field);
    1043          10 :   TestSubclassBuiltin("A5", JS_ERROR_TYPE, "SyntaxError", "'err'", first_field);
    1044          10 :   TestSubclassBuiltin("A6", JS_ERROR_TYPE, "TypeError", "'err'", first_field);
    1045          10 :   TestSubclassBuiltin("A7", JS_ERROR_TYPE, "URIError", "'err'", first_field);
    1046          10 : }
    1047             : 
    1048             : 
    1049       26644 : TEST(SubclassErrorBuiltinNoInlineNew) {
    1050           5 :   FLAG_inline_new = false;
    1051           5 :   TestSubclassErrorBuiltin();
    1052           5 : }
    1053             : 
    1054             : 
    1055       26649 : TEST(SubclassNumberBuiltin) {
    1056             :   // Avoid eventual completion of in-object slack tracking.
    1057          10 :   FLAG_always_opt = false;
    1058          10 :   CcTest::InitializeVM();
    1059          20 :   v8::HandleScope scope(CcTest::isolate());
    1060             : 
    1061          10 :   TestSubclassBuiltin("A1", JS_VALUE_TYPE, "Number", "42");
    1062          10 :   TestSubclassBuiltin("A2", JS_VALUE_TYPE, "Number", "4.2");
    1063          10 : }
    1064             : 
    1065             : 
    1066       26644 : TEST(SubclassNumberBuiltinNoInlineNew) {
    1067           5 :   FLAG_inline_new = false;
    1068           5 :   TestSubclassNumberBuiltin();
    1069           5 : }
    1070             : 
    1071             : 
    1072       26649 : TEST(SubclassDateBuiltin) {
    1073             :   // Avoid eventual completion of in-object slack tracking.
    1074          10 :   FLAG_always_opt = false;
    1075          10 :   CcTest::InitializeVM();
    1076          20 :   v8::HandleScope scope(CcTest::isolate());
    1077             : 
    1078          10 :   TestSubclassBuiltin("A1", JS_DATE_TYPE, "Date", "123456789");
    1079          10 : }
    1080             : 
    1081             : 
    1082       26644 : TEST(SubclassDateBuiltinNoInlineNew) {
    1083           5 :   FLAG_inline_new = false;
    1084           5 :   TestSubclassDateBuiltin();
    1085           5 : }
    1086             : 
    1087             : 
    1088       26649 : TEST(SubclassStringBuiltin) {
    1089             :   // Avoid eventual completion of in-object slack tracking.
    1090          10 :   FLAG_always_opt = false;
    1091          10 :   CcTest::InitializeVM();
    1092          20 :   v8::HandleScope scope(CcTest::isolate());
    1093             : 
    1094          10 :   TestSubclassBuiltin("A1", JS_VALUE_TYPE, "String", "'some string'");
    1095          10 :   TestSubclassBuiltin("A2", JS_VALUE_TYPE, "String", "");
    1096          10 : }
    1097             : 
    1098             : 
    1099       26644 : TEST(SubclassStringBuiltinNoInlineNew) {
    1100           5 :   FLAG_inline_new = false;
    1101           5 :   TestSubclassStringBuiltin();
    1102           5 : }
    1103             : 
    1104             : 
    1105       26649 : TEST(SubclassRegExpBuiltin) {
    1106             :   // Avoid eventual completion of in-object slack tracking.
    1107          10 :   FLAG_always_opt = false;
    1108          10 :   CcTest::InitializeVM();
    1109          20 :   v8::HandleScope scope(CcTest::isolate());
    1110             : 
    1111             :   const int first_field = 1;
    1112             :   TestSubclassBuiltin("A1", JS_REGEXP_TYPE, "RegExp", "'o(..)h', 'g'",
    1113          10 :                       first_field);
    1114          10 : }
    1115             : 
    1116             : 
    1117       26644 : TEST(SubclassRegExpBuiltinNoInlineNew) {
    1118           5 :   FLAG_inline_new = false;
    1119           5 :   TestSubclassRegExpBuiltin();
    1120           5 : }
    1121             : 
    1122             : 
    1123       26649 : TEST(SubclassArrayBuiltin) {
    1124             :   // Avoid eventual completion of in-object slack tracking.
    1125          10 :   FLAG_always_opt = false;
    1126          10 :   CcTest::InitializeVM();
    1127          20 :   v8::HandleScope scope(CcTest::isolate());
    1128             : 
    1129          10 :   TestSubclassBuiltin("A1", JS_ARRAY_TYPE, "Array", "42");
    1130          10 : }
    1131             : 
    1132             : 
    1133       26644 : TEST(SubclassArrayBuiltinNoInlineNew) {
    1134           5 :   FLAG_inline_new = false;
    1135           5 :   TestSubclassArrayBuiltin();
    1136           5 : }
    1137             : 
    1138             : 
    1139       26649 : TEST(SubclassTypedArrayBuiltin) {
    1140             :   // Avoid eventual completion of in-object slack tracking.
    1141          10 :   FLAG_always_opt = false;
    1142          10 :   CcTest::InitializeVM();
    1143          20 :   v8::HandleScope scope(CcTest::isolate());
    1144             : 
    1145             : #define TYPED_ARRAY_TEST(Type, type, TYPE, elementType) \
    1146             :   TestSubclassBuiltin("A" #Type, JS_TYPED_ARRAY_TYPE, #Type "Array", "42");
    1147             : 
    1148          10 :   TYPED_ARRAYS(TYPED_ARRAY_TEST)
    1149             : 
    1150             : #undef TYPED_ARRAY_TEST
    1151          10 : }
    1152             : 
    1153             : 
    1154       26644 : TEST(SubclassTypedArrayBuiltinNoInlineNew) {
    1155           5 :   FLAG_inline_new = false;
    1156           5 :   TestSubclassTypedArrayBuiltin();
    1157           5 : }
    1158             : 
    1159             : 
    1160       26649 : TEST(SubclassCollectionBuiltin) {
    1161             :   // Avoid eventual completion of in-object slack tracking.
    1162          10 :   FLAG_always_opt = false;
    1163          10 :   CcTest::InitializeVM();
    1164          20 :   v8::HandleScope scope(CcTest::isolate());
    1165             : 
    1166          10 :   TestSubclassBuiltin("A1", JS_SET_TYPE, "Set", "");
    1167          10 :   TestSubclassBuiltin("A2", JS_MAP_TYPE, "Map", "");
    1168          10 :   TestSubclassBuiltin("A3", JS_WEAK_SET_TYPE, "WeakSet", "");
    1169          10 :   TestSubclassBuiltin("A4", JS_WEAK_MAP_TYPE, "WeakMap", "");
    1170          10 : }
    1171             : 
    1172             : 
    1173       26644 : TEST(SubclassCollectionBuiltinNoInlineNew) {
    1174           5 :   FLAG_inline_new = false;
    1175           5 :   TestSubclassCollectionBuiltin();
    1176           5 : }
    1177             : 
    1178             : 
    1179       26649 : TEST(SubclassArrayBufferBuiltin) {
    1180             :   // Avoid eventual completion of in-object slack tracking.
    1181          10 :   FLAG_always_opt = false;
    1182          10 :   CcTest::InitializeVM();
    1183          20 :   v8::HandleScope scope(CcTest::isolate());
    1184             : 
    1185          10 :   TestSubclassBuiltin("A1", JS_ARRAY_BUFFER_TYPE, "ArrayBuffer", "42");
    1186             :   TestSubclassBuiltin("A2", JS_DATA_VIEW_TYPE, "DataView",
    1187          10 :                       "new ArrayBuffer(42)");
    1188          10 : }
    1189             : 
    1190             : 
    1191       26644 : TEST(SubclassArrayBufferBuiltinNoInlineNew) {
    1192           5 :   FLAG_inline_new = false;
    1193           5 :   TestSubclassArrayBufferBuiltin();
    1194           5 : }
    1195             : 
    1196             : 
    1197       26649 : TEST(SubclassPromiseBuiltin) {
    1198             :   // Avoid eventual completion of in-object slack tracking.
    1199          10 :   FLAG_always_opt = false;
    1200          10 :   CcTest::InitializeVM();
    1201          20 :   v8::HandleScope scope(CcTest::isolate());
    1202             : 
    1203             :   TestSubclassBuiltin("A1", JS_PROMISE_TYPE, "Promise",
    1204          10 :                       "function(resolve, reject) { resolve('ok'); }");
    1205          10 : }
    1206             : 
    1207             : 
    1208       26644 : TEST(SubclassPromiseBuiltinNoInlineNew) {
    1209           5 :   FLAG_inline_new = false;
    1210           5 :   TestSubclassPromiseBuiltin();
    1211           5 : }
    1212             : 
    1213       26644 : TEST(SubclassTranspiledClassHierarchy) {
    1214           5 :   CcTest::InitializeVM();
    1215          10 :   v8::HandleScope scope(CcTest::isolate());
    1216             : 
    1217             :   CompileRun(
    1218             :       "Object.setPrototypeOf(B, A);\n"
    1219             :       "function A() {\n"
    1220             :       "  this.a0 = 0;\n"
    1221             :       "  this.a1 = 1;\n"
    1222             :       "  this.a2 = 1;\n"
    1223             :       "  this.a3 = 1;\n"
    1224             :       "  this.a4 = 1;\n"
    1225             :       "  this.a5 = 1;\n"
    1226             :       "  this.a6 = 1;\n"
    1227             :       "  this.a7 = 1;\n"
    1228             :       "  this.a8 = 1;\n"
    1229             :       "  this.a9 = 1;\n"
    1230             :       "  this.a10 = 1;\n"
    1231             :       "  this.a11 = 1;\n"
    1232             :       "  this.a12 = 1;\n"
    1233             :       "  this.a13 = 1;\n"
    1234             :       "  this.a14 = 1;\n"
    1235             :       "  this.a15 = 1;\n"
    1236             :       "  this.a16 = 1;\n"
    1237             :       "  this.a17 = 1;\n"
    1238             :       "  this.a18 = 1;\n"
    1239             :       "  this.a19 = 1;\n"
    1240             :       "};\n"
    1241             :       "function B() {\n"
    1242             :       "  A.call(this);\n"
    1243             :       "  this.b = 1;\n"
    1244             :       "};\n");
    1245             : 
    1246           5 :   Handle<JSFunction> func = GetGlobal<JSFunction>("B");
    1247             : 
    1248             :   // Zero instances have been created so far.
    1249           5 :   CHECK(!func->has_initial_map());
    1250             : 
    1251             :   v8::Local<v8::Script> new_script = v8_compile("new B()");
    1252             : 
    1253             :   RunI<JSObject>(new_script);
    1254             : 
    1255           5 :   CHECK(func->has_initial_map());
    1256             :   Handle<Map> initial_map(func->initial_map(), func->GetIsolate());
    1257             : 
    1258           5 :   CHECK_EQ(JS_OBJECT_TYPE, initial_map->instance_type());
    1259             : 
    1260             :   // One instance of a subclass created.
    1261           5 :   CHECK_EQ(Map::kSlackTrackingCounterStart - 1,
    1262             :            initial_map->construction_counter());
    1263           5 :   CHECK(initial_map->IsInobjectSlackTrackingInProgress());
    1264             : 
    1265             :   // Create two instances in order to ensure that |obj|.o is a data field
    1266             :   // in case of Function subclassing.
    1267             :   Handle<JSObject> obj = RunI<JSObject>(new_script);
    1268             : 
    1269             :   // Two instances of a subclass created.
    1270           5 :   CHECK_EQ(Map::kSlackTrackingCounterStart - 2,
    1271             :            initial_map->construction_counter());
    1272           5 :   CHECK(initial_map->IsInobjectSlackTrackingInProgress());
    1273           5 :   CHECK(IsObjectShrinkable(*obj));
    1274             : 
    1275             :   // Create several subclass instances to complete the tracking.
    1276          55 :   for (int i = 2; i < Map::kGenerousAllocationCount; i++) {
    1277          25 :     CHECK(initial_map->IsInobjectSlackTrackingInProgress());
    1278             :     Handle<JSObject> tmp = RunI<JSObject>(new_script);
    1279          50 :     CHECK_EQ(initial_map->IsInobjectSlackTrackingInProgress(),
    1280             :              IsObjectShrinkable(*tmp));
    1281             :   }
    1282           5 :   CHECK(!initial_map->IsInobjectSlackTrackingInProgress());
    1283           5 :   CHECK(!IsObjectShrinkable(*obj));
    1284             : 
    1285             :   // No slack left.
    1286           5 :   CHECK_EQ(21, obj->map()->GetInObjectProperties());
    1287           5 :   CHECK_EQ(JS_OBJECT_TYPE, obj->map()->instance_type());
    1288           5 : }
    1289             : 
    1290       26644 : TEST(Regress8853_ClassConstructor) {
    1291           5 :   CcTest::InitializeVM();
    1292          10 :   v8::HandleScope scope(CcTest::isolate());
    1293             : 
    1294             :   // For classes without any this.prop assignments in their
    1295             :   // constructors we start out with 10 inobject properties.
    1296           5 :   Handle<JSObject> obj = CompileRunI<JSObject>("new (class {});\n");
    1297           5 :   CHECK(obj->map()->IsInobjectSlackTrackingInProgress());
    1298           5 :   CHECK(IsObjectShrinkable(*obj));
    1299           5 :   CHECK_EQ(10, obj->map()->GetInObjectProperties());
    1300             : 
    1301             :   // For classes with N explicit this.prop assignments in their
    1302             :   // constructors we start out with N+8 inobject properties.
    1303             :   obj = CompileRunI<JSObject>(
    1304             :       "new (class {\n"
    1305             :       "  constructor() {\n"
    1306             :       "    this.x = 1;\n"
    1307             :       "    this.y = 2;\n"
    1308             :       "    this.z = 3;\n"
    1309             :       "  }\n"
    1310           5 :       "});\n");
    1311           5 :   CHECK(obj->map()->IsInobjectSlackTrackingInProgress());
    1312           5 :   CHECK(IsObjectShrinkable(*obj));
    1313           5 :   CHECK_EQ(3 + 8, obj->map()->GetInObjectProperties());
    1314           5 : }
    1315             : 
    1316       26644 : TEST(Regress8853_ClassHierarchy) {
    1317           5 :   CcTest::InitializeVM();
    1318          10 :   v8::HandleScope scope(CcTest::isolate());
    1319             : 
    1320             :   // For class hierarchies without any this.prop assignments in their
    1321             :   // constructors we reserve 2 inobject properties per constructor plus
    1322             :   // 8 inobject properties slack on top.
    1323           5 :   std::string base = "(class {})";
    1324          95 :   for (int i = 1; i < 10; ++i) {
    1325          90 :     std::string script = "new " + base + ";\n";
    1326          45 :     Handle<JSObject> obj = CompileRunI<JSObject>(script.c_str());
    1327          45 :     CHECK(obj->map()->IsInobjectSlackTrackingInProgress());
    1328          45 :     CHECK(IsObjectShrinkable(*obj));
    1329          45 :     CHECK_EQ(8 + 2 * i, obj->map()->GetInObjectProperties());
    1330         135 :     base = "(class extends " + base + " {})";
    1331             :   }
    1332           5 : }
    1333             : 
    1334       26644 : TEST(Regress8853_FunctionConstructor) {
    1335           5 :   CcTest::InitializeVM();
    1336          10 :   v8::HandleScope scope(CcTest::isolate());
    1337             : 
    1338             :   // For constructor functions without any this.prop assignments in
    1339             :   // them we start out with 10 inobject properties.
    1340           5 :   Handle<JSObject> obj = CompileRunI<JSObject>("new (function() {});\n");
    1341           5 :   CHECK(obj->map()->IsInobjectSlackTrackingInProgress());
    1342           5 :   CHECK(IsObjectShrinkable(*obj));
    1343           5 :   CHECK_EQ(10, obj->map()->GetInObjectProperties());
    1344             : 
    1345             :   // For constructor functions with N explicit this.prop assignments
    1346             :   // in them we start out with N+8 inobject properties.
    1347             :   obj = CompileRunI<JSObject>(
    1348             :       "new (function() {\n"
    1349             :       "  this.a = 1;\n"
    1350             :       "  this.b = 2;\n"
    1351             :       "  this.c = 3;\n"
    1352             :       "  this.d = 3;\n"
    1353             :       "  this.c = 3;\n"
    1354             :       "  this.f = 3;\n"
    1355           5 :       "});\n");
    1356           5 :   CHECK(obj->map()->IsInobjectSlackTrackingInProgress());
    1357           5 :   CHECK(IsObjectShrinkable(*obj));
    1358           5 :   CHECK_EQ(6 + 8, obj->map()->GetInObjectProperties());
    1359           5 : }
    1360             : 
    1361       26644 : TEST(InstanceFieldsArePropertiesDefaultConstructorLazy) {
    1362           5 :   CcTest::InitializeVM();
    1363          10 :   v8::HandleScope scope(CcTest::isolate());
    1364             : 
    1365             :   Handle<JSObject> obj = CompileRunI<JSObject>(
    1366             :       "new (class {\n"
    1367             :       "  x00 = null;\n"
    1368             :       "  x01 = null;\n"
    1369             :       "  x02 = null;\n"
    1370             :       "  x03 = null;\n"
    1371             :       "  x04 = null;\n"
    1372             :       "  x05 = null;\n"
    1373             :       "  x06 = null;\n"
    1374             :       "  x07 = null;\n"
    1375             :       "  x08 = null;\n"
    1376             :       "  x09 = null;\n"
    1377             :       "  x10 = null;\n"
    1378           5 :       "});\n");
    1379           5 :   CHECK_EQ(11 + 8, obj->map()->GetInObjectProperties());
    1380           5 : }
    1381             : 
    1382       26644 : TEST(InstanceFieldsArePropertiesFieldsAndConstructorLazy) {
    1383           5 :   CcTest::InitializeVM();
    1384          10 :   v8::HandleScope scope(CcTest::isolate());
    1385             : 
    1386             :   Handle<JSObject> obj = CompileRunI<JSObject>(
    1387             :       "new (class {\n"
    1388             :       "  x00 = null;\n"
    1389             :       "  x01 = null;\n"
    1390             :       "  x02 = null;\n"
    1391             :       "  x03 = null;\n"
    1392             :       "  x04 = null;\n"
    1393             :       "  x05 = null;\n"
    1394             :       "  x06 = null;\n"
    1395             :       "  x07 = null;\n"
    1396             :       "  x08 = null;\n"
    1397             :       "  x09 = null;\n"
    1398             :       "  x10 = null;\n"
    1399             :       "  constructor() {\n"
    1400             :       "    this.x11 = null;\n"
    1401             :       "    this.x12 = null;\n"
    1402             :       "    this.x12 = null;\n"
    1403             :       "    this.x14 = null;\n"
    1404             :       "    this.x15 = null;\n"
    1405             :       "    this.x16 = null;\n"
    1406             :       "    this.x17 = null;\n"
    1407             :       "    this.x18 = null;\n"
    1408             :       "    this.x19 = null;\n"
    1409             :       "    this.x20 = null;\n"
    1410             :       "  }\n"
    1411           5 :       "});\n");
    1412           5 :   CHECK_EQ(21 + 8, obj->map()->GetInObjectProperties());
    1413           5 : }
    1414             : 
    1415       26644 : TEST(InstanceFieldsArePropertiesDefaultConstructorEager) {
    1416           5 :   i::FLAG_lazy = false;
    1417           5 :   CcTest::InitializeVM();
    1418          10 :   v8::HandleScope scope(CcTest::isolate());
    1419             : 
    1420             :   Handle<JSObject> obj = CompileRunI<JSObject>(
    1421             :       "new (class {\n"
    1422             :       "  x00 = null;\n"
    1423             :       "  x01 = null;\n"
    1424             :       "  x02 = null;\n"
    1425             :       "  x03 = null;\n"
    1426             :       "  x04 = null;\n"
    1427             :       "  x05 = null;\n"
    1428             :       "  x06 = null;\n"
    1429             :       "  x07 = null;\n"
    1430             :       "  x08 = null;\n"
    1431             :       "  x09 = null;\n"
    1432             :       "  x10 = null;\n"
    1433           5 :       "});\n");
    1434           5 :   CHECK_EQ(11 + 8, obj->map()->GetInObjectProperties());
    1435           5 : }
    1436             : 
    1437       26644 : TEST(InstanceFieldsArePropertiesFieldsAndConstructorEager) {
    1438           5 :   i::FLAG_lazy = false;
    1439           5 :   CcTest::InitializeVM();
    1440          10 :   v8::HandleScope scope(CcTest::isolate());
    1441             : 
    1442             :   Handle<JSObject> obj = CompileRunI<JSObject>(
    1443             :       "new (class {\n"
    1444             :       "  x00 = null;\n"
    1445             :       "  x01 = null;\n"
    1446             :       "  x02 = null;\n"
    1447             :       "  x03 = null;\n"
    1448             :       "  x04 = null;\n"
    1449             :       "  x05 = null;\n"
    1450             :       "  x06 = null;\n"
    1451             :       "  x07 = null;\n"
    1452             :       "  x08 = null;\n"
    1453             :       "  x09 = null;\n"
    1454             :       "  x10 = null;\n"
    1455             :       "  constructor() {\n"
    1456             :       "    this.x11 = null;\n"
    1457             :       "    this.x12 = null;\n"
    1458             :       "    this.x12 = null;\n"
    1459             :       "    this.x14 = null;\n"
    1460             :       "    this.x15 = null;\n"
    1461             :       "    this.x16 = null;\n"
    1462             :       "    this.x17 = null;\n"
    1463             :       "    this.x18 = null;\n"
    1464             :       "    this.x19 = null;\n"
    1465             :       "    this.x20 = null;\n"
    1466             :       "  }\n"
    1467           5 :       "});\n");
    1468           5 :   CHECK_EQ(21 + 8, obj->map()->GetInObjectProperties());
    1469           5 : }
    1470             : 
    1471             : }  // namespace test_inobject_slack_tracking
    1472             : }  // namespace internal
    1473       79917 : }  // namespace v8

Generated by: LCOV version 1.10