1/*
2 * Copyright (c) 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 ECMASCRIPT_JSPANDAFILE_BYTECODE_INST_INSTRUCTION_H
17#define ECMASCRIPT_JSPANDAFILE_BYTECODE_INST_INSTRUCTION_H
18
19#include <cstdint>
20
21#include "libpandabase/utils/bit_helpers.h"
22
23#if !PANDA_TARGET_WINDOWS
24#include "securec.h"
25#endif
26
27
28namespace panda::ecmascript {
29class OldBytecodeInstBase {
30public:
31    OldBytecodeInstBase() = default;
32    explicit OldBytecodeInstBase(const uint8_t *pc) : pc_ {pc} {}
33    ~OldBytecodeInstBase() = default;
34
35protected:
36    const uint8_t *GetPointer(int32_t offset) const
37    {
38        // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
39        return pc_ + offset;
40    }
41
42    const uint8_t *GetAddress() const
43    {
44        return pc_;
45    }
46
47    const uint8_t *GetAddress() volatile const
48    {
49        return pc_;
50    }
51
52    uint8_t GetPrimaryOpcode() const
53    {
54        return ReadByte(0);
55    }
56
57    uint8_t GetSecondaryOpcode() const
58    {
59        return ReadByte(1);
60    }
61
62    template <class T>
63    T Read(size_t offset) const
64    {
65        using unaligned_type __attribute__((aligned(1))) = const T;
66        return *reinterpret_cast<unaligned_type *>(GetPointer(offset));
67    }
68
69    void Write(uint32_t value, uint32_t offset, uint32_t width)
70    {
71        auto *dst = const_cast<uint8_t *>(GetPointer(offset));
72        if (memcpy_s(dst, width, &value, width) != 0) {
73            LOG(FATAL, PANDAFILE) << "Cannot write value : " << value << "at the dst offset : " << offset;
74        }
75    }
76
77    uint8_t ReadByte(size_t offset) const
78    {
79        return Read<uint8_t>(offset);
80    }
81
82    template <class R, class S>
83    inline auto ReadHelper(size_t byteoffset, size_t bytecount, size_t offset, size_t width) const
84    {
85        constexpr size_t BYTE_WIDTH = 8;
86
87        size_t right_shift = offset % BYTE_WIDTH;
88
89        S v = 0;
90        for (size_t i = 0; i < bytecount; i++) {
91            S mask = static_cast<S>(ReadByte(byteoffset + i)) << (i * BYTE_WIDTH);
92            v |= mask;
93        }
94
95        v >>= right_shift;
96        size_t left_shift = sizeof(R) * BYTE_WIDTH - width;
97
98        // Do sign extension using arithmetic shift. It's implementation defined
99        // so we check such behavior using static assert
100        // NOLINTNEXTLINE(hicpp-signed-bitwise)
101        static_assert((-1 >> 1) == -1);
102
103        // NOLINTNEXTLINE(hicpp-signed-bitwise)
104        return static_cast<R>(v << left_shift) >> left_shift;
105    }
106
107    template <size_t offset, size_t width, bool is_signed = false>
108    inline auto Read() const
109    {
110        constexpr size_t BYTE_WIDTH = 8;
111        constexpr size_t BYTE_OFFSET = offset / BYTE_WIDTH;
112        constexpr size_t BYTE_OFFSET_END = (offset + width + BYTE_WIDTH - 1) / BYTE_WIDTH;
113        constexpr size_t BYTE_COUNT = BYTE_OFFSET_END - BYTE_OFFSET;
114
115        using storage_type = helpers::TypeHelperT<BYTE_COUNT * BYTE_WIDTH, false>;
116        using return_type = helpers::TypeHelperT<width, is_signed>;
117
118        return ReadHelper<return_type, storage_type>(BYTE_OFFSET, BYTE_COUNT, offset, width);
119    }
120
121    template <bool is_signed = false>
122    inline auto Read64(size_t offset, size_t width) const
123    {
124        constexpr size_t BIT64 = 64;
125        constexpr size_t BYTE_WIDTH = 8;
126
127        ASSERT((offset % BYTE_WIDTH) + width <= BIT64);
128
129        size_t byteoffset = offset / BYTE_WIDTH;
130        size_t byteoffset_end = (offset + width + BYTE_WIDTH - 1) / BYTE_WIDTH;
131        size_t bytecount = byteoffset_end - byteoffset;
132
133        using storage_type = helpers::TypeHelperT<BIT64, false>;
134        using return_type = helpers::TypeHelperT<BIT64, is_signed>;
135
136        return ReadHelper<return_type, storage_type>(byteoffset, bytecount, offset, width);
137    }
138
139private:
140    const uint8_t *pc_ {nullptr};
141};
142
143}  // panda::ecmascript
144
145#endif  // ECMASCRIPT_JSPANDAFILE_BYTECODE_INST_OLD_INSTRUCTION_H