1 /*
2 * Copyright (c) 2023-2024 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
TEST_F(BytecodeOptPeepholes,TryBlock)57 TEST_F(BytecodeOptPeepholes, TryBlock)
58 {
59 pandasm::Parser p;
60
61 auto source = R"(
62 .record E {}
63 .record R {
64 u1 field
65 }
66
67 .function void R.ctor(R a0) <ctor> {
68 newobj v0, E
69 throw v0
70 }
71
72 .function u8 try_catch() {
73 try_begin:
74 movi v1, 0x1
75 newobj v0, R
76 movi v1, 0x2
77 call.short R.ctor, v0
78 try_end:
79 ldai 0x0
80 return
81 catch_all:
82 lda v1
83 return
84 .catchall try_begin, try_end, catch_all
85 }
86 )";
87
88 auto res = p.Parse(source);
89 auto &program = res.Value();
90 pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps;
91 std::string fileName = "bc_peepholes";
92 auto piece = pandasm::AsmEmitter::Emit(fileName, program, nullptr, &maps);
93 ASSERT_NE(piece, false);
94
95 EXPECT_TRUE(OptimizeBytecode(&program, &maps, fileName, false, true));
96
97 // Check if there is initobj instruction in the bytecode
98 bool containsInitobj = false;
99 const auto sigTryCatch = pandasm::GetFunctionSignatureFromName("try_catch", {});
100 for (const auto &inst : program.functionTable.at(sigTryCatch).ins) {
101 if (inst.opcode == pandasm::Opcode::INITOBJ) {
102 containsInitobj = true;
103 }
104 }
105 EXPECT_FALSE(containsInitobj);
106
107 auto pf = pandasm::AsmEmitter::Emit(program);
108 ASSERT_NE(pf, nullptr);
109
110 ClassLinker *classLinker = Runtime::GetCurrent()->GetClassLinker();
111 classLinker->AddPandaFile(std::move(pf));
112 auto *extension = classLinker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
113 PandaString descriptor;
114
115 auto *klass = extension->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("_GLOBAL"), &descriptor));
116 ASSERT_NE(klass, nullptr);
117
118 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("try_catch"));
119 ASSERT_NE(method, nullptr);
120
121 std::vector<Value> args;
122 args.emplace_back(Value(1U));
123 Value v = method->Invoke(ManagedThread::GetCurrent(), args.data());
124 EXPECT_EQ(v.GetAsLong(), 0x2U);
125 }
126
127 } // namespace ark::bytecodeopt::test
128