Supporting IR-build of functions with try-catch

Issue:https://gitee.com/openharmony/arkcompiler_runtime_core/issues/I6RW02

Signed-off-by: ctw-ian <chentingwei2@huawei.com>
Change-Id: I0783cb829c3175b2cd16c1e1451f125256a7d2eb
This commit is contained in:
ctw-ian 2023-03-31 11:32:50 +08:00
parent 345bd89a1f
commit 145b9fd2ae
10 changed files with 844 additions and 24 deletions

View File

@ -311,4 +311,9 @@ if (!ark_standalone_build) {
"$ark_root/platforms/tests:host_unittest",
]
}
group("compiler_host_unittest") {
testonly = true
deps = [ "$ark_root/compiler/tests:host_unittest" ]
}
}

View File

@ -379,7 +379,7 @@ void IntrinsicInst::DumpOpcode(std::ostream *out) const
{
const auto &adapter = GetBasicBlock()->GetGraph()->GetLocalAllocator()->Adapter();
ArenaString intrinsic(ArenaString("Intrinsic.", adapter));
ArenaString opcode("", adapter);
ArenaString opcode(GetIntrinsicOpcodeName(), adapter);
(*out) << std::setw(INDENT_OPCODE) << intrinsic + opcode << " ";
}

View File

@ -1275,6 +1275,11 @@ public:
return opcode_ == Opcode::SaveState;
}
bool IsTry() const
{
return opcode_ == Opcode::Try;
}
virtual void SetVnObject([[maybe_unused]] VnObject *vn_obj) {}
Register GetDstReg() const
@ -2588,6 +2593,8 @@ protected:
using LastField = Relocate;
private:
std::string GetIntrinsicOpcodeName() const;
IntrinsicId intrinsic_id_ {RuntimeInterface::IntrinsicId::COUNT};
ArenaVector<uint32_t> *imms_ {nullptr}; // record imms appeared in intrinsics
};

View File

@ -80,13 +80,7 @@ inline panda::compiler::DataType::Type AnyBaseTypeToDataType([[maybe_unused]] An
inline const char *AnyTypeTypeToString(AnyBaseType any_type)
{
static constexpr auto COUNT = static_cast<uint32_t>(AnyBaseType::COUNT);
static constexpr std::array<const char *, COUNT> ANYBASETYPE_NAMES = {
"UNDEFINED_TYPE",
};
auto idx = static_cast<uint32_t>(any_type);
ASSERT(idx < COUNT);
return ANYBASETYPE_NAMES[idx];
return "UNDEFINED_TYPE";
}
} // namespace panda::compiler

View File

