1/**
2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef LIBPANDAFILE_BYTECODE_INSTRUCTION_INL_H
17#define LIBPANDAFILE_BYTECODE_INSTRUCTION_INL_H
18
19#include "bytecode_instruction.h"
20#include "macros.h"
21
22namespace panda {
23
24template <const BytecodeInstMode Mode>
25template <class R, class S>
26inline auto BytecodeInst<Mode>::ReadHelper(size_t byteoffset, size_t bytecount, size_t offset, size_t width) const
27{
28    constexpr size_t BYTE_WIDTH = 8;
29
30    size_t right_shift = offset % BYTE_WIDTH;
31
32    S v = 0;
33    for (size_t i = 0; i < bytecount; i++) {
34        S mask = static_cast<S>(ReadByte(byteoffset + i)) << (i * BYTE_WIDTH);
35        v |= mask;
36    }
37
38    v >>= right_shift;
39    size_t left_shift = sizeof(R) * BYTE_WIDTH - width;
40
41    // Do sign extension using arithmetic shift. It's implementation defined
42    // so we check such behavior using static assert
43    // NOLINTNEXTLINE(hicpp-signed-bitwise)
44    static_assert((-1 >> 1) == -1);
45
46    // NOLINTNEXTLINE(hicpp-signed-bitwise)
47    return static_cast<R>(v << left_shift) >> left_shift;
48}
49
50template <const BytecodeInstMode Mode>
51template <size_t offset, size_t width, bool is_signed /* = false */>
52inline auto BytecodeInst<Mode>::Read() const
53{
54    constexpr size_t BYTE_WIDTH = 8;
55    constexpr size_t BYTE_OFFSET = offset / BYTE_WIDTH;
56    constexpr size_t BYTE_OFFSET_END = (offset + width + BYTE_WIDTH - 1) / BYTE_WIDTH;
57    constexpr size_t BYTE_COUNT = BYTE_OFFSET_END - BYTE_OFFSET;
58
59    using storage_type = helpers::TypeHelperT<BYTE_COUNT * BYTE_WIDTH, false>;
60    using return_type = helpers::TypeHelperT<width, is_signed>;
61
62    return ReadHelper<return_type, storage_type>(BYTE_OFFSET, BYTE_COUNT, offset, width);
63}
64
65template <const BytecodeInstMode Mode>
66template <bool is_signed /* = false */>
67inline auto BytecodeInst<Mode>::Read64(size_t offset, size_t width) const
68{
69    constexpr size_t BIT64 = 64;
70    constexpr size_t BYTE_WIDTH = 8;
71
72    ASSERT((offset % BYTE_WIDTH) + width <= BIT64);
73
74    size_t byteoffset = offset / BYTE_WIDTH;
75    size_t byteoffset_end = (offset + width + BYTE_WIDTH - 1) / BYTE_WIDTH;
76    size_t bytecount = byteoffset_end - byteoffset;
77
78    using storage_type = helpers::TypeHelperT<BIT64, false>;
79    using return_type = helpers::TypeHelperT<BIT64, is_signed>;
80
81    return ReadHelper<return_type, storage_type>(byteoffset, bytecount, offset, width);
82}
83
84template <const BytecodeInstMode Mode>
85inline size_t BytecodeInst<Mode>::GetSize() const
86{
87    return Size(GetFormat());
88}
89
90#include <bytecode_instruction-inl_gen.h>
91
92}  // namespace panda
93
94#endif  // LIBPANDAFILE_BYTECODE_INSTRUCTION_INL_H
95