LCOV - code coverage report
Current view: top level - test/cctest - test-hashcode.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 159 159 100.0 %
Date: 2019-04-17 Functions: 23 23 100.0 %

          Line data    Source code
       1             : // Copyright 2017 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/objects-inl.h"
      10             : #include "src/objects.h"
      11             : #include "src/objects/ordered-hash-table.h"
      12             : #include "src/third_party/siphash/halfsiphash.h"
      13             : #include "src/utils.h"
      14             : #include "src/v8.h"
      15             : 
      16             : #include "test/cctest/cctest.h"
      17             : 
      18             : namespace v8 {
      19             : namespace internal {
      20             : 
      21          50 : int AddToSetAndGetHash(Isolate* isolate, Handle<JSObject> obj,
      22             :                        bool has_fast_properties) {
      23          50 :   CHECK_EQ(has_fast_properties, obj->HasFastProperties());
      24         100 :   CHECK_EQ(ReadOnlyRoots(isolate).undefined_value(), obj->GetHash());
      25          50 :   Handle<OrderedHashSet> set = isolate->factory()->NewOrderedHashSet();
      26          50 :   OrderedHashSet::Add(isolate, set, obj);
      27          50 :   CHECK_EQ(has_fast_properties, obj->HasFastProperties());
      28         100 :   return Smi::ToInt(obj->GetHash());
      29             : }
      30             : 
      31          20 : void CheckFastObject(Handle<JSObject> obj, int hash) {
      32          20 :   CHECK(obj->HasFastProperties());
      33          20 :   CHECK(obj->raw_properties_or_hash()->IsPropertyArray());
      34          40 :   CHECK_EQ(Smi::FromInt(hash), obj->GetHash());
      35          40 :   CHECK_EQ(hash, obj->property_array()->Hash());
      36          20 : }
      37             : 
      38          15 : void CheckDictionaryObject(Handle<JSObject> obj, int hash) {
      39          15 :   CHECK(!obj->HasFastProperties());
      40          15 :   CHECK(obj->raw_properties_or_hash()->IsDictionary());
      41          30 :   CHECK_EQ(Smi::FromInt(hash), obj->GetHash());
      42          30 :   CHECK_EQ(hash, obj->property_dictionary()->Hash());
      43          15 : }
      44             : 
      45       26644 : TEST(AddHashCodeToFastObjectWithoutProperties) {
      46           5 :   CcTest::InitializeVM();
      47          10 :   v8::HandleScope scope(CcTest::isolate());
      48             :   Isolate* isolate = CcTest::i_isolate();
      49             : 
      50             :   Handle<JSObject> obj =
      51           5 :       isolate->factory()->NewJSObject(isolate->object_function());
      52           5 :   CHECK(obj->HasFastProperties());
      53             : 
      54           5 :   int hash = AddToSetAndGetHash(isolate, obj, true);
      55           5 :   CHECK_EQ(Smi::FromInt(hash), obj->raw_properties_or_hash());
      56           5 : }
      57             : 
      58       26644 : TEST(AddHashCodeToFastObjectWithInObjectProperties) {
      59           5 :   CcTest::InitializeVM();
      60          10 :   v8::HandleScope scope(CcTest::isolate());
      61             :   Isolate* isolate = CcTest::i_isolate();
      62             : 
      63             :   const char* source = " var x = { a: 1};";
      64             :   CompileRun(source);
      65             : 
      66           5 :   Handle<JSObject> obj = GetGlobal<JSObject>("x");
      67           5 :   CHECK_EQ(ReadOnlyRoots(isolate).empty_fixed_array(),
      68             :            obj->raw_properties_or_hash());
      69             : 
      70           5 :   int hash = AddToSetAndGetHash(isolate, obj, true);
      71           5 :   CHECK_EQ(Smi::FromInt(hash), obj->raw_properties_or_hash());
      72           5 : }
      73             : 
      74       26644 : TEST(AddHashCodeToFastObjectWithPropertiesArray) {
      75           5 :   CcTest::InitializeVM();
      76          10 :   v8::HandleScope scope(CcTest::isolate());
      77             :   Isolate* isolate = CcTest::i_isolate();
      78             : 
      79             :   const char* source =
      80             :       " var x = {}; "
      81             :       " x.a = 1; x.b = 2; x.c = 3; x.d = 4; x.e = 5; ";
      82             :   CompileRun(source);
      83             : 
      84           5 :   Handle<JSObject> obj = GetGlobal<JSObject>("x");
      85           5 :   CHECK(obj->HasFastProperties());
      86             : 
      87           5 :   int hash = AddToSetAndGetHash(isolate, obj, true);
      88           5 :   CheckFastObject(obj, hash);
      89           5 : }
      90             : 
      91       26644 : TEST(AddHashCodeToSlowObject) {
      92           5 :   CcTest::InitializeVM();
      93          10 :   v8::HandleScope scope(CcTest::isolate());
      94             :   Isolate* isolate = CcTest::i_isolate();
      95             : 
      96             :   Handle<JSObject> obj =
      97           5 :       isolate->factory()->NewJSObject(isolate->object_function());
      98           5 :   CHECK(obj->HasFastProperties());
      99             :   JSObject::NormalizeProperties(obj, CLEAR_INOBJECT_PROPERTIES, 0,
     100           5 :                                 "cctest/test-hashcode");
     101           5 :   CHECK(obj->raw_properties_or_hash()->IsDictionary());
     102             : 
     103           5 :   int hash = AddToSetAndGetHash(isolate, obj, false);
     104           5 :   CheckDictionaryObject(obj, hash);
     105           5 : }
     106             : 
     107       26644 : TEST(TransitionFastWithInObjectToFastWithPropertyArray) {
     108           5 :   CcTest::InitializeVM();
     109          10 :   v8::HandleScope scope(CcTest::isolate());
     110             :   Isolate* isolate = CcTest::i_isolate();
     111             : 
     112             :   const char* source =
     113             :       " var x = { };"
     114             :       " x.a = 1; x.b = 2; x.c = 3; x.d = 4;";
     115             :   CompileRun(source);
     116             : 
     117           5 :   Handle<JSObject> obj = GetGlobal<JSObject>("x");
     118           5 :   CHECK(obj->HasFastProperties());
     119             : 
     120           5 :   int hash = AddToSetAndGetHash(isolate, obj, true);
     121           5 :   CHECK_EQ(Smi::FromInt(hash), obj->raw_properties_or_hash());
     122             : 
     123          10 :   int length = obj->property_array()->length();
     124             :   CompileRun("x.e = 5;");
     125          10 :   CHECK(obj->property_array()->length() > length);
     126           5 :   CheckFastObject(obj, hash);
     127           5 : }
     128             : 
     129       26644 : TEST(TransitionFastWithPropertyArray) {
     130           5 :   CcTest::InitializeVM();
     131          10 :   v8::HandleScope scope(CcTest::isolate());
     132             :   Isolate* isolate = CcTest::i_isolate();
     133             : 
     134             :   const char* source =
     135             :       " var x = { };"
     136             :       " x.a = 1; x.b = 2; x.c = 3; x.d = 4; x.e = 5; ";
     137             :   CompileRun(source);
     138             : 
     139           5 :   Handle<JSObject> obj = GetGlobal<JSObject>("x");
     140           5 :   CHECK(obj->raw_properties_or_hash()->IsPropertyArray());
     141             : 
     142           5 :   int hash = AddToSetAndGetHash(isolate, obj, true);
     143          10 :   CHECK_EQ(hash, obj->property_array()->Hash());
     144             : 
     145          10 :   int length = obj->property_array()->length();
     146             :   CompileRun("x.f = 2; x.g = 5; x.h = 2");
     147          10 :   CHECK(obj->property_array()->length() > length);
     148           5 :   CheckFastObject(obj, hash);
     149           5 : }
     150             : 
     151       26644 : TEST(TransitionFastWithPropertyArrayToSlow) {
     152           5 :   CcTest::InitializeVM();
     153          10 :   v8::HandleScope scope(CcTest::isolate());
     154             :   Isolate* isolate = CcTest::i_isolate();
     155             : 
     156             :   const char* source =
     157             :       " var x = { };"
     158             :       " x.a = 1; x.b = 2; x.c = 3; x.d = 4; x.e = 5; ";
     159             :   CompileRun(source);
     160             : 
     161           5 :   Handle<JSObject> obj = GetGlobal<JSObject>("x");
     162           5 :   CHECK(obj->raw_properties_or_hash()->IsPropertyArray());
     163             : 
     164           5 :   int hash = AddToSetAndGetHash(isolate, obj, true);
     165           5 :   CHECK(obj->raw_properties_or_hash()->IsPropertyArray());
     166          10 :   CHECK_EQ(hash, obj->property_array()->Hash());
     167             : 
     168             :   JSObject::NormalizeProperties(obj, KEEP_INOBJECT_PROPERTIES, 0,
     169           5 :                                 "cctest/test-hashcode");
     170           5 :   CheckDictionaryObject(obj, hash);
     171           5 : }
     172             : 
     173       26644 : TEST(TransitionSlowToSlow) {
     174           5 :   CcTest::InitializeVM();
     175          10 :   v8::HandleScope scope(CcTest::isolate());
     176             :   Isolate* isolate = CcTest::i_isolate();
     177             : 
     178             :   const char* source = " var x = {}; ";
     179             :   CompileRun(source);
     180             : 
     181           5 :   Handle<JSObject> obj = GetGlobal<JSObject>("x");
     182             :   JSObject::NormalizeProperties(obj, CLEAR_INOBJECT_PROPERTIES, 0,
     183           5 :                                 "cctest/test-hashcode");
     184           5 :   CHECK(obj->raw_properties_or_hash()->IsDictionary());
     185             : 
     186           5 :   int hash = AddToSetAndGetHash(isolate, obj, false);
     187          10 :   CHECK_EQ(hash, obj->property_dictionary()->Hash());
     188             : 
     189          10 :   int length = obj->property_dictionary()->length();
     190             :   CompileRun("for(var i = 0; i < 10; i++) { x['f'+i] = i };");
     191          10 :   CHECK(obj->property_dictionary()->length() > length);
     192           5 :   CheckDictionaryObject(obj, hash);
     193           5 : }
     194             : 
     195       26644 : TEST(TransitionSlowToFastWithoutProperties) {
     196           5 :   CcTest::InitializeVM();
     197          10 :   v8::HandleScope scope(CcTest::isolate());
     198             :   Isolate* isolate = CcTest::i_isolate();
     199             : 
     200             :   Handle<JSObject> obj =
     201           5 :       isolate->factory()->NewJSObject(isolate->object_function());
     202             :   JSObject::NormalizeProperties(obj, CLEAR_INOBJECT_PROPERTIES, 0,
     203           5 :                                 "cctest/test-hashcode");
     204           5 :   CHECK(obj->raw_properties_or_hash()->IsDictionary());
     205             : 
     206           5 :   int hash = AddToSetAndGetHash(isolate, obj, false);
     207          10 :   CHECK_EQ(hash, obj->property_dictionary()->Hash());
     208             : 
     209           5 :   JSObject::MigrateSlowToFast(obj, 0, "cctest/test-hashcode");
     210          10 :   CHECK_EQ(Smi::FromInt(hash), obj->GetHash());
     211           5 : }
     212             : 
     213       26644 : TEST(TransitionSlowToFastWithPropertyArray) {
     214           5 :   CcTest::InitializeVM();
     215          10 :   v8::HandleScope scope(CcTest::isolate());
     216             :   Isolate* isolate = CcTest::i_isolate();
     217             : 
     218             :   const char* source =
     219             :       " var x = Object.create(null); "
     220             :       " for(var i = 0; i < 10; i++) { x['f'+i] = i }; ";
     221             :   CompileRun(source);
     222             : 
     223           5 :   Handle<JSObject> obj = GetGlobal<JSObject>("x");
     224           5 :   CHECK(obj->raw_properties_or_hash()->IsDictionary());
     225             : 
     226           5 :   int hash = AddToSetAndGetHash(isolate, obj, false);
     227          10 :   CHECK_EQ(hash, obj->property_dictionary()->Hash());
     228             : 
     229           5 :   JSObject::MigrateSlowToFast(obj, 0, "cctest/test-hashcode");
     230           5 :   CheckFastObject(obj, hash);
     231           5 : }
     232             : 
     233             : namespace {
     234             : 
     235             : typedef uint32_t (*HashFunction)(uint32_t key, uint64_t seed);
     236             : 
     237         180 : void TestIntegerHashQuality(const int samples_log2, int num_buckets_log2,
     238             :                             uint64_t seed, double max_var,
     239             :                             HashFunction hash_function) {
     240         180 :   int samples = 1 << samples_log2;
     241         180 :   int num_buckets = 1 << num_buckets_log2;
     242         180 :   int mean = samples / num_buckets;
     243         180 :   int* buckets = new int[num_buckets];
     244             : 
     245      272340 :   for (int i = 0; i < num_buckets; i++) buckets[i] = 0;
     246             : 
     247    15483060 :   for (int i = 0; i < samples; i++) {
     248     7741440 :     uint32_t hash = hash_function(i, seed);
     249     7741440 :     buckets[hash % num_buckets]++;
     250             :   }
     251             : 
     252             :   int sum_deviation = 0;
     253      544500 :   for (int i = 0; i < num_buckets; i++) {
     254      272160 :     int deviation = abs(buckets[i] - mean);
     255      272160 :     sum_deviation += deviation * deviation;
     256             :   }
     257         180 :   delete[] buckets;
     258             : 
     259         180 :   double variation_coefficient = sqrt(sum_deviation * 1.0 / num_buckets) / mean;
     260             : 
     261             :   printf("samples: 1 << %2d, buckets: 1 << %2d, var_coeff: %0.3f\n",
     262             :          samples_log2, num_buckets_log2, variation_coefficient);
     263         180 :   CHECK_LT(variation_coefficient, max_var);
     264         180 : }
     265     2580480 : uint32_t HalfSipHash(uint32_t key, uint64_t seed) {
     266     2580480 :   return halfsiphash(key, seed);
     267             : }
     268             : 
     269     2580480 : uint32_t JenkinsHash(uint32_t key, uint64_t seed) {
     270     5160960 :   return ComputeLongHash(static_cast<uint64_t>(key) ^ seed);
     271             : }
     272             : 
     273     2580480 : uint32_t DefaultHash(uint32_t key, uint64_t seed) {
     274     2580480 :   return ComputeSeededHash(key, seed);
     275             : }
     276             : }  // anonymous namespace
     277             : 
     278          15 : void TestIntegerHashQuality(HashFunction hash_function) {
     279          15 :   TestIntegerHashQuality(17, 13, 0x123456789ABCDEFU, 0.4, hash_function);
     280          15 :   TestIntegerHashQuality(16, 12, 0x123456789ABCDEFU, 0.4, hash_function);
     281          15 :   TestIntegerHashQuality(15, 11, 0xFEDCBA987654321U, 0.4, hash_function);
     282          15 :   TestIntegerHashQuality(14, 10, 0xFEDCBA987654321U, 0.4, hash_function);
     283          15 :   TestIntegerHashQuality(13, 9, 1, 0.4, hash_function);
     284          15 :   TestIntegerHashQuality(12, 8, 1, 0.4, hash_function);
     285             : 
     286          15 :   TestIntegerHashQuality(17, 10, 0x123456789ABCDEFU, 0.2, hash_function);
     287          15 :   TestIntegerHashQuality(16, 9, 0x123456789ABCDEFU, 0.2, hash_function);
     288          15 :   TestIntegerHashQuality(15, 8, 0xFEDCBA987654321U, 0.2, hash_function);
     289          15 :   TestIntegerHashQuality(14, 7, 0xFEDCBA987654321U, 0.2, hash_function);
     290          15 :   TestIntegerHashQuality(13, 6, 1, 0.2, hash_function);
     291          15 :   TestIntegerHashQuality(12, 5, 1, 0.2, hash_function);
     292          15 : }
     293             : 
     294       26644 : TEST(HalfSipHashQuality) { TestIntegerHashQuality(HalfSipHash); }
     295             : 
     296       26644 : TEST(JenkinsHashQuality) { TestIntegerHashQuality(JenkinsHash); }
     297             : 
     298       26644 : TEST(DefaultHashQuality) { TestIntegerHashQuality(DefaultHash); }
     299             : 
     300             : }  // namespace internal
     301       79917 : }  // namespace v8

Generated by: LCOV version 1.10