1 /*
2 * Copyright (C) 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <dirent.h>
18 #include <errno.h>
19 #include <string.h>
20 #include <sys/types.h>
21
22 #include <fstream>
23 #include <map>
24 #include <regex>
25
26 #include "gtest/gtest.h"
27
28 #include "indirect_reference_table.h"
29 #include "lock_word.h"
30 #include "jni/quick/calling_convention.h"
31 #include "utils/riscv64/jni_macro_assembler_riscv64.h"
32 #include "utils/assembler_test_base.h"
33
34 #include "base/macros.h"
35 #include "base/malloc_arena_pool.h"
36
37 namespace art HIDDEN {
38 namespace riscv64 {
39
40 #define __ assembler_.
41
42 class JniMacroAssemblerRiscv64Test : public AssemblerTestBase {
43 public:
JniMacroAssemblerRiscv64Test()44 JniMacroAssemblerRiscv64Test() : pool_(), allocator_(&pool_), assembler_(&allocator_) { }
45
46 protected:
GetIsa()47 InstructionSet GetIsa() override { return InstructionSet::kRiscv64; }
48
DriverStr(const std::string & assembly_text,const std::string & test_name)49 void DriverStr(const std::string& assembly_text, const std::string& test_name) {
50 assembler_.FinalizeCode();
51 size_t cs = assembler_.CodeSize();
52 std::vector<uint8_t> data(cs);
53 MemoryRegion code(&data[0], data.size());
54 assembler_.CopyInstructions(code);
55 Driver(data, assembly_text, test_name);
56 }
57
AsManaged(XRegister reg)58 static Riscv64ManagedRegister AsManaged(XRegister reg) {
59 return Riscv64ManagedRegister::FromXRegister(reg);
60 }
61
AsManaged(FRegister reg)62 static Riscv64ManagedRegister AsManaged(FRegister reg) {
63 return Riscv64ManagedRegister::FromFRegister(reg);
64 }
65
EmitRet()66 std::string EmitRet() {
67 __ RemoveFrame(/*frame_size=*/ 0u,
68 /*callee_save_regs=*/ ArrayRef<const ManagedRegister>(),
69 /*may_suspend=*/ false);
70 return "ret\n";
71 }
72
73 static const size_t kWordSize = 4u;
74 static const size_t kDoubleWordSize = 8u;
75
76 MallocArenaPool pool_;
77 ArenaAllocator allocator_;
78 Riscv64JNIMacroAssembler assembler_;
79 };
80
TEST_F(JniMacroAssemblerRiscv64Test,StackFrame)81 TEST_F(JniMacroAssemblerRiscv64Test, StackFrame) {
82 std::string expected;
83
84 std::unique_ptr<JniCallingConvention> jni_conv = JniCallingConvention::Create(
85 &allocator_,
86 /*is_static=*/ false,
87 /*is_synchronized=*/ false,
88 /*is_fast_native=*/ false,
89 /*is_critical_native=*/ false,
90 /*shorty=*/ "V",
91 InstructionSet::kRiscv64);
92 size_t frame_size = jni_conv->FrameSize();
93 ManagedRegister method_reg = AsManaged(A0);
94 ArrayRef<const ManagedRegister> callee_save_regs = jni_conv->CalleeSaveRegisters();
95
96 __ BuildFrame(frame_size, method_reg, callee_save_regs);
97 expected += "addi sp, sp, -208\n"
98 "sd ra, 200(sp)\n"
99 "sd s11, 192(sp)\n"
100 "sd s10, 184(sp)\n"
101 "sd s9, 176(sp)\n"
102 "sd s8, 168(sp)\n"
103 "sd s7, 160(sp)\n"
104 "sd s6, 152(sp)\n"
105 "sd s5, 144(sp)\n"
106 "sd s4, 136(sp)\n"
107 "sd s3, 128(sp)\n"
108 "sd s2, 120(sp)\n"
109 "sd s0, 112(sp)\n"
110 "fsd fs11, 104(sp)\n"
111 "fsd fs10, 96(sp)\n"
112 "fsd fs9, 88(sp)\n"
113 "fsd fs8, 80(sp)\n"
114 "fsd fs7, 72(sp)\n"
115 "fsd fs6, 64(sp)\n"
116 "fsd fs5, 56(sp)\n"
117 "fsd fs4, 48(sp)\n"
118 "fsd fs3, 40(sp)\n"
119 "fsd fs2, 32(sp)\n"
120 "fsd fs1, 24(sp)\n"
121 "fsd fs0, 16(sp)\n"
122 "sd a0, 0(sp)\n";
123
124 __ RemoveFrame(frame_size, callee_save_regs, /*may_suspend=*/ false);
125 expected += "fld fs0, 16(sp)\n"
126 "fld fs1, 24(sp)\n"
127 "fld fs2, 32(sp)\n"
128 "fld fs3, 40(sp)\n"
129 "fld fs4, 48(sp)\n"
130 "fld fs5, 56(sp)\n"
131 "fld fs6, 64(sp)\n"
132 "fld fs7, 72(sp)\n"
133 "fld fs8, 80(sp)\n"
134 "fld fs9, 88(sp)\n"
135 "fld fs10, 96(sp)\n"
136 "fld fs11, 104(sp)\n"
137 "ld s0, 112(sp)\n"
138 "ld s2, 120(sp)\n"
139 "ld s3, 128(sp)\n"
140 "ld s4, 136(sp)\n"
141 "ld s5, 144(sp)\n"
142 "ld s6, 152(sp)\n"
143 "ld s7, 160(sp)\n"
144 "ld s8, 168(sp)\n"
145 "ld s9, 176(sp)\n"
146 "ld s10, 184(sp)\n"
147 "ld s11, 192(sp)\n"
148 "ld ra, 200(sp)\n"
149 "addi sp, sp, 208\n"
150 "ret\n";
151
152 DriverStr(expected, "StackFrame");
153 }
154
TEST_F(JniMacroAssemblerRiscv64Test,ChangeFrameSize)155 TEST_F(JniMacroAssemblerRiscv64Test, ChangeFrameSize) {
156 std::string expected;
157
158 __ IncreaseFrameSize(128);
159 expected += "addi sp, sp, -128\n";
160 __ DecreaseFrameSize(128);
161 expected += "addi sp, sp, 128\n";
162
163 __ IncreaseFrameSize(0); // No-op
164 __ DecreaseFrameSize(0); // No-op
165
166 __ IncreaseFrameSize(2048);
167 expected += "addi sp, sp, -2048\n";
168 __ DecreaseFrameSize(2048);
169 expected += "addi t6, sp, 2047\n"
170 "addi sp, t6, 1\n";
171
172 __ IncreaseFrameSize(4096);
173 expected += "addi t6, sp, -2048\n"
174 "addi sp, t6, -2048\n";
175 __ DecreaseFrameSize(4096);
176 expected += "lui t6, 1\n"
177 "add sp, sp, t6\n";
178
179 __ IncreaseFrameSize(6 * KB);
180 expected += "addi t6, zero, -3\n"
181 "slli t6, t6, 11\n"
182 "add sp, sp, t6\n";
183 __ DecreaseFrameSize(6 * KB);
184 expected += "addi t6, zero, 3\n"
185 "slli t6, t6, 11\n"
186 "add sp, sp, t6\n";
187
188 __ IncreaseFrameSize(6 * KB + 16);
189 expected += "lui t6, 0xffffe\n"
190 "addiw t6, t6, 2048-16\n"
191 "add sp, sp, t6\n";
192 __ DecreaseFrameSize(6 * KB + 16);
193 expected += "lui t6, 2\n"
194 "addiw t6, t6, 16-2048\n"
195 "add sp, sp, t6\n";
196
197 DriverStr(expected, "ChangeFrameSize");
198 }
199
TEST_F(JniMacroAssemblerRiscv64Test,Store)200 TEST_F(JniMacroAssemblerRiscv64Test, Store) {
201 std::string expected;
202
203 __ Store(FrameOffset(0), AsManaged(A0), kWordSize);
204 expected += "sw a0, 0(sp)\n";
205 __ Store(FrameOffset(2048), AsManaged(S0), kDoubleWordSize);
206 expected += "addi t6, sp, 0x7f8\n"
207 "sd s0, 8(t6)\n";
208
209 __ Store(AsManaged(A1), MemberOffset(256), AsManaged(S2), kDoubleWordSize);
210 expected += "sd s2, 256(a1)\n";
211 __ Store(AsManaged(S3), MemberOffset(4 * KB), AsManaged(T1), kWordSize);
212 expected += "lui t6, 1\n"
213 "add t6, t6, s3\n"
214 "sw t1, 0(t6)\n";
215
216 __ Store(AsManaged(A3), MemberOffset(384), AsManaged(FA5), kDoubleWordSize);
217 expected += "fsd fa5, 384(a3)\n";
218 __ Store(AsManaged(S4), MemberOffset(4 * KB + 16), AsManaged(FT10), kWordSize);
219 expected += "lui t6, 1\n"
220 "add t6, t6, s4\n"
221 "fsw ft10, 16(t6)\n";
222
223 __ StoreRawPtr(FrameOffset(128), AsManaged(A7));
224 expected += "sd a7, 128(sp)\n";
225 __ StoreRawPtr(FrameOffset(6 * KB), AsManaged(S11));
226 expected += "lui t6, 2\n"
227 "add t6, t6, sp\n"
228 "sd s11, -2048(t6)\n";
229
230 __ StoreStackPointerToThread(ThreadOffset64(512), /*tag_sp=*/ false);
231 expected += "sd sp, 512(s1)\n";
232 __ StoreStackPointerToThread(ThreadOffset64(3 * KB), /*tag_sp=*/ true);
233 expected += "ori t6, sp, 0x2\n"
234 "addi t5, s1, 0x7f8\n"
235 "sd t6, 0x408(t5)\n";
236
237 DriverStr(expected, "Store");
238 }
239
TEST_F(JniMacroAssemblerRiscv64Test,Load)240 TEST_F(JniMacroAssemblerRiscv64Test, Load) {
241 std::string expected;
242
243 __ Load(AsManaged(A0), FrameOffset(0), kWordSize);
244 expected += "lw a0, 0(sp)\n";
245 __ Load(AsManaged(S0), FrameOffset(2048), kDoubleWordSize);
246 expected += "addi t6, sp, 0x7f8\n"
247 "ld s0, 8(t6)\n";
248
249 __ Load(AsManaged(S2), AsManaged(A1), MemberOffset(256), kDoubleWordSize);
250 expected += "ld s2, 256(a1)\n";
251 __ Load(AsManaged(T1), AsManaged(S3), MemberOffset(4 * KB), kWordSize);
252 expected += "lui t6, 1\n"
253 "add t6, t6, s3\n"
254 "lw t1, 0(t6)\n";
255
256 __ Load(AsManaged(FA5), AsManaged(A3), MemberOffset(384), kDoubleWordSize);
257 expected += "fld fa5, 384(a3)\n";
258 __ Load(AsManaged(FT10), AsManaged(S4), MemberOffset(4 * KB + 16), kWordSize);
259 expected += "lui t6, 1\n"
260 "add t6, t6, s4\n"
261 "flw ft10, 16(t6)\n";
262
263 __ LoadRawPtrFromThread(AsManaged(A7), ThreadOffset64(512));
264 expected += "ld a7, 512(s1)\n";
265 __ LoadRawPtrFromThread(AsManaged(S11), ThreadOffset64(3 * KB));
266 expected += "addi t6, s1, 0x7f8\n"
267 "ld s11, 0x408(t6)\n";
268
269 __ LoadGcRootWithoutReadBarrier(AsManaged(T0), AsManaged(A0), MemberOffset(0));
270 expected += "lwu t0, 0(a0)\n";
271 __ LoadGcRootWithoutReadBarrier(AsManaged(T1), AsManaged(S2), MemberOffset(0x800));
272 expected += "addi t6, s2, 0x7f8\n"
273 "lwu t1, 8(t6)\n";
274
275 __ LoadStackReference(AsManaged(T0), FrameOffset(0));
276 expected += "lwu t0, 0(sp)\n";
277 __ LoadStackReference(AsManaged(T1), FrameOffset(0x800));
278 expected += "addi t6, sp, 0x7f8\n"
279 "lwu t1, 8(t6)\n";
280
281 DriverStr(expected, "Load");
282 }
283
TEST_F(JniMacroAssemblerRiscv64Test,CreateJObject)284 TEST_F(JniMacroAssemblerRiscv64Test, CreateJObject) {
285 std::string expected;
286
287 __ CreateJObject(AsManaged(A0), FrameOffset(8), AsManaged(A0), /*null_allowed=*/ true);
288 expected += "beqz a0, 1f\n"
289 "addi a0, sp, 8\n"
290 "1:\n";
291 __ CreateJObject(AsManaged(A1), FrameOffset(12), AsManaged(A1), /*null_allowed=*/ false);
292 expected += "addi a1, sp, 12\n";
293 __ CreateJObject(AsManaged(A2), FrameOffset(16), AsManaged(A3), /*null_allowed=*/ true);
294 expected += "li a2, 0\n"
295 "beqz a3, 2f\n"
296 "addi a2, sp, 16\n"
297 "2:\n";
298 __ CreateJObject(AsManaged(A4), FrameOffset(2048), AsManaged(A5), /*null_allowed=*/ false);
299 expected += "addi t6, sp, 2047\n"
300 "addi a4, t6, 1\n";
301
302 DriverStr(expected, "CreateJObject");
303 }
304
TEST_F(JniMacroAssemblerRiscv64Test,MoveArguments)305 TEST_F(JniMacroAssemblerRiscv64Test, MoveArguments) {
306 std::string expected;
307
308 static constexpr FrameOffset kInvalidReferenceOffset =
309 JNIMacroAssembler<kArmPointerSize>::kInvalidReferenceOffset;
310 static constexpr size_t kNativePointerSize = static_cast<size_t>(kRiscv64PointerSize);
311 static constexpr size_t kFloatSize = 4u;
312 static constexpr size_t kXlenInBytes = 8u; // Used for integral args and `double`.
313
314 // Normal or @FastNative static with parameters "LIJIJILJI".
315 // Note: This shall not spill references to the stack. The JNI compiler spills
316 // references in an separate initial pass before moving arguments and creating `jobject`s.
317 ArgumentLocation move_dests1[] = {
318 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A1), kNativePointerSize), // `jclass`
319 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A2), kNativePointerSize),
320 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A3), kXlenInBytes),
321 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A4), kXlenInBytes),
322 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A5), kXlenInBytes),
323 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A6), kXlenInBytes),
324 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A7), kXlenInBytes),
325 ArgumentLocation(FrameOffset(0), kNativePointerSize),
326 ArgumentLocation(FrameOffset(8), kXlenInBytes),
327 ArgumentLocation(FrameOffset(16), kXlenInBytes),
328 };
329 ArgumentLocation move_srcs1[] = {
330 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A0), kNativePointerSize), // `jclass`
331 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A1), kVRegSize),
332 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A2), kVRegSize),
333 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A3), 2 * kVRegSize),
334 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A4), kVRegSize),
335 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A5), 2 * kVRegSize),
336 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A6), kVRegSize),
337 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A7), kVRegSize),
338 ArgumentLocation(FrameOffset(76), 2 * kVRegSize),
339 ArgumentLocation(FrameOffset(84), kVRegSize),
340 };
341 FrameOffset move_refs1[] {
342 FrameOffset(kInvalidReferenceOffset),
343 FrameOffset(40),
344 FrameOffset(kInvalidReferenceOffset),
345 FrameOffset(kInvalidReferenceOffset),
346 FrameOffset(kInvalidReferenceOffset),
347 FrameOffset(kInvalidReferenceOffset),
348 FrameOffset(kInvalidReferenceOffset),
349 FrameOffset(72),
350 FrameOffset(kInvalidReferenceOffset),
351 FrameOffset(kInvalidReferenceOffset),
352 };
353 __ MoveArguments(ArrayRef<ArgumentLocation>(move_dests1),
354 ArrayRef<ArgumentLocation>(move_srcs1),
355 ArrayRef<FrameOffset>(move_refs1));
356 expected += "beqz a7, 1f\n"
357 "addi a7, sp, 72\n"
358 "1:\n"
359 "sd a7, 0(sp)\n"
360 "ld t6, 76(sp)\n"
361 "sd t6, 8(sp)\n"
362 "lw t6, 84(sp)\n"
363 "sd t6, 16(sp)\n"
364 "mv a7, a6\n"
365 "mv a6, a5\n"
366 "mv a5, a4\n"
367 "mv a4, a3\n"
368 "mv a3, a2\n"
369 "li a2, 0\n"
370 "beqz a1, 2f\n"
371 "add a2, sp, 40\n"
372 "2:\n"
373 "mv a1, a0\n";
374
375 // Normal or @FastNative static with parameters "LIJIJILJI" - spill references.
376 ArgumentLocation move_dests1_spill_refs[] = {
377 ArgumentLocation(FrameOffset(40), kVRegSize),
378 ArgumentLocation(FrameOffset(72), kVRegSize),
379 };
380 ArgumentLocation move_srcs1_spill_refs[] = {
381 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A1), kVRegSize),
382 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A7), kVRegSize),
383 };
384 FrameOffset move_refs1_spill_refs[] {
385 FrameOffset(kInvalidReferenceOffset),
386 FrameOffset(kInvalidReferenceOffset),
387 };
388 __ MoveArguments(ArrayRef<ArgumentLocation>(move_dests1_spill_refs),
389 ArrayRef<ArgumentLocation>(move_srcs1_spill_refs),
390 ArrayRef<FrameOffset>(move_refs1_spill_refs));
391 expected += "sw a1, 40(sp)\n"
392 "sw a7, 72(sp)\n";
393
394 // Normal or @FastNative with parameters "LLIJIJIJLI" (first is `this`).
395 // Note: This shall not spill references to the stack. The JNI compiler spills
396 // references in an separate initial pass before moving arguments and creating `jobject`s.
397 ArgumentLocation move_dests2[] = {
398 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A1), kNativePointerSize),
399 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A2), kNativePointerSize),
400 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A3), kXlenInBytes),
401 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A4), kXlenInBytes),
402 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A5), kXlenInBytes),
403 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A6), kXlenInBytes),
404 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A7), kXlenInBytes),
405 ArgumentLocation(FrameOffset(0), kXlenInBytes),
406 ArgumentLocation(FrameOffset(8), kNativePointerSize),
407 ArgumentLocation(FrameOffset(16), kXlenInBytes),
408 };
409 ArgumentLocation move_srcs2[] = {
410 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A1), kVRegSize),
411 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A2), kVRegSize),
412 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A3), kVRegSize),
413 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A4), 2 * kVRegSize),
414 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A5), kVRegSize),
415 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A6), 2 * kVRegSize),
416 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A7), kVRegSize),
417 ArgumentLocation(FrameOffset(76), 2 * kVRegSize),
418 ArgumentLocation(FrameOffset(84), kVRegSize),
419 ArgumentLocation(FrameOffset(88), kVRegSize),
420 };
421 FrameOffset move_refs2[] {
422 FrameOffset(40),
423 FrameOffset(44),
424 FrameOffset(kInvalidReferenceOffset),
425 FrameOffset(kInvalidReferenceOffset),
426 FrameOffset(kInvalidReferenceOffset),
427 FrameOffset(kInvalidReferenceOffset),
428 FrameOffset(kInvalidReferenceOffset),
429 FrameOffset(kInvalidReferenceOffset),
430 FrameOffset(84),
431 FrameOffset(kInvalidReferenceOffset),
432 };
433 __ MoveArguments(ArrayRef<ArgumentLocation>(move_dests2),
434 ArrayRef<ArgumentLocation>(move_srcs2),
435 ArrayRef<FrameOffset>(move_refs2));
436 // Args in A1-A7 do not move but references are converted to `jobject`.
437 expected += "addi a1, sp, 40\n"
438 "beqz a2, 1f\n"
439 "addi a2, sp, 44\n"
440 "1:\n"
441 "ld t6, 76(sp)\n"
442 "sd t6, 0(sp)\n"
443 "lwu t6, 84(sp)\n"
444 "beqz t6, 2f\n"
445 "addi t6, sp, 84\n"
446 "2:\n"
447 "sd t6, 8(sp)\n"
448 "lw t6, 88(sp)\n"
449 "sd t6, 16(sp)\n";
450
451 // Normal or @FastNative static with parameters "FDFDFDFDFDIJIJIJL".
452 ArgumentLocation move_dests3[] = {
453 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A1), kNativePointerSize), // `jclass`
454 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA0), kFloatSize),
455 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA1), kXlenInBytes),
456 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA2), kFloatSize),
457 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA3), kXlenInBytes),
458 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA4), kFloatSize),
459 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA5), kXlenInBytes),
460 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA6), kFloatSize),
461 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA7), kXlenInBytes),
462 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A2), kFloatSize),
463 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A3), kXlenInBytes),
464 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A4), kXlenInBytes),
465 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A5), kXlenInBytes),
466 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A6), kXlenInBytes),
467 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A7), kXlenInBytes),
468 ArgumentLocation(FrameOffset(0), kXlenInBytes),
469 ArgumentLocation(FrameOffset(8), kXlenInBytes),
470 ArgumentLocation(FrameOffset(16), kNativePointerSize),
471 };
472 ArgumentLocation move_srcs3[] = {
473 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A0), kNativePointerSize), // `jclass`
474 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA0), kVRegSize),
475 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA1), 2 * kVRegSize),
476 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA2), kVRegSize),
477 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA3), 2 * kVRegSize),
478 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA4), kVRegSize),
479 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA5), 2 * kVRegSize),
480 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA6), kVRegSize),
481 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA7), 2 * kVRegSize),
482 ArgumentLocation(FrameOffset(88), kVRegSize),
483 ArgumentLocation(FrameOffset(92), 2 * kVRegSize),
484 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A1), kVRegSize),
485 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A2), 2 * kVRegSize),
486 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A3), kVRegSize),
487 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A4), 2 * kVRegSize),
488 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A5), kVRegSize),
489 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A6), 2 * kVRegSize),
490 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A7), kVRegSize),
491 };
492 FrameOffset move_refs3[] {
493 FrameOffset(kInvalidReferenceOffset),
494 FrameOffset(kInvalidReferenceOffset),
495 FrameOffset(kInvalidReferenceOffset),
496 FrameOffset(kInvalidReferenceOffset),
497 FrameOffset(kInvalidReferenceOffset),
498 FrameOffset(kInvalidReferenceOffset),
499 FrameOffset(kInvalidReferenceOffset),
500 FrameOffset(kInvalidReferenceOffset),
501 FrameOffset(kInvalidReferenceOffset),
502 FrameOffset(kInvalidReferenceOffset),
503 FrameOffset(kInvalidReferenceOffset),
504 FrameOffset(kInvalidReferenceOffset),
505 FrameOffset(kInvalidReferenceOffset),
506 FrameOffset(kInvalidReferenceOffset),
507 FrameOffset(kInvalidReferenceOffset),
508 FrameOffset(kInvalidReferenceOffset),
509 FrameOffset(kInvalidReferenceOffset),
510 FrameOffset(88),
511 };
512 __ MoveArguments(ArrayRef<ArgumentLocation>(move_dests3),
513 ArrayRef<ArgumentLocation>(move_srcs3),
514 ArrayRef<FrameOffset>(move_refs3));
515 // FP args in FA0-FA7 do not move.
516 expected += "sd a5, 0(sp)\n"
517 "sd a6, 8(sp)\n"
518 "beqz a7, 1f\n"
519 "addi a7, sp, 88\n"
520 "1:\n"
521 "sd a7, 16(sp)\n"
522 "mv a5, a2\n"
523 "mv a6, a3\n"
524 "mv a7, a4\n"
525 "lw a2, 88(sp)\n"
526 "ld a3, 92(sp)\n"
527 "mv a4, a1\n"
528 "mv a1, a0\n";
529
530 // @CriticalNative with parameters "DFDFDFDFIDJIJFDIIJ".
531 ArgumentLocation move_dests4[] = {
532 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA0), kXlenInBytes),
533 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA1), kFloatSize),
534 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA2), kXlenInBytes),
535 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA3), kFloatSize),
536 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA4), kXlenInBytes),
537 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA5), kFloatSize),
538 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA6), kXlenInBytes),
539 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA7), kFloatSize),
540 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A0), kXlenInBytes),
541 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A1), kXlenInBytes),
542 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A2), kXlenInBytes),
543 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A3), kXlenInBytes),
544 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A4), kXlenInBytes),
545 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A5), kFloatSize),
546 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A6), kXlenInBytes),
547 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A7), kXlenInBytes),
548 ArgumentLocation(FrameOffset(0), kXlenInBytes),
549 ArgumentLocation(FrameOffset(8), kXlenInBytes),
550 };
551 ArgumentLocation move_srcs4[] = {
552 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA0), 2 * kVRegSize),
553 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA1), kVRegSize),
554 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA2), 2 * kVRegSize),
555 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA3), kVRegSize),
556 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA4), 2 * kVRegSize),
557 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA5), kVRegSize),
558 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA6), 2 * kVRegSize),
559 ArgumentLocation(Riscv64ManagedRegister::FromFRegister(FA7), kVRegSize),
560 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A1), kVRegSize),
561 ArgumentLocation(FrameOffset(92), 2 * kVRegSize),
562 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A2), 2 * kVRegSize),
563 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A3), kVRegSize),
564 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A4), 2 * kVRegSize),
565 ArgumentLocation(FrameOffset(112), kVRegSize),
566 ArgumentLocation(FrameOffset(116), 2 * kVRegSize),
567 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A5), kVRegSize),
568 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A6), kVRegSize),
569 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A7), 2 * kVRegSize),
570 };
571 FrameOffset move_refs4[] {
572 FrameOffset(kInvalidReferenceOffset),
573 FrameOffset(kInvalidReferenceOffset),
574 FrameOffset(kInvalidReferenceOffset),
575 FrameOffset(kInvalidReferenceOffset),
576 FrameOffset(kInvalidReferenceOffset),
577 FrameOffset(kInvalidReferenceOffset),
578 FrameOffset(kInvalidReferenceOffset),
579 FrameOffset(kInvalidReferenceOffset),
580 FrameOffset(kInvalidReferenceOffset),
581 FrameOffset(kInvalidReferenceOffset),
582 FrameOffset(kInvalidReferenceOffset),
583 FrameOffset(kInvalidReferenceOffset),
584 FrameOffset(kInvalidReferenceOffset),
585 FrameOffset(kInvalidReferenceOffset),
586 FrameOffset(kInvalidReferenceOffset),
587 FrameOffset(kInvalidReferenceOffset),
588 FrameOffset(kInvalidReferenceOffset),
589 FrameOffset(kInvalidReferenceOffset),
590 };
591 __ MoveArguments(ArrayRef<ArgumentLocation>(move_dests4),
592 ArrayRef<ArgumentLocation>(move_srcs4),
593 ArrayRef<FrameOffset>(move_refs4));
594 // FP args in FA0-FA7 and integral args in A2-A4 do not move.
595 expected += "sd a6, 0(sp)\n"
596 "sd a7, 8(sp)\n"
597 "mv a0, a1\n"
598 "ld a1, 92(sp)\n"
599 "ld a6, 116(sp)\n"
600 "mv a7, a5\n"
601 "lw a5, 112(sp)\n";
602
603 // @CriticalNative with parameters "JIJIJIJIJI".
604 ArgumentLocation move_dests5[] = {
605 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A0), kXlenInBytes),
606 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A1), kXlenInBytes),
607 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A2), kXlenInBytes),
608 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A3), kXlenInBytes),
609 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A4), kXlenInBytes),
610 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A5), kXlenInBytes),
611 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A6), kXlenInBytes),
612 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A7), kXlenInBytes),
613 ArgumentLocation(FrameOffset(0), kXlenInBytes),
614 ArgumentLocation(FrameOffset(8), kXlenInBytes),
615 };
616 ArgumentLocation move_srcs5[] = {
617 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A1), 2 * kVRegSize),
618 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A2), kVRegSize),
619 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A3), 2 * kVRegSize),
620 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A4), kVRegSize),
621 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A5), 2 * kVRegSize),
622 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A6), kVRegSize),
623 ArgumentLocation(Riscv64ManagedRegister::FromXRegister(A7), 2 * kVRegSize),
624 ArgumentLocation(FrameOffset(84), kVRegSize),
625 ArgumentLocation(FrameOffset(88), 2 * kVRegSize),
626 ArgumentLocation(FrameOffset(96), kVRegSize),
627 };
628 FrameOffset move_refs5[] {
629 FrameOffset(kInvalidReferenceOffset),
630 FrameOffset(kInvalidReferenceOffset),
631 FrameOffset(kInvalidReferenceOffset),
632 FrameOffset(kInvalidReferenceOffset),
633 FrameOffset(kInvalidReferenceOffset),
634 FrameOffset(kInvalidReferenceOffset),
635 FrameOffset(kInvalidReferenceOffset),
636 FrameOffset(kInvalidReferenceOffset),
637 FrameOffset(kInvalidReferenceOffset),
638 FrameOffset(kInvalidReferenceOffset),
639 };
640 __ MoveArguments(ArrayRef<ArgumentLocation>(move_dests5),
641 ArrayRef<ArgumentLocation>(move_srcs5),
642 ArrayRef<FrameOffset>(move_refs5));
643 expected += "ld t6, 88(sp)\n"
644 "sd t6, 0(sp)\n"
645 "lw t6, 96(sp)\n"
646 "sd t6, 8(sp)\n"
647 "mv a0, a1\n"
648 "mv a1, a2\n"
649 "mv a2, a3\n"
650 "mv a3, a4\n"
651 "mv a4, a5\n"
652 "mv a5, a6\n"
653 "mv a6, a7\n"
654 "lw a7, 84(sp)\n";
655
656 DriverStr(expected, "MoveArguments");
657 }
658
TEST_F(JniMacroAssemblerRiscv64Test,Move)659 TEST_F(JniMacroAssemblerRiscv64Test, Move) {
660 std::string expected;
661
662 __ Move(AsManaged(A0), AsManaged(A1), kWordSize);
663 expected += "mv a0, a1\n";
664 __ Move(AsManaged(A2), AsManaged(A3), kDoubleWordSize);
665 expected += "mv a2, a3\n";
666
667 __ Move(AsManaged(A4), AsManaged(A4), kWordSize); // No-op.
668 __ Move(AsManaged(A5), AsManaged(A5), kDoubleWordSize); // No-op.
669
670 DriverStr(expected, "Move");
671 }
672
TEST_F(JniMacroAssemblerRiscv64Test,GetCurrentThread)673 TEST_F(JniMacroAssemblerRiscv64Test, GetCurrentThread) {
674 std::string expected;
675
676 __ GetCurrentThread(AsManaged(A0));
677 expected += "mv a0, s1\n";
678
679 __ GetCurrentThread(FrameOffset(256));
680 expected += "sd s1, 256(sp)\n";
681 __ GetCurrentThread(FrameOffset(3 * KB));
682 expected += "addi t6, sp, 0x7f8\n"
683 "sd s1, 0x408(t6)\n";
684
685 DriverStr(expected, "GetCurrentThread");
686 }
687
TEST_F(JniMacroAssemblerRiscv64Test,DecodeJNITransitionOrLocalJObject)688 TEST_F(JniMacroAssemblerRiscv64Test, DecodeJNITransitionOrLocalJObject) {
689 std::string expected;
690
691 constexpr int64_t kGlobalOrWeakGlobalMask = IndirectReferenceTable::GetGlobalOrWeakGlobalMask();
692 constexpr int64_t kIndirectRefKindMask = IndirectReferenceTable::GetIndirectRefKindMask();
693
694 std::unique_ptr<JNIMacroLabel> slow_path = __ CreateLabel();
695 std::unique_ptr<JNIMacroLabel> resume = __ CreateLabel();
696
697 __ DecodeJNITransitionOrLocalJObject(AsManaged(A0), slow_path.get(), resume.get());
698 expected += "beqz a0, 1f\n"
699 "andi t6, a0, " + std::to_string(kGlobalOrWeakGlobalMask) + "\n"
700 "bnez t6, 2f\n"
701 "andi a0, a0, ~" + std::to_string(kIndirectRefKindMask) + "\n"
702 "lwu a0, (a0)\n";
703
704 __ Bind(resume.get());
705 expected += "1:\n";
706
707 expected += EmitRet();
708
709 __ Bind(slow_path.get());
710 expected += "2:\n";
711
712 __ Jump(resume.get());
713 expected += "j 1b\n";
714
715 DriverStr(expected, "DecodeJNITransitionOrLocalJObject");
716 }
717
TEST_F(JniMacroAssemblerRiscv64Test,JumpCodePointer)718 TEST_F(JniMacroAssemblerRiscv64Test, JumpCodePointer) {
719 std::string expected;
720
721 __ Jump(AsManaged(A0), Offset(24));
722 expected += "ld t6, 24(a0)\n"
723 "jr t6\n";
724
725 __ Jump(AsManaged(S2), Offset(2048));
726 expected += "addi t6, s2, 0x7f8\n"
727 "ld t6, 8(t6)\n"
728 "jr t6\n";
729
730 DriverStr(expected, "JumpCodePointer");
731 }
732
TEST_F(JniMacroAssemblerRiscv64Test,Call)733 TEST_F(JniMacroAssemblerRiscv64Test, Call) {
734 std::string expected;
735
736 __ Call(AsManaged(A0), Offset(32));
737 expected += "ld ra, 32(a0)\n"
738 "jalr ra\n";
739
740 __ Call(AsManaged(S2), Offset(2048));
741 expected += "addi t6, s2, 0x7f8\n"
742 "ld ra, 8(t6)\n"
743 "jalr ra\n";
744
745 __ CallFromThread(ThreadOffset64(256));
746 expected += "ld ra, 256(s1)\n"
747 "jalr ra\n";
748
749 __ CallFromThread(ThreadOffset64(3 * KB));
750 expected += "addi t6, s1, 0x7f8\n"
751 "ld ra, 0x408(t6)\n"
752 "jalr ra\n";
753
754 DriverStr(expected, "Call");
755 }
756
TEST_F(JniMacroAssemblerRiscv64Test,Transitions)757 TEST_F(JniMacroAssemblerRiscv64Test, Transitions) {
758 std::string expected;
759
760 constexpr uint32_t kNativeStateValue = Thread::StoredThreadStateValue(ThreadState::kNative);
761 constexpr uint32_t kRunnableStateValue = Thread::StoredThreadStateValue(ThreadState::kRunnable);
762 static_assert(kRunnableStateValue == 0u);
763 constexpr ThreadOffset64 thread_flags_offset = Thread::ThreadFlagsOffset<kRiscv64PointerSize>();
764 static_assert(thread_flags_offset.SizeValue() == 0u);
765 constexpr size_t thread_held_mutex_mutator_lock_offset =
766 Thread::HeldMutexOffset<kRiscv64PointerSize>(kMutatorLock).SizeValue();
767 constexpr size_t thread_mutator_lock_offset =
768 Thread::MutatorLockOffset<kRiscv64PointerSize>().SizeValue();
769
770 std::unique_ptr<JNIMacroLabel> slow_path = __ CreateLabel();
771 std::unique_ptr<JNIMacroLabel> resume = __ CreateLabel();
772
773 const ManagedRegister raw_scratch_regs[] = { AsManaged(T0), AsManaged(T1) };
774 const ArrayRef<const ManagedRegister> scratch_regs(raw_scratch_regs);
775
776 __ TryToTransitionFromRunnableToNative(slow_path.get(), scratch_regs);
777 expected += "1:\n"
778 "lr.w t0, (s1)\n"
779 "li t1, " + std::to_string(kNativeStateValue) + "\n"
780 "bnez t0, 4f\n"
781 "sc.w.rl t0, t1, (s1)\n"
782 "bnez t0, 1b\n"
783 "addi t6, s1, 0x7f8\n"
784 "sd x0, " + std::to_string(thread_held_mutex_mutator_lock_offset - 0x7f8u) + "(t6)\n";
785
786 __ TryToTransitionFromNativeToRunnable(slow_path.get(), scratch_regs, AsManaged(A0));
787 expected += "2:\n"
788 "lr.w.aq t0, (s1)\n"
789 "li t1, " + std::to_string(kNativeStateValue) + "\n"
790 "bne t0, t1, 4f\n"
791 "sc.w t0, x0, (s1)\n"
792 "bnez t0, 2b\n"
793 "ld t0, " + std::to_string(thread_mutator_lock_offset) + "(s1)\n"
794 "addi t6, s1, 0x7f8\n"
795 "sd t0, " + std::to_string(thread_held_mutex_mutator_lock_offset - 0x7f8u) + "(t6)\n";
796
797 __ Bind(resume.get());
798 expected += "3:\n";
799
800 expected += EmitRet();
801
802 __ Bind(slow_path.get());
803 expected += "4:\n";
804
805 __ Jump(resume.get());
806 expected += "j 3b";
807
808 DriverStr(expected, "SuspendCheck");
809 }
810
TEST_F(JniMacroAssemblerRiscv64Test,SuspendCheck)811 TEST_F(JniMacroAssemblerRiscv64Test, SuspendCheck) {
812 std::string expected;
813
814 ThreadOffset64 thread_flags_offet = Thread::ThreadFlagsOffset<kRiscv64PointerSize>();
815
816 std::unique_ptr<JNIMacroLabel> slow_path = __ CreateLabel();
817 std::unique_ptr<JNIMacroLabel> resume = __ CreateLabel();
818
819 __ SuspendCheck(slow_path.get());
820 expected += "lw t6, " + std::to_string(thread_flags_offet.Int32Value()) + "(s1)\n"
821 "andi t6, t6, " + std::to_string(Thread::SuspendOrCheckpointRequestFlags()) + "\n"
822 "bnez t6, 2f\n";
823
824 __ Bind(resume.get());
825 expected += "1:\n";
826
827 expected += EmitRet();
828
829 __ Bind(slow_path.get());
830 expected += "2:\n";
831
832 __ Jump(resume.get());
833 expected += "j 1b";
834
835 DriverStr(expected, "SuspendCheck");
836 }
837
TEST_F(JniMacroAssemblerRiscv64Test,Exception)838 TEST_F(JniMacroAssemblerRiscv64Test, Exception) {
839 std::string expected;
840
841 ThreadOffset64 exception_offset = Thread::ExceptionOffset<kArm64PointerSize>();
842 ThreadOffset64 deliver_offset = QUICK_ENTRYPOINT_OFFSET(kArm64PointerSize, pDeliverException);
843
844 std::unique_ptr<JNIMacroLabel> slow_path = __ CreateLabel();
845
846 __ ExceptionPoll(slow_path.get());
847 expected += "ld t6, " + std::to_string(exception_offset.Int32Value()) + "(s1)\n"
848 "bnez t6, 1f\n";
849
850 expected += EmitRet();
851
852 __ Bind(slow_path.get());
853 expected += "1:\n";
854
855 __ DeliverPendingException();
856 expected += "ld a0, " + std::to_string(exception_offset.Int32Value()) + "(s1)\n"
857 "ld ra, " + std::to_string(deliver_offset.Int32Value()) + "(s1)\n"
858 "jalr ra\n"
859 "unimp\n";
860
861 DriverStr(expected, "Exception");
862 }
863
TEST_F(JniMacroAssemblerRiscv64Test,JumpLabel)864 TEST_F(JniMacroAssemblerRiscv64Test, JumpLabel) {
865 std::string expected;
866
867 std::unique_ptr<JNIMacroLabel> target = __ CreateLabel();
868 std::unique_ptr<JNIMacroLabel> back = __ CreateLabel();
869
870 __ Jump(target.get());
871 expected += "j 2f\n";
872
873 __ Bind(back.get());
874 expected += "1:\n";
875
876 __ Move(AsManaged(A0), AsManaged(A1), static_cast<size_t>(kRiscv64PointerSize));
877 expected += "mv a0, a1\n";
878
879 __ Bind(target.get());
880 expected += "2:\n";
881
882 __ Jump(back.get());
883 expected += "j 1b\n";
884
885 DriverStr(expected, "JumpLabel");
886 }
887
TEST_F(JniMacroAssemblerRiscv64Test,ReadBarrier)888 TEST_F(JniMacroAssemblerRiscv64Test, ReadBarrier) {
889 std::string expected;
890
891 ThreadOffset64 is_gc_marking_offset = Thread::IsGcMarkingOffset<kRiscv64PointerSize>();
892 MemberOffset monitor_offset = mirror::Object::MonitorOffset();
893
894 std::unique_ptr<JNIMacroLabel> slow_path = __ CreateLabel();
895 std::unique_ptr<JNIMacroLabel> resume = __ CreateLabel();
896
897 __ TestGcMarking(slow_path.get(), JNIMacroUnaryCondition::kNotZero);
898 expected += "lw t6, " + std::to_string(is_gc_marking_offset.Int32Value()) + "(s1)\n"
899 "bnez t6, 2f\n";
900
901 __ TestGcMarking(slow_path.get(), JNIMacroUnaryCondition::kZero);
902 expected += "lw t6, " + std::to_string(is_gc_marking_offset.Int32Value()) + "(s1)\n"
903 "beqz t6, 2f\n";
904
905 __ Bind(resume.get());
906 expected += "1:\n";
907
908 expected += EmitRet();
909
910 __ Bind(slow_path.get());
911 expected += "2:\n";
912
913 __ TestMarkBit(AsManaged(A0), resume.get(), JNIMacroUnaryCondition::kNotZero);
914 expected += "lw t6, " + std::to_string(monitor_offset.Int32Value()) + "(a0)\n"
915 "slliw t6, t6, " + std::to_string(31 - LockWord::kMarkBitStateShift) + "\n"
916 "bltz t6, 1b\n";
917
918 __ TestMarkBit(AsManaged(T0), resume.get(), JNIMacroUnaryCondition::kZero);
919 expected += "lw t6, " + std::to_string(monitor_offset.Int32Value()) + "(t0)\n"
920 "slliw t6, t6, " + std::to_string(31 - LockWord::kMarkBitStateShift) + "\n"
921 "bgez t6, 1b\n";
922
923 DriverStr(expected, "ReadBarrier");
924 }
925
TEST_F(JniMacroAssemblerRiscv64Test,TestByteAndJumpIfNotZero)926 TEST_F(JniMacroAssemblerRiscv64Test, TestByteAndJumpIfNotZero) {
927 // Note: The `TestByteAndJumpIfNotZero()` takes the address as a `uintptr_t`.
928 // Use 32-bit addresses, so that we can include this test in 32-bit host tests.
929
930 std::string expected;
931
932 std::unique_ptr<JNIMacroLabel> slow_path = __ CreateLabel();
933 std::unique_ptr<JNIMacroLabel> resume = __ CreateLabel();
934
935 __ TestByteAndJumpIfNotZero(0x12345678u, slow_path.get());
936 expected += "lui t6, 0x12345\n"
937 "lb t6, 0x678(t6)\n"
938 "bnez t6, 2f\n";
939
940 __ TestByteAndJumpIfNotZero(0x87654321u, slow_path.get());
941 expected += "lui t6, 0x87654/4\n"
942 "slli t6, t6, 2\n"
943 "lb t6, 0x321(t6)\n"
944 "bnez t6, 2f\n";
945
946 __ Bind(resume.get());
947 expected += "1:\n";
948
949 expected += EmitRet();
950
951 __ Bind(slow_path.get());
952 expected += "2:\n";
953
954 __ TestByteAndJumpIfNotZero(0x456789abu, resume.get());
955 expected += "lui t6, 0x45678+1\n"
956 "lb t6, 0x9ab-0x1000(t6)\n"
957 "bnez t6, 1b\n";
958
959 DriverStr(expected, "TestByteAndJumpIfNotZero");
960 }
961
962 #undef __
963
964 } // namespace riscv64
965 } // namespace art
966