1 /*
2 * Copyright (c) 2023-2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <gtest/gtest.h>
17
18 #include "assembler/assembly-emitter.h"
19 #include "assembler/assembly-parser.h"
20 #include "bytecode_optimizer/optimize_bytecode.h"
21 #include "runtime/include/class_linker.h"
22 #include "runtime/include/runtime.h"
23 #include "mangling.h"
24
25 namespace ark::bytecodeopt::test {
26
27 class BytecodeOptPeepholes : public testing::Test {
28 public:
BytecodeOptPeepholes()29 BytecodeOptPeepholes()
30 {
31 RuntimeOptions options;
32 // NOLINTNEXTLINE(readability-magic-numbers)
33 options.SetHeapSizeLimit(128_MB);
34 options.SetShouldLoadBootPandaFiles(false);
35 options.SetShouldInitializeIntrinsics(false);
36 Logger::InitializeDummyLogging();
37
38 Runtime::Create(options);
39 thread_ = ark::MTManagedThread::GetCurrent();
40 thread_->ManagedCodeBegin();
41 }
42
~BytecodeOptPeepholes()43 ~BytecodeOptPeepholes() override
44 {
45 thread_->ManagedCodeEnd();
46 Runtime::Destroy();
47 }
48
49 NO_COPY_SEMANTIC(BytecodeOptPeepholes);
50 NO_MOVE_SEMANTIC(BytecodeOptPeepholes);
51
52 protected:
53 // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
54 ark::MTManagedThread *thread_;
55 };
56
57 // CC-OFFNXT(huge_method[C++], G.FUN.01-CPP) solid logic
TEST_F(BytecodeOptPeepholes,TryBlock)58 TEST_F(BytecodeOptPeepholes, TryBlock)
59 {
60 pandasm::Parser p;
61
62 auto source = R"(
63 .record E {}
64 .record R {
65 u1 field
66 }
67
68 .function void R.ctor(R a0) <ctor> {
69 newobj v0, E
70 throw v0
71 }
72
73 .function u8 try_catch() {
74 try_begin:
75 movi v1, 0x1
76 newobj v0, R
77 movi v1, 0x2
78 call.short R.ctor, v0
79 try_end:
80 ldai 0x0
81 return
82 catch_all:
83 lda v1
84 return
85 .catchall try_begin, try_end, catch_all
86 }
87 )";
88
89 auto res = p.Parse(source);
90 auto &program = res.Value();
91 pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps;
92 std::string fileName = "bc_peepholes";
93 auto piece = pandasm::AsmEmitter::Emit(fileName, program, nullptr, &maps);
94 ASSERT_NE(piece, false);
95
96 EXPECT_TRUE(OptimizeBytecode(&program, &maps, fileName, false, true));
97
98 // Check if there is initobj instruction in the bytecode
99 bool containsInitobj = false;
100 const auto sigTryCatch = pandasm::GetFunctionSignatureFromName("try_catch", {});
101 for (const auto &inst : program.functionStaticTable.at(sigTryCatch).ins) {
102 if (inst.opcode == pandasm::Opcode::INITOBJ) {
103 containsInitobj = true;
104 }
105 }
106 EXPECT_FALSE(containsInitobj);
107
108 auto pf = pandasm::AsmEmitter::Emit(program);
109 ASSERT_NE(pf, nullptr);
110
111 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
112 classLinker->AddPandaFile(std::move(pf));
113 auto *extension = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
114 PandaString descriptor;
115
116 auto *klass = extension->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("_GLOBAL"), &descriptor));
117 ASSERT_NE(klass, nullptr);
118
119 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("try_catch"));
120 ASSERT_NE(method, nullptr);
121
122 std::vector<Value> args;
123 args.emplace_back(Value(1U));
124 Value v = method->Invoke(ManagedThread::GetCurrent(), args.data());
125 EXPECT_EQ(v.GetAsLong(), 0x2U);
126 }
127
128 } // namespace ark::bytecodeopt::test
129