1 /**
2 * Copyright (c) 2021-2022 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 panda::bytecodeopt::test {
26
27 class BytecodeOptPeepholes : public testing::Test {
28 public:
BytecodeOptPeepholes()29 BytecodeOptPeepholes()
30 {
31 RuntimeOptions options;
32 options.SetHeapSizeLimit(128_MB);
33 options.SetShouldLoadBootPandaFiles(false);
34 options.SetShouldInitializeIntrinsics(false);
35 Logger::InitializeDummyLogging();
36
37 Runtime::Create(options);
38 thread_ = panda::MTManagedThread::GetCurrent();
39 thread_->ManagedCodeBegin();
40 }
41
~BytecodeOptPeepholes()42 ~BytecodeOptPeepholes()
43 {
44 thread_->ManagedCodeEnd();
45 Runtime::Destroy();
46 }
47
48 protected:
49 panda::MTManagedThread *thread_;
50 };
51
TEST_F(BytecodeOptPeepholes,TryBlock)52 TEST_F(BytecodeOptPeepholes, TryBlock)
53 {
54 pandasm::Parser p;
55
56 auto source = R"(
57 .record E {}
58 .record R {
59 u1 field
60 }
61
62 .function void R.ctor(R a0) <ctor> {
63 newobj v0, E
64 throw v0
65 }
66
67 .function u8 try_catch() {
68 try_begin:
69 movi v1, 0x1
70 newobj v0, R
71 movi v1, 0x2
72 call.short R.ctor, v0
73 try_end:
74 ldai 0x0
75 return
76 catch_all:
77 lda v1
78 return
79 .catchall try_begin, try_end, catch_all
80 }
81 )";
82
83 auto res = p.Parse(source);
84 auto &program = res.Value();
85 pandasm::AsmEmitter::PandaFileToPandaAsmMaps maps;
86 std::string file_name = "bc_peepholes";
87 auto piece = pandasm::AsmEmitter::Emit(file_name, program, nullptr, &maps);
88 ASSERT_NE(piece, false);
89
90 EXPECT_TRUE(OptimizeBytecode(&program, &maps, file_name, false, true));
91
92 // Check if there is initobj instruction in the bytecode
93 bool contains_initobj = false;
94 const auto sig_try_catch = pandasm::GetFunctionSignatureFromName("try_catch", {});
95 for (const auto &inst : program.function_table.at(sig_try_catch).ins) {
96 if (inst.opcode == pandasm::Opcode::INITOBJ) {
97 contains_initobj = true;
98 }
99 }
100 EXPECT_FALSE(contains_initobj);
101
102 auto pf = pandasm::AsmEmitter::Emit(program);
103 ASSERT_NE(pf, nullptr);
104
105 ClassLinker *class_linker = Runtime::GetCurrent()->GetClassLinker();
106 class_linker->AddPandaFile(std::move(pf));
107 auto *extension = class_linker->GetExtension(panda_file::SourceLang::PANDA_ASSEMBLY);
108 PandaString descriptor;
109
110 auto *klass = extension->GetClass(ClassHelper::GetDescriptor(utf::CStringAsMutf8("_GLOBAL"), &descriptor));
111 ASSERT_NE(klass, nullptr);
112
113 Method *method = klass->GetDirectMethod(utf::CStringAsMutf8("try_catch"));
114 ASSERT_NE(method, nullptr);
115
116 std::vector<Value> args;
117 args.emplace_back(Value(1, interpreter::TypeTag::INT));
118 Value v = method->Invoke(ManagedThread::GetCurrent(), args.data());
119 EXPECT_EQ(v.GetAsLong(), 0x2);
120 }
121
122 } // namespace panda::bytecodeopt::test
123