LCOV - code coverage report
Current view: top level - test/cctest - test-object.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 138 162 85.2 %
Date: 2019-04-17 Functions: 20 32 62.5 %

          Line data    Source code
       1             : // Copyright 2016 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 "src/api-inl.h"
       6             : #include "src/function-kind.h"
       7             : #include "src/globals.h"
       8             : #include "src/handles-inl.h"
       9             : #include "src/heap/factory.h"
      10             : #include "src/isolate.h"
      11             : #include "src/objects-inl.h"
      12             : #include "src/v8.h"
      13             : #include "test/cctest/cctest.h"
      14             : 
      15             : namespace v8 {
      16             : namespace internal {
      17             : 
      18          70 : static void CheckObject(Isolate* isolate, Handle<Object> obj,
      19             :                         const char* string) {
      20         140 :   Object print_string = *Object::NoSideEffectsToString(isolate, obj);
      21          70 :   CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
      22          70 : }
      23             : 
      24           5 : static void CheckSmi(Isolate* isolate, int value, const char* string) {
      25             :   Handle<Object> handle(Smi::FromInt(value), isolate);
      26           5 :   CheckObject(isolate, handle, string);
      27           5 : }
      28             : 
      29           5 : static void CheckString(Isolate* isolate, const char* value,
      30             :                         const char* string) {
      31           5 :   Handle<String> handle(isolate->factory()->NewStringFromAsciiChecked(value));
      32           5 :   CheckObject(isolate, handle, string);
      33           5 : }
      34             : 
      35           5 : static void CheckNumber(Isolate* isolate, double value, const char* string) {
      36           5 :   Handle<Object> number = isolate->factory()->NewNumber(value);
      37           5 :   CHECK(number->IsNumber());
      38           5 :   CheckObject(isolate, number, string);
      39           5 : }
      40             : 
      41             : static void CheckBoolean(Isolate* isolate, bool value, const char* string) {
      42          15 :   CheckObject(isolate, value ? isolate->factory()->true_value()
      43             :                              : isolate->factory()->false_value(),
      44          15 :               string);
      45             : }
      46             : 
      47       26644 : TEST(NoSideEffectsToString) {
      48           5 :   CcTest::InitializeVM();
      49             :   Isolate* isolate = CcTest::i_isolate();
      50             :   Factory* factory = isolate->factory();
      51             : 
      52             :   HandleScope scope(isolate);
      53             : 
      54           5 :   CheckString(isolate, "fisk hest", "fisk hest");
      55           5 :   CheckNumber(isolate, 42.3, "42.3");
      56           5 :   CheckSmi(isolate, 42, "42");
      57             :   CheckBoolean(isolate, true, "true");
      58             :   CheckBoolean(isolate, false, "false");
      59             :   CheckBoolean(isolate, false, "false");
      60             :   Handle<Object> smi_42 = handle(Smi::FromInt(42), isolate);
      61          10 :   CheckObject(isolate, BigInt::FromNumber(isolate, smi_42).ToHandleChecked(),
      62           5 :               "42");
      63           5 :   CheckObject(isolate, factory->undefined_value(), "undefined");
      64           5 :   CheckObject(isolate, factory->null_value(), "null");
      65             : 
      66           5 :   CheckObject(isolate, factory->error_to_string(), "[object Error]");
      67           5 :   CheckObject(isolate, factory->unscopables_symbol(),
      68           5 :               "Symbol(Symbol.unscopables)");
      69           5 :   CheckObject(isolate, factory->NewError(isolate->error_function(),
      70             :                                          factory->empty_string()),
      71           5 :               "Error");
      72           5 :   CheckObject(isolate, factory->NewError(
      73             :                            isolate->error_function(),
      74             :                            factory->NewStringFromAsciiChecked("fisk hest")),
      75           5 :               "Error: fisk hest");
      76          10 :   CheckObject(isolate, factory->NewJSObject(isolate->object_function()),
      77           5 :               "#<Object>");
      78           5 : }
      79             : 
      80       26644 : TEST(EnumCache) {
      81           5 :   LocalContext env;
      82           5 :   v8::Isolate* isolate = env->GetIsolate();
      83             :   i::Factory* factory = CcTest::i_isolate()->factory();
      84          10 :   v8::HandleScope scope(isolate);
      85             : 
      86             :   // Create a nice transition tree:
      87             :   // (a) --> (b) --> (c)   shared DescriptorArray 1
      88             :   //          |
      89             :   //          +---> (cc)   shared DescriptorArray 2
      90             :   CompileRun(
      91             :       "function O(a) { this.a = 1 };"
      92             : 
      93             :       "a = new O();"
      94             : 
      95             :       "b = new O();"
      96             :       "b.b = 2;"
      97             : 
      98             :       "c = new O();"
      99             :       "c.b = 2;"
     100             :       "c.c = 3;"
     101             : 
     102             :       "cc = new O();"
     103             :       "cc.b = 2;"
     104             :       "cc.cc = 4;");
     105             : 
     106             :   Handle<JSObject> a = Handle<JSObject>::cast(v8::Utils::OpenHandle(
     107          20 :       *env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked()));
     108             :   Handle<JSObject> b = Handle<JSObject>::cast(v8::Utils::OpenHandle(
     109          20 :       *env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked()));
     110             :   Handle<JSObject> c = Handle<JSObject>::cast(v8::Utils::OpenHandle(
     111          20 :       *env->Global()->Get(env.local(), v8_str("c")).ToLocalChecked()));
     112             :   Handle<JSObject> cc = Handle<JSObject>::cast(v8::Utils::OpenHandle(
     113          20 :       *env->Global()->Get(env.local(), v8_str("cc")).ToLocalChecked()));
     114             : 
     115             :   // Check the transition tree.
     116           5 :   CHECK_EQ(a->map()->instance_descriptors(), b->map()->instance_descriptors());
     117           5 :   CHECK_EQ(b->map()->instance_descriptors(), c->map()->instance_descriptors());
     118           5 :   CHECK_NE(c->map()->instance_descriptors(), cc->map()->instance_descriptors());
     119           5 :   CHECK_NE(b->map()->instance_descriptors(), cc->map()->instance_descriptors());
     120             : 
     121             :   // Check that the EnumLength is unset.
     122           5 :   CHECK_EQ(a->map()->EnumLength(), kInvalidEnumCacheSentinel);
     123           5 :   CHECK_EQ(b->map()->EnumLength(), kInvalidEnumCacheSentinel);
     124           5 :   CHECK_EQ(c->map()->EnumLength(), kInvalidEnumCacheSentinel);
     125           5 :   CHECK_EQ(cc->map()->EnumLength(), kInvalidEnumCacheSentinel);
     126             : 
     127             :   // Check that the EnumCache is empty.
     128           5 :   CHECK_EQ(a->map()->instance_descriptors()->enum_cache(),
     129             :            *factory->empty_enum_cache());
     130           5 :   CHECK_EQ(b->map()->instance_descriptors()->enum_cache(),
     131             :            *factory->empty_enum_cache());
     132           5 :   CHECK_EQ(c->map()->instance_descriptors()->enum_cache(),
     133             :            *factory->empty_enum_cache());
     134           5 :   CHECK_EQ(cc->map()->instance_descriptors()->enum_cache(),
     135             :            *factory->empty_enum_cache());
     136             : 
     137             :   // The EnumCache is shared on the DescriptorArray, creating it on {cc} has no
     138             :   // effect on the other maps.
     139             :   CompileRun("var s = 0; for (let key in cc) { s += cc[key] };");
     140             :   {
     141           5 :     CHECK_EQ(a->map()->EnumLength(), kInvalidEnumCacheSentinel);
     142           5 :     CHECK_EQ(b->map()->EnumLength(), kInvalidEnumCacheSentinel);
     143           5 :     CHECK_EQ(c->map()->EnumLength(), kInvalidEnumCacheSentinel);
     144           5 :     CHECK_EQ(cc->map()->EnumLength(), 3);
     145             : 
     146           5 :     CHECK_EQ(a->map()->instance_descriptors()->enum_cache(),
     147             :              *factory->empty_enum_cache());
     148           5 :     CHECK_EQ(b->map()->instance_descriptors()->enum_cache(),
     149             :              *factory->empty_enum_cache());
     150           5 :     CHECK_EQ(c->map()->instance_descriptors()->enum_cache(),
     151             :              *factory->empty_enum_cache());
     152             : 
     153             :     EnumCache enum_cache = cc->map()->instance_descriptors()->enum_cache();
     154           5 :     CHECK_NE(enum_cache, *factory->empty_enum_cache());
     155           5 :     CHECK_EQ(enum_cache->keys()->length(), 3);
     156           5 :     CHECK_EQ(enum_cache->indices()->length(), 3);
     157             :   }
     158             : 
     159             :   // Initializing the EnumCache for the the topmost map {a} will not create the
     160             :   // cache for the other maps.
     161             :   CompileRun("var s = 0; for (let key in a) { s += a[key] };");
     162             :   {
     163           5 :     CHECK_EQ(a->map()->EnumLength(), 1);
     164           5 :     CHECK_EQ(b->map()->EnumLength(), kInvalidEnumCacheSentinel);
     165           5 :     CHECK_EQ(c->map()->EnumLength(), kInvalidEnumCacheSentinel);
     166           5 :     CHECK_EQ(cc->map()->EnumLength(), 3);
     167             : 
     168             :     // The enum cache is shared on the descriptor array of maps {a}, {b} and
     169             :     // {c} only.
     170             :     EnumCache enum_cache = a->map()->instance_descriptors()->enum_cache();
     171           5 :     CHECK_NE(enum_cache, *factory->empty_enum_cache());
     172           5 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(),
     173             :              *factory->empty_enum_cache());
     174           5 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(), enum_cache);
     175           5 :     CHECK_EQ(a->map()->instance_descriptors()->enum_cache(), enum_cache);
     176           5 :     CHECK_EQ(b->map()->instance_descriptors()->enum_cache(), enum_cache);
     177           5 :     CHECK_EQ(c->map()->instance_descriptors()->enum_cache(), enum_cache);
     178             : 
     179           5 :     CHECK_EQ(enum_cache->keys()->length(), 1);
     180           5 :     CHECK_EQ(enum_cache->indices()->length(), 1);
     181             :   }
     182             : 
     183             :   // Creating the EnumCache for {c} will create a new EnumCache on the shared
     184             :   // DescriptorArray.
     185             :   Handle<EnumCache> previous_enum_cache(
     186             :       a->map()->instance_descriptors()->enum_cache(), a->GetIsolate());
     187             :   Handle<FixedArray> previous_keys(previous_enum_cache->keys(),
     188             :                                    a->GetIsolate());
     189             :   Handle<FixedArray> previous_indices(previous_enum_cache->indices(),
     190             :                                       a->GetIsolate());
     191             :   CompileRun("var s = 0; for (let key in c) { s += c[key] };");
     192             :   {
     193           5 :     CHECK_EQ(a->map()->EnumLength(), 1);
     194           5 :     CHECK_EQ(b->map()->EnumLength(), kInvalidEnumCacheSentinel);
     195           5 :     CHECK_EQ(c->map()->EnumLength(), 3);
     196           5 :     CHECK_EQ(cc->map()->EnumLength(), 3);
     197             : 
     198             :     EnumCache enum_cache = c->map()->instance_descriptors()->enum_cache();
     199           5 :     CHECK_NE(enum_cache, *factory->empty_enum_cache());
     200             :     // The keys and indices caches are updated.
     201           5 :     CHECK_EQ(enum_cache, *previous_enum_cache);
     202           5 :     CHECK_NE(enum_cache->keys(), *previous_keys);
     203           5 :     CHECK_NE(enum_cache->indices(), *previous_indices);
     204           5 :     CHECK_EQ(previous_keys->length(), 1);
     205           5 :     CHECK_EQ(previous_indices->length(), 1);
     206           5 :     CHECK_EQ(enum_cache->keys()->length(), 3);
     207           5 :     CHECK_EQ(enum_cache->indices()->length(), 3);
     208             : 
     209             :     // The enum cache is shared on the descriptor array of maps {a}, {b} and
     210             :     // {c} only.
     211           5 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(),
     212             :              *factory->empty_enum_cache());
     213           5 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(), enum_cache);
     214           5 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(),
     215             :              *previous_enum_cache);
     216           5 :     CHECK_EQ(a->map()->instance_descriptors()->enum_cache(), enum_cache);
     217           5 :     CHECK_EQ(b->map()->instance_descriptors()->enum_cache(), enum_cache);
     218           5 :     CHECK_EQ(c->map()->instance_descriptors()->enum_cache(), enum_cache);
     219             :   }
     220             : 
     221             :   // {b} can reuse the existing EnumCache, hence we only need to set the correct
     222             :   // EnumLength on the map without modifying the cache itself.
     223             :   previous_enum_cache =
     224             :       handle(a->map()->instance_descriptors()->enum_cache(), a->GetIsolate());
     225             :   previous_keys = handle(previous_enum_cache->keys(), a->GetIsolate());
     226             :   previous_indices = handle(previous_enum_cache->indices(), a->GetIsolate());
     227             :   CompileRun("var s = 0; for (let key in b) { s += b[key] };");
     228             :   {
     229           5 :     CHECK_EQ(a->map()->EnumLength(), 1);
     230           5 :     CHECK_EQ(b->map()->EnumLength(), 2);
     231           5 :     CHECK_EQ(c->map()->EnumLength(), 3);
     232           5 :     CHECK_EQ(cc->map()->EnumLength(), 3);
     233             : 
     234             :     EnumCache enum_cache = c->map()->instance_descriptors()->enum_cache();
     235           5 :     CHECK_NE(enum_cache, *factory->empty_enum_cache());
     236             :     // The keys and indices caches are not updated.
     237           5 :     CHECK_EQ(enum_cache, *previous_enum_cache);
     238           5 :     CHECK_EQ(enum_cache->keys(), *previous_keys);
     239           5 :     CHECK_EQ(enum_cache->indices(), *previous_indices);
     240           5 :     CHECK_EQ(enum_cache->keys()->length(), 3);
     241           5 :     CHECK_EQ(enum_cache->indices()->length(), 3);
     242             : 
     243             :     // The enum cache is shared on the descriptor array of maps {a}, {b} and
     244             :     // {c} only.
     245           5 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(),
     246             :              *factory->empty_enum_cache());
     247           5 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(), enum_cache);
     248           5 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(),
     249             :              *previous_enum_cache);
     250           5 :     CHECK_EQ(a->map()->instance_descriptors()->enum_cache(), enum_cache);
     251           5 :     CHECK_EQ(b->map()->instance_descriptors()->enum_cache(), enum_cache);
     252           5 :     CHECK_EQ(c->map()->instance_descriptors()->enum_cache(), enum_cache);
     253             :   }
     254           5 : }
     255             : 
     256             : #define TEST_FUNCTION_KIND(Name)                                \
     257             :   TEST(Name) {                                                  \
     258             :     for (int i = 0; i < FunctionKind::kLastFunctionKind; i++) { \
     259             :       FunctionKind kind = static_cast<FunctionKind>(i);         \
     260             :       CHECK_EQ(FunctionKind##Name(kind), Name(kind));           \
     261             :     }                                                           \
     262             :   }
     263             : 
     264           0 : bool FunctionKindIsArrowFunction(FunctionKind kind) {
     265          85 :   switch (kind) {
     266             :     case FunctionKind::kArrowFunction:
     267             :     case FunctionKind::kAsyncArrowFunction:
     268             :       return true;
     269             :     default:
     270           0 :       return false;
     271             :   }
     272             : }
     273       26729 : TEST_FUNCTION_KIND(IsArrowFunction)
     274             : 
     275           0 : bool FunctionKindIsAsyncGeneratorFunction(FunctionKind kind) {
     276          85 :   switch (kind) {
     277             :     case FunctionKind::kAsyncConciseGeneratorMethod:
     278             :     case FunctionKind::kAsyncGeneratorFunction:
     279             :       return true;
     280             :     default:
     281           0 :       return false;
     282             :   }
     283             : }
     284       26729 : TEST_FUNCTION_KIND(IsAsyncGeneratorFunction)
     285             : 
     286           0 : bool FunctionKindIsGeneratorFunction(FunctionKind kind) {
     287          85 :   switch (kind) {
     288             :     case FunctionKind::kConciseGeneratorMethod:
     289             :     case FunctionKind::kAsyncConciseGeneratorMethod:
     290             :     case FunctionKind::kGeneratorFunction:
     291             :     case FunctionKind::kAsyncGeneratorFunction:
     292             :       return true;
     293             :     default:
     294           0 :       return false;
     295             :   }
     296             : }
     297       26729 : TEST_FUNCTION_KIND(IsGeneratorFunction)
     298             : 
     299           0 : bool FunctionKindIsAsyncFunction(FunctionKind kind) {
     300          85 :   switch (kind) {
     301             :     case FunctionKind::kAsyncFunction:
     302             :     case FunctionKind::kAsyncArrowFunction:
     303             :     case FunctionKind::kAsyncConciseMethod:
     304             :     case FunctionKind::kAsyncConciseGeneratorMethod:
     305             :     case FunctionKind::kAsyncGeneratorFunction:
     306             :       return true;
     307             :     default:
     308           0 :       return false;
     309             :   }
     310             : }
     311       26729 : TEST_FUNCTION_KIND(IsAsyncFunction)
     312             : 
     313           0 : bool FunctionKindIsConciseMethod(FunctionKind kind) {
     314             :   switch (kind) {
     315             :     case FunctionKind::kConciseMethod:
     316             :     case FunctionKind::kConciseGeneratorMethod:
     317             :     case FunctionKind::kAsyncConciseMethod:
     318             :     case FunctionKind::kAsyncConciseGeneratorMethod:
     319             :     case FunctionKind::kClassMembersInitializerFunction:
     320             :       return true;
     321             :     default:
     322           0 :       return false;
     323             :   }
     324             : }
     325       26729 : TEST_FUNCTION_KIND(IsConciseMethod)
     326             : 
     327           0 : bool FunctionKindIsAccessorFunction(FunctionKind kind) {
     328          85 :   switch (kind) {
     329             :     case FunctionKind::kGetterFunction:
     330             :     case FunctionKind::kSetterFunction:
     331             :       return true;
     332             :     default:
     333           0 :       return false;
     334             :   }
     335             : }
     336       26729 : TEST_FUNCTION_KIND(IsAccessorFunction)
     337             : 
     338           0 : bool FunctionKindIsDefaultConstructor(FunctionKind kind) {
     339          85 :   switch (kind) {
     340             :     case FunctionKind::kDefaultBaseConstructor:
     341             :     case FunctionKind::kDefaultDerivedConstructor:
     342             :       return true;
     343             :     default:
     344           0 :       return false;
     345             :   }
     346             : }
     347       26729 : TEST_FUNCTION_KIND(IsDefaultConstructor)
     348             : 
     349           0 : bool FunctionKindIsBaseConstructor(FunctionKind kind) {
     350          85 :   switch (kind) {
     351             :     case FunctionKind::kBaseConstructor:
     352             :     case FunctionKind::kDefaultBaseConstructor:
     353             :       return true;
     354             :     default:
     355           0 :       return false;
     356             :   }
     357             : }
     358       26729 : TEST_FUNCTION_KIND(IsBaseConstructor)
     359             : 
     360           0 : bool FunctionKindIsDerivedConstructor(FunctionKind kind) {
     361          85 :   switch (kind) {
     362             :     case FunctionKind::kDefaultDerivedConstructor:
     363             :     case FunctionKind::kDerivedConstructor:
     364             :       return true;
     365             :     default:
     366           0 :       return false;
     367             :   }
     368             : }
     369       26729 : TEST_FUNCTION_KIND(IsDerivedConstructor)
     370             : 
     371           0 : bool FunctionKindIsClassConstructor(FunctionKind kind) {
     372          85 :   switch (kind) {
     373             :     case FunctionKind::kBaseConstructor:
     374             :     case FunctionKind::kDefaultBaseConstructor:
     375             :     case FunctionKind::kDefaultDerivedConstructor:
     376             :     case FunctionKind::kDerivedConstructor:
     377             :       return true;
     378             :     default:
     379           0 :       return false;
     380             :   }
     381             : }
     382       26729 : TEST_FUNCTION_KIND(IsClassConstructor)
     383             : 
     384           0 : bool FunctionKindIsConstructable(FunctionKind kind) {
     385          85 :   switch (kind) {
     386             :     case FunctionKind::kGetterFunction:
     387             :     case FunctionKind::kSetterFunction:
     388             :     case FunctionKind::kArrowFunction:
     389             :     case FunctionKind::kAsyncArrowFunction:
     390             :     case FunctionKind::kAsyncFunction:
     391             :     case FunctionKind::kAsyncConciseMethod:
     392             :     case FunctionKind::kAsyncConciseGeneratorMethod:
     393             :     case FunctionKind::kAsyncGeneratorFunction:
     394             :     case FunctionKind::kGeneratorFunction:
     395             :     case FunctionKind::kConciseGeneratorMethod:
     396             :     case FunctionKind::kConciseMethod:
     397             :     case FunctionKind::kClassMembersInitializerFunction:
     398             :       return false;
     399             :     default:
     400           0 :       return true;
     401             :   }
     402             : }
     403       26729 : TEST_FUNCTION_KIND(IsConstructable)
     404             : 
     405           0 : bool FunctionKindIsStrictFunctionWithoutPrototype(FunctionKind kind) {
     406         160 :   return IsArrowFunction(kind) || IsConciseMethod(kind) ||
     407           0 :          IsAccessorFunction(kind);
     408             : }
     409       26729 : TEST_FUNCTION_KIND(IsStrictFunctionWithoutPrototype)
     410             : 
     411             : #undef TEST_FUNCTION_KIND
     412             : 
     413             : }  // namespace internal
     414       79917 : }  // namespace v8

Generated by: LCOV version 1.10