LCOV - code coverage report
Current view: top level - test/cctest - test-object.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 120 120 100.0 %
Date: 2019-01-20 Functions: 8 8 100.0 %

          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/handles-inl.h"
       7             : #include "src/heap/factory.h"
       8             : #include "src/isolate.h"
       9             : #include "src/objects-inl.h"
      10             : #include "src/v8.h"
      11             : #include "test/cctest/cctest.h"
      12             : 
      13             : namespace v8 {
      14             : namespace internal {
      15             : 
      16          70 : static void CheckObject(Isolate* isolate, Handle<Object> obj,
      17             :                         const char* string) {
      18         140 :   Object print_string = *Object::NoSideEffectsToString(isolate, obj);
      19          70 :   CHECK(String::cast(print_string)->IsUtf8EqualTo(CStrVector(string)));
      20          70 : }
      21             : 
      22           5 : static void CheckSmi(Isolate* isolate, int value, const char* string) {
      23             :   Handle<Object> handle(Smi::FromInt(value), isolate);
      24           5 :   CheckObject(isolate, handle, string);
      25           5 : }
      26             : 
      27           5 : static void CheckString(Isolate* isolate, const char* value,
      28             :                         const char* string) {
      29           5 :   Handle<String> handle(isolate->factory()->NewStringFromAsciiChecked(value));
      30           5 :   CheckObject(isolate, handle, string);
      31           5 : }
      32             : 
      33           5 : static void CheckNumber(Isolate* isolate, double value, const char* string) {
      34           5 :   Handle<Object> number = isolate->factory()->NewNumber(value);
      35          10 :   CHECK(number->IsNumber());
      36           5 :   CheckObject(isolate, number, string);
      37           5 : }
      38             : 
      39             : static void CheckBoolean(Isolate* isolate, bool value, const char* string) {
      40             :   CheckObject(isolate, value ? isolate->factory()->true_value()
      41             :                              : isolate->factory()->false_value(),
      42          15 :               string);
      43             : }
      44             : 
      45       28342 : TEST(NoSideEffectsToString) {
      46           5 :   CcTest::InitializeVM();
      47             :   Isolate* isolate = CcTest::i_isolate();
      48             :   Factory* factory = isolate->factory();
      49             : 
      50             :   HandleScope scope(isolate);
      51             : 
      52           5 :   CheckString(isolate, "fisk hest", "fisk hest");
      53           5 :   CheckNumber(isolate, 42.3, "42.3");
      54           5 :   CheckSmi(isolate, 42, "42");
      55             :   CheckBoolean(isolate, true, "true");
      56             :   CheckBoolean(isolate, false, "false");
      57             :   CheckBoolean(isolate, false, "false");
      58             :   Handle<Object> smi_42 = handle(Smi::FromInt(42), isolate);
      59             :   CheckObject(isolate, BigInt::FromNumber(isolate, smi_42).ToHandleChecked(),
      60          10 :               "42");
      61           5 :   CheckObject(isolate, factory->undefined_value(), "undefined");
      62           5 :   CheckObject(isolate, factory->null_value(), "null");
      63             : 
      64           5 :   CheckObject(isolate, factory->error_to_string(), "[object Error]");
      65             :   CheckObject(isolate, factory->unscopables_symbol(),
      66           5 :               "Symbol(Symbol.unscopables)");
      67             :   CheckObject(isolate, factory->NewError(isolate->error_function(),
      68             :                                          factory->empty_string()),
      69           5 :               "Error");
      70             :   CheckObject(isolate, factory->NewError(
      71             :                            isolate->error_function(),
      72             :                            factory->NewStringFromAsciiChecked("fisk hest")),
      73           5 :               "Error: fisk hest");
      74             :   CheckObject(isolate, factory->NewJSObject(isolate->object_function()),
      75          10 :               "#<Object>");
      76           5 : }
      77             : 
      78       28342 : TEST(EnumCache) {
      79           5 :   LocalContext env;
      80           5 :   v8::Isolate* isolate = env->GetIsolate();
      81             :   i::Factory* factory = CcTest::i_isolate()->factory();
      82          10 :   v8::HandleScope scope(isolate);
      83             : 
      84             :   // Create a nice transition tree:
      85             :   // (a) --> (b) --> (c)   shared DescriptorArray 1
      86             :   //          |
      87             :   //          +---> (cc)   shared DescriptorArray 2
      88             :   CompileRun(
      89             :       "function O(a) { this.a = 1 };"
      90             : 
      91             :       "a = new O();"
      92             : 
      93             :       "b = new O();"
      94             :       "b.b = 2;"
      95             : 
      96             :       "c = new O();"
      97             :       "c.b = 2;"
      98             :       "c.c = 3;"
      99             : 
     100             :       "cc = new O();"
     101             :       "cc.b = 2;"
     102             :       "cc.cc = 4;");
     103             : 
     104             :   Handle<JSObject> a = Handle<JSObject>::cast(v8::Utils::OpenHandle(
     105          25 :       *env->Global()->Get(env.local(), v8_str("a")).ToLocalChecked()));
     106             :   Handle<JSObject> b = Handle<JSObject>::cast(v8::Utils::OpenHandle(
     107          25 :       *env->Global()->Get(env.local(), v8_str("b")).ToLocalChecked()));
     108             :   Handle<JSObject> c = Handle<JSObject>::cast(v8::Utils::OpenHandle(
     109          25 :       *env->Global()->Get(env.local(), v8_str("c")).ToLocalChecked()));
     110             :   Handle<JSObject> cc = Handle<JSObject>::cast(v8::Utils::OpenHandle(
     111          25 :       *env->Global()->Get(env.local(), v8_str("cc")).ToLocalChecked()));
     112             : 
     113             :   // Check the transition tree.
     114          15 :   CHECK_EQ(a->map()->instance_descriptors(), b->map()->instance_descriptors());
     115          15 :   CHECK_EQ(b->map()->instance_descriptors(), c->map()->instance_descriptors());
     116          15 :   CHECK_NE(c->map()->instance_descriptors(), cc->map()->instance_descriptors());
     117          15 :   CHECK_NE(b->map()->instance_descriptors(), cc->map()->instance_descriptors());
     118             : 
     119             :   // Check that the EnumLength is unset.
     120           5 :   CHECK_EQ(a->map()->EnumLength(), kInvalidEnumCacheSentinel);
     121           5 :   CHECK_EQ(b->map()->EnumLength(), kInvalidEnumCacheSentinel);
     122           5 :   CHECK_EQ(c->map()->EnumLength(), kInvalidEnumCacheSentinel);
     123           5 :   CHECK_EQ(cc->map()->EnumLength(), kInvalidEnumCacheSentinel);
     124             : 
     125             :   // Check that the EnumCache is empty.
     126          15 :   CHECK_EQ(a->map()->instance_descriptors()->enum_cache(),
     127             :            *factory->empty_enum_cache());
     128          15 :   CHECK_EQ(b->map()->instance_descriptors()->enum_cache(),
     129             :            *factory->empty_enum_cache());
     130          15 :   CHECK_EQ(c->map()->instance_descriptors()->enum_cache(),
     131             :            *factory->empty_enum_cache());
     132          15 :   CHECK_EQ(cc->map()->instance_descriptors()->enum_cache(),
     133             :            *factory->empty_enum_cache());
     134             : 
     135             :   // The EnumCache is shared on the DescriptorArray, creating it on {cc} has no
     136             :   // effect on the other maps.
     137             :   CompileRun("var s = 0; for (let key in cc) { s += cc[key] };");
     138             :   {
     139           5 :     CHECK_EQ(a->map()->EnumLength(), kInvalidEnumCacheSentinel);
     140           5 :     CHECK_EQ(b->map()->EnumLength(), kInvalidEnumCacheSentinel);
     141           5 :     CHECK_EQ(c->map()->EnumLength(), kInvalidEnumCacheSentinel);
     142           5 :     CHECK_EQ(cc->map()->EnumLength(), 3);
     143             : 
     144          15 :     CHECK_EQ(a->map()->instance_descriptors()->enum_cache(),
     145             :              *factory->empty_enum_cache());
     146          15 :     CHECK_EQ(b->map()->instance_descriptors()->enum_cache(),
     147             :              *factory->empty_enum_cache());
     148          15 :     CHECK_EQ(c->map()->instance_descriptors()->enum_cache(),
     149             :              *factory->empty_enum_cache());
     150             : 
     151           5 :     EnumCache enum_cache = cc->map()->instance_descriptors()->enum_cache();
     152          10 :     CHECK_NE(enum_cache, *factory->empty_enum_cache());
     153          10 :     CHECK_EQ(enum_cache->keys()->length(), 3);
     154          10 :     CHECK_EQ(enum_cache->indices()->length(), 3);
     155             :   }
     156             : 
     157             :   // Initializing the EnumCache for the the topmost map {a} will not create the
     158             :   // cache for the other maps.
     159             :   CompileRun("var s = 0; for (let key in a) { s += a[key] };");
     160             :   {
     161           5 :     CHECK_EQ(a->map()->EnumLength(), 1);
     162           5 :     CHECK_EQ(b->map()->EnumLength(), kInvalidEnumCacheSentinel);
     163           5 :     CHECK_EQ(c->map()->EnumLength(), kInvalidEnumCacheSentinel);
     164           5 :     CHECK_EQ(cc->map()->EnumLength(), 3);
     165             : 
     166             :     // The enum cache is shared on the descriptor array of maps {a}, {b} and
     167             :     // {c} only.
     168           5 :     EnumCache enum_cache = a->map()->instance_descriptors()->enum_cache();
     169          10 :     CHECK_NE(enum_cache, *factory->empty_enum_cache());
     170          15 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(),
     171             :              *factory->empty_enum_cache());
     172          10 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(), enum_cache);
     173          10 :     CHECK_EQ(a->map()->instance_descriptors()->enum_cache(), enum_cache);
     174          10 :     CHECK_EQ(b->map()->instance_descriptors()->enum_cache(), enum_cache);
     175          10 :     CHECK_EQ(c->map()->instance_descriptors()->enum_cache(), enum_cache);
     176             : 
     177          10 :     CHECK_EQ(enum_cache->keys()->length(), 1);
     178          10 :     CHECK_EQ(enum_cache->indices()->length(), 1);
     179             :   }
     180             : 
     181             :   // Creating the EnumCache for {c} will create a new EnumCache on the shared
     182             :   // DescriptorArray.
     183             :   Handle<EnumCache> previous_enum_cache(
     184          10 :       a->map()->instance_descriptors()->enum_cache(), a->GetIsolate());
     185             :   Handle<FixedArray> previous_keys(previous_enum_cache->keys(),
     186          10 :                                    a->GetIsolate());
     187             :   Handle<FixedArray> previous_indices(previous_enum_cache->indices(),
     188          10 :                                       a->GetIsolate());
     189             :   CompileRun("var s = 0; for (let key in c) { s += c[key] };");
     190             :   {
     191           5 :     CHECK_EQ(a->map()->EnumLength(), 1);
     192           5 :     CHECK_EQ(b->map()->EnumLength(), kInvalidEnumCacheSentinel);
     193           5 :     CHECK_EQ(c->map()->EnumLength(), 3);
     194           5 :     CHECK_EQ(cc->map()->EnumLength(), 3);
     195             : 
     196           5 :     EnumCache enum_cache = c->map()->instance_descriptors()->enum_cache();
     197          10 :     CHECK_NE(enum_cache, *factory->empty_enum_cache());
     198             :     // The keys and indices caches are updated.
     199          10 :     CHECK_EQ(enum_cache, *previous_enum_cache);
     200          10 :     CHECK_NE(enum_cache->keys(), *previous_keys);
     201          10 :     CHECK_NE(enum_cache->indices(), *previous_indices);
     202           5 :     CHECK_EQ(previous_keys->length(), 1);
     203           5 :     CHECK_EQ(previous_indices->length(), 1);
     204          10 :     CHECK_EQ(enum_cache->keys()->length(), 3);
     205          10 :     CHECK_EQ(enum_cache->indices()->length(), 3);
     206             : 
     207             :     // The enum cache is shared on the descriptor array of maps {a}, {b} and
     208             :     // {c} only.
     209          15 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(),
     210             :              *factory->empty_enum_cache());
     211          10 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(), enum_cache);
     212          15 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(),
     213             :              *previous_enum_cache);
     214          10 :     CHECK_EQ(a->map()->instance_descriptors()->enum_cache(), enum_cache);
     215          10 :     CHECK_EQ(b->map()->instance_descriptors()->enum_cache(), enum_cache);
     216          10 :     CHECK_EQ(c->map()->instance_descriptors()->enum_cache(), enum_cache);
     217             :   }
     218             : 
     219             :   // {b} can reuse the existing EnumCache, hence we only need to set the correct
     220             :   // EnumLength on the map without modifying the cache itself.
     221             :   previous_enum_cache =
     222          10 :       handle(a->map()->instance_descriptors()->enum_cache(), a->GetIsolate());
     223          10 :   previous_keys = handle(previous_enum_cache->keys(), a->GetIsolate());
     224          10 :   previous_indices = handle(previous_enum_cache->indices(), a->GetIsolate());
     225             :   CompileRun("var s = 0; for (let key in b) { s += b[key] };");
     226             :   {
     227           5 :     CHECK_EQ(a->map()->EnumLength(), 1);
     228           5 :     CHECK_EQ(b->map()->EnumLength(), 2);
     229           5 :     CHECK_EQ(c->map()->EnumLength(), 3);
     230           5 :     CHECK_EQ(cc->map()->EnumLength(), 3);
     231             : 
     232           5 :     EnumCache enum_cache = c->map()->instance_descriptors()->enum_cache();
     233          10 :     CHECK_NE(enum_cache, *factory->empty_enum_cache());
     234             :     // The keys and indices caches are not updated.
     235          10 :     CHECK_EQ(enum_cache, *previous_enum_cache);
     236          10 :     CHECK_EQ(enum_cache->keys(), *previous_keys);
     237          10 :     CHECK_EQ(enum_cache->indices(), *previous_indices);
     238          10 :     CHECK_EQ(enum_cache->keys()->length(), 3);
     239          10 :     CHECK_EQ(enum_cache->indices()->length(), 3);
     240             : 
     241             :     // The enum cache is shared on the descriptor array of maps {a}, {b} and
     242             :     // {c} only.
     243          15 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(),
     244             :              *factory->empty_enum_cache());
     245          10 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(), enum_cache);
     246          15 :     CHECK_NE(cc->map()->instance_descriptors()->enum_cache(),
     247             :              *previous_enum_cache);
     248          10 :     CHECK_EQ(a->map()->instance_descriptors()->enum_cache(), enum_cache);
     249          10 :     CHECK_EQ(b->map()->instance_descriptors()->enum_cache(), enum_cache);
     250          10 :     CHECK_EQ(c->map()->instance_descriptors()->enum_cache(), enum_cache);
     251           5 :   }
     252           5 : }
     253             : 
     254             : }  // namespace internal
     255       85011 : }  // namespace v8

Generated by: LCOV version 1.10