1 /*
2  * Copyright (C) 2014 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 #include <fstream>
22 #include <map>
23 
24 #include "gtest/gtest.h"
25 
26 #include "jni/quick/calling_convention.h"
27 #include "utils/arm/jni_macro_assembler_arm_vixl.h"
28 
29 #include "base/hex_dump.h"
30 #include "base/malloc_arena_pool.h"
31 #include "common_runtime_test.h"
32 
33 namespace art {
34 namespace arm {
35 
36 // Include results file (generated manually)
37 #include "assembler_thumb_test_expected.cc.inc"
38 
39 #ifndef ART_TARGET_ANDROID
40 // This controls whether the results are printed to the
41 // screen or compared against the expected output.
42 // To generate new expected output, set this to true and
43 // copy the output into the .cc.inc file in the form
44 // of the other results.
45 //
46 // When this is false, the results are not printed to the
47 // output, but are compared against the expected results
48 // in the .cc.inc file.
49 static constexpr bool kPrintResults = false;
50 #endif
51 
SetAndroidData()52 void SetAndroidData() {
53   const char* data = getenv("ANDROID_DATA");
54   if (data == nullptr) {
55     setenv("ANDROID_DATA", "/tmp", 1);
56   }
57 }
58 
CompareIgnoringSpace(const char * s1,const char * s2)59 int CompareIgnoringSpace(const char* s1, const char* s2) {
60   while (*s1 != '\0') {
61     while (isspace(*s1)) ++s1;
62     while (isspace(*s2)) ++s2;
63     if (*s1 == '\0' || *s1 != *s2) {
64       break;
65     }
66     ++s1;
67     ++s2;
68   }
69   return *s1 - *s2;
70 }
71 
InitResults()72 void InitResults() {
73   if (test_results.empty()) {
74     setup_results();
75   }
76 }
77 
GetToolsDir()78 std::string GetToolsDir() {
79 #ifndef ART_TARGET_ANDROID
80   // This will only work on the host.  There is no as, objcopy or objdump on the device.
81   static std::string toolsdir;
82 
83   if (toolsdir.empty()) {
84     setup_results();
85     toolsdir = CommonRuntimeTest::GetAndroidTargetToolsDir(InstructionSet::kThumb2);
86     SetAndroidData();
87   }
88 
89   return toolsdir;
90 #else
91   return std::string();
92 #endif
93 }
94 
DumpAndCheck(std::vector<uint8_t> & code,const char * testname,const char * const * results)95 void DumpAndCheck(std::vector<uint8_t>& code, const char* testname, const char* const* results) {
96 #ifndef ART_TARGET_ANDROID
97   static std::string toolsdir = GetToolsDir();
98 
99   ScratchFile file;
100 
101   const char* filename = file.GetFilename().c_str();
102 
103   std::ofstream out(filename);
104   if (out) {
105     out << ".section \".text\"\n";
106     out << ".syntax unified\n";
107     out << ".arch armv7-a\n";
108     out << ".thumb\n";
109     out << ".thumb_func\n";
110     out << ".type " << testname << ", #function\n";
111     out << ".global " << testname << "\n";
112     out << testname << ":\n";
113     out << ".fnstart\n";
114 
115     for (uint32_t i = 0 ; i < code.size(); ++i) {
116       out << ".byte " << (static_cast<int>(code[i]) & 0xff) << "\n";
117     }
118     out << ".fnend\n";
119     out << ".size " << testname << ", .-" << testname << "\n";
120   }
121   out.close();
122 
123   char cmd[1024];
124 
125   // Assemble the .S
126   snprintf(cmd, sizeof(cmd), "%sas %s -o %s.o", toolsdir.c_str(), filename, filename);
127   int cmd_result = system(cmd);
128   ASSERT_EQ(cmd_result, 0) << cmd << strerror(errno);
129 
130   // Disassemble.
131   snprintf(cmd, sizeof(cmd), "%sobjdump -D -M force-thumb --section=.text %s.o  | grep '^  *[0-9a-f][0-9a-f]*:'",
132     toolsdir.c_str(), filename);
133   if (kPrintResults) {
134     // Print the results only, don't check. This is used to generate new output for inserting
135     // into the .inc file, so let's add the appropriate prefix/suffix needed in the C++ code.
136     strcat(cmd, " | sed '-es/^/  \"/' | sed '-es/$/\\\\n\",/'");
137     int cmd_result3 = system(cmd);
138     ASSERT_EQ(cmd_result3, 0) << strerror(errno);
139   } else {
140     // Check the results match the appropriate results in the .inc file.
141     FILE *fp = popen(cmd, "r");
142     ASSERT_TRUE(fp != nullptr);
143 
144     uint32_t lineindex = 0;
145 
146     while (!feof(fp)) {
147       char testline[256];
148       char *s = fgets(testline, sizeof(testline), fp);
149       if (s == nullptr) {
150         break;
151       }
152       if (CompareIgnoringSpace(results[lineindex], testline) != 0) {
153         LOG(FATAL) << "Output is not as expected at line: " << lineindex
154           << results[lineindex] << "/" << testline << ", test name: " << testname;
155       }
156       ++lineindex;
157     }
158     // Check that we are at the end.
159     ASSERT_TRUE(results[lineindex] == nullptr);
160     fclose(fp);
161   }
162 
163   char buf[FILENAME_MAX];
164   snprintf(buf, sizeof(buf), "%s.o", filename);
165   unlink(buf);
166 #endif  // ART_TARGET_ANDROID
167 }
168 
169 class ArmVIXLAssemblerTest : public ::testing::Test {
170  public:
ArmVIXLAssemblerTest()171   ArmVIXLAssemblerTest() : pool(), allocator(&pool), assembler(&allocator) { }
172 
173   MallocArenaPool pool;
174   ArenaAllocator allocator;
175   ArmVIXLJNIMacroAssembler assembler;
176 };
177 
178 #define __ assembler->
179 
EmitAndCheck(ArmVIXLJNIMacroAssembler * assembler,const char * testname,const char * const * results)180 void EmitAndCheck(ArmVIXLJNIMacroAssembler* assembler, const char* testname,
181                   const char* const* results) {
182   __ FinalizeCode();
183   size_t cs = __ CodeSize();
184   std::vector<uint8_t> managed_code(cs);
185   MemoryRegion code(&managed_code[0], managed_code.size());
186   __ FinalizeInstructions(code);
187 
188   DumpAndCheck(managed_code, testname, results);
189 }
190 
EmitAndCheck(ArmVIXLJNIMacroAssembler * assembler,const char * testname)191 void EmitAndCheck(ArmVIXLJNIMacroAssembler* assembler, const char* testname) {
192   InitResults();
193   std::map<std::string, const char* const*>::iterator results = test_results.find(testname);
194   ASSERT_NE(results, test_results.end());
195 
196   EmitAndCheck(assembler, testname, results->second);
197 }
198 
199 #undef __
200 
201 #define __ assembler.
202 
TEST_F(ArmVIXLAssemblerTest,VixlJniHelpers)203 TEST_F(ArmVIXLAssemblerTest, VixlJniHelpers) {
204   // Run the test only with Baker read barriers, as the expected
205   // generated code contains a Marking Register refresh instruction.
206   TEST_DISABLED_WITHOUT_BAKER_READ_BARRIERS();
207 
208   const bool is_static = true;
209   const bool is_synchronized = false;
210   const bool is_critical_native = false;
211   const char* shorty = "IIFII";
212 
213   std::unique_ptr<JniCallingConvention> jni_conv(
214       JniCallingConvention::Create(&allocator,
215                                    is_static,
216                                    is_synchronized,
217                                    is_critical_native,
218                                    shorty,
219                                    InstructionSet::kThumb2));
220   std::unique_ptr<ManagedRuntimeCallingConvention> mr_conv(
221       ManagedRuntimeCallingConvention::Create(
222           &allocator, is_static, is_synchronized, shorty, InstructionSet::kThumb2));
223   const int frame_size(jni_conv->FrameSize());
224   ArrayRef<const ManagedRegister> callee_save_regs = jni_conv->CalleeSaveRegisters();
225 
226   const ManagedRegister method_register = ArmManagedRegister::FromCoreRegister(R0);
227   const ManagedRegister scratch_register = ArmManagedRegister::FromCoreRegister(R12);
228 
229   __ BuildFrame(frame_size, mr_conv->MethodRegister(), callee_save_regs, mr_conv->EntrySpills());
230   __ IncreaseFrameSize(32);
231 
232   // Loads
233   __ IncreaseFrameSize(4096);
234   __ Load(method_register, FrameOffset(32), 4);
235   __ Load(method_register, FrameOffset(124), 4);
236   __ Load(method_register, FrameOffset(132), 4);
237   __ Load(method_register, FrameOffset(1020), 4);
238   __ Load(method_register, FrameOffset(1024), 4);
239   __ Load(scratch_register, FrameOffset(4092), 4);
240   __ Load(scratch_register, FrameOffset(4096), 4);
241   __ LoadRawPtrFromThread(scratch_register, ThreadOffset32(512));
242   __ LoadRef(method_register, scratch_register, MemberOffset(128), /* unpoison_reference= */ false);
243 
244   // Stores
245   __ Store(FrameOffset(32), method_register, 4);
246   __ Store(FrameOffset(124), method_register, 4);
247   __ Store(FrameOffset(132), method_register, 4);
248   __ Store(FrameOffset(1020), method_register, 4);
249   __ Store(FrameOffset(1024), method_register, 4);
250   __ Store(FrameOffset(4092), scratch_register, 4);
251   __ Store(FrameOffset(4096), scratch_register, 4);
252   __ StoreImmediateToFrame(FrameOffset(48), 0xFF, scratch_register);
253   __ StoreImmediateToFrame(FrameOffset(48), 0xFFFFFF, scratch_register);
254   __ StoreRawPtr(FrameOffset(48), scratch_register);
255   __ StoreRef(FrameOffset(48), scratch_register);
256   __ StoreSpanning(FrameOffset(48), method_register, FrameOffset(48), scratch_register);
257   __ StoreStackOffsetToThread(ThreadOffset32(512), FrameOffset(4096), scratch_register);
258   __ StoreStackPointerToThread(ThreadOffset32(512));
259 
260   // Other
261   __ Call(method_register, FrameOffset(48), scratch_register);
262   __ Copy(FrameOffset(48), FrameOffset(44), scratch_register, 4);
263   __ CopyRawPtrFromThread(FrameOffset(44), ThreadOffset32(512), scratch_register);
264   __ CopyRef(FrameOffset(48), FrameOffset(44), scratch_register);
265   __ GetCurrentThread(method_register);
266   __ GetCurrentThread(FrameOffset(48), scratch_register);
267   __ Move(scratch_register, method_register, 4);
268   __ VerifyObject(scratch_register, false);
269 
270   __ CreateHandleScopeEntry(scratch_register, FrameOffset(48), scratch_register, true);
271   __ CreateHandleScopeEntry(scratch_register, FrameOffset(48), scratch_register, false);
272   __ CreateHandleScopeEntry(method_register, FrameOffset(48), scratch_register, true);
273   __ CreateHandleScopeEntry(FrameOffset(48), FrameOffset(64), scratch_register, true);
274   __ CreateHandleScopeEntry(method_register, FrameOffset(0), scratch_register, true);
275   __ CreateHandleScopeEntry(method_register, FrameOffset(1025), scratch_register, true);
276   __ CreateHandleScopeEntry(scratch_register, FrameOffset(1025), scratch_register, true);
277 
278   __ ExceptionPoll(scratch_register, 0);
279 
280   // Push the target out of range of branch emitted by ExceptionPoll.
281   for (int i = 0; i < 64; i++) {
282     __ Store(FrameOffset(2047), scratch_register, 4);
283   }
284 
285   __ DecreaseFrameSize(4096);
286   __ DecreaseFrameSize(32);
287   __ RemoveFrame(frame_size, callee_save_regs, /* may_suspend= */ true);
288 
289   EmitAndCheck(&assembler, "VixlJniHelpers");
290 }
291 
292 #undef __
293 
294 // TODO: Avoid these macros.
295 #define R0 vixl::aarch32::r0
296 #define R2 vixl::aarch32::r2
297 #define R4 vixl::aarch32::r4
298 #define R12 vixl::aarch32::r12
299 
300 #define __ assembler.asm_.
301 
TEST_F(ArmVIXLAssemblerTest,VixlLoadFromOffset)302 TEST_F(ArmVIXLAssemblerTest, VixlLoadFromOffset) {
303   __ LoadFromOffset(kLoadWord, R2, R4, 12);
304   __ LoadFromOffset(kLoadWord, R2, R4, 0xfff);
305   __ LoadFromOffset(kLoadWord, R2, R4, 0x1000);
306   __ LoadFromOffset(kLoadWord, R2, R4, 0x1000a4);
307   __ LoadFromOffset(kLoadWord, R2, R4, 0x101000);
308   __ LoadFromOffset(kLoadWord, R4, R4, 0x101000);
309   __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 12);
310   __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 0xfff);
311   __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 0x1000);
312   __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 0x1000a4);
313   __ LoadFromOffset(kLoadUnsignedHalfword, R2, R4, 0x101000);
314   __ LoadFromOffset(kLoadUnsignedHalfword, R4, R4, 0x101000);
315   __ LoadFromOffset(kLoadWordPair, R2, R4, 12);
316   __ LoadFromOffset(kLoadWordPair, R2, R4, 0x3fc);
317   __ LoadFromOffset(kLoadWordPair, R2, R4, 0x400);
318   __ LoadFromOffset(kLoadWordPair, R2, R4, 0x400a4);
319   __ LoadFromOffset(kLoadWordPair, R2, R4, 0x40400);
320   __ LoadFromOffset(kLoadWordPair, R4, R4, 0x40400);
321 
322   vixl::aarch32::UseScratchRegisterScope temps(assembler.asm_.GetVIXLAssembler());
323   temps.Exclude(R12);
324   __ LoadFromOffset(kLoadWord, R0, R12, 12);  // 32-bit because of R12.
325   temps.Include(R12);
326   __ LoadFromOffset(kLoadWord, R2, R4, 0xa4 - 0x100000);
327 
328   __ LoadFromOffset(kLoadSignedByte, R2, R4, 12);
329   __ LoadFromOffset(kLoadUnsignedByte, R2, R4, 12);
330   __ LoadFromOffset(kLoadSignedHalfword, R2, R4, 12);
331 
332   EmitAndCheck(&assembler, "VixlLoadFromOffset");
333 }
334 
TEST_F(ArmVIXLAssemblerTest,VixlStoreToOffset)335 TEST_F(ArmVIXLAssemblerTest, VixlStoreToOffset) {
336   __ StoreToOffset(kStoreWord, R2, R4, 12);
337   __ StoreToOffset(kStoreWord, R2, R4, 0xfff);
338   __ StoreToOffset(kStoreWord, R2, R4, 0x1000);
339   __ StoreToOffset(kStoreWord, R2, R4, 0x1000a4);
340   __ StoreToOffset(kStoreWord, R2, R4, 0x101000);
341   __ StoreToOffset(kStoreWord, R4, R4, 0x101000);
342   __ StoreToOffset(kStoreHalfword, R2, R4, 12);
343   __ StoreToOffset(kStoreHalfword, R2, R4, 0xfff);
344   __ StoreToOffset(kStoreHalfword, R2, R4, 0x1000);
345   __ StoreToOffset(kStoreHalfword, R2, R4, 0x1000a4);
346   __ StoreToOffset(kStoreHalfword, R2, R4, 0x101000);
347   __ StoreToOffset(kStoreHalfword, R4, R4, 0x101000);
348   __ StoreToOffset(kStoreWordPair, R2, R4, 12);
349   __ StoreToOffset(kStoreWordPair, R2, R4, 0x3fc);
350   __ StoreToOffset(kStoreWordPair, R2, R4, 0x400);
351   __ StoreToOffset(kStoreWordPair, R2, R4, 0x400a4);
352   __ StoreToOffset(kStoreWordPair, R2, R4, 0x40400);
353   __ StoreToOffset(kStoreWordPair, R4, R4, 0x40400);
354 
355   vixl::aarch32::UseScratchRegisterScope temps(assembler.asm_.GetVIXLAssembler());
356   temps.Exclude(R12);
357   __ StoreToOffset(kStoreWord, R0, R12, 12);  // 32-bit because of R12.
358   temps.Include(R12);
359   __ StoreToOffset(kStoreWord, R2, R4, 0xa4 - 0x100000);
360 
361   __ StoreToOffset(kStoreByte, R2, R4, 12);
362 
363   EmitAndCheck(&assembler, "VixlStoreToOffset");
364 }
365 
366 #undef __
367 }  // namespace arm
368 }  // namespace art
369