summaryrefslogtreecommitdiff
path: root/src/vm/typehashingalgorithms.h
blob: c661451eff2cac6b6d1ad046fb1510daf2422202 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

// ---------------------------------------------------------------------------
// Generic functions to compute the hashcode value of types
// ---------------------------------------------------------------------------

#pragma once
#include <stdlib.h>

//
// Returns the hashcode value of the 'src' string
//
inline static int ComputeNameHashCode(LPCUTF8 src)
{
    LIMITED_METHOD_CONTRACT;

    if (src == NULL || *src == '\0')
        return 0;

    int hash1 = 0x6DA3B944;
    int hash2 = 0;

    // DIFFERENT FROM CORERT: We hash UTF-8 bytes here, while CoreRT hashes UTF-16 characters.

    for (COUNT_T i = 0; src[i] != '\0'; i += 2)
    {
        hash1 = (hash1 + _rotl(hash1, 5)) ^ src[i];
        if (src[i + 1] != '\0')
            hash2 = (hash2 + _rotl(hash2, 5)) ^ src[i + 1];
        else
            break;
    }

    hash1 += _rotl(hash1, 8);
    hash2 += _rotl(hash2, 8);

    return hash1 ^ hash2;
}

inline static int ComputeNameHashCode(LPCUTF8 pszNamespace, LPCUTF8 pszName)
{
    LIMITED_METHOD_CONTRACT;

    // DIFFERENT FROM CORERT: CoreRT hashes the full name as one string ("namespace.name"),
    // as the full name is already available. In CoreCLR we normally only have separate
    // strings for namespace and name, thus we hash them separately.
    return ComputeNameHashCode(pszNamespace) ^ ComputeNameHashCode(pszName);
}

inline static int ComputeArrayTypeHashCode(int elementTypeHashcode, int rank)
{
    LIMITED_METHOD_CONTRACT;

    // DIFFERENT FROM CORERT: This is much simplified compared to CoreRT, to avoid converting.rank to string.
    // For single-dimensinal array, the result is identical to CoreRT.
    int hashCode = 0xd5313556 + rank;
    if (rank == 1)
        _ASSERTE(hashCode == ComputeNameHashCode("System.Array`1"));

    hashCode = (hashCode + _rotl(hashCode, 13)) ^ elementTypeHashcode;
    return (hashCode + _rotl(hashCode, 15));
}

inline static int ComputePointerTypeHashCode(int pointeeTypeHashcode)
{
    LIMITED_METHOD_CONTRACT;

    return (pointeeTypeHashcode + _rotl(pointeeTypeHashcode, 5)) ^ 0x12D0;
}

inline static int ComputeByrefTypeHashCode(int parameterTypeHashcode)
{
    LIMITED_METHOD_CONTRACT;

    return (parameterTypeHashcode + _rotl(parameterTypeHashcode, 7)) ^ 0x4C85;
}

inline static int ComputeNestedTypeHashCode(int enclosingTypeHashcode, int nestedTypeNameHash)
{
    LIMITED_METHOD_CONTRACT;

    return (enclosingTypeHashcode + _rotl(enclosingTypeHashcode, 11)) ^ nestedTypeNameHash;
}

template <typename TA, typename TB>
inline static int ComputeGenericInstanceHashCode(int definitionHashcode, int arity, const TA& genericTypeArguments, int (*getHashCode)(TB))
{
    LIMITED_METHOD_CONTRACT;

    int hashcode = definitionHashcode;
    for (int i = 0; i < arity; i++)
    {
        int argumentHashCode = getHashCode(genericTypeArguments[i]);
        hashcode = (hashcode + _rotl(hashcode, 13)) ^ argumentHashCode;
    }
    return (hashcode + _rotl(hashcode, 15));
}