1b1994897Sopenharmony_ci/*
2b1994897Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
3b1994897Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4b1994897Sopenharmony_ci * you may not use this file except in compliance with the License.
5b1994897Sopenharmony_ci * You may obtain a copy of the License at
6b1994897Sopenharmony_ci *
7b1994897Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0
8b1994897Sopenharmony_ci *
9b1994897Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10b1994897Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11b1994897Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12b1994897Sopenharmony_ci * See the License for the specific language governing permissions and
13b1994897Sopenharmony_ci * limitations under the License.
14b1994897Sopenharmony_ci */
15b1994897Sopenharmony_ci
16b1994897Sopenharmony_ci#include "collect_util.h"
17b1994897Sopenharmony_ci
18b1994897Sopenharmony_ci#include <codecvt>
19b1994897Sopenharmony_ci#include <locale>
20b1994897Sopenharmony_ci
21b1994897Sopenharmony_cinamespace panda::libpandafile {
22b1994897Sopenharmony_ci
23b1994897Sopenharmony_ci/**
24b1994897Sopenharmony_ci * processed_ids: The literal array ids are collected from field and ins, needn't process nest.
25b1994897Sopenharmony_ci * nest_unprocessed_ids: The literal array ids are collected from ins, need process nest.
26b1994897Sopenharmony_ci */
27b1994897Sopenharmony_civoid CollectUtil::CollectLiteralArray(const panda_file::File &file_, std::unordered_set<uint32_t> &processed_ids)
28b1994897Sopenharmony_ci{
29b1994897Sopenharmony_ci    std::unordered_set<uint32_t> nest_unprocessed_ids;
30b1994897Sopenharmony_ci
31b1994897Sopenharmony_ci    for (uint32_t id : file_.GetClasses()) {
32b1994897Sopenharmony_ci        panda_file::File::EntityId class_id(id);
33b1994897Sopenharmony_ci        if (file_.IsExternal(class_id)) {
34b1994897Sopenharmony_ci            continue;
35b1994897Sopenharmony_ci        }
36b1994897Sopenharmony_ci        panda_file::ClassDataAccessor class_data_accessor(file_, class_id);
37b1994897Sopenharmony_ci        CollectClassLiteralArray(class_data_accessor, processed_ids, nest_unprocessed_ids);
38b1994897Sopenharmony_ci    }
39b1994897Sopenharmony_ci    ProcessNestLiteralArray(file_, processed_ids, nest_unprocessed_ids);
40b1994897Sopenharmony_ci}
41b1994897Sopenharmony_ci
42b1994897Sopenharmony_civoid CollectUtil::CollectClassLiteralArray(panda_file::ClassDataAccessor &class_data_accessor,
43b1994897Sopenharmony_ci                                           std::unordered_set<uint32_t> &processed_ids,
44b1994897Sopenharmony_ci                                           std::unordered_set<uint32_t> &nest_unprocessed_ids)
45b1994897Sopenharmony_ci{
46b1994897Sopenharmony_ci    panda_file::File::StringData csd = class_data_accessor.GetName();
47b1994897Sopenharmony_ci    const char *cn = utf::Mutf8AsCString(csd.data);
48b1994897Sopenharmony_ci    class_data_accessor.EnumerateFields([&](panda_file::FieldDataAccessor &field_accessor) -> void {
49b1994897Sopenharmony_ci        panda_file::File::EntityId field_name_id = field_accessor.GetNameId();
50b1994897Sopenharmony_ci        panda_file::File::StringData fsd = class_data_accessor.GetPandaFile().GetStringData(field_name_id);
51b1994897Sopenharmony_ci        const char *fn = utf::Mutf8AsCString(fsd.data);
52b1994897Sopenharmony_ci        if (std::strcmp(cn, ES_MODULE_RECORD.data()) != 0 &&
53b1994897Sopenharmony_ci            std::strcmp(cn, ES_SCOPE_NAMES_RECORD.data()) != 0 &&
54b1994897Sopenharmony_ci            std::strcmp(fn, SCOPE_NAMES.data()) != 0 &&
55b1994897Sopenharmony_ci            std::strcmp(fn, MODULE_RECORD_IDX.data()) != 0) {
56b1994897Sopenharmony_ci            return;
57b1994897Sopenharmony_ci        }
58b1994897Sopenharmony_ci        auto module_offset = field_accessor.GetValue<uint32_t>().value();
59b1994897Sopenharmony_ci        processed_ids.emplace(module_offset);
60b1994897Sopenharmony_ci    });
61b1994897Sopenharmony_ci    class_data_accessor.EnumerateMethods([&](panda_file::MethodDataAccessor &method_accessor) -> void {
62b1994897Sopenharmony_ci        if (!method_accessor.GetCodeId().has_value()) {
63b1994897Sopenharmony_ci            return;
64b1994897Sopenharmony_ci        }
65b1994897Sopenharmony_ci        panda_file::File::EntityId method_id = method_accessor.GetMethodId();
66b1994897Sopenharmony_ci        panda_file::File::EntityId code_id = method_accessor.GetCodeId().value();
67b1994897Sopenharmony_ci        panda_file::CodeDataAccessor code_data_accessor {class_data_accessor.GetPandaFile(), code_id};
68b1994897Sopenharmony_ci        uint32_t ins_size_ = code_data_accessor.GetCodeSize();
69b1994897Sopenharmony_ci        const uint8_t *ins_arr = code_data_accessor.GetInstructions();
70b1994897Sopenharmony_ci        auto bc_ins = panda::BytecodeInst<BytecodeInstMode::FAST>(ins_arr);
71b1994897Sopenharmony_ci        const auto bc_ins_last = bc_ins.JumpTo(ins_size_);
72b1994897Sopenharmony_ci        while (bc_ins.GetAddress() < bc_ins_last.GetAddress()) {
73b1994897Sopenharmony_ci            if (!bc_ins.IsPrimaryOpcodeValid()) {
74b1994897Sopenharmony_ci                LOG(FATAL, PANDAFILE) << "Fail to verify primary opcode!";
75b1994897Sopenharmony_ci            }
76b1994897Sopenharmony_ci            if (bc_ins.HasFlag(panda::BytecodeInst<BytecodeInstMode::FAST>::Flags::LITERALARRAY_ID)) {
77b1994897Sopenharmony_ci                const auto literal_id =
78b1994897Sopenharmony_ci                    GetLiteralArrayIdInBytecodeInst(class_data_accessor.GetPandaFile(), method_id, bc_ins);
79b1994897Sopenharmony_ci                nest_unprocessed_ids.insert(literal_id.GetOffset());
80b1994897Sopenharmony_ci            }
81b1994897Sopenharmony_ci            bc_ins = bc_ins.GetNext();
82b1994897Sopenharmony_ci        }
83b1994897Sopenharmony_ci    });
84b1994897Sopenharmony_ci}
85b1994897Sopenharmony_ci
86b1994897Sopenharmony_civoid CollectUtil::ProcessNestLiteralArray(const panda_file::File &file_, std::unordered_set<uint32_t> &processed_ids,
87b1994897Sopenharmony_ci                                          std::unordered_set<uint32_t> &nest_unprocessed_ids)
88b1994897Sopenharmony_ci{
89b1994897Sopenharmony_ci    if (nest_unprocessed_ids.empty()) {
90b1994897Sopenharmony_ci        return;
91b1994897Sopenharmony_ci    }
92b1994897Sopenharmony_ci
93b1994897Sopenharmony_ci    panda_file::File::EntityId lit_array_invalid(panda_file::INVALID_OFFSET);
94b1994897Sopenharmony_ci    panda_file::LiteralDataAccessor literal_data_accessor {file_, lit_array_invalid};
95b1994897Sopenharmony_ci    while (!nest_unprocessed_ids.empty()) {
96b1994897Sopenharmony_ci        auto nest_unprocess_id_iterator = nest_unprocessed_ids.begin();
97b1994897Sopenharmony_ci        uint32_t nest_unprocess_id = *nest_unprocess_id_iterator;
98b1994897Sopenharmony_ci        processed_ids.emplace(nest_unprocess_id);
99b1994897Sopenharmony_ci        panda_file::File::EntityId nest_unprocess_id_entity_id(nest_unprocess_id);
100b1994897Sopenharmony_ci        literal_data_accessor.EnumerateLiteralVals(
101b1994897Sopenharmony_ci            nest_unprocess_id_entity_id,
102b1994897Sopenharmony_ci            [processed_ids, &nest_unprocessed_ids](const panda_file::LiteralDataAccessor::LiteralValue &value,
103b1994897Sopenharmony_ci                                                 const panda_file::LiteralTag &tag) {
104b1994897Sopenharmony_ci                if (tag != panda_file::LiteralTag::LITERALARRAY) {
105b1994897Sopenharmony_ci                    return;
106b1994897Sopenharmony_ci                }
107b1994897Sopenharmony_ci                uint32_t idx = std::get<uint32_t>(value);
108b1994897Sopenharmony_ci                if ((processed_ids.find(idx) != processed_ids.end()) ||
109b1994897Sopenharmony_ci                    (nest_unprocessed_ids.find(idx) != nest_unprocessed_ids.end())) {
110b1994897Sopenharmony_ci                    return;
111b1994897Sopenharmony_ci                }
112b1994897Sopenharmony_ci                nest_unprocessed_ids.emplace(idx);
113b1994897Sopenharmony_ci            });
114b1994897Sopenharmony_ci        nest_unprocessed_ids.erase(nest_unprocess_id);
115b1994897Sopenharmony_ci    }
116b1994897Sopenharmony_ci}
117b1994897Sopenharmony_ci
118b1994897Sopenharmony_cipanda_file::File::EntityId CollectUtil::GetLiteralArrayIdInBytecodeInst(
119b1994897Sopenharmony_ci    const panda_file::File &file_, panda_file::File::EntityId method_id,
120b1994897Sopenharmony_ci    panda::BytecodeInst<BytecodeInstMode::FAST> bc_ins)
121b1994897Sopenharmony_ci{
122b1994897Sopenharmony_ci    size_t idx = bc_ins.GetLiteralIndex();
123b1994897Sopenharmony_ci    if (idx < 0) {
124b1994897Sopenharmony_ci        LOG(FATAL, PANDAFILE) << "Fail to verify ID Index!";
125b1994897Sopenharmony_ci    }
126b1994897Sopenharmony_ci    const auto arg_literal_idx = bc_ins.GetId(idx).AsIndex();
127b1994897Sopenharmony_ci    const auto literal_id = file_.ResolveMethodIndex(method_id, arg_literal_idx);
128b1994897Sopenharmony_ci    return literal_id;
129b1994897Sopenharmony_ci}
130b1994897Sopenharmony_ci
131b1994897Sopenharmony_ci}  // namespace panda::libpandafile