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_PROTO_DATA_ACCESSOR_INL_H 17 #define LIBPANDAFILE_PROTO_DATA_ACCESSOR_INL_H 18 19 #include "helpers.h" 20 21 #include "file_items.h" 22 #include "proto_data_accessor.h" 23 24 namespace panda::panda_file { 25 26 constexpr size_t SHORTY_ELEM_SIZE = sizeof(uint16_t); 27 constexpr size_t SHORTY_ELEM_WIDTH = 4; 28 constexpr size_t SHORTY_ELEM_MASK = 0xf; 29 constexpr size_t SHORTY_ELEM_PER16 = std::numeric_limits<uint16_t>::digits / SHORTY_ELEM_WIDTH; 30 SkipShorty()31inline void ProtoDataAccessor::SkipShorty() 32 { 33 EnumerateTypes([](Type /* unused */) {}); 34 } 35 36 template <class Callback> EnumerateTypes(const Callback & c)37inline void ProtoDataAccessor::EnumerateTypes(const Callback &c) 38 { 39 auto sp = panda_file_.GetSpanFromId(proto_id_); 40 41 uint32_t v = helpers::Read<SHORTY_ELEM_SIZE>(&sp); 42 uint32_t num_ref = 0; 43 size_ = SHORTY_ELEM_SIZE; 44 while (v != 0) { 45 size_t shift = (elem_num_ % SHORTY_ELEM_PER16) * SHORTY_ELEM_WIDTH; 46 uint8_t elem = (v >> shift) & SHORTY_ELEM_MASK; 47 48 if (elem == 0) { 49 break; 50 } 51 52 Type t(static_cast<Type::TypeId>(elem)); 53 c(t); 54 55 if (!t.IsPrimitive()) { 56 ++num_ref; 57 } 58 59 ++elem_num_; 60 61 if ((elem_num_ % SHORTY_ELEM_PER16) == 0) { 62 v = helpers::Read<SHORTY_ELEM_SIZE>(&sp); 63 size_ += SHORTY_ELEM_SIZE; 64 } 65 } 66 67 size_ += num_ref * IDX_SIZE; 68 ref_types_num_ = num_ref; 69 ref_types_sp_ = sp; 70 } 71 IsEqual(ProtoDataAccessor * other)72inline bool ProtoDataAccessor::IsEqual(ProtoDataAccessor *other) 73 { 74 size_t ref_num = 0; 75 size_t shorty_idx = 0; 76 auto sp1 = panda_file_.GetSpanFromId(proto_id_); 77 auto sp2 = other->panda_file_.GetSpanFromId(other->proto_id_); 78 auto v1 = helpers::Read<SHORTY_ELEM_SIZE>(&sp1); 79 auto v2 = helpers::Read<SHORTY_ELEM_SIZE>(&sp2); 80 while (true) { 81 size_t shift = (shorty_idx % SHORTY_ELEM_PER16) * SHORTY_ELEM_WIDTH; 82 uint8_t s1 = (v1 >> shift) & SHORTY_ELEM_MASK; // NOLINT(hicpp-signed-bitwise) 83 uint8_t s2 = (v2 >> shift) & SHORTY_ELEM_MASK; // NOLINT(hicpp-signed-bitwise) 84 if (s1 != s2) { 85 return false; 86 } 87 if (s1 == 0) { 88 break; 89 } 90 panda_file::Type t(static_cast<panda_file::Type::TypeId>(s1)); 91 if (!t.IsPrimitive()) { 92 ++ref_num; 93 } 94 if ((++shorty_idx % SHORTY_ELEM_PER16) == 0) { 95 v1 = helpers::Read<SHORTY_ELEM_SIZE>(&sp1); 96 v2 = helpers::Read<SHORTY_ELEM_SIZE>(&sp2); 97 } 98 } 99 100 // compare ref types 101 for (size_t ref_idx = 0; ref_idx < ref_num; ++ref_idx) { 102 auto id1 = panda_file_.ResolveClassIndex(proto_id_, helpers::Read<IDX_SIZE>(&sp1)); 103 auto id2 = other->panda_file_.ResolveClassIndex(other->proto_id_, helpers::Read<IDX_SIZE>(&sp2)); 104 if (panda_file_.GetStringData(id1) != other->panda_file_.GetStringData(id2)) { 105 return false; 106 } 107 } 108 109 return true; 110 } 111 GetNumArgs()112inline uint32_t ProtoDataAccessor::GetNumArgs() 113 { 114 if (ref_types_sp_.data() == nullptr) { 115 SkipShorty(); 116 } 117 118 return elem_num_ - 1; 119 } 120 GetReferenceType(size_t i)121inline File::EntityId ProtoDataAccessor::GetReferenceType(size_t i) 122 { 123 if (ref_types_sp_.data() == nullptr) { 124 SkipShorty(); 125 } 126 127 auto sp = ref_types_sp_.SubSpan(i * IDX_SIZE); 128 auto class_idx = helpers::Read<IDX_SIZE>(&sp); 129 return panda_file_.ResolveClassIndex(proto_id_, class_idx); 130 } 131 GetType(size_t idx)132inline Type ProtoDataAccessor::GetType(size_t idx) const 133 { 134 size_t block_idx = idx / SHORTY_ELEM_PER16; 135 size_t elem_shift = (idx % SHORTY_ELEM_PER16) * SHORTY_ELEM_WIDTH; 136 137 auto sp = panda_file_.GetSpanFromId(proto_id_); 138 139 sp = sp.SubSpan(SHORTY_ELEM_SIZE * block_idx); 140 141 uint32_t v = helpers::Read<SHORTY_ELEM_SIZE>(&sp); 142 return Type(static_cast<Type::TypeId>((v >> elem_shift) & SHORTY_ELEM_MASK)); 143 } 144 GetReturnType()145inline Type ProtoDataAccessor::GetReturnType() const 146 { 147 return GetType(0); 148 } 149 GetArgType(size_t idx)150inline Type ProtoDataAccessor::GetArgType(size_t idx) const 151 { 152 return GetType(idx + 1); 153 } 154 155 } // namespace panda::panda_file 156 157 #endif // LIBPANDAFILE_PROTO_DATA_ACCESSOR_INL_H 158