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