File: ExpressionInfo.h

package info (click to toggle)
webkit2gtk 2.48.3-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 429,620 kB
  • sloc: cpp: 3,696,936; javascript: 194,444; ansic: 169,997; python: 46,499; asm: 19,276; ruby: 18,528; perl: 16,602; xml: 4,650; yacc: 2,360; sh: 2,098; java: 1,993; lex: 1,327; pascal: 366; makefile: 298
file content (337 lines) | stat: -rw-r--r-- 13,040 bytes parent folder | download | duplicates (4)
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
/*
 * Copyright (C) 2024 Apple Inc. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "LineColumn.h"
#include <wtf/HashMap.h>
#include <wtf/HashTraits.h>
#include <wtf/IterationStatus.h>
#include <wtf/MallocPtr.h>
#include <wtf/PrintStream.h>
#include <wtf/StdLibExtras.h>
#include <wtf/Vector.h>

WTF_ALLOW_UNSAFE_BUFFER_USAGE_BEGIN

namespace JSC {

// See comment at the top of ExpressionInfo.cpp on how ExpressionInfo works.

class ExpressionInfo {
    WTF_MAKE_NONCOPYABLE(ExpressionInfo);
    WTF_MAKE_FAST_ALLOCATED;
public:
    enum class FieldID : uint8_t { InstPC, Divot, Start, End, Line, Column };

    class Decoder;

    using InstPC = unsigned; // aka bytecode PC.

    static constexpr InstPC maxInstPC = std::numeric_limits<unsigned>::max();

    struct Chapter {
        InstPC startInstPC;
        unsigned startEncodedInfoIndex;
    };

    struct Entry {
        void reset()
        {
            instPC = 0;
            lineColumn = { 0, 0 };
            divot = 0;
            startOffset = 0;
            endOffset = 0;
        }

        InstPC instPC { 0 };
        LineColumn lineColumn;
        unsigned divot { 0 };
        unsigned startOffset { 0 }; // This value is relative to divot.
        unsigned endOffset { 0 }; // This value is relative to divot.
    };

    struct EncodedInfo {
        bool isAbsInstPC() const;
        bool isExtension() const;
        unsigned value;
    };

    struct Diff;

    class Encoder {
    public:
        void encode(InstPC, unsigned divot, unsigned startOffset, unsigned endOffset, LineColumn);

        template<typename RemapFunc>
        void remap(Vector<unsigned>&& adjustments, RemapFunc);

        Entry entry() const { return m_entry; }

        MallocPtr<ExpressionInfo> createExpressionInfo();

        void dumpEncodedInfo() // For debugging use only.
        {
            ExpressionInfo::dumpEncodedInfo(m_expressionInfoEncodedInfo.begin(), m_expressionInfoEncodedInfo.end());
        }

    private:
        struct Wide {
            enum class SortOrder : uint8_t { Single, Duo, Multi };

            unsigned value;
            FieldID fieldID;
            SortOrder order { SortOrder::Multi };
        };

        static EncodedInfo encodeAbsInstPC(InstPC absInstPC);
        static EncodedInfo encodeExtension(unsigned offset);
        static constexpr EncodedInfo encodeExtensionEnd();
        static EncodedInfo encodeSingle(FieldID, unsigned);
        static EncodedInfo encodeDuo(FieldID, unsigned value1, FieldID, unsigned value2);
        static EncodedInfo encodeMultiHeader(unsigned numWides, Wide*);
        static EncodedInfo encodeBasic(const Diff&);

        void adjustInstPC(EncodedInfo*, unsigned instPCDelta);

        template<unsigned bitCount> bool fits(Wide);
        template<typename T, unsigned bitCount> bool fits(T);

        Entry m_entry;

        unsigned m_currentChapterStartIndex { 0 };
        unsigned m_numberOfEncodedInfoExtensions { 0 };
        Vector<ExpressionInfo::Chapter> m_expressionInfoChapters;
        Vector<ExpressionInfo::EncodedInfo> m_expressionInfoEncodedInfo;
    };

    class Decoder {
    public:
        Decoder() = default;
        Decoder(const ExpressionInfo&);
        Decoder(Vector<ExpressionInfo::EncodedInfo>&);

        IterationStatus decode(std::optional<InstPC> targetInstPC = std::nullopt);

        void recacheInfo(Vector<ExpressionInfo::EncodedInfo>&);
        EncodedInfo* currentInfo() const { return m_currentInfo; }

        // This is meant to be used to jump to the start of a chapter, where the encoder
        // always start over with no historical Entry values to compute diffs from.
        // If you use this to point to any EncodedInfo other than the start of a chapter,
        // then you're responsible for setting up the initial conditions of m_entry correctly
        // apriori.
        void setNextInfo(EncodedInfo* info) { m_nextInfo = info; }

        Entry entry() const { return m_entry; }
        void setEntry(Entry entry) { m_entry = entry; } // For debugging use only.

        InstPC instPC() const { return m_entry.instPC; }
        unsigned divot() const { return m_entry.divot; }
        unsigned startOffset() const { return m_entry.startOffset; }
        unsigned endOffset() const { return m_entry.endOffset; }
        LineColumn lineColumn() const { return m_entry.lineColumn; }

    private:
        struct Wide {
            FieldID fieldID;
            unsigned value;
        };

        void appendWide(FieldID id, unsigned value)
        {
            m_wides[m_numWides++] = { id, value };
        }

        Entry m_entry;
        EncodedInfo* m_startInfo { nullptr };
        EncodedInfo* m_endInfo { nullptr };
        EncodedInfo* m_endExtensionInfo { nullptr };
        EncodedInfo* m_currentInfo { nullptr };
        EncodedInfo* m_nextInfo { nullptr };
        bool m_hasDecodedFirstEntry { false };

        unsigned m_numWides { 0 };
        std::array<Wide, 6> m_wides;
    };

    ~ExpressionInfo() = default;

    LineColumn lineColumnForInstPC(InstPC);
    Entry entryForInstPC(InstPC);

    bool isEmpty() const { return !m_numberOfEncodedInfo; };
    size_t byteSize() const;

    template<unsigned bitCount>
    static void print(PrintStream&, FieldID, unsigned value);
    static void dumpEncodedInfo(EncodedInfo* start, EncodedInfo* end); // For debugging use only.

private:
    ExpressionInfo(unsigned numberOfChapters, unsigned numberOfEncodedInfo, unsigned numberOfEncodedInfoExtensions);
    ExpressionInfo(Vector<Chapter>&&, Vector<EncodedInfo>&&, unsigned numberOfEncodedInfoExtensions);

    template<typename T, unsigned bitCount> static T cast(unsigned);

    static bool isSpecial(unsigned);
    static bool isWideOrSpecial(unsigned);

    static size_t payloadSizeInBytes(size_t numChapters, size_t numberOfEncodedInfo, size_t numberOfEncodedInfoExtensions)
    {
        size_t size = numChapters * sizeof(Chapter) + (numberOfEncodedInfo + numberOfEncodedInfoExtensions) * sizeof(EncodedInfo);
        return roundUpToMultipleOf<sizeof(unsigned)>(size);
    }

    static size_t totalSizeInBytes(size_t numChapters, size_t numberOfEncodedInfo, size_t numberOfEncodedInfoExtensions)
    {
        return sizeof(ExpressionInfo) + payloadSizeInBytes(numChapters, numberOfEncodedInfo, numberOfEncodedInfoExtensions);
    }

    EncodedInfo* findChapterEncodedInfoJustBelow(InstPC) const;

    Chapter* chapters() const
    {
        return std::bit_cast<Chapter*>(this + 1);
    }

    EncodedInfo* encodedInfo() const
    {
        return std::bit_cast<EncodedInfo*>(&chapters()[m_numberOfChapters]);
    }

    EncodedInfo* endEncodedInfo() const
    {
        return &encodedInfo()[m_numberOfEncodedInfo];
    }

    EncodedInfo* endExtensionEncodedInfo() const
    {
        return &encodedInfo()[m_numberOfEncodedInfo + m_numberOfEncodedInfoExtensions];
    }

    size_t payloadSize() const
    {
        return payloadSizeInBytes(m_numberOfChapters, m_numberOfEncodedInfo, m_numberOfEncodedInfoExtensions) / sizeof(unsigned);
    }

    unsigned* payload() const
    {
        return std::bit_cast<unsigned*>(this + 1);
    }

    static MallocPtr<ExpressionInfo> createUninitialized(unsigned numberOfChapters, unsigned numberOfEncodedInfo, unsigned numberOfEncodedInfoExtensions);

    static constexpr unsigned bitsPerWord = sizeof(unsigned) * CHAR_BIT;

    // Number of bits of each field in Basic encoding.
    static constexpr unsigned instPCBits = 5;
    static constexpr unsigned divotBits = 7;
    static constexpr unsigned startBits = 6;
    static constexpr unsigned endBits = 6;
    static constexpr unsigned lineBits = 3;
    static constexpr unsigned columnBits = 5;
    static_assert(instPCBits + divotBits + startBits + endBits + lineBits + columnBits == bitsPerWord);

    // Bias values used for the signed diff values which make it easier to do range checks on these.
    static constexpr unsigned divotBias = (1 << divotBits) / 2;
    static constexpr unsigned lineBias = (1 << lineBits) / 2;
    static constexpr unsigned columnBias = (1 << columnBits) / 2;

    static constexpr unsigned instPCShift = bitsPerWord - instPCBits;
    static constexpr unsigned divotShift = instPCShift - divotBits;
    static constexpr unsigned startShift = divotShift - startBits;
    static constexpr unsigned endShift = startShift - endBits;
    static constexpr unsigned lineShift = endShift - lineBits;
    static constexpr unsigned columnShift = lineShift - columnBits;

    static constexpr unsigned specialHeader = (1 << instPCBits) - 1;
    static constexpr unsigned wideHeader = specialHeader - 1;

    static constexpr unsigned maxInstPCValue = wideHeader - 1;
    static constexpr unsigned maxBiasedDivotValue = (1 << divotBits) - 1;
    static constexpr unsigned maxStartValue = (1 << startBits) - 1;
    static constexpr unsigned maxEndValue = (1 << endBits) - 1;
    static constexpr unsigned maxBiasedLineValue = (1 << lineBits) - 1;

    static constexpr unsigned sameAsDivotValue = (1 << columnBits) - 1;
    static constexpr unsigned maxBiasedColumnValue = sameAsDivotValue - 1;

    // Number of bits in Wide / Special encodings.
    static constexpr unsigned specialValueBits = 26;
    static constexpr unsigned singleValueBits = 23;
    static constexpr unsigned duoValueBits = 10;
    static constexpr unsigned fullValueBits = 32;
    static constexpr unsigned multiSizeBits = 5;
    static constexpr unsigned fieldIDBits = 3;

    static constexpr unsigned maxSpecialValue = (1 << specialValueBits) - 1;
    static constexpr unsigned maxSingleValue = (1 << singleValueBits) - 1;
    static constexpr unsigned maxDuoValue = (1 << duoValueBits) - 1;
    static constexpr unsigned invalidFieldID = (1 << fieldIDBits) - 1;

    static constexpr unsigned multiSizeMask = (1 << multiSizeBits) - 1;
    static constexpr unsigned fieldIDMask = (1 << fieldIDBits) - 1;

    static constexpr unsigned headerShift = bitsPerWord - instPCBits;
    static constexpr unsigned multiBitShift = headerShift - 1;
    static_assert(headerShift == 27);
    static_assert(multiBitShift == 26);

    static constexpr unsigned specialValueShift = multiBitShift - specialValueBits;
    static_assert(!specialValueShift);

    static constexpr unsigned firstFieldIDShift = multiBitShift - fieldIDBits;
    static constexpr unsigned singleValueShift = firstFieldIDShift - singleValueBits;
    static_assert(!singleValueShift);

    static constexpr unsigned duoFirstValueShift = firstFieldIDShift - duoValueBits;
    static constexpr unsigned duoSecondFieldIDShift = duoFirstValueShift - fieldIDBits;
    static constexpr unsigned duoSecondValueShift = duoSecondFieldIDShift - duoValueBits;
    static_assert(!duoSecondValueShift);

    static constexpr unsigned multiSizeShift = firstFieldIDShift - multiSizeBits;
    static constexpr unsigned multiFirstFieldShift = multiSizeShift - fieldIDBits;

    static constexpr unsigned numberOfWordsBetweenChapters = 10000;

    using LineColumnMap = UncheckedKeyHashMap<InstPC, LineColumn, WTF::IntHash<InstPC>, WTF::UnsignedWithZeroKeyHashTraits<InstPC>>;

    mutable LineColumnMap m_cachedLineColumns;
    unsigned m_numberOfChapters;
    unsigned m_numberOfEncodedInfo;
    unsigned m_numberOfEncodedInfoExtensions;
    // Followed by the following which are allocated but are dynamically sized.
    //   Chapter chapters[numberOfChapters];
    //   EncodedInfo encodedInfo[numberOfEncodedInfo + numberOfEncodedInfoExtensions];

    friend class CachedExpressionInfo;
};

static_assert(roundUpToMultipleOf<sizeof(unsigned)>(sizeof(ExpressionInfo)) == sizeof(ExpressionInfo), "CachedExpressionInfo relies on this invariant");

} // namespace JSC

WTF_ALLOW_UNSAFE_BUFFER_USAGE_END