diff --git a/BUILD.gn b/BUILD.gn index 9fc37c2f6d..5c2c62d1ec 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -279,3 +279,7 @@ merge_yamls("merge_runtime_options_yamls") { output_file = "$target_gen_dir/runtime_options.yaml" add_yamls = [ "$ark_root/runtime/options.yaml" ] + runtime_options_yamls } + +group("bcopt_type_adapter_unit_test") { + deps = [ "$ark_root/bytecode_optimizer/tests:bcopt_type_adapter_unit_test(//build/toolchain/linux:clang_x64)" ] +} diff --git a/bytecode_optimizer/codegen.cpp b/bytecode_optimizer/codegen.cpp index 7a306dc66e..b94b8c5656 100644 --- a/bytecode_optimizer/codegen.cpp +++ b/bytecode_optimizer/codegen.cpp @@ -102,6 +102,10 @@ void BytecodeGen::VisitTryBegin(const compiler::BasicBlock *bb) bool BytecodeGen::RunImpl() { Reserve(function_->ins.size()); + std::vector elements; + AddTypeInfoIndexForArguments(&elements); + bool need_handle_ins_type = GetGraph()->GetRuntime()->HasInsTypeinfo(); + int32_t insn_order = 0; for (auto *bb : GetGraph()->GetBlocksLinearOrder()) { EmitLabel(BytecodeGen::LabelName(bb->GetId())); if (bb->IsTryEnd() || bb->IsCatchEnd()) { @@ -118,9 +122,13 @@ bool BytecodeGen::RunImpl() ASSERT(end >= start); for (auto i = start; i < end; ++i) { AddLineNumber(inst, i); - if (GetGraph()->IsDynamicMethod()) { - AddColumnNumber(inst, i); - } + AddColumnNumber(inst, i); + } + if (need_handle_ins_type && end > start) { + // fill ins types. Need to exclude invalid ins as they do not emit + insn_order += std::count_if(GetResult().begin() + start, GetResult().end(), + [](const auto &ins) { return ins.opcode != pandasm::Opcode::INVALID; }); + AddTypeInfoIndexForIns(insn_order - 1, inst->GetId(), &elements); } } if (bb->NeedsJump()) { @@ -136,9 +144,60 @@ bool BytecodeGen::RunImpl() } function_->ins = std::move(GetResult()); function_->catch_blocks = catch_blocks_; + UpdateTypeInfoIndexAnnotation(&elements); return true; } +void BytecodeGen::AddTypeInfoIndexForArguments(std::vector *elements) const +{ + std::unordered_map args_types_map; + if (GetGraph()->GetRuntime()->FillArgTypePairs(&args_types_map)) { + for (const auto &[arg, type] : args_types_map) { + ASSERT(arg < 0); + AddOrderAndTypeInfoIndex(arg, type, elements); + } + } +} + +void BytecodeGen::AddOrderAndTypeInfoIndex(int32_t order, TypeInfoIndex type, std::vector *elements) const +{ + ScalarValue insn_order(ScalarValue::Create(order)); + elements->emplace_back(std::move(insn_order)); + ScalarValue type_info_index(ScalarValue::Create(type)); + elements->emplace_back(std::move(type_info_index)); +} + +void BytecodeGen::AddTypeInfoIndexForIns(int32_t order, size_t id, std::vector *elements) const +{ + auto type = GetGraph()->GetRuntime()->GetTypeInfoIndexByInstId(id); + if (type != NO_EXPLICIT_TYPE) { + AddOrderAndTypeInfoIndex(order, type, elements); + } +} + +void BytecodeGen::UpdateTypeInfoIndexAnnotation(const std::vector *elements) +{ +#ifndef NDEBUG + LOG(DEBUG, BYTECODE_OPTIMIZER) << "Typeinfo after optimization for function : " << function_->name; + const size_t PAIR_GAP = 2; + for (size_t i = 0; i < elements->size(); i += PAIR_GAP) { + auto order = (*elements)[i].GetValue(); + auto type = (*elements)[i + 1].GetValue(); + LOG(DEBUG, BYTECODE_OPTIMIZER) << "[" << order << ", " << type << "], "; + } +#endif + const auto *type_idx = GetGraph()->GetRuntime()->GetTypeAnnotationIndex(); + ASSERT(type_idx != nullptr); + if (type_idx->first == INVALID_TYPE_INDEX || type_idx->second == INVALID_TYPE_INDEX) { + return; + } + ASSERT(type_idx->first < function_->metadata->GetAnnotations().size()); + panda::pandasm::ArrayValue arr(panda::pandasm::Value::Type::I32, *elements); + panda::pandasm::AnnotationElement anno_elem(TSTYPE_ANNO_ELEMENT_NAME, + std::make_unique(arr)); + function_->metadata->SetOrAddAnnotationElementByIndex(type_idx->first, type_idx->second, std::move(anno_elem)); +} + void BytecodeGen::EmitJump(const BasicBlock *bb) { BasicBlock *suc_bb = nullptr; diff --git a/bytecode_optimizer/codegen.h b/bytecode_optimizer/codegen.h index d0adb0e5e8..0e579d3018 100644 --- a/bytecode_optimizer/codegen.h +++ b/bytecode_optimizer/codegen.h @@ -16,6 +16,7 @@ #ifndef PANDA_BYTECODE_OPT_CODEGEN_H #define PANDA_BYTECODE_OPT_CODEGEN_H +#include "assembler/annotation.h" #include "assembler/assembly-function.h" #include "assembler/assembly-ins.h" #include "ins_create_api.h" @@ -146,6 +147,13 @@ private: const compiler::BasicBlock *catch_begin, const compiler::BasicBlock *catch_end = nullptr); void VisitTryBegin(const compiler::BasicBlock *bb); + // TypeInfoIndex typeinfo adaption + using ScalarValue = panda::pandasm::ScalarValue; + void AddTypeInfoIndexForArguments(std::vector *elements) const; + void AddOrderAndTypeInfoIndex(int32_t order, TypeInfoIndex type, std::vector *elements) const; + void AddTypeInfoIndexForIns(int32_t order, size_t id, std::vector *elements) const; + void UpdateTypeInfoIndexAnnotation(const std::vector *elements); + private: pandasm::Function *function_; const BytecodeOptIrInterface *ir_interface_; diff --git a/bytecode_optimizer/optimize_bytecode.cpp b/bytecode_optimizer/optimize_bytecode.cpp index 74a11b7737..ef683239be 100644 --- a/bytecode_optimizer/optimize_bytecode.cpp +++ b/bytecode_optimizer/optimize_bytecode.cpp @@ -149,6 +149,67 @@ void BuildMapFromPcToIns(pandasm::Function &function, BytecodeOptIrInterface &ir } } +static void ExtractTypeInfo(const pandasm::Function &function, compiler::RuntimeInterface *adapter, + std::unordered_map *order_type_map) +{ + const auto &annos = function.metadata->GetAnnotations(); + const auto type_anno = std::find_if(annos.begin(), annos.end(), + [](const auto &an) { return an.GetName() == TSTYPE_ANNO_RECORD_NAME; }); + if (type_anno == annos.end()) { + return; + } + const auto &elems = type_anno->GetElements(); + const auto type_elem = std::find_if(elems.begin(), elems.end(), + [](const auto &e) { return e.GetName() == TSTYPE_ANNO_ELEMENT_NAME; }); + if (type_elem == elems.end()) { + return; + } + adapter->SetTypeAnnotationIndex(type_anno - annos.begin(), type_elem - elems.begin()); + const auto *arr_val = type_elem->GetValue(); + ASSERT(arr_val != nullptr); + ASSERT(arr_val->IsArray()); + const auto &values = arr_val->GetAsArray()->GetValues(); + ASSERT(values.size() % 2 == 0); // 2: size must be even because values consits of pairs of orders and types + size_t i = 0; + while (i < values.size()) { + auto order = values[i++].GetValue(); + auto type = values[i++].GetValue(); + if (order < 0) { // arguments + adapter->AddPcTypePair(order, type); + } else { // instructions + order_type_map->emplace(order, type); + } + } +} + +static void BuildMapFromPcToType(const pandasm::Function &function, const compiler::Graph *graph, + compiler::RuntimeInterface::MethodPtr method_ptr) +{ + std::unordered_map tmp_order_type_map; + ExtractTypeInfo(function, graph->GetRuntime(), &tmp_order_type_map); + if (tmp_order_type_map.empty()) { + return; + } + const auto *instruction_buf = graph->GetRuntime()->GetMethodCode(method_ptr); + compiler::BytecodeInstructions instructions(instruction_buf, graph->GetRuntime()->GetMethodCodeSize(method_ptr)); + int32_t order = 0; + size_t num_collected = 0; + for (const auto &insn : instructions) { + const auto it = tmp_order_type_map.find(order++); + if (it == tmp_order_type_map.end()) { + continue; + } + auto pc = static_cast(instructions.GetPc(insn)); + graph->GetRuntime()->AddPcTypePair(pc, it->second); + num_collected++; + + // stop when all typeinfo has been collected + if (num_collected == tmp_order_type_map.size()) { + break; + } + } +} + static void ColumnNumberPropagate(pandasm::Function *function) { auto &ins_vec = function->ins; @@ -282,6 +343,8 @@ bool OptimizeFunction(pandasm::Program *prog, const pandasm::AsmEmitter::PandaFi return false; } + BuildMapFromPcToType(function, graph, method_ptr); + // build map from pc to pandasm::ins (to re-build line-number info in BytecodeGen) BuildMapFromPcToIns(function, ir_interface, graph, method_ptr); diff --git a/bytecode_optimizer/runtime_adapter.h b/bytecode_optimizer/runtime_adapter.h index 756aea6d5e..a520174b8f 100644 --- a/bytecode_optimizer/runtime_adapter.h +++ b/bytecode_optimizer/runtime_adapter.h @@ -342,6 +342,62 @@ public: return utf::Mutf8AsCString(string_data.data); } + TypeInfoIndex GetTypeInfoIndexByInstId(size_t id) const override + { + const auto it = instid_type_map_.find(id); + if (it == instid_type_map_.end()) { + return NO_EXPLICIT_TYPE; + } + return it->second; + } + + bool FillInstIdTypePairByPc(size_t id, int32_t pc) override + { + const auto it = pc_type_map_.find(pc); + if (it != pc_type_map_.end()) { + instid_type_map_.emplace(id, it->second); + return true; + } + return false; + } + + bool HasInsTypeinfo() const override + { + return !instid_type_map_.empty(); + } + + bool AddPcTypePair(int32_t pc, TypeInfoIndex type) override + { + if (pc_type_map_.find(pc) != pc_type_map_.end()) { + return false; + } + pc_type_map_.emplace(pc, type); + return true; + } + + bool FillArgTypePairs(std::unordered_map *map) const override + { + ASSERT(map != nullptr); + ASSERT(map->empty()); + for (const auto &[pc, type] : pc_type_map_) { + if (pc < 0) { + map->emplace(pc, type); + } + } + return !map->empty(); + } + + bool SetTypeAnnotationIndex(size_t anno_idx, size_t elem_idx) override + { + anno_elem_idx_ = { anno_idx, elem_idx }; + return anno_idx != INVALID_TYPE_INDEX && elem_idx != INVALID_TYPE_INDEX; + } + + const std::pair *GetTypeAnnotationIndex() const override + { + return &anno_elem_idx_; + } + private: static compiler::DataType::Type ToCompilerType(panda_file::Type type) { @@ -397,6 +453,9 @@ private: } const panda_file::File &panda_file_; + std::unordered_map instid_type_map_; + std::unordered_map pc_type_map_; + std::pair anno_elem_idx_ = std::make_pair(INVALID_TYPE_INDEX, INVALID_TYPE_INDEX); }; } // namespace panda diff --git a/bytecode_optimizer/tests/BUILD.gn b/bytecode_optimizer/tests/BUILD.gn new file mode 100644 index 0000000000..7a38092b2a --- /dev/null +++ b/bytecode_optimizer/tests/BUILD.gn @@ -0,0 +1,64 @@ +# Copyright (c) 2022 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import("//arkcompiler/runtime_core/ark_config.gni") +import("//build/ohos.gni") + +ohos_executable("bcopt_type_adapter_unit_test") { + sources = [ "bcopt_type_adaption_test.cpp" ] + + configs = [ + "$ark_root:ark_config", + "$ark_root/assembler:arkassembler_public_config", + "$ark_root/runtime:arkruntime_public_config", + "$ark_root/libpandabase:arkbase_public_config", + "$ark_root/libpandafile:arkfile_public_config", + "$ark_root/compiler:arkcompiler_public_config", + "$ark_root/bytecode_optimizer:bytecodeopt_public_config", + sdk_libc_secshared_config, + ] + + deps = [ sdk_libc_secshared_dep ] + + if (is_linux || is_mingw || is_mac) { + deps += [ + "$ark_root/assembler:libarkassembler_frontend_static", + "$ark_root/bytecode_optimizer:libarkbytecodeopt_frontend_static", + "$ark_root/compiler:libarkcompiler_frontend_static", + "$ark_root/libpandabase:libarkbase_frontend_static", + "$ark_root/libpandafile:libarkfile_frontend_static", + "$ark_root/libziparchive:libarkziparchive_frontend_static", + ] + } else { + deps += [ + "$ark_root/assembler:libarkassembler", + "$ark_root/bytecode_optimizer:libarkbytecodeopt", + "$ark_root/compiler:libarkcompiler", + "$ark_root/libpandabase:libarkbase", + "$ark_root/libpandafile:libarkfile", + "$ark_root/libziparchive:libarkziparchive", + ] + } + + if (is_linux) { + if (build_public_version) { + ldflags = [ "-static-libstdc++" ] + } else { + libs = [ libcpp_static_lib ] + } + } + + output_name = "bcopt_type_adapter_unit_test" + install_enable = true + subsystem_name = "ark" +} diff --git a/bytecode_optimizer/tests/bcopt_type_adaption_test.cpp b/bytecode_optimizer/tests/bcopt_type_adaption_test.cpp new file mode 100644 index 0000000000..3096ba835d --- /dev/null +++ b/bytecode_optimizer/tests/bcopt_type_adaption_test.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "assembler/meta.h" +#include "assembler/assembly-parser.h" +#include "bytecode_optimizer/optimize_bytecode.h" + +namespace panda::bytecodeopt::test { +using ArrayValue = panda::pandasm::ArrayValue; +using ScalarValue = panda::pandasm::ScalarValue; +using AnnotationData = panda::pandasm::AnnotationData; +using AnnotationElement = panda::pandasm::AnnotationElement; + +class TestBase { +public: + template + inline void TestAssertEqual(const T1 &left, const T2 &right) const + { + if (left != static_cast(right)) { + std::cout << "assertion equal failed." << std::endl; + UNREACHABLE(); + } + } + + template + inline void TestAssertNotEqual(const T1 &left, const T2 &right) const + { + if (left == static_cast(right)) { + std::cout << "assertion not equal failed." << std::endl; + UNREACHABLE(); + } + } + + inline void TestAssertTrue(bool val) const + { + if (!val) { + UNREACHABLE(); + } + } + + inline void TestAssertFalse(bool val) const + { + if (val) { + UNREACHABLE(); + } + } +}; + +class BytecodeOptimizerTypeAdaptionTest : TestBase { +public: + std::unordered_map ExtractTypeinfo(const panda::pandasm::Function &fun) const + { + const auto *ele = fun.metadata->GetAnnotations()[0].GetElements()[0].GetValue(); + const auto &values = ele->GetAsArray()->GetValues(); + std::unordered_map type_info; + const size_t PAIR_GAP = 2; + TestAssertEqual(values.size() % PAIR_GAP, 0); // must be even as it consits of pairs + for (size_t i = 0; i < values.size(); i += PAIR_GAP) { + type_info.emplace(values[i].GetValue(), values[i + 1].GetValue()); + } + return type_info; + } + + void CheckTypeExist(const std::unordered_map &typeinfo, int32_t order, int32_t type) const + { + auto type_it = typeinfo.find(order); + TestAssertNotEqual(type_it, typeinfo.end()); + TestAssertEqual(type_it->second, type); + } + + void AddTypeinfo(std::vector *elements, int32_t order, int32_t type) const + { + ScalarValue insn_order(ScalarValue::Create(order)); + elements->emplace_back(std::move(insn_order)); + ScalarValue insn_type(ScalarValue::Create(type)); + elements->emplace_back(std::move(insn_type)); + } + + void TypeAdaptionTest() const; + + static constexpr int32_t NUM_TYPE = 1; + static constexpr int32_t STR_TYPE = 4; +}; + +void BytecodeOptimizerTypeAdaptionTest::TypeAdaptionTest() const +{ + /* ts source code + function foo(a:number, b:string, c:string):string + { + let t:number = 100; + if (a > t) { + return b; + } + if (a < t) { + return c; + } + let ret:string = b + c; + return ret; + } + */ + const auto source = R"( + .language ECMAScript + .record _ESTypeAnnotation + .function any foo(any a0, any a1, any a2) { + mov.dyn v2, a2 + mov.dyn v1, a1 + mov.dyn v0, a0 + ecma.ldlexenvdyn + sta.dyn v6 + ldai.dyn 0x64 + sta.dyn v3 + lda.dyn v0 + sta.dyn v5 + lda.dyn v3 + ecma.greaterdyn v5 + jeqz jump_label_0 + lda.dyn v1 + sta.dyn v5 + lda.dyn v5 + return.dyn + jump_label_0: + lda.dyn v0 + sta.dyn v5 + lda.dyn v3 + ecma.lessdyn v5 + jeqz jump_label_1 + lda.dyn v2 + sta.dyn v5 + lda.dyn v5 + return.dyn + jump_label_1: + lda.dyn v1 + sta.dyn v5 + lda.dyn v2 + ecma.add2dyn v5 + sta.dyn v4 + lda.dyn v4 + sta.dyn v5 + lda.dyn v5 + return.dyn + } + )"; + panda::pandasm::Parser parser; + auto res = parser.Parse(source); + auto &program = res.Value(); + const std::string fun_name = "foo:(any,any,any)"; + auto it = program.function_table.find(fun_name); + TestAssertNotEqual(it, program.function_table.end()); + + auto &func = it->second; + std::vector elements; + // set arg type + AddTypeinfo(&elements, -1, NUM_TYPE); // -1 means first arg + AddTypeinfo(&elements, -2, STR_TYPE); // -2 means second arg + AddTypeinfo(&elements, -3, STR_TYPE); // -3 means third arg + // set ins type + const size_t LDAI_IDX = 5; + TestAssertEqual(func.ins[LDAI_IDX].opcode, panda::pandasm::Opcode::LDAI_DYN); + TestAssertEqual(func.ins[LDAI_IDX + 1].opcode, panda::pandasm::Opcode::STA_DYN); + AddTypeinfo(&elements, static_cast(LDAI_IDX + 1), NUM_TYPE); + const size_t ADD_IDX = 30; + TestAssertEqual(func.ins[ADD_IDX].opcode, panda::pandasm::Opcode::ECMA_ADD2DYN); + TestAssertEqual(func.ins[ADD_IDX + 1].opcode, panda::pandasm::Opcode::STA_DYN); + AddTypeinfo(&elements, static_cast(ADD_IDX + 1), STR_TYPE); + + ArrayValue array_value(panda::pandasm::Value::Type::I32, elements); + AnnotationElement anno_element(TSTYPE_ANNO_ELEMENT_NAME, std::make_unique(array_value)); + AnnotationData annotation(TSTYPE_ANNO_RECORD_NAME); + annotation.AddElement(std::move(anno_element)); + std::vector annos; + annos.emplace_back(std::move(annotation)); + func.metadata->SetAnnotations(std::move(annos)); + const auto iterator = program.record_table.find(TSTYPE_ANNO_RECORD_NAME.data()); + TestAssertNotEqual(iterator, program.record_table.end()); + iterator->second.metadata->SetAccessFlags(panda::ACC_ANNOTATION); + TestAssertTrue(program.record_table.find(TSTYPE_ANNO_RECORD_NAME.data())->second.metadata->IsAnnotation()); + + // emit and optimize + const std::string abc_file_name = "TypeAdaptionTest.abc"; + std::map stat; + std::map *statp = nullptr; + panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {}; + panda::pandasm::AsmEmitter::PandaFileToPandaAsmMaps *mapsp = &maps; + TestAssertTrue(panda::pandasm::AsmEmitter::Emit(abc_file_name, program, statp, mapsp, false)); + TestAssertTrue(panda::bytecodeopt::OptimizeBytecode(&program, mapsp, abc_file_name, true)); + + // check typeinfo after optimization + it = program.function_table.find(fun_name); + TestAssertNotEqual(it, program.function_table.end()); + const auto &foo = it->second; + const auto typeinfo = ExtractTypeinfo(foo); + CheckTypeExist(typeinfo, -1, NUM_TYPE); // -1 means first arg + CheckTypeExist(typeinfo, -2, STR_TYPE); // -2 means second arg + CheckTypeExist(typeinfo, -3, STR_TYPE); // -3 means third arg + auto ldai_it = std::find_if(foo.ins.begin(), foo.ins.end(), + [](const auto &in) { return in.opcode == panda::pandasm::Opcode::LDAI_DYN; }); + TestAssertNotEqual(ldai_it, foo.ins.end()); + const auto opt_ldai_idx = static_cast(ldai_it - foo.ins.begin()); + TestAssertEqual(foo.ins[opt_ldai_idx].opcode, panda::pandasm::Opcode::LDAI_DYN); + TestAssertTrue(opt_ldai_idx + 1 < foo.ins.size()); + TestAssertEqual(foo.ins[opt_ldai_idx + 1].opcode, panda::pandasm::Opcode::STA_DYN); + + int32_t num_invalid = std::count_if(foo.ins.begin(), ldai_it, + [](const auto &in) { return in.opcode == panda::pandasm::Opcode::INVALID; }); + int32_t ldai_type_idx = opt_ldai_idx - num_invalid; // exclude invalid insns because they do not emit + + CheckTypeExist(typeinfo, ldai_type_idx + 1, NUM_TYPE); // type is on sta.dyn + + auto add_it = std::find_if(foo.ins.begin(), foo.ins.end(), + [](const auto &in) { return in.opcode == panda::pandasm::Opcode::ECMA_ADD2DYN; }); + TestAssertNotEqual(add_it, foo.ins.end()); + const auto opt_add_idx = static_cast(add_it - foo.ins.begin()); + TestAssertEqual(foo.ins[opt_add_idx].opcode, panda::pandasm::Opcode::ECMA_ADD2DYN); + TestAssertTrue(opt_add_idx + 1 < foo.ins.size()); + TestAssertNotEqual(foo.ins[opt_add_idx + 1].opcode, panda::pandasm::Opcode::STA_DYN); + + num_invalid = std::count_if(foo.ins.begin(), add_it, + [](const auto &in) { return in.opcode == panda::pandasm::Opcode::INVALID; }); + int32_t add_type_idx = opt_add_idx - num_invalid; // exclude invalid insns because they do not emit + CheckTypeExist(typeinfo, add_type_idx, STR_TYPE); // type is on ecma.add2dyn as it does not have sta.dyn + + TestAssertTrue(panda::pandasm::AsmEmitter::Emit(abc_file_name, program, statp, mapsp, false)); +} +} // namespace panda::bytecodeopt::test + +int main() +{ + panda::bytecodeopt::test::BytecodeOptimizerTypeAdaptionTest test; + std::cout << "BytecodeOptimizerTypeAdaptionTest: " << std::endl; + test.TypeAdaptionTest(); + std::cout << "PASS!" << std::endl; + return 0; +} diff --git a/compiler/BUILD.gn b/compiler/BUILD.gn index 31daf6d5e0..bb6e6945b7 100644 --- a/compiler/BUILD.gn +++ b/compiler/BUILD.gn @@ -149,15 +149,6 @@ foreach(plugin, enabled_plugins) { source_files = [] } -if (!is_win && !is_mac && !is_mingw) { - libarkcompiler_sources += [ - "code_info/code_info.cpp", - "code_info/code_info_builder.cpp", - "compile_method.cpp", - "optimizer_run.cpp", - ] -} - libarkcompiler_sources += [ "$target_gen_dir/generated/inst_builder_gen.cpp" ] libarkcompiler_configs = [ diff --git a/compiler/optimizer/ir/constants.h b/compiler/optimizer/ir/constants.h index ede6f3041e..116241510a 100644 --- a/compiler/optimizer/ir/constants.h +++ b/compiler/optimizer/ir/constants.h @@ -18,6 +18,7 @@ #include #include +#include namespace panda::compiler { constexpr int BITS_PER_BYTE = 8; @@ -58,4 +59,10 @@ constexpr uint32_t MAX_SCALE = 3; constexpr int MAX_SUCCS_NUM = 2; } // namespace panda::compiler +// TypeInfoIndex adaption +using TypeInfoIndex = int32_t; +constexpr TypeInfoIndex NO_EXPLICIT_TYPE = 0; +constexpr const std::string_view TSTYPE_ANNO_RECORD_NAME = "_ESTypeAnnotation"; +constexpr const std::string_view TSTYPE_ANNO_ELEMENT_NAME = "_TypeOfInstruction"; +constexpr auto INVALID_TYPE_INDEX = std::numeric_limits::max(); #endif // COMPILER_OPTIMIZER_IR_CONSTANTS_H_ diff --git a/compiler/optimizer/ir/runtime_interface.h b/compiler/optimizer/ir/runtime_interface.h index 1a1801dde8..e2236a963a 100644 --- a/compiler/optimizer/ir/runtime_interface.h +++ b/compiler/optimizer/ir/runtime_interface.h @@ -44,6 +44,7 @@ enum class ClassType { class IClassHierarchyAnalysis; class InlineCachesInterface; class UnresolvedTypesInterface; +class Inst; class RuntimeInterface { public: @@ -907,6 +908,42 @@ public: return false; } + // TypeInfoIndex adaption + virtual TypeInfoIndex GetTypeInfoIndexByInstId([[maybe_unused]] size_t id) const + { + return NO_EXPLICIT_TYPE; + } + + virtual bool FillInstIdTypePairByPc([[maybe_unused]] size_t id, [[maybe_unused]] int32_t pc) + { + return false; + } + + virtual bool HasInsTypeinfo() const + { + return false; + } + + virtual bool AddPcTypePair([[maybe_unused]] int32_t pc, [[maybe_unused]] TypeInfoIndex type) + { + return false; + } + + virtual bool FillArgTypePairs([[maybe_unused]] std::unordered_map *map) const + { + return false; + } + + virtual bool SetTypeAnnotationIndex([[maybe_unused]] size_t anno_idx, [[maybe_unused]] size_t elem_idx) + { + return false; + } + + virtual const std::pair *GetTypeAnnotationIndex() const + { + return nullptr; + } + NO_COPY_SEMANTIC(RuntimeInterface); NO_MOVE_SEMANTIC(RuntimeInterface); diff --git a/compiler/optimizer/ir_builder/inst_builder.h b/compiler/optimizer/ir_builder/inst_builder.h index a9a0ff32b9..be8307318d 100644 --- a/compiler/optimizer/ir_builder/inst_builder.h +++ b/compiler/optimizer/ir_builder/inst_builder.h @@ -137,6 +137,12 @@ public: static void SetParamSpillFill(Graph *graph, ParameterInst *param_inst, size_t num_args, size_t i, DataType::Type type); + void TryFillInstIdTypePair(size_t id, int32_t pc) + { + ASSERT(GetGraph()->IsBytecodeOptimizer()); + ASSERT(GetGraph()->IsDynamicMethod()); + GetGraph()->GetRuntime()->FillInstIdTypePairByPc(id, pc); + } private: void SyncWithGraph(); diff --git a/compiler/optimizer/ir_builder/inst_templates.yaml b/compiler/optimizer/ir_builder/inst_templates.yaml index 67b6f5edef..6c077a1b7e 100644 --- a/compiler/optimizer/ir_builder/inst_templates.yaml +++ b/compiler/optimizer/ir_builder/inst_templates.yaml @@ -118,6 +118,11 @@ templates: % end sta: |- UpdateDefinition(instruction->GetVReg<<%=inst.get_format%>, 0>(), GetDefinitionAcc()); + % if inst.properties.include? "dynamic" + if (GetGraph()->IsBytecodeOptimizer() && GetGraph()->IsDynamicMethod()) { + TryFillInstIdTypePair(GetDefinitionAcc()->GetId(), static_cast(GetPc(instruction->GetAddress()))); + } + % end lda: |- % if inst.mnemonic.include? "null" UpdateDefinitionAcc(graph_->GetOrCreateNullPtr()); @@ -131,6 +136,9 @@ templates: % else UpdateDefinitionAcc(FindOrCreateConstant(instruction->GetImm<<%=inst.get_format%>, 0>())); % if inst.properties.include? "dynamic" + if (GetGraph()->IsBytecodeOptimizer() && GetGraph()->IsDynamicMethod()) { + TryFillInstIdTypePair(GetDefinitionAcc()->GetId(), static_cast(GetPc(instruction->GetAddress()))); + } BuildCastToAnyNumber(instruction); % end % end @@ -139,6 +147,11 @@ templates: BuildLoadConstArray(instruction); % else BuildLoadFromPool>(instruction); + % if inst.opcode =~ /lda_str/ + if (GetGraph()->IsBytecodeOptimizer() && GetGraph()->IsDynamicMethod()) { + TryFillInstIdTypePair(GetDefinitionAcc()->GetId(), static_cast(GetPc(instruction->GetAddress()))); + } + % end % end % else % raise "Unsupported instruction type" unless inst.acc_and_operands[1].reg? @@ -153,6 +166,9 @@ templates: UpdateDefinitionAcc(FindOrCreateDoubleConstant(imm)); % end % if inst.properties.include? "dynamic" + if (GetGraph()->IsBytecodeOptimizer() && GetGraph()->IsDynamicMethod()) { + TryFillInstIdTypePair(GetDefinitionAcc()->GetId(), static_cast(GetPc(instruction->GetAddress()))); + } BuildCastToAnyNumber(instruction); % end operands: |- @@ -228,6 +244,11 @@ templates: AddInstruction(jmp_inst); % else BuildEcma(instruction); + % if inst.acc.include?("out") + if (GetGraph()->IsBytecodeOptimizer() && GetGraph()->IsDynamicMethod()) { + TryFillInstIdTypePair(GetDefinitionAcc()->GetId(), static_cast(GetPc(instruction->GetAddress()))); + } + % end % end builtin: |- BuildBuiltin(instruction); diff --git a/libpandafile/BUILD.gn b/libpandafile/BUILD.gn index 3719102b9c..a8ba9e20d5 100644 --- a/libpandafile/BUILD.gn +++ b/libpandafile/BUILD.gn @@ -73,7 +73,6 @@ source_set("libarkfile_static") { ":isa_gen_libarkfile_bytecode_instruction_enum_gen_h", ":isa_gen_libarkfile_file_format_version_h", ":isa_gen_libarkfile_tests_bytecode_emitter_tests_gen_h", - ":libarkfile_file_items_gen_inc", ":libarkfile_type_gen_h", ":source_lang_enum_h", "$ark_root/libpandabase:libarkbase", @@ -108,7 +107,6 @@ source_set("libarkfile_frontend_set_static") { ":isa_gen_libarkfile_bytecode_instruction_enum_gen_h", ":isa_gen_libarkfile_file_format_version_h", ":isa_gen_libarkfile_tests_bytecode_emitter_tests_gen_h", - ":libarkfile_file_items_gen_inc", ":libarkfile_type_gen_h", ":source_lang_enum_h", "$ark_root/libpandabase:libarkbase_frontend_static", @@ -145,14 +143,6 @@ ark_isa_gen("isa_gen_libarkfile") { requires = [ "pandafile_isapi.rb" ] } -ark_gen_file("libarkfile_file_items_gen_inc") { - extra_dependencies = [ "$ark_root:concat_plugins_yamls" ] - template_file = "templates/file_items_gen.inc.erb" - data_file = "$target_gen_dir/../plugin_options.yaml" - requires = [ "$ark_root/templates/plugin_options.rb" ] - output_file = "$target_gen_dir/include/file_items_gen.inc" -} - ark_gen_file("source_lang_enum_h") { extra_dependencies = [ "$ark_root:concat_plugins_yamls" ] template_file = "templates/source_lang_enum.h.erb" diff --git a/libpandafile/LibpandafilePostPlugins.cmake b/libpandafile/LibpandafilePostPlugins.cmake index d58e5559f0..d0f8556f25 100644 --- a/libpandafile/LibpandafilePostPlugins.cmake +++ b/libpandafile/LibpandafilePostPlugins.cmake @@ -11,16 +11,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - -set(FILE_ITEMS_GEN_INC ${PANDA_BINARY_ROOT}/libpandafile/include/file_items_gen.inc) -panda_gen_file( - DATAFILE ${GEN_PLUGIN_OPTIONS_YAML} - TEMPLATE ${PANDA_ROOT}/libpandafile/templates/file_items_gen.inc.erb - REQUIRES ${PANDA_ROOT}/templates/plugin_options.rb - EXTRA_DEPENDENCIES plugin_options_merge - OUTPUTFILE ${FILE_ITEMS_GEN_INC} -) - set(SOURCE_LANG_ENUM_H ${PANDA_BINARY_ROOT}/libpandafile/include/source_lang_enum.h) panda_gen_file( DATAFILE ${GEN_PLUGIN_OPTIONS_YAML} @@ -32,7 +22,6 @@ panda_gen_file( add_custom_target(arkfile_gen DEPENDS plugin_options_gen - ${FILE_ITEMS_GEN_INC} ${SOURCE_LANG_ENUM_H} ) diff --git a/libpandafile/file_items.cpp b/libpandafile/file_items.cpp index 10fd86132c..914c60b25a 100644 --- a/libpandafile/file_items.cpp +++ b/libpandafile/file_items.cpp @@ -23,7 +23,44 @@ namespace panda::panda_file { -#include "file_items_gen.inc" +bool IsDynamicLanguage(panda::panda_file::SourceLang lang) +{ + return lang == panda::panda_file::SourceLang::ECMASCRIPT; +} + +std::optional LanguageFromString(std::string_view lang) +{ + if (lang == "ECMAScript") { + return panda::panda_file::SourceLang::ECMASCRIPT; + } + return panda::panda_file::SourceLang::PANDA_ASSEMBLY; +} + +const char *LanguageToString(panda::panda_file::SourceLang lang) +{ + if (lang == panda::panda_file::SourceLang::ECMASCRIPT) { + return "ECMAScript"; + } + return "PandaAssembly"; +} + +const char *GetCtorName([[maybe_unused]] panda::panda_file::SourceLang lang) +{ + return ".ctor"; +} + +const char *GetCctorName([[maybe_unused]] panda::panda_file::SourceLang lang) +{ + return ".cctor"; +} + +const char *GetStringClassDescriptor(panda::panda_file::SourceLang lang) +{ + if (lang == panda::panda_file::SourceLang::ECMASCRIPT) { + return "Lpanda/JSString;"; + } + return "Lpanda/String;"; +} template static bool WriteUlebTaggedValue(Writer *writer, Tag tag, Val v) diff --git a/libpandafile/templates/file_items_gen.inc.erb b/libpandafile/templates/file_items_gen.inc.erb deleted file mode 100644 index 2f5bb63cf6..0000000000 --- a/libpandafile/templates/file_items_gen.inc.erb +++ /dev/null @@ -1,91 +0,0 @@ -/** - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -bool IsDynamicLanguage([[maybe_unused]] panda::panda_file::SourceLang lang) -{ -% Common::plugins.each_value do |plugin_opts| -% next unless plugin_opts["language_config"] -% next unless plugin_opts["language_config"]["lang_type"] - if (lang == <%= plugin_opts["lang_enum"] %>) { - return <%= plugin_opts["language_config"]["lang_type"] == "dynamic" %>; //NOLINT(readability-simplify-boolean-expr) - } -% end - - return false; -} - -std::optional LanguageFromString([[maybe_unused]] std::string_view lang) -{ -% Common::plugins.each_value do |plugin_opts| -% next unless plugin_opts["directive_name"] - if (lang == "<%= plugin_opts["directive_name"] %>") { - return <%= plugin_opts["lang_enum"] %>; - } -% end - - if (lang == "PandaAssembly") { - return panda::panda_file::SourceLang::PANDA_ASSEMBLY; - } - - return {}; -} - -const char *LanguageToString([[maybe_unused]] panda::panda_file::SourceLang lang) -{ -% Common::plugins.each_value do |plugin_opts| -% next unless plugin_opts["directive_name"] - if (lang == <%= plugin_opts["lang_enum"] %>) { - return "<%= plugin_opts["directive_name"] %>"; - } -% end - - return "PandaAssembly"; -} - -const char *GetCtorName([[maybe_unused]] panda::panda_file::SourceLang lang) -{ -% Common::plugins.each_value do |plugin_opts| -% next unless plugin_opts["ctor_name"] - if (lang == <%= plugin_opts["lang_enum"] %>) { - return "<%= plugin_opts["ctor_name"] %>"; - } -% end - - return ".ctor"; -} - -const char *GetCctorName([[maybe_unused]] panda::panda_file::SourceLang lang) -{ -% Common::plugins.each_value do |plugin_opts| -% next unless plugin_opts["cctor_name"] - if (lang == <%= plugin_opts["lang_enum"] %>) { - return "<%= plugin_opts["cctor_name"] %>"; - } -% end - - return ".cctor"; -} - -const char *GetStringClassDescriptor([[maybe_unused]] panda::panda_file::SourceLang lang) -{ -% Common::plugins.each do |plugin_lang, plugin_opts| -% next unless plugin_opts["string_class_descriptor"] - if (lang == <%= plugin_opts["lang_enum"] %>) { - return "<%= plugin_opts["string_class_descriptor"] %>"; - } -% end - - return "Lpanda/String;"; -}