1 /**
2 * Copyright (c) 2024 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 "libabckit/src/wrappers/graph_wrapper/graph_wrapper.h"
17 #include "libabckit/include/c/statuses.h"
18 #include "libabckit/src/wrappers/abcfile_wrapper.h"
19 #include "libabckit/src/macros.h"
20 #include "libabckit/src/irbuilder_dynamic/ir_builder_dyn.h"
21 #include "libabckit/src/adapter_dynamic/runtime_adapter_dynamic.h"
22 #include "libabckit/src/adapter_dynamic/convert.h"
23 #include "libabckit/src/adapter_static/helpers_static.h"
24 #include "libabckit/src/codegen/codegen_dynamic.h"
25 #include "libabckit/src/codegen/ic_slot_allocator.h"
26 #include "libabckit/src/helpers_common.h"
27
28 #include "static_core/compiler/optimizer/analysis/dominators_tree.h"
29 #include "static_core/assembler/assembly-function.h"
30 #include "static_core/assembler/assembly-record.h"
31 #include "static_core/assembler/mangling.h"
32 #include "static_core/bytecode_optimizer/check_resolver.h"
33 #include "static_core/bytecode_optimizer/reg_encoder.h"
34 #include "static_core/compiler/optimizer/ir/graph.h"
35 #include "static_core/compiler/optimizer/ir/graph_checker.h"
36 #include "static_core/compiler/optimizer/ir/graph_cloner.h"
37 #include "static_core/compiler/optimizer/optimizations/move_constants.h"
38 #include "static_core/compiler/optimizer/optimizations/cleanup.h"
39 #include "static_core/compiler/optimizer/optimizations/try_catch_resolving.h"
40 #include "static_core/libpandabase/utils/arch.h"
41
42 #include <cstdint>
43 #include <iostream>
44
45 namespace libabckit {
46 // CC-OFFNXT(WordsTool.95) sensitive word conflict
47 // NOLINTNEXTLINE(google-build-using-namespace)
48 using namespace ark;
49
50 struct CtxGInternalDynamic {
51 ArenaAllocator *allocator;
52 ArenaAllocator *localAllocator;
53 const AbckitIrInterface *irInterface;
54 AbckitRuntimeAdapterDynamic *runtimeAdapter;
55 };
56
BuildGraphDynamic(FileWrapper * pf,AbckitIrInterface * irInterface,AbckitFile * file,uint32_t methodOffset)57 AbckitGraph *GraphWrapper::BuildGraphDynamic(FileWrapper *pf, AbckitIrInterface *irInterface, AbckitFile *file,
58 uint32_t methodOffset)
59 {
60 ark::compiler::g_options.SetCompilerUseSafepoint(false);
61 ark::compiler::g_options.SetCompilerFrameSize("large");
62
63 auto *allocator = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER);
64 auto *localAllocator = new ArenaAllocator(SpaceType::SPACE_TYPE_COMPILER, nullptr, true);
65 auto *adapter = new AbckitRuntimeAdapterDynamic(*pf);
66
67 auto methodPtr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(methodOffset); // NOTE
68 auto graphImpl = allocator->New<compiler::Graph>(
69 compiler::Graph::GraphArgs {allocator, localAllocator, Arch::NONE, methodPtr, adapter}, nullptr, false, false,
70 true);
71 if (graphImpl == nullptr) {
72 LIBABCKIT_LOG(DEBUG) << "graph == nullptr\n";
73 delete allocator;
74 delete localAllocator;
75 delete adapter;
76 statuses::SetLastError(AbckitStatus::ABCKIT_STATUS_MEMORY_ALLOCATION);
77 return nullptr;
78 }
79 graphImpl->SetDynamicMethod();
80 graphImpl->SetAbcKit();
81 if (!graphImpl->RunPass<IrBuilderDynamic>()) {
82 LIBABCKIT_LOG(DEBUG) << "IrBuilder failed!\n";
83 // Input file with bad bytecode
84 statuses::SetLastError(AbckitStatus::ABCKIT_STATUS_BAD_ARGUMENT);
85 return nullptr;
86 }
87 if (GraphHasUnreachableBlocks(graphImpl)) {
88 LIBABCKIT_LOG(DEBUG) << "Cannot build graph, there are unreachable blocks in graph\n";
89 statuses::SetLastError(ABCKIT_STATUS_BAD_ARGUMENT);
90 return nullptr;
91 }
92 graphImpl->RunPass<ark::bytecodeopt::CheckResolver>();
93 graphImpl->RunPass<ark::compiler::Cleanup>();
94 CheckInvalidOpcodes(graphImpl, true);
95
96 auto graph = new AbckitGraph;
97 graph->irInterface = irInterface;
98 graph->impl = graphImpl;
99 graph->file = file;
100 CreateGraphWrappers(graph);
101
102 auto *ctxGInternal = new CtxGInternalDynamic {allocator, localAllocator, irInterface, adapter};
103 graph->internal = ctxGInternal;
104
105 return graph;
106 }
107
108 // false positive
109 // NOLINTNEXTLINE(readability-non-const-parameter)
RunPreliminaryPasses(ark::compiler::Graph * graphImpl,uint16_t * icSlotNumber)110 static bool RunPreliminaryPasses(ark::compiler::Graph *graphImpl, uint16_t *icSlotNumber)
111 {
112 graphImpl->RemoveUnreachableBlocks();
113
114 graphImpl->InvalidateAnalysis<compiler::LoopAnalyzer>();
115
116 CheckInvalidOpcodes(graphImpl, true);
117
118 if (!ark::compiler::GraphChecker(graphImpl).Check()) {
119 LIBABCKIT_LOG(DEBUG) << ": Graph Verifier failed!\n";
120 statuses::SetLastError(AbckitStatus::ABCKIT_STATUS_BAD_ARGUMENT);
121 return false;
122 }
123
124 graphImpl->InvalidateAnalysis<compiler::DominatorsTree>();
125
126 if (!graphImpl->RunPass<compiler::DominatorsTree>()) {
127 LIBABCKIT_LOG(DEBUG) << ": ICDominatorsTree failed!\n";
128 statuses::SetLastError(AbckitStatus::ABCKIT_STATUS_INTERNAL_ERROR);
129 return false;
130 }
131
132 if (!graphImpl->RunPass<ICSlotAllocator>(icSlotNumber)) {
133 LIBABCKIT_LOG(DEBUG) << ": ICSlotAllocator failed!\n";
134 statuses::SetLastError(AbckitStatus::ABCKIT_STATUS_INTERNAL_ERROR);
135 return false;
136 }
137
138 graphImpl->RunPass<compiler::MoveConstants>();
139
140 if (!AllocateRegisters(graphImpl, CodeGenDynamic::RESERVED_REG)) {
141 LIBABCKIT_LOG(DEBUG) << ": RegAllocGraphColoring failed!\n";
142 statuses::SetLastError(AbckitStatus::ABCKIT_STATUS_INTERNAL_ERROR);
143 return false;
144 }
145
146 if (!graphImpl->RunPass<bytecodeopt::RegEncoder>()) {
147 LIBABCKIT_LOG(DEBUG) << ": RegEncoder failed!\n";
148 statuses::SetLastError(AbckitStatus::ABCKIT_STATUS_INTERNAL_ERROR);
149 return false;
150 }
151
152 return true;
153 }
154
BuildCodeDynamic(AbckitGraph * graph,const std::string & funcName)155 void *GraphWrapper::BuildCodeDynamic(AbckitGraph *graph, const std::string &funcName)
156 {
157 LIBABCKIT_LOG(DEBUG) << "Building code for function " << funcName << "\n";
158
159 auto graphImpl =
160 compiler::GraphCloner(graph->impl, graph->impl->GetAllocator(), graph->impl->GetLocalAllocator()).CloneGraph();
161
162 graphImpl->RemoveUnreachableBlocks();
163 GraphInvalidateAnalyses(graphImpl);
164
165 LIBABCKIT_LOG(DEBUG) << "BEFORE======================================\n";
166 LIBABCKIT_LOG_DUMP(graphImpl->Dump(&std::cerr), DEBUG);
167 LIBABCKIT_LOG(DEBUG) << "============================================\n";
168
169 uint16_t icSlotNumber = 0;
170 if (!RunPreliminaryPasses(graphImpl, &icSlotNumber)) {
171 return nullptr;
172 }
173
174 LIBABCKIT_LOG(DEBUG) << "AFTER=======================================\n";
175 LIBABCKIT_LOG_DUMP(graphImpl->Dump(&std::cerr), DEBUG);
176 LIBABCKIT_LOG(DEBUG) << "============================================\n";
177
178 const auto lang = convert::ToSourceLang(graph->function->owningModule->target);
179 FunctionWrapper *wrFunc = PandasmWrapper::CreateWrappedFunction(lang);
180 if (!graphImpl->RunPass<CodeGenDynamic>(wrFunc, graph->irInterface)) {
181 LIBABCKIT_LOG(DEBUG) << funcName << ": Code generation failed!\n";
182 statuses::SetLastError(AbckitStatus::ABCKIT_STATUS_INTERNAL_ERROR);
183 return nullptr;
184 }
185
186 wrFunc->valueOfFirstParam =
187 static_cast<int64_t>(graphImpl->GetStackSlotsCount()) - 1L; // Work-around promotion rules
188 wrFunc->regsNum = static_cast<size_t>(wrFunc->valueOfFirstParam + 1U);
189 wrFunc->slotsNum = static_cast<size_t>(icSlotNumber);
190
191 return PandasmWrapper::GetPandasmFunction(wrFunc);
192 }
193
CreateGraphWrappers(AbckitGraph * graph)194 void GraphWrapper::CreateGraphWrappers(AbckitGraph *graph)
195 {
196 auto *graphImpl = graph->impl;
197
198 for (auto *bbImpl : graphImpl->GetBlocksRPO()) {
199 auto *bb = graphImpl->GetLocalAllocator()->New<AbckitBasicBlock>();
200 bb->graph = graph;
201 bb->impl = bbImpl;
202 graph->implToBB.insert({bbImpl, bb});
203 for (auto *instImpl : bbImpl->AllInsts()) {
204 CreateInstFromImpl(graph, instImpl);
205 }
206 }
207
208 auto *file = graph->file;
209
210 // NOTE(ivagin)
211 // Valid only for static, because in dynamic mode
212 // classes are contained as functions
213 if (file->frontend == Mode::STATIC) {
214 // Find all class names and abckit classes
215 std::unordered_map<std::string, AbckitCoreClass *> namesToClasses;
216 for (auto &[_, module] : file->localModules) {
217 for (auto &[_, klass] : module->ct) {
218 auto *func = klass->GetArkTSImpl()->impl.GetStaticClass();
219 namesToClasses[func->name] = klass.get();
220 }
221 }
222 // Fill map offset to AbckitCoreClass for this graph context
223 for (auto &[offset, str] : graph->irInterface->classes) {
224 auto it = namesToClasses.find(pandasm::DeMangleName(str));
225 if (it != namesToClasses.end()) {
226 graph->ptrToClass[offset] = it->second;
227 }
228 }
229 }
230 }
231
DestroyGraphDynamic(AbckitGraph * graph)232 void GraphWrapper::DestroyGraphDynamic(AbckitGraph *graph)
233 {
234 LIBABCKIT_LOG_FUNC;
235 auto *ctxGInternal = reinterpret_cast<CtxGInternalDynamic *>(graph->internal);
236 // dirty hack to obtain FileWrapper pointer
237 // NOTE(mshimenkov): refactor it
238 auto *fileWrapper = reinterpret_cast<FileWrapper *>(ctxGInternal->runtimeAdapter->GetBinaryFileForMethod(nullptr));
239 delete fileWrapper;
240 delete ctxGInternal->runtimeAdapter;
241 delete ctxGInternal->irInterface;
242 delete ctxGInternal->localAllocator;
243 delete ctxGInternal->allocator;
244 delete ctxGInternal;
245 delete graph;
246 }
247
248 } // namespace libabckit
249