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 28 namespace panda::ecmascript { 29 class OldBytecodeInstBase { 30 public: 31 OldBytecodeInstBase() = default; OldBytecodeInstBase(const uint8_t * pc)32 explicit OldBytecodeInstBase(const uint8_t *pc) : pc_ {pc} {} 33 ~OldBytecodeInstBase() = default; 34 35 protected: GetPointer(int32_t offset)36 const uint8_t *GetPointer(int32_t offset) const 37 { 38 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 39 return pc_ + offset; 40 } 41 GetAddress()42 const uint8_t *GetAddress() const 43 { 44 return pc_; 45 } 46 GetAddress()47 const uint8_t *GetAddress() volatile const 48 { 49 return pc_; 50 } 51 GetPrimaryOpcode()52 uint8_t GetPrimaryOpcode() const 53 { 54 return ReadByte(0); 55 } 56 GetSecondaryOpcode()57 uint8_t GetSecondaryOpcode() const 58 { 59 return ReadByte(1); 60 } 61 62 template <class T> Read(size_t offset)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 Write(uint32_t value,uint32_t offset,uint32_t width)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 ReadByte(size_t offset)77 uint8_t ReadByte(size_t offset) const 78 { 79 return Read<uint8_t>(offset); 80 } 81 82 template <class R, class S> ReadHelper(size_t byteoffset,size_t bytecount,size_t offset,size_t width)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> Read()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> Read64(size_t offset,size_t width)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 139 private: 140 const uint8_t *pc_ {nullptr}; 141 }; 142 143 } // panda::ecmascript 144 145 #endif // ECMASCRIPT_JSPANDAFILE_BYTECODE_INST_OLD_INSTRUCTION_H