1/*
2 * Copyright (c) 2023 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#include "ecmascript/compiler/aot_snapshot/snapshot_global_data.h"
17
18#include "ecmascript/compiler/aot_snapshot/aot_snapshot_constants.h"
19#include "ecmascript/jspandafile/program_object.h"
20
21namespace panda::ecmascript::kungfu {
22JSHandle<ConstantPool> ReviseData::GetConstantPoolFromSnapshotData(JSThread *thread,
23                                                                   const SnapshotGlobalData *globalData,
24                                                                   uint32_t dataIdx, uint32_t cpArrayIdx)
25{
26    JSHandle<TaggedArray> data(thread, globalData->GetData());
27    auto cpArrayOffset = SnapshotGlobalData::Cast(SnapshotGlobalData::CP_TOP_ITEM::CP_ARRAY_ID);
28    JSHandle<TaggedArray> cpArr(thread, data->Get(dataIdx + cpArrayOffset));
29    return JSHandle<ConstantPool>(thread, cpArr->Get(cpArrayIdx));
30}
31
32void ReviseData::Resolve(JSThread *thread, const SnapshotGlobalData *globalData,
33    const CMap<std::pair<std::string, uint32_t>, uint32_t> &methodToEntryIndexMap)
34{
35    for (auto &item: data_) {
36        JSHandle<ConstantPool> newCP = GetConstantPoolFromSnapshotData(thread, globalData,
37                                                                       item.dataIdx_, item.cpArrayIdx_);
38
39        JSTaggedValue val = newCP->GetObjectFromCache(item.constpoolIdx_);
40        if (val.IsHole()) {
41            continue;
42        }
43        std::string name = globalData->GetFileNameByDataIdx(item.dataIdx_).c_str();
44        // For MethodSnaphotInfo which does not have ihc info, we insert JSTaggedValue(methodOffset) as revervation.
45        // We need to set JSTaggedValue(codeEntry); to replace JSTaggedValue(methodOffset).
46        if (val.IsInt()) {
47            if (val.GetInt() == static_cast<int>(AOTLiteralInfo::NO_FUNC_ENTRY_VALUE)) {
48                continue;
49            }
50            uint32_t methodOffset = static_cast<uint32_t>(val.GetInt());
51            if (thread->GetEcmaVM()->GetJSOptions().IsEnableCompilerLogSnapshot()) {
52                LOG_COMPILER(INFO) << "[aot-snapshot] store AOT entry index of method (offset: "
53                                   << methodOffset << ") ";
54            }
55            AnFileInfo::FuncEntryIndexKey key = std::make_pair(name, methodOffset);
56            uint32_t entryIndex = methodToEntryIndexMap.at(key);
57            newCP->SetObjectToCache(thread, item.constpoolIdx_, JSTaggedValue(entryIndex));
58            continue;
59        }
60        AOTLiteralInfo *aotLiteralInfo = AOTLiteralInfo::Cast(val.GetTaggedObject());
61        uint32_t aotLiteralInfoLen = aotLiteralInfo->GetCacheLength();
62        for (uint32_t i = 0; i < aotLiteralInfoLen; ++i) {
63            JSTaggedValue methodOffsetVal = aotLiteralInfo->GetObjectFromCache(i);
64            if (methodOffsetVal.GetInt() == static_cast<int>(AOTLiteralInfo::NO_FUNC_ENTRY_VALUE)) {
65                continue;
66            }
67            uint32_t methodOffset = static_cast<uint32_t>(methodOffsetVal.GetInt());
68            if (thread->GetEcmaVM()->GetJSOptions().IsEnableCompilerLogSnapshot()) {
69                LOG_COMPILER(INFO) << "[aot-snapshot] store AOT entry index of method (offset: "
70                                   << methodOffset << ") ";
71            }
72            AnFileInfo::FuncEntryIndexKey key = std::make_pair(name, methodOffset);
73            uint32_t entryIndex = methodToEntryIndexMap.at(key);
74            aotLiteralInfo->SetObjectToCache(thread, i, JSTaggedValue(entryIndex));
75        }
76    }
77}
78
79void SnapshotGlobalData::AddSnapshotCpArrayToData(JSThread *thread, CString fileName, uint32_t fileIndex,
80                                                  JSHandle<TaggedArray> snapshotCpArray)
81{
82    if (isFirstData_) {
83        isFirstData_ = false;
84    } else {
85        curDataIdx_ += AOTSnapshotConstants::SNAPSHOT_DATA_ITEM_SIZE;
86    }
87    // handle file info
88    JSHandle<EcmaString> nameStr = thread->GetEcmaVM()->GetFactory()->NewFromStdString(fileName.c_str());
89    auto fileInfo = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(Cast(CP_PANDA_INFO_ITEM::COUNT));
90    fileInfo->Set(thread, Cast(CP_PANDA_INFO_ITEM::NAME_ID), nameStr);
91    fileInfo->Set(thread, Cast(CP_PANDA_INFO_ITEM::INDEX_ID), JSTaggedValue(fileIndex));
92
93    JSHandle<TaggedArray> dataHandle(thread, data_);
94    dataHandle->Set(thread, curDataIdx_ + Cast(CP_TOP_ITEM::PANDA_INFO_ID), fileInfo);
95
96    // handle constant pool
97    curSnapshotCpArray_ = snapshotCpArray.GetTaggedValue();
98    dataHandle->Set(thread, curDataIdx_ + Cast(CP_TOP_ITEM::CP_ARRAY_ID), curSnapshotCpArray_);
99    dataIdxToFileNameMap_[curDataIdx_] = fileName;
100}
101
102CString SnapshotGlobalData::GetFileNameByDataIdx(uint32_t dataIdx) const
103{
104    auto it = dataIdxToFileNameMap_.find(dataIdx);
105    if (it != dataIdxToFileNameMap_.end()) {
106        return it->second;
107    }
108    LOG_COMPILER(FATAL) << "Can't find snapshot data by index '" << dataIdx << "'";
109    UNREACHABLE();
110}
111}  // namespace panda::ecmascript
112