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 #include "typeExtractorEmitter.h"
17
18 #include <assembly-emitter.h>
19 #include <binder/binder.h>
20 #include <compiler/core/compilerContext.h>
21 #include <compiler/core/emitter/emitter.h>
22
23 namespace panda::es2panda::compiler {
24
25 using AnnotationElement = panda::pandasm::AnnotationElement;
26 using ArrayValue = panda::pandasm::ArrayValue;
27 using Field = panda::pandasm::Field;
28 using Record = panda::pandasm::Record;
29 using ScalarValue = panda::pandasm::ScalarValue;
30 using Type = panda::pandasm::Type;
31 using ValueType = panda::pandasm::Value::Type;
32
TypeExtractorEmitter(const PandaGen * pg,panda::pandasm::Function * func)33 TypeExtractorEmitter::TypeExtractorEmitter(const PandaGen *pg, panda::pandasm::Function *func) : pg_(pg), func_(func)
34 {
35 auto prog = pg_->Context()->GetEmitter()->GetProgram();
36 GenFunctionTypeInfo(prog);
37 if (IsFuncMain0(func->name, pg_->Context()->IsMergeAbc())) {
38 if (pg_->Context()->TypeRecorder()->ExportType().size() > 0U) {
39 GenExportTypeInfo(prog);
40 }
41 if (pg_->Context()->TypeRecorder()->DeclareType().size() > 0U) {
42 GenDeclareTypeInfo(prog);
43 }
44 }
45 }
46
IsFuncMain0(const std::string & funcName,bool isMergeAbc) const47 bool TypeExtractorEmitter::IsFuncMain0(const std::string &funcName, bool isMergeAbc) const
48 {
49 std::string expectedName(binder::Binder::MAIN_FUNC_NAME);
50 if (isMergeAbc) {
51 expectedName = std::string(pg_->Context()->RecordName()) + "." + expectedName;
52 }
53 return funcName == expectedName;
54 }
55
GenTypeInfo(const extractor::TypeRecorder * recorder,int64_t typeIndex,std::vector<Literal> & typeInfo)56 static void GenTypeInfo(const extractor::TypeRecorder *recorder, int64_t typeIndex, std::vector<Literal> &typeInfo)
57 {
58 Literal typeTag;
59 Literal typeValue;
60 typeTag.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
61 if (typeIndex >= recorder->GetUserTypeIndexShift()) {
62 typeTag.value_ = static_cast<uint8_t>(panda::panda_file::LiteralTag::LITERALARRAY);
63 typeValue.tag_ = panda::panda_file::LiteralTag::LITERALARRAY;
64 typeValue.value_ = std::string(recorder->GetRecordName()) + "_" +
65 std::to_string(typeIndex - recorder->GetUserTypeIndexShift());
66 } else {
67 typeTag.value_ = static_cast<uint8_t>(panda::panda_file::LiteralTag::BUILTINTYPEINDEX);
68 typeValue.tag_ = panda::panda_file::LiteralTag::BUILTINTYPEINDEX;
69 typeValue.value_ = static_cast<uint8_t>(typeIndex);
70 }
71 typeInfo.emplace_back(typeTag);
72 typeInfo.emplace_back(typeValue);
73 }
74
GenInsnTypeInfo(const extractor::TypeRecorder * recorder,uint32_t orderIndex,int64_t typeIndex,std::vector<Literal> & typedInsns)75 static void GenInsnTypeInfo(const extractor::TypeRecorder *recorder, uint32_t orderIndex, int64_t typeIndex,
76 std::vector<Literal> &typedInsns)
77 {
78 Literal insnOrderTag;
79 Literal insnOrderValue;
80 insnOrderTag.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
81 insnOrderTag.value_ = static_cast<uint8_t>(panda::panda_file::LiteralTag::INTEGER);
82 insnOrderValue.tag_ = panda::panda_file::LiteralTag::INTEGER;
83 insnOrderValue.value_ = static_cast<uint32_t>(orderIndex);
84 typedInsns.emplace_back(insnOrderTag);
85 typedInsns.emplace_back(insnOrderValue);
86
87 GenTypeInfo(recorder, typeIndex, typedInsns);
88 }
89
GenFunctionTypeInfo(panda::pandasm::Program * prog)90 void TypeExtractorEmitter::GenFunctionTypeInfo(panda::pandasm::Program *prog)
91 {
92 auto recorder = pg_->Context()->TypeRecorder();
93 std::vector<Literal> typedInsns;
94 typedInsns.reserve(pg_->TypedInsns().size() * 4U); // Expand to 4 pieces of information
95 uint32_t index = 0;
96 uint32_t remove = 0;
97 for (const auto *ins : pg_->Insns()) {
98 if (func_->ins[index].opcode == panda::pandasm::Opcode::INVALID) {
99 remove++;
100 index++;
101 continue;
102 }
103 auto t = pg_->TypedInsns().find(ins);
104 if (t != pg_->TypedInsns().end()) {
105 int64_t typeIndex = t->second;
106 uint32_t orderIndex = index;
107 if (typeIndex > extractor::TypeRecorder::PRIMITIVETYPE_ANY) {
108 uint32_t realOrderIndex = orderIndex - remove;
109 GenInsnTypeInfo(recorder, realOrderIndex, typeIndex, typedInsns);
110 DCOUT << "[LOG] " << func_->name << ": " << func_->ins[index].ToString("", true, func_->regs_num) <<
111 " | " << realOrderIndex << " | " << typeIndex << std::endl;
112 }
113 }
114 index++;
115 }
116
117 if (pg_->TypedFunc().first != extractor::TypeRecorder::PRIMITIVETYPE_ANY) {
118 // -1 for function type
119 GenInsnTypeInfo(recorder, static_cast<uint32_t>(-1), pg_->TypedFunc().first, typedInsns);
120 DCOUT << "[LOG]" << func_->name << ": -1 | " << pg_->TypedFunc().first << std::endl;
121 }
122 if (pg_->TypedFunc().second > extractor::TypeRecorder::PRIMITIVETYPE_ANY) {
123 // -2 for method 'this' type
124 GenInsnTypeInfo(recorder, static_cast<uint32_t>(-2), pg_->TypedFunc().second, typedInsns);
125 DCOUT << "[LOG]" << func_->name << ": -2 | " << pg_->TypedFunc().second << std::endl;
126 }
127
128 if (typedInsns.empty()) {
129 return;
130 }
131
132 std::lock_guard<std::mutex> lock(pg_->Context()->GetEmitter()->GetEmitterLock());
133 std::string literalId = std::string(recorder->GetRecordName()) + "_" +
134 func_->name + "_" + std::to_string(literalId_--);
135 auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(typedInsns));
136 prog->literalarray_table.emplace(literalId, std::move(literalArrayInstance));
137
138 AnnotationData funcTypeAnnotation(TypeExtractorEmitter::TYPE_ANNOTATION);
139 AnnotationElement funcTypeAnnotationElement(TypeExtractorEmitter::TYPE_INSTRUCTION,
140 std::make_unique<ScalarValue>(ScalarValue::Create<ValueType::LITERALARRAY>(literalId)));
141 funcTypeAnnotation.AddElement(std::move(funcTypeAnnotationElement));
142 func_->metadata->AddAnnotations({ funcTypeAnnotation });
143 }
144
145 template <bool isExport, typename M>
GenImportOrDeclareTypeInfo(panda::pandasm::Program * prog,const extractor::TypeRecorder * recorder,const M & map,AnnotationData & funcTypeAnnotation)146 void TypeExtractorEmitter::GenImportOrDeclareTypeInfo(panda::pandasm::Program *prog,
147 const extractor::TypeRecorder *recorder, const M &map, AnnotationData &funcTypeAnnotation)
148 {
149 std::string symbolTypeStr;
150 if constexpr (isExport) {
151 symbolTypeStr = TypeExtractorEmitter::EXPORTED_SYMBOL_TYPES;
152 } else {
153 symbolTypeStr = TypeExtractorEmitter::DECLARED_SYMBOL_TYPES;
154 }
155
156 std::vector<Literal> typedSymbols;
157 typedSymbols.reserve(map.size() * 4U); // Expand to 4 pieces of information
158 for (const auto &t : map) {
159 Literal symbolTag;
160 Literal symbolValue;
161 symbolTag.tag_ = panda::panda_file::LiteralTag::TAGVALUE;
162 symbolTag.value_ = static_cast<uint8_t>(panda::panda_file::LiteralTag::STRING);
163 symbolValue.tag_ = panda::panda_file::LiteralTag::STRING;
164 symbolValue.value_ = t.first;
165 typedSymbols.emplace_back(symbolTag);
166 typedSymbols.emplace_back(symbolValue);
167
168 GenTypeInfo(recorder, t.second, typedSymbols);
169 }
170
171 std::lock_guard<std::mutex> lock(pg_->Context()->GetEmitter()->GetEmitterLock());
172 std::string literalId = std::string(recorder->GetRecordName()) + "_" +
173 func_->name + "_" + std::to_string(literalId_--);
174 auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(typedSymbols));
175 prog->literalarray_table.emplace(literalId, std::move(literalArrayInstance));
176
177 AnnotationElement funcSymbolTypeElement(symbolTypeStr,
178 std::make_unique<ScalarValue>(ScalarValue::Create<ValueType::LITERALARRAY>(literalId)));
179 funcTypeAnnotation.AddElement(std::move(funcSymbolTypeElement));
180 }
181
GenExportTypeInfo(panda::pandasm::Program * prog)182 void TypeExtractorEmitter::GenExportTypeInfo(panda::pandasm::Program *prog)
183 {
184 AnnotationData funcTypeAnnotation(TypeExtractorEmitter::TYPE_ANNOTATION);
185 GenImportOrDeclareTypeInfo<true>(prog, pg_->Context()->TypeRecorder(),
186 pg_->Context()->TypeRecorder()->ExportType(), funcTypeAnnotation);
187 func_->metadata->AddAnnotations({ funcTypeAnnotation });
188 }
189
GenDeclareTypeInfo(panda::pandasm::Program * prog)190 void TypeExtractorEmitter::GenDeclareTypeInfo(panda::pandasm::Program *prog)
191 {
192 AnnotationData funcTypeAnnotation(TypeExtractorEmitter::TYPE_ANNOTATION);
193 GenImportOrDeclareTypeInfo<false>(prog, pg_->Context()->TypeRecorder(),
194 pg_->Context()->TypeRecorder()->DeclareType(), funcTypeAnnotation);
195 func_->metadata->AddAnnotations({ funcTypeAnnotation });
196 }
197
GenTypeSummaryInfo(bool typeFlag,int64_t typeSummaryIndex,const std::string & recordName,Record & record)198 static void GenTypeSummaryInfo(bool typeFlag, int64_t typeSummaryIndex, const std::string &recordName, Record &record)
199 {
200 constexpr const auto LANG_EXT = panda::pandasm::extensions::Language::ECMASCRIPT;
201
202 auto typeFlagField = Field(LANG_EXT);
203 typeFlagField.name = TypeExtractorEmitter::TYPE_FLAG;
204 typeFlagField.type = Type("u8", 0);
205 typeFlagField.metadata->SetValue(ScalarValue::Create<ValueType::U8>(static_cast<uint8_t>(typeFlag)));
206 record.field_list.emplace_back(std::move(typeFlagField));
207
208 if (typeFlag) {
209 auto typeSummaryIndexField = Field(LANG_EXT);
210 typeSummaryIndexField.name = TypeExtractorEmitter::TYPE_SUMMARY;
211 typeSummaryIndexField.type = Type("u32", 0);
212 typeSummaryIndexField.metadata->SetValue(ScalarValue::Create<ValueType::LITERALARRAY>(
213 "" + recordName + "_" + std::to_string(typeSummaryIndex)));
214 record.field_list.emplace_back(std::move(typeSummaryIndexField));
215 }
216 }
217
218 // static
GenTypeInfoRecord(panda::pandasm::Program * prog,bool typeFlag,int64_t typeSummaryIndex,const std::string & recordName)219 void TypeExtractorEmitter::GenTypeInfoRecord(panda::pandasm::Program *prog, bool typeFlag,
220 int64_t typeSummaryIndex, const std::string &recordName)
221 {
222 auto iter = prog->record_table.find(TypeExtractorEmitter::TYPE_INFO_RECORD);
223 ASSERT(iter != prog->record_table.end());
224 GenTypeSummaryInfo(typeFlag, typeSummaryIndex, recordName, iter->second);
225 }
226
GenTypeInfoRecordForMergeABC(panda::pandasm::Program * prog,bool typeFlag,int64_t typeSummaryIndex,const std::string & recordName)227 void TypeExtractorEmitter::GenTypeInfoRecordForMergeABC(panda::pandasm::Program *prog, bool typeFlag,
228 int64_t typeSummaryIndex, const std::string &recordName)
229 {
230 auto iter = prog->record_table.find(recordName);
231 ASSERT(iter != prog->record_table.end());
232 GenTypeSummaryInfo(typeFlag, typeSummaryIndex, recordName, iter->second);
233 }
234
GenTypeLiteralBuffers(panda::pandasm::Program * prog,const extractor::TypeRecorder * recorder)235 void TypeExtractorEmitter::GenTypeLiteralBuffers(panda::pandasm::Program *prog,
236 const extractor::TypeRecorder *recorder)
237 {
238 ArenaVector<std::pair<int32_t, std::vector<Literal>>> literalBuffers(recorder->Allocator()->Adapter());
239 for (const auto *buff : recorder->BuffStorage()) {
240 Emitter::GenBufferLiterals(literalBuffers, buff);
241 }
242
243 for (auto &[idx, buf] : literalBuffers) {
244 std::string literalId = std::string(recorder->GetRecordName()) + "_" + std::to_string(idx);
245 auto literalArrayInstance = panda::pandasm::LiteralArray(std::move(buf));
246 prog->literalarray_table.emplace(literalId, std::move(literalArrayInstance));
247 }
248 }
249
250 } // namespace panda::es2panda::compiler
251