@ -146,19 +146,19 @@ bool IrBuilder::BuildInstructionsForBB(BasicBlock *bb, InstBuilder *inst_builder
COMPILER_LOG(WARNING, IR_BUILDER) << "Unsupported instruction";
return false;
}
if (inst.CanThrow()) {
// One PBC instruction can be expanded to the group of IR's instructions, find first built instruction in
// this group, and then mark all instructions as throwable; All instructions should be marked, since some of
// them can be deleted during optimizations, unnecessary catch-phi moves will be resolved before Register
// Allocator
auto throwable_inst = (current_last_inst == nullptr) ? bb->GetFirstInst() : current_last_inst->GetNext();
ProcessThrowableInstructions(inst_builder, throwable_inst);
auto &vb = GetGraph()->GetVectorBlocks();
for (size_t i = bb_count; i < vb.size(); i++) {
ProcessThrowableInstructions(inst_builder, vb[i]->GetFirstInst());
}
// One PBC instruction can be expanded to the group of IR's instructions, find first built instruction in
// this group, and then mark all instructions as throwable; All instructions should be marked, since some of
// them can be deleted during optimizations, unnecessary catch-phi moves will be resolved before Register
// Allocator
auto throwable_inst = (current_last_inst == nullptr) ? bb->GetFirstInst() : current_last_inst->GetNext();
ProcessThrowableInstructions(inst_builder, throwable_inst);
auto &vb = GetGraph()->GetVectorBlocks();
for (size_t i = bb_count; i < vb.size(); i++) {
ProcessThrowableInstructions(inst_builder, vb[i]->GetFirstInst());
}
// Break if we meet terminator instruction. If instruction in the middle of basic block we don't create
// further dead instructions.
if (inst.IsTerminator() && !inst.IsSuspend()) {
@ -268,9 +268,13 @@ void IrBuilder::CreateTryCatchBoundariesBlocks()
panda_file::CodeDataAccessor cda(*panda_file, mda.GetCodeId().value());
cda.EnumerateTryBlocks([this](panda_file::CodeDataAccessor::TryBlock &try_block) {
try_block.EnumerateCatchBlocks([this](panda_file::CodeDataAccessor::CatchBlock &catch_block) {
auto start_pc = try_block.GetStartPc();
auto end_pc = start_pc + try_block.GetLength();
auto try_info = InsertTryBlockInfo({start_pc, end_pc});
try_block.EnumerateCatchBlocks([this, try_info](panda_file::CodeDataAccessor::CatchBlock &catch_block) {
auto pc = catch_block.GetHandlerPc();
catches_pc_.insert(pc);
try_info->catches->emplace_back(CatchCodeBlock {pc, 0u});
return true;
});
@ -371,10 +375,8 @@ void IrBuilder::TrackTryBoundaries(size_t pc, const BytecodeInstruction &inst)
}
}
if (inst.CanThrow()) {
for (auto &try_block : opened_try_blocks_) {
try_block->contains_throwable_inst = true;
}
for (auto &try_block : opened_try_blocks_) {
try_block->contains_throwable_inst = true;
}
}

View File

@ -376,4 +376,18 @@ void InstBuilder::BuildEcmaAsIntrinsics(const BytecodeInstruction* bc_inst) // N
return;
}
}
std::string IntrinsicInst::GetIntrinsicOpcodeName() const
{
switch(GetIntrinsicId()) {
% Panda::instructions.select{|b| b.namespace == "ecmascript"}.each do |inst|
case compiler::RuntimeInterface::IntrinsicId::<%= inst.opcode.upcase %>: {
return "<%= inst.mnemonic%>";
}
% end
default: {
return "";
}
}
}
} // namespace panda::compiler

76
compiler/tests/BUILD.gn Normal file
View File

@ -0,0 +1,76 @@
# Copyright (c) 2023 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/ets_frontend/ts2panda/ts2abc_config.gni")
import("//arkcompiler/runtime_core/ark_config.gni")
import("$ark_root/tests/test_helper.gni")
compiler_test_configs = [
"$ark_root:ark_config",
"$ark_root/assembler:arkassembler_public_config",
"$ark_root/bytecode_optimizer:bytecodeopt_public_config",
"$ark_root/compiler:arkcompiler_public_config",
"$ark_root/libpandabase:arkbase_public_config",
"$ark_root/libpandafile:arkfile_public_config",
sdk_libc_secshared_config,
]
compiler_test_deps = [
"$ark_root/assembler:libarkassembler",
"$ark_root/bytecode_optimizer:libarkbytecodeopt",
"$ark_root/compiler:libarkcompiler",
"$ark_root/libpandabase:libarkbase",
"$ark_root/libpandafile:libarkfile",
sdk_libc_secshared_dep,
]
test_js_path = "//arkcompiler/runtime_core/compiler/tests/js/"
test_js_files = [
"simpleTryCatch",
"nestedTryCatch",
]
foreach(file, test_js_files) {
ts2abc_gen_abc("gen_${file}_abc") {
test_js = "${test_js_path}${file}.js"
test_abc = "$target_out_dir/${file}.abc"
src_js = rebase_path(test_js)
dst_file = rebase_path(test_abc)
in_puts = [ test_js ]
out_puts = [ test_abc ]
}
}
host_unittest_action("IrBuilderTest") {
module_out_path = module_output_path
sources = [ "irBuilder_tests.cpp" ]
configs = compiler_test_configs
deps = compiler_test_deps
test_abc_dir = rebase_path(target_out_dir)
defines = [ "IRBUILDER_ABC_DIR=\"${test_abc_dir}/\"" ]
foreach(file, test_js_files) {
deps += [ ":gen_${file}_abc" ]
}
}
group("host_unittest") {
testonly = true
deps = [ ":IrBuilderTestAction" ]
}

View File

@ -0,0 +1,678 @@
/*
* Copyright (c) 2023 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 <gtest/gtest.h>
#include "assembly-parser.h"
#include "bytecode_optimizer/ir_interface.h"
#include "bytecode_optimizer/runtime_adapter.h"
#include "libpandabase/mem/arena_allocator.h"
#include "libpandabase/mem/pool_manager.h"
#include "libpandafile/class_data_accessor.h"
#include "libpandafile/class_data_accessor-inl.h"
#include "libpandafile/method_data_accessor.h"
#include "libpandafile/file.h"
#include "macros.h"
#include "optimizer/ir/graph.h"
#include "optimizer/ir/inst.h"
#include "optimizer/ir/runtime_interface.h"
#include "optimizer/ir_builder/ir_builder.h"
namespace panda::compiler {
class IrBuilderTest : public testing::Test {
public:
static void SetUpTestCase(void) {};
static void TearDownTestCase(void) {};
void SetUp() {};
void TearDown() {};
IrBuilderTest()
{
PoolManager::Initialize(PoolType::MALLOC);
}
~IrBuilderTest()
{
PoolManager::Finalize();
}
template <class Callback>
void TestBuildGraphFromFunc(pandasm::Program &prog, const char *methodName, const Callback &cb)
{
pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps {};
auto pfile = pandasm::AsmEmitter::Emit(prog, &maps);
for (uint32_t id : pfile->GetClasses()) {
panda_file::File::EntityId record_id {id};
panda_file::ClassDataAccessor cda {*pfile, record_id};
cda.EnumerateMethods([&prog, maps, methodName, &cb](panda_file::MethodDataAccessor &mda) {
auto ir_interface = panda::bytecodeopt::BytecodeOptIrInterface(&maps, &prog);
auto func_name = ir_interface.GetMethodIdByOffset(mda.GetMethodId().GetOffset());
if (func_name != methodName) {
return;
}
ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER};
ArenaAllocator local_allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
auto method_ptr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(
mda.GetMethodId().GetOffset());
panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile());
auto *graph = allocator.New<Graph>(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter,
false, nullptr, true, true);
graph->RunPass<panda::compiler::IrBuilder>();
cb(graph);
});
}
}
template <class Callback>
void TestBuildGraphFromFile(const std::string &pFileName, const Callback &cb)
{
auto pfile = panda_file::OpenPandaFile(pFileName);
for (uint32_t id : pfile->GetClasses()) {
panda_file::File::EntityId record_id {id};
if (pfile->IsExternal(record_id)) {
continue;
}
panda_file::ClassDataAccessor cda {*pfile, record_id};
cda.EnumerateMethods([&pfile, &cb](panda_file::MethodDataAccessor &mda) {
if (!mda.IsExternal()) {
ArenaAllocator allocator {SpaceType::SPACE_TYPE_COMPILER};
ArenaAllocator local_allocator {SpaceType::SPACE_TYPE_COMPILER, nullptr, true};
auto method_ptr = reinterpret_cast<compiler::RuntimeInterface::MethodPtr>(
mda.GetMethodId().GetOffset());
panda::BytecodeOptimizerRuntimeAdapter adapter(mda.GetPandaFile());
auto *graph = allocator.New<Graph>(&allocator, &local_allocator, Arch::NONE, method_ptr, &adapter,
false, nullptr, true, true);
graph->RunPass<panda::compiler::IrBuilder>();
auto methodName = std::string(utf::Mutf8AsCString(pfile->GetStringData(mda.GetNameId()).data));
cb(graph, methodName);
}
});
}
}
};
HWTEST_F(IrBuilderTest, simpleTryCatchAsm, testing::ext::TestSize.Level1)
{
/**
* try {
* a = 1;
* } catch(e) {
* a = 2;
* }
*/
const auto source = R"(
.language ECMAScript
.function any foo(any a0, any a1, any a2) {
mov v0, a0
mov v1, a1
mov v2, a2
try_begin:
ldai 0x1
trystglobalbyname 0x0, "a"
try_end:
jmp catch_end
catch_begin:
sta v4
tryldglobalbyname 0x1, "a"
catch_end:
returnundefined
}
)";
panda::pandasm::Parser parser;
auto res = parser.Parse(source);
auto &prog = res.Value();
for (auto &[name, func] : prog.function_table) {
auto &catchBlock = func.catch_blocks.emplace_back();
catchBlock.try_begin_label = "try_begin";
catchBlock.try_end_label = "try_end";
catchBlock.catch_begin_label = "catch_begin";
catchBlock.catch_end_label = "catch_end";
}
TestBuildGraphFromFunc(prog, "foo:(any,any,any)", [](Graph* graph) {
EXPECT_NE(graph, nullptr);
for (auto bb : graph->GetBlocksRPO()) {
EXPECT_NE(bb, nullptr);
if (bb->IsTryBegin()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
EXPECT_TRUE(bb->GetSuccessor(0)->IsTry());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
EXPECT_TRUE(bb->GetFirstInst()->IsTry());
continue;
}
if (bb->IsTry()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
EXPECT_TRUE(bb->GetPredecessor(0)->IsTryBegin());
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::TRYSTGLOBALBYNAME_IMM8_ID16);
continue;
}
if (bb->IsTryEnd()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
EXPECT_TRUE(bb->GetPredecessor(0)->IsTry());
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
EXPECT_TRUE(bb->GetSuccessor(0)->GetGuestPc() == bb->GetGuestPc());
EXPECT_TRUE(!bb->GetSuccessor(0)->IsCatch());
EXPECT_TRUE(!bb->GetSuccessor(0)->IsCatchBegin());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
EXPECT_TRUE(bb->IsEmpty());
continue;
}
if (bb->IsCatchBegin()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 2);
EXPECT_TRUE(bb->GetPredecessor(0)->IsTryBegin());
EXPECT_TRUE(bb->GetPredecessor(1)->IsTryEnd());
EXPECT_TRUE(bb->GetSuccessor(0)->IsCatch());
EXPECT_TRUE(bb->IsEmpty());
continue;
}
if (bb->IsCatch() && !bb->IsCatchBegin()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
EXPECT_TRUE(bb->GetPredecessor(0)->IsCatchBegin());
EXPECT_TRUE(bb->GetSuccessor(0)->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetSuccessor(0)->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetSuccessor(0)->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::RETURNUNDEFINED);
EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::TRYLDGLOBALBYNAME_IMM8_ID16);
continue;
}
}
});
}
HWTEST_F(IrBuilderTest, nestedTryCatchAsm, testing::ext::TestSize.Level1)
{
/**
* try {
* try {
* a = 1;
* } catch(e) {
* a;
* }
* } catch(e) {
* print(e);
* }
*/
const auto source = R"(
.language ECMAScript
.function any foo(any a0, any a1, any a2) {
mov v2, a2
mov v1, a1
mov v0, a0
lda.str "use strict"
LABEL_0:
LABEL_1:
ldai 1
trystglobalbyname 0, "a"
LABEL_2:
jmp LABEL_3
LABEL_4:
sta v3
tryldglobalbyname 1, "a"
LABEL_3:
LABEL_5:
jmp LABEL_6
LABEL_7:
sta v4
tryldglobalbyname 2, "print"
sta v5
lda v4
sta v6
lda v5
callarg1 3, v6
LABEL_6:
returnundefined
}
)";
panda::pandasm::Parser parser;
auto res = parser.Parse(source);
auto &prog = res.Value();
EXPECT_TRUE(prog.function_table.size() == 1);
for (auto &[name, func] : prog.function_table) {
auto &catchBlock1 = func.catch_blocks.emplace_back();
catchBlock1.try_begin_label = "LABEL_0";
catchBlock1.try_end_label = "LABEL_1";
catchBlock1.catch_begin_label = "LABEL_7";
catchBlock1.catch_end_label = "LABEL_6";
auto &catchBlock2 = func.catch_blocks.emplace_back();
catchBlock2.try_begin_label = "LABEL_1";
catchBlock2.try_end_label = "LABEL_2";
catchBlock2.catch_begin_label = "LABEL_4";
catchBlock2.catch_end_label = "LABEL_3";
auto &catchBlock3 = func.catch_blocks.emplace_back();
catchBlock3.try_begin_label = "LABEL_2";
catchBlock3.try_end_label = "LABEL_5";
catchBlock3.catch_begin_label = "LABEL_7";
catchBlock3.catch_end_label = "LABEL_6";
}
TestBuildGraphFromFunc(prog, "foo:(any,any,any)", [](Graph* graph) {
EXPECT_NE(graph, nullptr);
int32_t numOfTry = 0;
for (auto bb : graph->GetBlocksRPO()) {
EXPECT_NE(bb, nullptr);
if (bb->IsTryBegin()) {
numOfTry++;
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
EXPECT_TRUE(bb->GetSuccessor(0)->IsTry());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
EXPECT_TRUE(bb->GetSuccessor(0)->GetTryId() == bb->GetTryId());
continue;
}
if (bb->IsTry()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
if (!bb->GetPredecessor(0)->IsTryBegin()) {
EXPECT_TRUE(bb->GetPredecessor(0)->IsCatchBegin());
EXPECT_TRUE(bb->GetPredecessor(0)->IsCatch());
EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::TRYLDGLOBALBYNAME_IMM8_ID16);
continue;
}
EXPECT_TRUE(bb->GetPredecessor(0)->GetTryId() == bb->GetTryId());
EXPECT_TRUE(bb->GetPredecessor(0)->GetGuestPc() == bb->GetGuestPc());
if (bb->GetPredecessor(0)->GetTryId() == 1) {
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
EXPECT_TRUE(bb->GetSuccessor(0)->IsTryEnd());
EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::TRYSTGLOBALBYNAME_IMM8_ID16);
continue;
}
EXPECT_TRUE(bb->GetPredecessor(0)->GetTryId() == 2);
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
EXPECT_TRUE(bb->IsEmpty());
for (auto inst : bb->GetSuccessor(0)->AllInsts()) {
EXPECT_TRUE(inst->IsPhi());
}
continue;
}
if (bb->IsTryEnd()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
EXPECT_TRUE(bb->GetPredecessor(0)->IsTry());
EXPECT_TRUE(bb->GetPredecessor(0)->GetTryId() == bb->GetTryId());
EXPECT_TRUE(bb->IsEmpty());
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
if (bb->GetTryId() == 1) {
EXPECT_TRUE(bb->GetSuccessor(0)->IsTryBegin());
EXPECT_TRUE(bb->GetSuccessor(0)->GetGuestPc() == bb->GetGuestPc());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
for (auto inst : bb->GetSuccessor(1)->AllInsts()) {
EXPECT_TRUE(inst->IsCatchPhi());
}
continue;
}
EXPECT_TRUE(bb->GetTryId() == 2);
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
for (auto inst : bb->GetSuccessor(0)->AllInsts()) {
EXPECT_TRUE(inst->IsPhi());
}
continue;
}
if (bb->IsCatchBegin()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 2);
EXPECT_TRUE(bb->GetPredecessor(0)->IsTryBegin());
EXPECT_TRUE(bb->GetPredecessor(1)->IsTryEnd());
EXPECT_TRUE(bb->GetSuccessor(0)->IsCatch());
continue;
}
if (bb->IsCatch() && !bb->IsCatchBegin()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
if (bb->IsTry()) {
EXPECT_TRUE(bb->GetTryId() == 2);
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
EXPECT_TRUE(bb->GetSuccessor(0)->IsTryEnd());
EXPECT_TRUE(bb->GetSuccessor(0)->IsCatch());
EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::TRYLDGLOBALBYNAME_IMM8_ID16);
continue;
}
if (bb->IsTryEnd()) {
EXPECT_TRUE(bb->GetPredecessor(0)->IsTry());
EXPECT_TRUE(bb->GetPredecessor(0)->IsCatch());
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
for (auto inst : bb->GetSuccessor(0)->AllInsts()) {
EXPECT_TRUE(inst->IsPhi());
}
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
EXPECT_TRUE(bb->IsEmpty());
continue;
}
EXPECT_TRUE(bb->GetPredecessor(0)->IsCatchBegin());
EXPECT_TRUE(bb->GetPredecessor(0)->IsCatch());
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
auto *successor = bb->GetSuccessor(0);
EXPECT_TRUE(successor->GetFirstInst()->IsSaveState());
EXPECT_TRUE(successor->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(successor->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::RETURNUNDEFINED);
for (auto inst : successor->GetPredecessor(0)->AllInsts()) {
EXPECT_TRUE(inst->IsPhi());
}
EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::CALLARG1_IMM8_V8);
}
}
EXPECT_EQ(numOfTry, 2);
});
}
HWTEST_F(IrBuilderTest, simpleTryCatchAbc, testing::ext::TestSize.Level1)
{
std::string pFile = IRBUILDER_ABC_DIR "simpleTryCatch.abc";
const char *testMethodName = "func_main_0";
TestBuildGraphFromFile(pFile, [&testMethodName](Graph* graph, std::string &methodName) {
if (testMethodName != methodName) {
return;
}
EXPECT_NE(graph, nullptr);
for (auto bb : graph->GetBlocksRPO()) {
EXPECT_NE(bb, nullptr);
if (bb->IsTryBegin()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
EXPECT_TRUE(bb->GetSuccessor(0)->IsTry());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
EXPECT_TRUE(bb->GetFirstInst()->IsTry());
continue;
}
if (bb->IsTry()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
EXPECT_TRUE(bb->GetPredecessor(0)->IsTryBegin());
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::TRYSTGLOBALBYNAME_IMM8_ID16);
continue;
}
if (bb->IsTryEnd()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
EXPECT_TRUE(bb->GetPredecessor(0)->IsTry());
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
EXPECT_TRUE(bb->GetSuccessor(0)->GetGuestPc() == bb->GetGuestPc());
EXPECT_TRUE(!bb->GetSuccessor(0)->IsCatch());
EXPECT_TRUE(!bb->GetSuccessor(0)->IsCatchBegin());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
EXPECT_TRUE(bb->IsEmpty());
continue;
}
if (bb->IsCatchBegin()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 2);
EXPECT_TRUE(bb->GetPredecessor(0)->IsTryBegin());
EXPECT_TRUE(bb->GetPredecessor(1)->IsTryEnd());
EXPECT_TRUE(bb->GetSuccessor(0)->IsCatch());
EXPECT_TRUE(bb->IsEmpty());
continue;
}
if (bb->IsCatch() && !bb->IsCatchBegin()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
EXPECT_TRUE(bb->GetPredecessor(0)->IsCatchBegin());
EXPECT_TRUE(bb->GetSuccessor(0)->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetSuccessor(0)->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetSuccessor(0)->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::RETURNUNDEFINED);
EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::TRYLDGLOBALBYNAME_IMM8_ID16);
continue;
}
}
});
}
HWTEST_F(IrBuilderTest, nestedTryCatchAbc, testing::ext::TestSize.Level1)
{
std::string pFile = IRBUILDER_ABC_DIR "nestedTryCatch.abc";
const char *testMethodName = "func_main_0";
TestBuildGraphFromFile(pFile, [testMethodName](Graph* graph, std::string &methodName) {
if (testMethodName != methodName) {
return;
}
EXPECT_NE(graph, nullptr);
int32_t numOfTry = 0;
for (auto bb : graph->GetBlocksRPO()) {
EXPECT_NE(bb, nullptr);
if (bb->IsTryBegin()) {
numOfTry++;
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
EXPECT_TRUE(bb->GetSuccessor(0)->IsTry());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
EXPECT_TRUE(bb->GetSuccessor(0)->GetTryId() == bb->GetTryId());
continue;
}
if (bb->IsTry()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
if (!bb->GetPredecessor(0)->IsTryBegin()) {
EXPECT_TRUE(bb->GetPredecessor(0)->IsCatchBegin());
EXPECT_TRUE(bb->GetPredecessor(0)->IsCatch());
EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::TRYLDGLOBALBYNAME_IMM8_ID16);
continue;
}
EXPECT_TRUE(bb->GetPredecessor(0)->GetTryId() == bb->GetTryId());
EXPECT_TRUE(bb->GetPredecessor(0)->GetGuestPc() == bb->GetGuestPc());
if (bb->GetPredecessor(0)->GetTryId() == 0) {
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
EXPECT_TRUE(bb->GetSuccessor(0)->IsTryEnd());
EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::TRYSTGLOBALBYNAME_IMM8_ID16);
continue;
}
EXPECT_TRUE(bb->GetPredecessor(0)->GetTryId() == 2);
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
EXPECT_TRUE(bb->IsEmpty());
for (auto inst : bb->GetSuccessor(0)->AllInsts()) {
EXPECT_TRUE(inst->IsPhi());
}
continue;
}
if (bb->IsTryEnd()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
EXPECT_TRUE(bb->GetPredecessor(0)->IsTry());
EXPECT_TRUE(bb->GetPredecessor(0)->GetTryId() == bb->GetTryId());
EXPECT_TRUE(bb->IsEmpty());
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
if (bb->GetTryId() == 0) {
EXPECT_TRUE(bb->GetSuccessor(0)->IsTryBegin());
EXPECT_TRUE(bb->GetSuccessor(0)->GetGuestPc() == bb->GetGuestPc());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
for (auto inst : bb->GetSuccessor(1)->AllInsts()) {
EXPECT_TRUE(inst->IsCatchPhi());
}
continue;
}
EXPECT_TRUE(bb->GetTryId() == 2);
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
for (auto inst : bb->GetSuccessor(0)->AllInsts()) {
EXPECT_TRUE(inst->IsPhi());
}
continue;
}
if (bb->IsCatchBegin()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 2);
EXPECT_TRUE(bb->GetPredecessor(0)->IsTryBegin());
EXPECT_TRUE(bb->GetPredecessor(1)->IsTryEnd());
EXPECT_TRUE(bb->GetSuccessor(0)->IsCatch());
continue;
}
if (bb->IsCatch() && !bb->IsCatchBegin()) {
EXPECT_TRUE(bb->GetPredsBlocks().size() == 1);
if (bb->IsTry()) {
EXPECT_TRUE(bb->GetTryId() == 2);
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
EXPECT_TRUE(bb->GetSuccessor(0)->IsTryEnd());
EXPECT_TRUE(bb->GetSuccessor(0)->IsCatch());
EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::TRYLDGLOBALBYNAME_IMM8_ID16);
continue;
}
if (bb->IsTryEnd()) {
EXPECT_TRUE(bb->GetPredecessor(0)->IsTry());
EXPECT_TRUE(bb->GetPredecessor(0)->IsCatch());
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 2);
for (auto inst : bb->GetSuccessor(0)->AllInsts()) {
EXPECT_TRUE(inst->IsPhi());
}
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatchBegin());
EXPECT_TRUE(bb->GetSuccessor(1)->IsCatch());
EXPECT_TRUE(bb->IsEmpty());
continue;
}
EXPECT_TRUE(bb->GetPredecessor(0)->IsCatchBegin());
EXPECT_TRUE(bb->GetPredecessor(0)->IsCatch());
EXPECT_TRUE(bb->GetSuccsBlocks().size() == 1);
auto *successor = bb->GetSuccessor(0);
EXPECT_TRUE(successor->GetFirstInst()->IsSaveState());
EXPECT_TRUE(successor->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(successor->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::RETURNUNDEFINED);
for (auto inst : successor->GetPredecessor(0)->AllInsts()) {
EXPECT_TRUE(inst->IsPhi());
}
EXPECT_TRUE(bb->GetFirstInst()->IsSaveState());
EXPECT_TRUE(bb->GetLastInst()->IsIntrinsic());
EXPECT_TRUE((static_cast<IntrinsicInst *>(bb->GetLastInst()))->GetIntrinsicId() ==
RuntimeInterface::IntrinsicId::CALLARG1_IMM8_V8);
}
}
EXPECT_EQ(numOfTry, 2);
});
}
} // namespace panda::compiler

View File

@ -0,0 +1,24 @@
/*
Copyright (c) 2023 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.
*/
try {
try {
a = 1;
} catch(e) {
a;
}
} catch(e) {
print(e);
}

View File

@ -0,0 +1,20 @@
/*
Copyright (c) 2023 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.
*/
try {
a = 1;
} catch(e) {
a;
}