1 /*
2 * Copyright (c) 2021-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 <cstdio>
17 #include <string>
18
19 #include "assembler/assembly-program.h"
20 #include "assembler/assembly-function.h"
21 #include "assembler/assembly-ins.h"
22 #include "assembly-type.h"
23 #include "ins_create_api.h"
24
25 #include "runtime/include/runtime.h"
26 #include "plugins/ets/runtime/ets_coroutine.h"
27
28 #include "ets_typeapi_create.h"
29 #include "ets_object.h"
30 #include "ets_array.h"
31
32 namespace ark::ets {
33
34 constexpr size_t TYPEAPI_CTX_DATA_CCTOR_ARR_REG = 0;
35
AddInitField(uint32_t id,const pandasm::Type & type)36 std::string TypeCreatorCtx::AddInitField(uint32_t id, const pandasm::Type &type)
37 {
38 ASSERT(!type.IsPrimitive());
39 auto &rec = GetTypeAPICtxDataRecord();
40 auto filedIdForIns = rec.name;
41 pandasm::Field fld {SourceLanguage::ETS};
42 fld.name = "f";
43 fld.name += std::to_string(id);
44 filedIdForIns += ".";
45 filedIdForIns += fld.name;
46
47 fld.type = type;
48 fld.metadata->SetAttribute(typeapi_create_consts::ATTR_FINAL);
49 fld.metadata->SetAttribute(typeapi_create_consts::ATTR_STATIC);
50 rec.fieldList.emplace_back(std::move(fld));
51
52 ctxDataRecordCctor_.AddInstruction(pandasm::Create_LDAI(id));
53 ctxDataRecordCctor_.AddInstruction(pandasm::Create_LDARR_OBJ(TYPEAPI_CTX_DATA_CCTOR_ARR_REG));
54 ctxDataRecordCctor_.AddInstruction(pandasm::Create_CHECKCAST(type.GetPandasmName()));
55 ctxDataRecordCctor_.AddInstruction(pandasm::Create_STSTATIC_OBJ(filedIdForIns));
56
57 return filedIdForIns;
58 }
59
FlushTypeAPICtxDataRecordsToProgram()60 void TypeCreatorCtx::FlushTypeAPICtxDataRecordsToProgram()
61 {
62 if (ctxDataRecord_.name.empty()) {
63 return;
64 }
65
66 ctxDataRecordCctor_.AddInstruction(pandasm::Create_RETURN_VOID());
67
68 auto name = ctxDataRecord_.name;
69 prog_.recordTable.emplace(std::move(name), std::move(ctxDataRecord_));
70 name = ctxDataRecordCctor_.name;
71 prog_.functionTable.emplace(std::move(name), std::move(ctxDataRecordCctor_));
72 }
73
SaveObjects(EtsCoroutine * coro,VMHandle<EtsArray> & objects)74 void TypeCreatorCtx::SaveObjects(EtsCoroutine *coro, VMHandle<EtsArray> &objects)
75 {
76 auto arrayKlass = coro->GetPandaVM()->GetClassLinker()->GetClass(
77 pandasm::Type {typeapi_create_consts::TYPE_OBJECT, 1, true}.GetDescriptor(true).c_str());
78 auto arr = coretypes::Array::Create(arrayKlass->GetRuntimeClass(), 1, SpaceType::SPACE_TYPE_NON_MOVABLE_OBJECT);
79 arr->Set<ObjectHeader *>(0, objects.GetPtr()->GetCoreType());
80 initArrObject_ = arr;
81 objects = VMHandle<EtsArray>(coro, initArrObject_);
82 }
83
GetObjects(EtsCoroutine * coro)84 EtsArray *TypeCreatorCtx::GetObjects([[maybe_unused]] EtsCoroutine *coro)
85 {
86 // NOTE: this code is possible because that array is allocated as non-movable!
87 // and is stored in vmhandle => can't be moved or deallcoated
88 return reinterpret_cast<EtsArray *>(initArrObject_->Get<ObjectHeader *>(0));
89 }
90
InitializeCtxDataRecord(EtsCoroutine * coro)91 void TypeCreatorCtx::InitializeCtxDataRecord(EtsCoroutine *coro)
92 {
93 if (ctxDataRecordName_.empty()) {
94 return;
95 }
96 auto name = pandasm::Type(ctxDataRecordName_, 0).GetDescriptor();
97 auto klass = coro->GetPandaVM()->GetClassLinker()->GetClass(name.c_str());
98 ASSERT(!klass->IsInitialized());
99 auto linker = Runtime::GetCurrent()->GetClassLinker();
100 [[maybe_unused]] auto result = linker->InitializeClass(coro, klass->GetRuntimeClass());
101 ASSERT(result);
102 ASSERT(klass->IsInitialized());
103 }
104
GetTypeAPICtxDataRecord()105 pandasm::Record &TypeCreatorCtx::GetTypeAPICtxDataRecord()
106 {
107 if (!ctxDataRecord_.name.empty()) {
108 return ctxDataRecord_;
109 }
110 static std::atomic_uint ctxDataNextName {};
111 ctxDataRecordName_ = typeapi_create_consts::CREATOR_CTX_DATA_PREFIX;
112 ctxDataRecordName_ += std::to_string(ctxDataNextName++);
113 ctxDataRecord_.name = ctxDataRecordName_;
114
115 AddRefTypeAsExternal(std::string {typeapi_create_consts::TYPE_OBJECT});
116 AddRefTypeAsExternal(pandasm::Type {typeapi_create_consts::TYPE_OBJECT, 1}.GetName());
117
118 ctxDataRecordCctor_.name = ctxDataRecord_.name;
119 ctxDataRecordCctor_.name += '.';
120 ctxDataRecordCctor_.name += panda_file::GetCctorName(SourceLanguage::ETS);
121 ctxDataRecordCctor_.metadata->SetAttribute(typeapi_create_consts::ATTR_CCTOR);
122 ctxDataRecordCctor_.metadata->SetAttribute(typeapi_create_consts::ATTR_STATIC);
123 ctxDataRecordCctor_.regsNum = 1;
124 ctxDataRecordCctor_.AddInstruction(pandasm::Create_MOVI_64(0, reinterpret_cast<EtsLong>(this)));
125 ctxDataRecordCctor_.AddInstruction(
126 pandasm::Create_CALL_SHORT(0, 0, std::string {typeapi_create_consts::FUNCTION_GET_OBJECTS_FOR_CCTOR}));
127 ctxDataRecordCctor_.AddInstruction(pandasm::Create_STA_OBJ(TYPEAPI_CTX_DATA_CCTOR_ARR_REG));
128
129 AddRefTypeAsExternal(std::string {typeapi_create_consts::TYPE_TYPE_CREATOR_CTX});
130 pandasm::Function getObjectsArray {std::string {typeapi_create_consts::FUNCTION_GET_OBJECTS_FOR_CCTOR},
131 SourceLanguage::ETS};
132 getObjectsArray.metadata->SetAttribute(typeapi_create_consts::ATTR_EXTERNAL);
133 getObjectsArray.returnType = pandasm::Type {typeapi_create_consts::TYPE_OBJECT, 1};
134 getObjectsArray.params.emplace_back(
135 pandasm::Type::FromPrimitiveId(ConvertEtsTypeToPandaType(EtsType::LONG).GetId()), SourceLanguage::ETS);
136 auto getObjectsArrayName = getObjectsArray.name;
137 prog_.functionTable.emplace(std::move(getObjectsArrayName), std::move(getObjectsArray));
138
139 return ctxDataRecord_;
140 }
141
AddRefTypeAsExternal(const std::string & name)142 pandasm::Record &TypeCreatorCtx::AddRefTypeAsExternal(const std::string &name)
143 {
144 pandasm::Record objectRec {name, SourceLanguage::ETS};
145 objectRec.metadata->SetAttribute(typeapi_create_consts::ATTR_EXTERNAL);
146 return prog_.recordTable.emplace(objectRec.name, std::move(objectRec)).first->second;
147 }
148
DeclarePrimitive(const std::string & primTypeName)149 const std::pair<std::string, std::string> &TypeCreatorCtx::DeclarePrimitive(const std::string &primTypeName)
150 {
151 if (auto found = primitiveTypesCtorDtor_.find(primTypeName); found != primitiveTypesCtorDtor_.end()) {
152 return found->second;
153 }
154
155 auto primType = pandasm::Type {primTypeName, 0};
156
157 std::string objectTypeName {typeapi_create_consts::TYPE_BOXED_PREFIX};
158 if (primTypeName == "u1") {
159 objectTypeName += "Boolean";
160 } else if (primTypeName == "i8") {
161 objectTypeName += "Byte";
162 } else if (primTypeName == "i16") {
163 objectTypeName += "Short";
164 } else if (primTypeName == "i32") {
165 objectTypeName += "Int";
166 } else if (primTypeName == "i64") {
167 objectTypeName += "Long";
168 } else if (primTypeName == "u16") {
169 objectTypeName += "Char";
170 } else if (primTypeName == "void") {
171 objectTypeName += "Void";
172 } else if (primTypeName == "f32") {
173 objectTypeName += "Float";
174 } else if (primTypeName == "f64") {
175 objectTypeName += "Double";
176 } else {
177 UNREACHABLE();
178 }
179 AddRefTypeAsExternal(objectTypeName);
180 auto objectType = pandasm::Type {objectTypeName, 0};
181
182 PandasmMethodCreator ctor {objectTypeName + "." + panda_file::GetCtorName(SourceLanguage::ETS), this};
183 ctor.AddParameter(objectType);
184 ctor.AddParameter(primType);
185 ctor.GetFn().metadata->SetAttribute(typeapi_create_consts::ATTR_EXTERNAL);
186 ctor.GetFn().metadata->SetAttribute(typeapi_create_consts::ATTR_CTOR);
187 ctor.Create();
188
189 PandasmMethodCreator unboxed {objectTypeName + ".unboxed", this};
190 unboxed.AddParameter(objectType);
191 unboxed.AddResult(primType);
192 unboxed.GetFn().metadata->SetAttribute(typeapi_create_consts::ATTR_EXTERNAL);
193 unboxed.Create();
194
195 return primitiveTypesCtorDtor_
196 .emplace(primTypeName, std::make_pair(ctor.GetFunctionName(), unboxed.GetFunctionName()))
197 .first->second;
198 }
199
AddParameter(pandasm::Type param)200 void LambdaTypeCreator::AddParameter(pandasm::Type param)
201 {
202 ASSERT(!param.IsVoid());
203 fn_.params.emplace_back(std::move(param), SourceLanguage::ETS);
204 }
205
AddResult(const pandasm::Type & type)206 void LambdaTypeCreator::AddResult(const pandasm::Type &type)
207 {
208 fn_.returnType = type;
209 }
210
Create()211 void LambdaTypeCreator::Create()
212 {
213 ASSERT(!finished_);
214 finished_ = true;
215 // IMPORTANT: must be synchronized with
216 // tools/es2panda/varbinder/ETSBinder.cpp
217 // ETSBinder::FormLambdaName
218
219 static constexpr size_t MAX_NUMBER_OF_PARAMS_FOR_FUNCTIONAL_INTERFACE = 16;
220
221 if (fn_.params.size() > MAX_NUMBER_OF_PARAMS_FOR_FUNCTIONAL_INTERFACE) {
222 GetCtx()->AddError("Function types with more than 16 parameters are not supported");
223 return;
224 }
225 name_ += std::to_string(fn_.params.size());
226
227 rec_.name = name_;
228 fnName_ = fn_.name = name_ + ".invoke0";
229 fn_.params.insert(fn_.params.begin(), pandasm::Function::Parameter(pandasm::Type(name_, 0), SourceLanguage::ETS));
230 for (const auto &attr : typeapi_create_consts::ATTR_ABSTRACT_METHOD) {
231 fn_.metadata->SetAttribute(attr);
232 }
233 fn_.metadata->SetAttributeValue(typeapi_create_consts::ATTR_ACCESS, typeapi_create_consts::ATTR_ACCESS_VAL_PUBLIC);
234 GetCtx()->Program().recordTable.emplace(name_, std::move(rec_));
235 GetCtx()->Program().functionTable.emplace(fnName_, std::move(fn_));
236 }
237
AddParameter(pandasm::Type param)238 void PandasmMethodCreator::AddParameter(pandasm::Type param)
239 {
240 name_ += ':';
241 name_ += param.GetName();
242 fn_.params.emplace_back(std::move(param), SourceLanguage::ETS);
243 }
244
AddResult(pandasm::Type type)245 void PandasmMethodCreator::AddResult(pandasm::Type type)
246 {
247 if (fn_.metadata->IsCtor()) {
248 fn_.returnType = pandasm::Type {"void", 0};
249 return;
250 }
251 fn_.returnType = std::move(type);
252 }
253
Create()254 void PandasmMethodCreator::Create()
255 {
256 ASSERT(!finished_);
257 finished_ = true;
258 fn_.name = name_;
259 auto ok = ctx_->Program().functionTable.emplace(name_, std::move(fn_)).second;
260 if (!ok) {
261 ctx_->AddError("duplicate function " + name_);
262 }
263 }
264 } // namespace ark::ets
265