mirror of
https://gitee.com/openharmony/arkcompiler_runtime_core
synced 2024-11-23 23:00:08 +00:00
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:
parent
345bd89a1f
commit
145b9fd2ae
5
BUILD.gn
5
BUILD.gn
@ -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" ]
|
||||
}
|
||||
}
|
||||
|
@ -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 << " ";
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
76
compiler/tests/BUILD.gn
Normal 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" ]
|
||||
}
|
678
compiler/tests/irBuilder_tests.cpp
Normal file
678
compiler/tests/irBuilder_tests.cpp
Normal 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
|
24
compiler/tests/js/nestedTryCatch.js
Normal file
24
compiler/tests/js/nestedTryCatch.js
Normal 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);
|
||||
}
|
20
compiler/tests/js/simpleTryCatch.js
Normal file
20
compiler/tests/js/simpleTryCatch.js
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user