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 "bytecodeopt_peepholes.h"
17 #include "common.h"
18 #include "compiler/optimizer/optimizations/cleanup.h"
19
20 namespace panda::bytecodeopt::test {
21
TEST_F(IrBuilderTest,PeepholesTryBlockInstBetween)22 TEST_F(IrBuilderTest, PeepholesTryBlockInstBetween)
23 {
24 auto source = R"(
25 .record E {}
26 .record R {
27 u1 field
28 }
29
30 .function void R.ctor(R a0) <ctor> {
31 newobj v0, E
32 throw v0
33 }
34
35 .function u8 main() {
36 try_begin:
37 movi v1, 0x1
38 newobj v0, R
39 movi v1, 0x2
40 call.short R.ctor, v0
41 try_end:
42 ldai 0x0
43 return
44 catch_all:
45 lda v1
46 return
47 .catchall try_begin, try_end, catch_all
48 }
49 )";
50 ASSERT_TRUE(ParseToGraph(source, "main"));
51
52 EXPECT_FALSE(GetGraph()->RunPass<BytecodeOptPeepholes>());
53 }
54
TEST_F(IrBuilderTest,PeepholesTryBlockNoInstBetween)55 TEST_F(IrBuilderTest, PeepholesTryBlockNoInstBetween)
56 {
57 auto source = R"(
58 .record E {}
59 .record R {
60 u1 field
61 }
62
63 .function void R.ctor(R a0) <ctor> {
64 newobj v0, E
65 throw v0
66 }
67
68 .function u8 main() {
69 try_begin:
70 movi v1, 0x1
71 newobj v0, R
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 ASSERT_TRUE(ParseToGraph(source, "main"));
83
84 EXPECT_TRUE(GetGraph()->RunPass<BytecodeOptPeepholes>());
85 }
86
87 // TODO(aromanov): enable
TEST_F(CommonTest,DISABLED_NoNullCheck)88 TEST_F(CommonTest, DISABLED_NoNullCheck)
89 {
90 RuntimeInterfaceMock runtime(0);
91 auto graph = CreateEmptyGraph();
92 graph->SetRuntime(&runtime);
93 GRAPH(graph)
94 {
95 using namespace compiler::DataType;
96 CONSTANT(6, 0);
97 BASIC_BLOCK(2, -1)
98 {
99 INST(0, Opcode::SaveState).NoVregs();
100 INST(1, Opcode::LoadAndInitClass).ref().Inputs(0).TypeId(68);
101 INST(2, Opcode::NewObject).ref().Inputs(1, 0).TypeId(68);
102 INST(3, Opcode::SaveState).NoVregs();
103 INST(5, Opcode::CallStatic).v0id().Inputs({{REFERENCE, 2}, {NO_TYPE, 3}});
104 INST(7, Opcode::Return).s32().Inputs(6);
105 }
106 }
107
108 EXPECT_TRUE(graph->RunPass<BytecodeOptPeepholes>());
109 EXPECT_TRUE(graph->RunPass<compiler::Cleanup>());
110
111 auto after = CreateEmptyGraph();
112 GRAPH(after)
113 {
114 using namespace compiler::DataType;
115 CONSTANT(6, 0);
116 BASIC_BLOCK(2, -1)
117 {
118 INST(0, Opcode::SaveState).NoVregs();
119 INST(1, Opcode::LoadAndInitClass).ref().Inputs(0).TypeId(68);
120 INST(3, Opcode::SaveState).NoVregs();
121 INST(8, Opcode::InitObject).ref().Inputs({{REFERENCE, 1}, {NO_TYPE, 3}});
122 INST(7, Opcode::Return).s32().Inputs(6);
123 }
124 }
125
126 EXPECT_TRUE(GraphComparator().Compare(graph, after));
127 }
128
129 // TODO(aromanov): enable
TEST_F(CommonTest,DISABLED_NotRelatedNullCheck)130 TEST_F(CommonTest, DISABLED_NotRelatedNullCheck)
131 {
132 RuntimeInterfaceMock runtime(1);
133 auto graph = CreateEmptyGraph();
134 graph->SetRuntime(&runtime);
135 GRAPH(graph)
136 {
137 using namespace compiler::DataType;
138 PARAMETER(10, 0).ref();
139 CONSTANT(6, 0);
140 BASIC_BLOCK(2, -1)
141 {
142 INST(0, Opcode::SaveState).NoVregs();
143 INST(1, Opcode::LoadAndInitClass).ref().Inputs(0);
144 INST(2, Opcode::NewObject).ref().Inputs(1, 0);
145 INST(3, Opcode::SaveState).NoVregs();
146 INST(4, Opcode::NullCheck).ref().Inputs(10, 3);
147 INST(5, Opcode::CallStatic).v0id().Inputs({{REFERENCE, 2}, {NO_TYPE, 3}});
148 INST(7, Opcode::Return).s32().Inputs(6);
149 }
150 }
151
152 EXPECT_FALSE(graph->RunPass<BytecodeOptPeepholes>());
153 }
154
TEST_F(CommonTest,CallStaticOtherBasicBlock)155 TEST_F(CommonTest, CallStaticOtherBasicBlock)
156 {
157 RuntimeInterfaceMock runtime(1);
158 auto graph = CreateEmptyGraph();
159 graph->SetRuntime(&runtime);
160 GRAPH(graph)
161 {
162 using namespace compiler::DataType;
163 PARAMETER(10, 0).ref();
164 CONSTANT(6, 0);
165 BASIC_BLOCK(2, 3)
166 {
167 INST(0, Opcode::SaveState).NoVregs();
168 INST(1, Opcode::LoadAndInitClass).ref().Inputs(0);
169 INST(2, Opcode::NewObject).ref().Inputs(1, 0);
170 INST(3, Opcode::SaveState).NoVregs();
171 }
172 BASIC_BLOCK(3, -1)
173 {
174 INST(5, Opcode::CallStatic).v0id().Inputs({{REFERENCE, 2}, {NO_TYPE, 3}});
175 INST(7, Opcode::Return).s32().Inputs(6);
176 }
177 }
178
179 EXPECT_FALSE(graph->RunPass<BytecodeOptPeepholes>());
180 }
181
182 // TODO(aromanov): enable
TEST_F(CommonTest,DISABLED_NoSaveStateNullCheckAfterNewObject)183 TEST_F(CommonTest, DISABLED_NoSaveStateNullCheckAfterNewObject)
184 {
185 RuntimeInterfaceMock runtime(0);
186 auto graph = CreateEmptyGraph();
187 graph->SetRuntime(&runtime);
188 GRAPH(graph)
189 {
190 using namespace compiler::DataType;
191 BASIC_BLOCK(2, -1)
192 {
193 INST(0, Opcode::SaveState).NoVregs();
194 INST(1, Opcode::LoadAndInitClass).ref().Inputs(0);
195 INST(2, Opcode::NewObject).ref().Inputs(1, 0);
196 CONSTANT(3, 0).s32();
197 INST(4, Opcode::SaveState).NoVregs();
198 INST(5, Opcode::CallStatic).v0id().Inputs({{REFERENCE, 2}, {NO_TYPE, 4}});
199 INST(6, Opcode::ReturnVoid).v0id();
200 }
201 }
202
203 EXPECT_FALSE(graph->RunPass<BytecodeOptPeepholes>());
204 }
205
TEST_F(CommonTest,CallConstructorOtherClass)206 TEST_F(CommonTest, CallConstructorOtherClass)
207 {
208 RuntimeInterfaceMock runtime(1, false);
209 auto graph = CreateEmptyGraph();
210 graph->SetRuntime(&runtime);
211 GRAPH(graph)
212 {
213 using namespace compiler::DataType;
214 PARAMETER(10, 0).ref();
215 CONSTANT(6, 0);
216 BASIC_BLOCK(2, -1)
217 {
218 INST(0, Opcode::SaveState).NoVregs();
219 INST(1, Opcode::LoadAndInitClass).ref().Inputs(0);
220 INST(2, Opcode::NewObject).ref().Inputs(1, 0);
221 INST(3, Opcode::SaveState).NoVregs();
222 INST(5, Opcode::CallStatic).v0id().Inputs({{REFERENCE, 2}, {NO_TYPE, 3}});
223 INST(7, Opcode::Return).s32().Inputs(6);
224 }
225 }
226
227 EXPECT_FALSE(graph->RunPass<BytecodeOptPeepholes>());
228 }
229
230 } // namespace panda::bytecodeopt::test
231