• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "ecmascript/compiler/assembler/x64/assembler_x64.h"
17 
18 #include <ostream>
19 
20 #include "ecmascript/compiler/assembler/aarch64/assembler_aarch64.h"
21 #include "ecmascript/compiler/assembler/x64/extended_assembler_x64.h"
22 #include "ecmascript/compiler/llvm_codegen.h"
23 #include "ecmascript/compiler/trampoline/x64/common_call.h"
24 #include "ecmascript/ecma_vm.h"
25 #include "ecmascript/mem/dyn_chunk.h"
26 #include "ecmascript/tests/test_helper.h"
27 
28 #include "llvm-c/Analysis.h"
29 #include "llvm-c/Core.h"
30 #include "llvm-c/Disassembler.h"
31 #include "llvm-c/ExecutionEngine.h"
32 #include "llvm-c/Target.h"
33 
34 
35 namespace panda::test {
36 using namespace panda::ecmascript;
37 using namespace panda::ecmascript::x64;
38 
39 class AssemblerX64Test : public testing::Test {
40 public:
SetUpTestCase()41     static void SetUpTestCase()
42     {
43         GTEST_LOG_(INFO) << "SetUpTestCase";
44     }
45 
TearDownTestCase()46     static void TearDownTestCase()
47     {
48         GTEST_LOG_(INFO) << "TearDownCase";
49     }
50 
SetUp()51     void SetUp() override
52     {
53         InitializeLLVM("x86_64-unknown-linux-gnu");
54         TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
55         chunk_ = thread->GetEcmaVM()->GetChunk();
56     }
57 
TearDown()58     void TearDown() override
59     {
60         TestHelper::DestroyEcmaVMWithScope(instance, scope);
61     }
62 
SymbolLookupCallback(void * disInfo,uint64_t referenceValue,uint64_t * referenceType,uint64_t referencePC,const char ** referenceName)63     static const char *SymbolLookupCallback([[maybe_unused]] void *disInfo, [[maybe_unused]] uint64_t referenceValue,
64                                             uint64_t *referenceType, [[maybe_unused]]uint64_t referencePC,
65                                             [[maybe_unused]] const char **referenceName)
66     {
67         *referenceType = LLVMDisassembler_ReferenceType_InOut_None;
68         return nullptr;
69     }
70 
InitializeLLVM(std::string triple)71     void InitializeLLVM(std::string triple)
72     {
73         if (triple.compare("x86_64-unknown-linux-gnu") == 0) {
74             LLVMInitializeX86TargetInfo();
75             LLVMInitializeX86TargetMC();
76             LLVMInitializeX86Disassembler();
77             /* this method must be called, ohterwise "Target does not support MC emission" */
78             LLVMInitializeX86AsmPrinter();
79             LLVMInitializeX86AsmParser();
80             LLVMInitializeX86Target();
81         } else if (triple.compare("aarch64-unknown-linux-gnu") == 0) {
82             LLVMInitializeAArch64TargetInfo();
83             LLVMInitializeAArch64TargetMC();
84             LLVMInitializeAArch64Disassembler();
85             LLVMInitializeAArch64AsmPrinter();
86             LLVMInitializeAArch64AsmParser();
87             LLVMInitializeAArch64Target();
88         } else if (triple.compare("arm-unknown-linux-gnu") == 0) {
89             LLVMInitializeARMTargetInfo();
90             LLVMInitializeARMTargetMC();
91             LLVMInitializeARMDisassembler();
92             LLVMInitializeARMAsmPrinter();
93             LLVMInitializeARMAsmParser();
94             LLVMInitializeARMTarget();
95         } else {
96             UNREACHABLE();
97         }
98     }
99 
DisassembleChunk(const char * triple,Assembler * assemlber,std::ostream & os)100     void DisassembleChunk(const char *triple, Assembler *assemlber, std::ostream &os)
101     {
102         LLVMDisasmContextRef dcr = LLVMCreateDisasm(triple, nullptr, 0, nullptr, SymbolLookupCallback);
103         uint8_t *byteSp = assemlber->GetBegin();
104         size_t numBytes = assemlber->GetCurrentPosition();
105         unsigned pc = 0;
106         const char outStringSize = 100;
107         char outString[outStringSize];
108         while (numBytes > 0) {
109             size_t InstSize = LLVMDisasmInstruction(dcr, byteSp, numBytes, pc, outString, outStringSize);
110             if (InstSize == 0) {
111                 // 8 : 8 means width of the pc offset and instruction code
112                 os << std::setw(8) << std::setfill('0') << std::hex << pc << ":" << std::setw(8)
113                    << *reinterpret_cast<uint32_t *>(byteSp) << "maybe constant" << std::endl;
114                 pc += 4; // 4 pc length
115                 byteSp += 4; // 4 sp offset
116                 numBytes -= 4; // 4 num bytes
117             }
118             // 8 : 8 means width of the pc offset and instruction code
119             os << std::setw(8) << std::setfill('0') << std::hex << pc << ":" << std::setw(8)
120                << *reinterpret_cast<uint32_t *>(byteSp) << " " << outString << std::endl;
121             pc += InstSize;
122             byteSp += InstSize;
123             numBytes -= InstSize;
124         }
125         LLVMDisasmDispose(dcr);
126     }
127 
128     EcmaVM *instance {nullptr};
129     JSThread *thread {nullptr};
130     EcmaHandleScope *scope {nullptr};
131     Chunk *chunk_ {nullptr};
132 };
133 
134 #define __ masm.
HWTEST_F_L0(AssemblerX64Test,Emit)135 HWTEST_F_L0(AssemblerX64Test, Emit)
136 {
137     x64::AssemblerX64 masm(chunk_);
138     Label lable1;
139 
140     size_t current = 0;
141     __ Pushq(rbp);
142     uint32_t value = masm.GetU8(current++);
143     ASSERT_EQ(value, 0x55U);
144     __ Pushq(0);
145     value = masm.GetU8(current++);
146     ASSERT_EQ(value, 0x6AU);
147     value = masm.GetU8(current++);
148     ASSERT_EQ(value, 0x00U);
149     __ Popq(rbp);
150     value = masm.GetU8(current++);
151     ASSERT_EQ(value, 0x5DU);
152     __ Bind(&lable1);
153     __ Movq(rcx, rbx);
154     value = masm.GetU8(current++);
155     ASSERT_EQ(value, 0x48U);
156     value = masm.GetU8(current++);
157     ASSERT_EQ(value, 0x89U);
158     value = masm.GetU8(current++);
159     ASSERT_EQ(value, 0xCBU);
160     __ Movq(Operand(rsp, 0x40U), rbx);
161     value = masm.GetU8(current++);
162     ASSERT_EQ(value, 0x48U);
163     value = masm.GetU8(current++);
164     ASSERT_EQ(value, 0x8BU);
165     value = masm.GetU8(current++);
166     ASSERT_EQ(value, 0x5CU);
167     value = masm.GetU8(current++);
168     ASSERT_EQ(value, 0x24U);
169     value = masm.GetU8(current++);
170     ASSERT_EQ(value, 0x40U);
171     __ Jmp(&lable1);
172     value = masm.GetU8(current++);
173     ASSERT_EQ(value, 0xEBU);
174     value = masm.GetU8(current++);
175     ASSERT_EQ(value, 0xF6U);
176     __ Ret();
177     value = masm.GetU8(current++);
178     ASSERT_EQ(value, 0xC3U);
179 
180     ecmascript::kungfu::LLVMAssembler::Disassemble(masm.GetBegin(), masm.GetCurrentPosition());
181 }
182 
HWTEST_F_L0(AssemblerX64Test,Emit1)183 HWTEST_F_L0(AssemblerX64Test, Emit1)
184 {
185     x64::AssemblerX64 masm(chunk_);
186 
187     size_t current = 0;
188     __ Movl(Operand(rax, 0x38), rax);
189     uint32_t value = masm.GetU8(current++);
190     ASSERT_EQ(value, 0x8BU);
191     value = masm.GetU8(current++);
192     ASSERT_EQ(value, 0x40U);
193     value = masm.GetU8(current++);
194     ASSERT_EQ(value, 0x38U);
195 
196     // 41 89 f6 movl    %esi, %r14d
197     __ Movl(rsi, r14);
198     value = masm.GetU8(current++);
199     ASSERT_EQ(value, 0x41U);
200     value = masm.GetU8(current++);
201     ASSERT_EQ(value, 0x89U);
202     value = masm.GetU8(current++);
203     ASSERT_EQ(value, 0xF6U);
204 
205     // movzbq  (%rcx), %rax
206     __ Movzbq(Operand(rcx, 0), rax);
207     value = masm.GetU8(current++);
208     ASSERT_EQ(value, 0x48U);
209     value = masm.GetU8(current++);
210     ASSERT_EQ(value, 0x0FU);
211     value = masm.GetU8(current++);
212     ASSERT_EQ(value, 0xB6U);
213     value = masm.GetU8(current++);
214     ASSERT_EQ(value, 0x01U);
215 
216     // 48 ba 02 00 00 00 00 00 00 00   movabs $0x2,%rdx
217     __ Movabs(0x2, rdx);
218     value = masm.GetU8(current++);
219     ASSERT_EQ(value, 0x48U);
220     value = masm.GetU8(current++);
221     ASSERT_EQ(value, 0xBAU);
222     value = masm.GetU8(current++);
223     ASSERT_EQ(value, 0x02U);
224     value = masm.GetU8(current++);
225     ASSERT_EQ(value, 0x00U);
226     value = masm.GetU8(current++);
227     ASSERT_EQ(value, 0x00U);
228     value = masm.GetU8(current++);
229     ASSERT_EQ(value, 0x00U);
230     value = masm.GetU8(current++);
231     ASSERT_EQ(value, 0x00U);
232     value = masm.GetU8(current++);
233     ASSERT_EQ(value, 0x00U);
234     value = masm.GetU8(current++);
235     ASSERT_EQ(value, 0x00U);
236     value = masm.GetU8(current++);
237     ASSERT_EQ(value, 0x00U);
238 
239     __ Movq(0x5, rdx);
240     value = masm.GetU8(current++);
241     ASSERT_EQ(value, 0xBAU);
242     value = masm.GetU8(current++);
243     ASSERT_EQ(value, 0x05U);
244     value = masm.GetU8(current++);
245     ASSERT_EQ(value, 0x00U);
246     value = masm.GetU8(current++);
247     ASSERT_EQ(value, 0x00U);
248     value = masm.GetU8(current++);
249     ASSERT_EQ(value, 0x00U);
250 
251     // 49 89 e0        mov    %rsp,%r8
252     __ Movq(rsp, r8);
253     value = masm.GetU8(current++);
254     ASSERT_EQ(value, 0x49U);
255     value = masm.GetU8(current++);
256     ASSERT_EQ(value, 0x89U);
257     value = masm.GetU8(current++);
258     ASSERT_EQ(value, 0xE0U);
259 
260     ecmascript::kungfu::LLVMAssembler::Disassemble(masm.GetBegin(), masm.GetCurrentPosition());
261 }
262 
HWTEST_F_L0(AssemblerX64Test,Emit2)263 HWTEST_F_L0(AssemblerX64Test, Emit2)
264 {
265     x64::AssemblerX64 masm(chunk_);
266 
267     size_t current = 0;
268     // 81 fa ff ff ff 09       cmpl    $0x9ffffff,%edx
269     __ Cmpl(0x9FFFFFF, rdx);
270     uint32_t value = masm.GetU8(current++);
271     ASSERT_EQ(value, 0x81U);
272     value = masm.GetU8(current++);
273     ASSERT_EQ(value, 0xFAU);
274     value = masm.GetU8(current++);
275     ASSERT_EQ(value, 0xFFU);
276     value = masm.GetU8(current++);
277     ASSERT_EQ(value, 0xFFU);
278     value = masm.GetU8(current++);
279     ASSERT_EQ(value, 0xFFU);
280     value = masm.GetU8(current++);
281     ASSERT_EQ(value, 0x09U);
282 
283     // 39 cb   cmpl    %ecx,%ebx
284     __ Cmpl(rcx, rbx);
285     value = masm.GetU8(current++);
286     ASSERT_EQ(value, 0x39U);
287     value = masm.GetU8(current++);
288     ASSERT_EQ(value, 0xCBU);
289 
290     // 48 83 fa 00     cmp    $0x0,%rdx
291     __ Cmp(0x0, rdx);
292     value = masm.GetU8(current++);
293     ASSERT_EQ(value, 0x48U);
294     value = masm.GetU8(current++);
295     ASSERT_EQ(value, 0x83U);
296     value = masm.GetU8(current++);
297     ASSERT_EQ(value, 0xFAU);
298     value = masm.GetU8(current++);
299     ASSERT_EQ(value, 0x00U);
300 
301     // 4c 39 D8 cmpq    %r11, %rax
302     __ Cmpq(r11, rax);
303     value = masm.GetU8(current++);
304     ASSERT_EQ(value, 0x4CU);
305     value = masm.GetU8(current++);
306     ASSERT_EQ(value, 0x39U);
307     value = masm.GetU8(current++);
308     ASSERT_EQ(value, 0xD8U);
309 
310 
311     // 0f ba e0 08     bt     $0x8,%eax
312     __ Btl(0x8, rax);
313     value = masm.GetU8(current++);
314     ASSERT_EQ(value, 0x0FU);
315     value = masm.GetU8(current++);
316     ASSERT_EQ(value, 0xBAU);
317     value = masm.GetU8(current++);
318     ASSERT_EQ(value, 0xE0U);
319     value = masm.GetU8(current++);
320     ASSERT_EQ(value, 0x08U);
321     ecmascript::kungfu::LLVMAssembler::Disassemble(masm.GetBegin(), masm.GetCurrentPosition());
322 }
323 
HWTEST_F_L0(AssemblerX64Test,Emit3)324 HWTEST_F_L0(AssemblerX64Test, Emit3)
325 {
326     x64::AssemblerX64 masm(chunk_);
327     size_t current = 0;
328 
329     // cmovbe  %ebx, %ecx
330     __ CMovbe(rbx, rcx);
331     uint32_t value = masm.GetU8(current++);
332 
333     ASSERT_EQ(value, 0x0FU);
334     value = masm.GetU8(current++);
335     ASSERT_EQ(value, 0x46U);
336     value = masm.GetU8(current++);
337     ASSERT_EQ(value, 0xCBU);
338 
339     // testb   $0x1, %r14b
340     __ Testb(0x1, r14);
341     value = masm.GetU8(current++);
342     ASSERT_EQ(value, 0x41U);
343     value = masm.GetU8(current++);
344     ASSERT_EQ(value, 0xF6U);
345     value = masm.GetU8(current++);
346     ASSERT_EQ(value, 0xC6U);
347     value = masm.GetU8(current++);
348     ASSERT_EQ(value, 0x01U);
349 
350     // 48 f6 c4 0f testq   $15, %rsp
351     __ Testq(15, rsp);
352     value = masm.GetU8(current++);
353     ASSERT_EQ(value, 0x40U);
354     value = masm.GetU8(current++);
355     ASSERT_EQ(value, 0xF6U);
356     value = masm.GetU8(current++);
357     ASSERT_EQ(value, 0xC4U);
358     value = masm.GetU8(current++);
359     ASSERT_EQ(value, 0x0FU);
360 
361     // andq    $ASM_JS_METHOD_NUM_VREGS_MASK, %r11
362     __ Andq(0xfffffff, r11);
363     value = masm.GetU8(current++);
364     ASSERT_EQ(value, 0x49U);
365     value = masm.GetU8(current++);
366     ASSERT_EQ(value, 0x81U);
367     value = masm.GetU8(current++);
368     ASSERT_EQ(value, 0xE3U);
369     value = masm.GetU8(current++);
370     ASSERT_EQ(value, 0xFFU);
371     value = masm.GetU8(current++);
372     ASSERT_EQ(value, 0xFFU);
373     value = masm.GetU8(current++);
374     ASSERT_EQ(value, 0xFFU);
375     value = masm.GetU8(current++);
376     ASSERT_EQ(value, 0x0FU);
377 
378     // andl 0xfffffff, %eax
379     __ Andl(0xfffffff, rax);
380     value = masm.GetU8(current++);
381     ASSERT_EQ(value, 0x25U);
382     value = masm.GetU8(current++);
383     ASSERT_EQ(value, 0xFFU);
384     value = masm.GetU8(current++);
385     ASSERT_EQ(value, 0xFFU);
386     value = masm.GetU8(current++);
387     ASSERT_EQ(value, 0xFFU);
388     value = masm.GetU8(current++);
389     ASSERT_EQ(value, 0x0FU);
390 
391     // and     %rax, %rdx
392     __ And(rax, rdx);
393     value = masm.GetU8(current++);
394     ASSERT_EQ(value, 0x48U);
395     value = masm.GetU8(current++);
396     ASSERT_EQ(value, 0x21U);
397     value = masm.GetU8(current++);
398     ASSERT_EQ(value, 0xC2U);
399     ecmascript::kungfu::LLVMAssembler::Disassemble(masm.GetBegin(), masm.GetCurrentPosition());
400 }
401 
HWTEST_F_L0(AssemblerX64Test,Emit4)402 HWTEST_F_L0(AssemblerX64Test, Emit4)
403 {
404     x64::AssemblerX64 masm(chunk_);
405     size_t current = 0;
406 
407     // 4a 8d 0c f5 00 00 00 00 leaq    0x0(,%r14,8),%rcx
408     __ Leaq(Operand(r14, Scale::Times8, 0), rcx);
409     uint32_t value = masm.GetU8(current++);
410     ASSERT_EQ(value, 0x4AU);
411     value = masm.GetU8(current++);
412     ASSERT_EQ(value, 0x8DU);
413     value = masm.GetU8(current++);
414     ASSERT_EQ(value, 0x0CU);
415     value = masm.GetU8(current++);
416     ASSERT_EQ(value, 0xF5U);
417     value = masm.GetU8(current++);
418     ASSERT_EQ(value, 0x00U);
419     value = masm.GetU8(current++);
420     ASSERT_EQ(value, 0x00U);
421     value = masm.GetU8(current++);
422     ASSERT_EQ(value, 0x00U);
423     value = masm.GetU8(current++);
424     ASSERT_EQ(value, 0x00U);
425 
426     // 8d 90 ff ff ff fc       leal    -0x3000001(%rax),%edx
427     __ Leal(Operand(rax, -50331649), rdx);
428     value = masm.GetU8(current++);
429     ASSERT_EQ(value, 0x8DU);
430     value = masm.GetU8(current++);
431     ASSERT_EQ(value, 0x90U);
432     value = masm.GetU8(current++);
433     ASSERT_EQ(value, 0xFFU);
434     value = masm.GetU8(current++);
435     ASSERT_EQ(value, 0xFFU);
436     value = masm.GetU8(current++);
437     ASSERT_EQ(value, 0xFFU);
438     value = masm.GetU8(current++);
439     ASSERT_EQ(value, 0xFCU);
440 
441     // c1 e0 18        shl    $0x18,%eax
442     __ Shll(0x18, rax);
443     value = masm.GetU8(current++);
444     ASSERT_EQ(value, 0xC1U);
445     value = masm.GetU8(current++);
446     ASSERT_EQ(value, 0xE0U);
447     value = masm.GetU8(current++);
448     ASSERT_EQ(value, 0x18U);
449 
450     // shrq    $ASM_JS_METHOD_NUM_ARGS_START_BIT(32), %r11
451     __ Shrq(32, r11);
452     value = masm.GetU8(current++);
453     ASSERT_EQ(value, 0x49U);
454     value = masm.GetU8(current++);
455     ASSERT_EQ(value, 0xC1U);
456     value = masm.GetU8(current++);
457     ASSERT_EQ(value, 0xEBU);
458     value = masm.GetU8(current++);
459     ASSERT_EQ(value, 0x20U);
460 
461     // int3
462     __ Int3();
463     value = masm.GetU8(current++);
464     ASSERT_EQ(value, 0xCCU);
465     ecmascript::kungfu::LLVMAssembler::Disassemble(masm.GetBegin(), masm.GetCurrentPosition());
466 }
467 #undef __
468 }  // namespace panda::test
469