mirror of
https://gitee.com/openharmony/arkcompiler_runtime_core
synced 2024-11-23 06:40:32 +00:00
Type system adaption for Bytecode optimizer
1. Adapt typescript type system for bytecode optimizer 2. Delete file_items_gen_inc as we do not have multi languages to support 3. Add log which can display typeinfo after optimizations in debug mode Issue: I5HYBL Signed-off-by: qiuyu <qiuyu22@huawei.com> Change-Id: I97ce3fb3aca1592329abad86e022e74ecff4b9eb
This commit is contained in:
parent
9a5d32a838
commit
5a0298be18
4
BUILD.gn
4
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)" ]
|
||||
}
|
||||
|
@ -102,6 +102,10 @@ void BytecodeGen::VisitTryBegin(const compiler::BasicBlock *bb)
|
||||
bool BytecodeGen::RunImpl()
|
||||
{
|
||||
Reserve(function_->ins.size());
|
||||
std::vector<ScalarValue> 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<ScalarValue> *elements) const
|
||||
{
|
||||
std::unordered_map<int32_t, TypeInfoIndex> 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<ScalarValue> *elements) const
|
||||
{
|
||||
ScalarValue insn_order(ScalarValue::Create<panda::pandasm::Value::Type::I32>(order));
|
||||
elements->emplace_back(std::move(insn_order));
|
||||
ScalarValue type_info_index(ScalarValue::Create<panda::pandasm::Value::Type::I32>(type));
|
||||
elements->emplace_back(std::move(type_info_index));
|
||||
}
|
||||
|
||||
void BytecodeGen::AddTypeInfoIndexForIns(int32_t order, size_t id, std::vector<ScalarValue> *elements) const
|
||||
{
|
||||
auto type = GetGraph()->GetRuntime()->GetTypeInfoIndexByInstId(id);
|
||||
if (type != NO_EXPLICIT_TYPE) {
|
||||
AddOrderAndTypeInfoIndex(order, type, elements);
|
||||
}
|
||||
}
|
||||
|
||||
void BytecodeGen::UpdateTypeInfoIndexAnnotation(const std::vector<ScalarValue> *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<int32_t>();
|
||||
auto type = (*elements)[i + 1].GetValue<int32_t>();
|
||||
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<panda::pandasm::ArrayValue>(arr));
|
||||
function_->metadata->SetOrAddAnnotationElementByIndex(type_idx->first, type_idx->second, std::move(anno_elem));
|
||||
}
|
||||
|
||||
void BytecodeGen::EmitJump(const BasicBlock *bb)
|
||||
{
|
||||
BasicBlock *suc_bb = nullptr;
|
||||
|
@ -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<ScalarValue> *elements) const;
|
||||
void AddOrderAndTypeInfoIndex(int32_t order, TypeInfoIndex type, std::vector<ScalarValue> *elements) const;
|
||||
void AddTypeInfoIndexForIns(int32_t order, size_t id, std::vector<ScalarValue> *elements) const;
|
||||
void UpdateTypeInfoIndexAnnotation(const std::vector<ScalarValue> *elements);
|
||||
|
||||
private:
|
||||
pandasm::Function *function_;
|
||||
const BytecodeOptIrInterface *ir_interface_;
|
||||
|
@ -149,6 +149,67 @@ void BuildMapFromPcToIns(pandasm::Function &function, BytecodeOptIrInterface &ir
|
||||
}
|
||||
}
|
||||
|
||||
static void ExtractTypeInfo(const pandasm::Function &function, compiler::RuntimeInterface *adapter,
|
||||
std::unordered_map<int32_t, TypeInfoIndex> *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<int32_t>();
|
||||
auto type = values[i++].GetValue<int32_t>();
|
||||
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<int32_t, TypeInfoIndex> 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<int32_t>(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);
|
||||
|
||||
|
@ -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<int32_t, TypeInfoIndex> *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<size_t, size_t> *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<size_t, TypeInfoIndex> instid_type_map_;
|
||||
std::unordered_map<int32_t, TypeInfoIndex> pc_type_map_;
|
||||
std::pair<size_t, size_t> anno_elem_idx_ = std::make_pair(INVALID_TYPE_INDEX, INVALID_TYPE_INDEX);
|
||||
};
|
||||
} // namespace panda
|
||||
|
||||
|
64
bytecode_optimizer/tests/BUILD.gn
Normal file
64
bytecode_optimizer/tests/BUILD.gn
Normal file
@ -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"
|
||||
}
|
245
bytecode_optimizer/tests/bcopt_type_adaption_test.cpp
Normal file
245
bytecode_optimizer/tests/bcopt_type_adaption_test.cpp
Normal file
@ -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 <typename T1, typename T2>
|
||||
inline void TestAssertEqual(const T1 &left, const T2 &right) const
|
||||
{
|
||||
if (left != static_cast<T1>(right)) {
|
||||
std::cout << "assertion equal failed." << std::endl;
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
inline void TestAssertNotEqual(const T1 &left, const T2 &right) const
|
||||
{
|
||||
if (left == static_cast<T1>(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<int32_t, int32_t> 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<int32_t, int32_t> 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<int32_t>(), values[i + 1].GetValue<int32_t>());
|
||||
}
|
||||
return type_info;
|
||||
}
|
||||
|
||||
void CheckTypeExist(const std::unordered_map<int32_t, int32_t> &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<ScalarValue> *elements, int32_t order, int32_t type) const
|
||||
{
|
||||
ScalarValue insn_order(ScalarValue::Create<panda::pandasm::Value::Type::I32>(order));
|
||||
elements->emplace_back(std::move(insn_order));
|
||||
ScalarValue insn_type(ScalarValue::Create<panda::pandasm::Value::Type::I32>(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 <external>
|
||||
.function any foo(any a0, any a1, any a2) <static> {
|
||||
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<panda::pandasm::ScalarValue> 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<int32_t>(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<int32_t>(ADD_IDX + 1), STR_TYPE);
|
||||
|
||||
ArrayValue array_value(panda::pandasm::Value::Type::I32, elements);
|
||||
AnnotationElement anno_element(TSTYPE_ANNO_ELEMENT_NAME, std::make_unique<ArrayValue>(array_value));
|
||||
AnnotationData annotation(TSTYPE_ANNO_RECORD_NAME);
|
||||
annotation.AddElement(std::move(anno_element));
|
||||
std::vector<AnnotationData> 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<std::string, size_t> stat;
|
||||
std::map<std::string, size_t> *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<size_t>(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<size_t>(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;
|
||||
}
|
@ -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 = [
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
|
||||
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<std::size_t>::max();
|
||||
#endif // COMPILER_OPTIMIZER_IR_CONSTANTS_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<int32_t, TypeInfoIndex> *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<size_t, size_t> *GetTypeAnnotationIndex() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NO_COPY_SEMANTIC(RuntimeInterface);
|
||||
NO_MOVE_SEMANTIC(RuntimeInterface);
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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<int>(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<int>(GetPc(instruction->GetAddress())));
|
||||
}
|
||||
BuildCastToAnyNumber(instruction);
|
||||
% end
|
||||
% end
|
||||
@ -139,6 +147,11 @@ templates:
|
||||
BuildLoadConstArray(instruction);
|
||||
% else
|
||||
BuildLoadFromPool<Opcode::<%= inst.opcode =~ /lda_type/ ? 'LoadType' : 'LoadString' %>>(instruction);
|
||||
% if inst.opcode =~ /lda_str/
|
||||
if (GetGraph()->IsBytecodeOptimizer() && GetGraph()->IsDynamicMethod()) {
|
||||
TryFillInstIdTypePair(GetDefinitionAcc()->GetId(), static_cast<int>(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<int>(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<int>(GetPc(instruction->GetAddress())));
|
||||
}
|
||||
% end
|
||||
% end
|
||||
builtin: |-
|
||||
BuildBuiltin(instruction);
|
||||
|
@ -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"
|
||||
|
@ -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}
|
||||
)
|
||||
|
||||
|
@ -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<panda::panda_file::SourceLang> 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 <class Tag, class Val>
|
||||
static bool WriteUlebTaggedValue(Writer *writer, Tag tag, Val v)
|
||||
|
@ -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<panda::panda_file::SourceLang> 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;";
|
||||
}
|
Loading…
Reference in New Issue
Block a user