• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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