!309 Store type info as pairs of instruction orders and types

Merge pull request !309 from qiuyu/master
This commit is contained in:
openharmony_ci
2022-06-28 02:07:27 +00:00
committed by Gitee
10 changed files with 475 additions and 8 deletions
+7
View File
@@ -255,3 +255,10 @@ group("ts2abc_unittests") {
deps = [ "tests:ts2abc_tests(${buildtool_linux})" ]
}
}
group("ts2abc_type_adapter_unit_tests") {
if (host_os == "linux") {
testonly = true
deps = [ "${ts2abc_root}/ts2abc/tests/type_adapter_test:ts2abc_type_adapter_unit_tests(${buildtool_linux})" ]
}
}
+17 -1
View File
@@ -44,7 +44,9 @@ const ts2pandaOptions = [
{ name: 'record-type', alias: 'p', type: Boolean, defaultValue: false, description: "Record type info. Default: true" },
{ name: 'dts-type-record', alias: 'q', type: Boolean, defaultValue: false, description: "Record type info for .d.ts files. Default: false" },
{ name: 'debug-type', alias: 'g', type: Boolean, defaultValue: false, description: "Print type-related log. Default: false" },
{ name: 'output-type', type: Boolean, defaultValue: false, description: "set output type."}
{ name: 'output-type', type: Boolean, defaultValue: false, description: "set output type."},
{ name: 'enable-typeinfo', type: Boolean, defaultValue: false, description: "Enable typeinfo of pairs of instruction orders and types" },
{ name: 'display-typeinfo', type: Boolean, defaultValue: false, description: "Display typeinfo of pairs of instruction orders and types when enable-typeinfo is true" }
]
@@ -53,6 +55,20 @@ export class CmdOptions {
private static parsedResult: ts.ParsedCommandLine;
private static options: commandLineArgs.CommandLineOptions;
static getEnableTypeinfo(): boolean {
if (!this.options) {
return false;
}
return this.options["enable-typeinfo"];
}
static getDisplayTypeinfo(): boolean {
if (!this.options) {
return false;
}
return this.options["display-typeinfo"];
}
static isEnableDebugLog(): boolean {
if (!this.options) {
return false;
+3 -1
View File
@@ -194,7 +194,9 @@ export class Ts2Panda {
"debug_mode": CmdOptions.isDebugMode(),
"log_enabled": CmdOptions.isEnableDebugLog(),
"opt_level": CmdOptions.getOptLevel(),
"opt_log_level": CmdOptions.getOptLogLevel()
"opt_log_level": CmdOptions.getOptLogLevel(),
"enable_typeinfo": CmdOptions.getEnableTypeinfo(),
"display_typeinfo": CmdOptions.getDisplayTypeinfo()
};
let jsonOpt = JSON.stringify(options, null, 2);
jsonOpt = "$" + jsonOpt.replace(dollarSign, '#$') + "$";
+1
View File
@@ -80,6 +80,7 @@ if (!defined(ark_independent_build)) {
sources = [
"main.cpp",
"ts2abc.cpp",
"type_adapter.cpp",
]
configs = [ ":ts2abc_config" ]
+12
View File
@@ -30,6 +30,10 @@ import("//ark/ts2abc/ts2panda/ts2abc_config.gni")
# sources = [ "functions_test.cpp" ]
# }
ts2abc_unittest_action("TypeAdapterTest") {
sources = [ "type_adapter_test.cpp" ]
}
# group("unittest") {
# testonly = true
# deps = [
@@ -39,3 +43,11 @@ import("//ark/ts2abc/ts2panda/ts2abc_config.gni")
# ":StringArrTestAction",
# ]
# }
group("type_adapter_unit_tests") {
testonly = true
deps = [
":TypeAdapterTest",
"$ark_root/assembler:libarkassembler_frontend_static",
]
}
@@ -0,0 +1,60 @@
# 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("//ark/runtime_core/ark_config.gni")
import("//ark/ts2abc/ts2panda/ts2abc_config.gni")
ohos_executable("ts2abc_type_adapter_unit_tests") {
sources = [
"//ark/ts2abc/ts2panda/ts2abc/type_adapter.cpp",
"type_adapter_test.cpp",
]
configs = [ "//ark/ts2abc/ts2panda/ts2abc:ts2abc_config" ]
cflags = [
"-Wno-c++20-designator",
"-Wno-c99-extensions",
"-Wno-unknown-warning-option",
]
deps = [ sdk_libc_secshared_dep ]
if (is_linux || is_mingw || is_mac) {
deps += [
"$ark_root/assembler:libarkassembler_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/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 = "ts2abc_type_adapter_unit_tests"
install_enable = true
subsystem_name = "ark"
}
@@ -0,0 +1,143 @@
/*
* 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.
*/
#include "type_adapter.h"
#include "assembler/meta.h"
#include "assembler/assembly-parser.h"
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();
}
}
};
class TypeAdapterTest : TestBase {
public:
void TestVariablesArgsType() const;
void TestBuiltinsType() const;
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);
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 TypeAdapterTest::TestVariablesArgsType() const
{
std::string source = R"(
.function any foo(any a0, any a1) {
mov.dyn v1, a1
mov.dyn v0, a0
ecma.ldlexenvdyn
sta.dyn v4
lda.dyn v0
sta.dyn v3
lda.dyn v1
ecma.add2dyn v3
sta.dyn v2
lda.dyn v2
sta.dyn v3
lda.dyn v3
return.dyn
}
)";
panda::pandasm::Parser p;
auto res = p.Parse(source);
auto &program = res.Value();
auto it = program.function_table.find("foo");
TestAssertNotEqual(it, program.function_table.end());
auto &foo = it->second;
// set up args types
std::vector<ScalarValue> elements;
AddTypeinfo(&elements, 0, 1);
AddTypeinfo(&elements, 1, 1);
// set up variable type
const int32_t var_reg = 2;
AddTypeinfo(&elements, var_reg, 1);
ArrayValue arr(panda::pandasm::Value::Type::I32, elements);
AnnotationElement anno_ele(TypeAdapter::TSTYPE_ANNO_ELEMENT_NAME, std::make_unique<ArrayValue>(arr));
AnnotationData anno_data(TypeAdapter::TSTYPE_ANNO_RECORD_NAME);
anno_data.AddElement(std::move(anno_ele));
std::vector<panda::pandasm::AnnotationData> annos;
annos.emplace_back(std::move(anno_data));
foo.metadata->SetAnnotations(std::move(annos));
TypeAdapter ta;
ta.AdaptTypeForProgram(&program);
// Check types
const auto typeinfo = ExtractTypeinfo(foo);
// first arg type
CheckTypeExist(typeinfo, -1, 1);
// second arg type
const int32_t second_arg = -2;
CheckTypeExist(typeinfo, second_arg, 1);
// variable type
const int32_t instruction_location = 8;
CheckTypeExist(typeinfo, instruction_location, 1);
}
int main(int argc, const char *argv[])
{
TypeAdapterTest test;
std::cout << "TypeAdapterTest TestVariablesArgsType: " << std::endl;
test.TestVariablesArgsType();
std::cout << "PASS!" << std::endl;
// should enable TestBuiltinsType when builtins adaption is ready
}
+32 -6
View File
@@ -24,8 +24,9 @@
#include "assembly-program.h"
#include "assembly-emitter.h"
#include "json/json.h"
#include "ts2abc_options.h"
#include "securec.h"
#include "ts2abc_options.h"
#include "type_adapter.h"
#include "ts2abc.h"
#ifdef ENABLE_BYTECODE_OPT
@@ -39,6 +40,8 @@ namespace {
bool g_debugModeEnabled = false;
bool g_debugLogEnabled = false;
int g_optLevel = 0;
bool g_enableTypeinfo = false;
bool g_displayTypeinfo = false;
std::string g_optLogLevel = "error";
uint32_t g_literalArrayCount = 0;
@@ -626,7 +629,7 @@ static void ParseFunctionTypeInfo(const Json::Value &function, panda::pandasm::F
{
if (function.isMember("ti") && function["ti"].isArray()) {
auto typeInfo = function["ti"];
panda::pandasm::AnnotationData funcAnnotation("_ESTypeAnnotation");
panda::pandasm::AnnotationData funcAnnotation(TypeAdapter::TSTYPE_ANNO_RECORD_NAME);
std::vector<panda::pandasm::ScalarValue> elements;
for (Json::ArrayIndex i = 0; i < typeInfo.size(); i++) {
@@ -640,7 +643,7 @@ static void ParseFunctionTypeInfo(const Json::Value &function, panda::pandasm::F
elements.emplace_back(std::move(tIndex));
}
std::string annotationName = "typeOfVreg";
std::string annotationName = TypeAdapter::TSTYPE_ANNO_ELEMENT_NAME;
panda::pandasm::AnnotationElement typeOfVregElement(
annotationName, std::make_unique<panda::pandasm::ArrayValue>(panda::pandasm::ArrayValue(
panda::pandasm::Value::Type::U32, elements)));
@@ -662,7 +665,7 @@ static void ParseFunctionExportedType(const Json::Value &function, panda::pandas
if (function.isMember("es2t") && function["es2t"].isArray()) {
auto exportedTypes = function["es2t"];
panda::pandasm::AnnotationData funcAnnotation("_ESTypeAnnotation");
panda::pandasm::AnnotationData funcAnnotation(TypeAdapter::TSTYPE_ANNO_RECORD_NAME);
std::vector<panda::pandasm::ScalarValue> symbolElements;
std::vector<panda::pandasm::ScalarValue> symbolTypeElements;
for (Json::ArrayIndex i = 0; i < exportedTypes.size(); i++) {
@@ -718,7 +721,7 @@ static void ParseFunctionDeclaredType(const Json::Value &function, panda::pandas
if (function.isMember("ds2t") && function["ds2t"].isArray()) {
auto declaredTypes = function["ds2t"];
panda::pandasm::AnnotationData funcAnnotation("_ESTypeAnnotation");
panda::pandasm::AnnotationData funcAnnotation(TypeAdapter::TSTYPE_ANNO_RECORD_NAME);
std::vector<panda::pandasm::ScalarValue> symbolElements;
std::vector<panda::pandasm::ScalarValue> symbolTypeElements;
for (Json::ArrayIndex i = 0; i < declaredTypes.size(); i++) {
@@ -788,7 +791,7 @@ static void GenerateESCallTypeAnnotationRecord(panda::pandasm::Program &prog)
}
static void GenerateESTypeAnnotationRecord(panda::pandasm::Program &prog)
{
auto tsTypeAnnotationRecord = panda::pandasm::Record("_ESTypeAnnotation", LANG_EXT);
auto tsTypeAnnotationRecord = panda::pandasm::Record(TypeAdapter::TSTYPE_ANNO_RECORD_NAME, LANG_EXT);
tsTypeAnnotationRecord.metadata->SetAttribute("external");
tsTypeAnnotationRecord.metadata->SetAccessFlags(panda::ACC_ANNOTATION);
prog.record_table.emplace(tsTypeAnnotationRecord.name, std::move(tsTypeAnnotationRecord));
@@ -897,6 +900,22 @@ static void ParseOptLevel(const Json::Value &rootValue)
}
}
static void ParseEnableTypeinfo(const Json::Value &rootValue)
{
Logd("-----------------parse enable_typeinfo-----------------");
if (rootValue.isMember("enable_typeinfo") && rootValue["enable_typeinfo"].isBool()) {
g_enableTypeinfo = rootValue["enable_typeinfo"].asBool();
}
}
static void ParseDisplayTypeinfo(const Json::Value &rootValue)
{
Logd("-----------------parse enable_typeinfo-----------------");
if (rootValue.isMember("display_typeinfo") && rootValue["display_typeinfo"].isBool()) {
g_displayTypeinfo = rootValue["display_typeinfo"].asBool();
}
}
static void ParseOptLogLevel(const Json::Value &rootValue)
{
Logd("-----------------parse opt log level-----------------");
@@ -925,6 +944,8 @@ static void ParseOptions(const Json::Value &rootValue, panda::pandasm::Program &
ParseLogEnable(rootValue);
ParseDebugMode(rootValue);
ParseOptLevel(rootValue);
ParseEnableTypeinfo(rootValue);
ParseDisplayTypeinfo(rootValue);
ParseOptLogLevel(rootValue);
}
@@ -1297,6 +1318,11 @@ bool GenerateProgram([[maybe_unused]] const std::string &data, const std::string
Logd("parsing done, calling pandasm\n");
if (g_enableTypeinfo) {
TypeAdapter ada(g_displayTypeinfo);
ada.AdaptTypeForProgram(&prog);
}
#ifdef ENABLE_BYTECODE_OPT
if (g_optLevel != static_cast<int>(OptLevel::O_LEVEL0) || optLevel != static_cast<int>(OptLevel::O_LEVEL0)) {
optLogLevel = (optLogLevel != "error") ? optLogLevel : g_optLogLevel;
+153
View File
@@ -0,0 +1,153 @@
/*
* 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.
*/
#include "type_adapter.h"
#include "assembler/meta.h"
void TypeAdapter::AdaptTypeForProgram(panda::pandasm::Program *prog) const
{
for (auto &[name, func] : prog->function_table) {
if (ShouldDisplayTypeInfo()) {
std::cout << "Handle types for funtion: " << name << "\n";
}
AdaptTypeForFunction(&func);
}
}
void TypeAdapter::AdaptTypeForFunction(panda::pandasm::Function *func) const
{
const auto &annos = func->metadata->GetAnnotations();
std::unordered_map<int32_t, int32_t> vreg_type_map;
size_t anno_idx = 0;
size_t ele_idx = 0;
for (; anno_idx < annos.size(); anno_idx++) {
const auto &anno_data = annos[anno_idx];
if (anno_data.GetName() != TSTYPE_ANNO_RECORD_NAME) {
continue;
}
const auto &elements = anno_data.GetElements();
for (; ele_idx < elements.size(); ele_idx++) {
const auto &element = elements[ele_idx];
if (element.GetName() != TSTYPE_ANNO_ELEMENT_NAME) {
continue;
}
const auto *array_value = element.GetValue();
ASSERT(array_value->IsArray());
const auto &values = array_value->GetAsArray()->GetValues();
size_t i = 0;
while (i < values.size()) {
auto vreg = static_cast<int32_t>(values[i++].GetValue<uint32_t>());
auto type = static_cast<int32_t>(values[i++].GetValue<uint32_t>());
vreg_type_map.emplace(vreg, type);
}
break;
}
break;
}
if (!vreg_type_map.empty()) {
HandleTypeForFunction(func, anno_idx, ele_idx, vreg_type_map);
}
}
static bool MaybeArg(const panda::pandasm::Function *func, size_t idx)
{
return idx < func->params.size() && func->ins[idx].opcode == panda::pandasm::Opcode::MOV_DYN;
}
void TypeAdapter::HandleTypeForFunction(panda::pandasm::Function *func, size_t anno_idx, size_t ele_idx,
const std::unordered_map<int32_t, int32_t> &vreg_type_map) const
{
std::unordered_map<int32_t, int32_t> order_type_map;
std::vector<int32_t> finished_vregs;
int32_t order = 0;
for (size_t i = 0; i < func->ins.size(); i++) {
const auto &insn = func->ins[i];
if (insn.opcode == panda::pandasm::Opcode::INVALID) {
continue;
}
order++;
bool maybe_arg = MaybeArg(func, i);
if (!maybe_arg && insn.opcode != panda::pandasm::Opcode::STA_DYN) {
continue;
}
if (maybe_arg) {
auto vreg = insn.regs[0];
auto arg = insn.regs[1];
if (vreg >= func->params.size() || arg < func->regs_num) {
continue; // not arg
}
auto it = vreg_type_map.find(vreg);
if (it != vreg_type_map.end()) {
ASSERT(std::find(finished_vregs.begin(), finished_vregs.end(), vreg) == finished_vregs.end());
int32_t arg_order = func->regs_num - arg - 1;
order_type_map.emplace(arg_order, it->second);
finished_vregs.emplace_back(vreg);
}
continue;
}
// vregs binded with variables must be filled through sta_dyn
ASSERT(insn.opcode == panda::pandasm::Opcode::STA_DYN);
ASSERT(!insn.regs.empty());
auto vreg = insn.regs[0];
auto it = vreg_type_map.find(vreg);
if (it != vreg_type_map.end() &&
std::find(finished_vregs.begin(), finished_vregs.end(), vreg) == finished_vregs.end()) {
order_type_map.emplace(order - 1, it->second);
finished_vregs.emplace_back(vreg);
}
}
UpdateTypeAnnotation(func, anno_idx, ele_idx, order_type_map);
}
void TypeAdapter::UpdateTypeAnnotation(panda::pandasm::Function *func, size_t anno_idx, size_t ele_idx,
const std::unordered_map<int32_t, int32_t> &order_type_map) const
{
ASSERT(anno_idx <= func->metadata->GetAnnotations().size());
if (anno_idx == func->metadata->GetAnnotations().size()) {
std::vector<panda::pandasm::AnnotationData> added_datas;
panda::pandasm::AnnotationData data(TSTYPE_ANNO_RECORD_NAME);
added_datas.push_back(std::forward<panda::pandasm::AnnotationData>(data));
func->metadata->AddAnnotations(std::forward<std::vector<panda::pandasm::AnnotationData>>(added_datas));
ele_idx = 0;
}
using ArrayValue = panda::pandasm::ArrayValue;
using ScalarValue = panda::pandasm::ScalarValue;
std::vector<ScalarValue> elements;
for (const auto &[order, type] : order_type_map) {
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));
}
ArrayValue arr(panda::pandasm::Value::Type::I32, elements);
panda::pandasm::AnnotationElement anno_ele(TSTYPE_ANNO_ELEMENT_NAME, std::make_unique<ArrayValue>(arr));
func->metadata->SetOrAddAnnotationElementByIndex(anno_idx, ele_idx, std::move(anno_ele));
if (ShouldDisplayTypeInfo()) {
std::cout << "(instruction order, type): ";
const auto data = func->metadata->GetAnnotations()[anno_idx];
const auto vars = data.GetElements()[ele_idx].GetValue()->GetAsArray()->GetValues();
size_t pair_gap = 2;
for (size_t i = 0; i < vars.size(); i += pair_gap) {
std::cout << "(" << static_cast<int32_t>(vars[i].GetValue<int32_t>()) << ", "
<< static_cast<int32_t>(vars[i + 1].GetValue<uint32_t>()) << "), ";
}
std::cout << "\n";
}
}
+47
View File
@@ -0,0 +1,47 @@
/*
* 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.
*/
#ifndef TS2PANDA_TS2ABC_TYPE_ADAPTER_H
#define TS2PANDA_TS2ABC_TYPE_ADAPTER_H
#include "assembler/assembly-program.h"
#include "assembler/assembly-function.h"
class TypeAdapter {
public:
TypeAdapter() {};
~TypeAdapter() {};
explicit TypeAdapter(bool display) : display_typeinfo_(display) {};
static constexpr const char* TSTYPE_ANNO_RECORD_NAME = "_ESTypeAnnotation";
static constexpr const char* TSTYPE_ANNO_ELEMENT_NAME = "_TypeOfInstruction";
bool ShouldDisplayTypeInfo() const
{
return display_typeinfo_;
}
void AdaptTypeForProgram(panda::pandasm::Program *prog) const;
private:
void AdaptTypeForFunction(panda::pandasm::Function *func) const;
void HandleTypeForFunction(panda::pandasm::Function *func, size_t anno_idx, size_t ele_idx,
const std::unordered_map<int32_t, int32_t> &vreg_type_map) const;
void UpdateTypeAnnotation(panda::pandasm::Function *func, size_t anno_idx, size_t ele_idx,
const std::unordered_map<int32_t, int32_t> &order_type_map) const;
bool display_typeinfo_ = false;
};
#endif // TS2PANDA_TS2ABC_TYPE_ADAPTER_H