• 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/codegen/llvm/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(TARGET_X64);
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(TARGET_X64) == 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(TARGET_AARCH64) == 0) {
82             LLVMInitializeAArch64TargetInfo();
83             LLVMInitializeAArch64TargetMC();
84             LLVMInitializeAArch64Disassembler();
85             LLVMInitializeAArch64AsmPrinter();
86             LLVMInitializeAArch64AsmParser();
87             LLVMInitializeAArch64Target();
88         } else {
89             LOG_ECMA(FATAL) << "this branch is unreachable";
90             UNREACHABLE();
91         }
92     }
93 
DisassembleChunk(const char * triple,Assembler * assemlber,std::ostream & os)94     void DisassembleChunk(const char *triple, Assembler *assemlber, std::ostream &os)
95     {
96         LLVMDisasmContextRef dcr = LLVMCreateDisasm(triple, nullptr, 0, nullptr, SymbolLookupCallback);
97         uint8_t *byteSp = assemlber->GetBegin();
98         size_t numBytes = assemlber->GetCurrentPosition();
99         unsigned pc = 0;
100         const char outStringSize = 100;
101         char outString[outStringSize];
102         while (numBytes > 0) {
103             size_t InstSize = LLVMDisasmInstruction(dcr, byteSp, numBytes, pc, outString, outStringSize);
104             if (InstSize == 0) {
105                 // 8 : 8 means width of the pc offset and instruction code
106                 os << std::setw(8) << std::setfill('0') << std::hex << pc << ":" << std::setw(8)
107                    << *reinterpret_cast<uint32_t *>(byteSp) << "maybe constant" << std::endl;
108                 pc += 4; // 4 pc length
109                 byteSp += 4; // 4 sp offset
110                 numBytes -= 4; // 4 num bytes
111             }
112             // 8 : 8 means width of the pc offset and instruction code
113             os << std::setw(8) << std::setfill('0') << std::hex << pc << ":" << std::setw(8)
114                << *reinterpret_cast<uint32_t *>(byteSp) << " " << outString << std::endl;
115             pc += InstSize;
116             byteSp += InstSize;
117             numBytes -= InstSize;
118         }
119         LLVMDisasmDispose(dcr);
120     }
121 
122     EcmaVM *instance {nullptr};
123     JSThread *thread {nullptr};
124     EcmaHandleScope *scope {nullptr};
125     Chunk *chunk_ {nullptr};
126 };
127 
128 #define __ masm.
HWTEST_F_L0(AssemblerX64Test,Emit)129 HWTEST_F_L0(AssemblerX64Test, Emit)
130 {
131     x64::AssemblerX64 masm(chunk_);
132     Label lable1;
133 
134     size_t current = 0;
135     __ Pushq(rbp);
136     uint32_t value = masm.GetU8(current++);
137     ASSERT_EQ(value, 0x55U);
138     __ Pushq(0);
139     value = masm.GetU8(current++);
140     ASSERT_EQ(value, 0x6AU);
141     value = masm.GetU8(current++);
142     ASSERT_EQ(value, 0x00U);
143     __ Popq(rbp);
144     value = masm.GetU8(current++);
145     ASSERT_EQ(value, 0x5DU);
146     __ Bind(&lable1);
147     __ Movq(rcx, rbx);
148     value = masm.GetU8(current++);
149     ASSERT_EQ(value, 0x48U);
150     value = masm.GetU8(current++);
151     ASSERT_EQ(value, 0x89U);
152     value = masm.GetU8(current++);
153     ASSERT_EQ(value, 0xCBU);
154     __ Movq(Operand(rsp, 0x40U), rbx);
155     value = masm.GetU8(current++);
156     ASSERT_EQ(value, 0x48U);
157     value = masm.GetU8(current++);
158     ASSERT_EQ(value, 0x8BU);
159     value = masm.GetU8(current++);
160     ASSERT_EQ(value, 0x5CU);
161     value = masm.GetU8(current++);
162     ASSERT_EQ(value, 0x24U);
163     value = masm.GetU8(current++);
164     ASSERT_EQ(value, 0x40U);
165     __ Jmp(&lable1);
166     value = masm.GetU8(current++);
167     ASSERT_EQ(value, 0xEBU);
168     value = masm.GetU8(current++);
169     ASSERT_EQ(value, 0xF6U);
170     __ Ret();
171     value = masm.GetU8(current++);
172     ASSERT_EQ(value, 0xC3U);
173 
174     ecmascript::kungfu::LLVMAssembler::Disassemble(nullptr, TARGET_X64,
175                                                    masm.GetBegin(), masm.GetCurrentPosition());
176 }
177 
HWTEST_F_L0(AssemblerX64Test,Emit1)178 HWTEST_F_L0(AssemblerX64Test, Emit1)
179 {
180     x64::AssemblerX64 masm(chunk_);
181 
182     size_t current = 0;
183     __ Movl(Operand(rax, 0x38), rax);
184     uint32_t value = masm.GetU8(current++);
185     ASSERT_EQ(value, 0x8BU);
186     value = masm.GetU8(current++);
187     ASSERT_EQ(value, 0x40U);
188     value = masm.GetU8(current++);
189     ASSERT_EQ(value, 0x38U);
190 
191     // 41 89 f6 movl    %esi, %r14d
192     __ Movl(rsi, r14);
193     value = masm.GetU8(current++);
194     ASSERT_EQ(value, 0x41U);
195     value = masm.GetU8(current++);
196     ASSERT_EQ(value, 0x89U);
197     value = masm.GetU8(current++);
198     ASSERT_EQ(value, 0xF6U);
199 
200     // movzbq  (%rcx), %rax
201     __ Movzbq(Operand(rcx, 0), rax);
202     value = masm.GetU8(current++);
203     ASSERT_EQ(value, 0x48U);
204     value = masm.GetU8(current++);
205     ASSERT_EQ(value, 0x0FU);
206     value = masm.GetU8(current++);
207     ASSERT_EQ(value, 0xB6U);
208     value = masm.GetU8(current++);
209     ASSERT_EQ(value, 0x01U);
210 
211     // 48 ba 02 00 00 00 00 00 00 00   movabs $0x2,%rdx
212     __ Movabs(0x2, rdx);
213     value = masm.GetU8(current++);
214     ASSERT_EQ(value, 0x48U);
215     value = masm.GetU8(current++);
216     ASSERT_EQ(value, 0xBAU);
217     value = masm.GetU8(current++);
218     ASSERT_EQ(value, 0x02U);
219     value = masm.GetU8(current++);
220     ASSERT_EQ(value, 0x00U);
221     value = masm.GetU8(current++);
222     ASSERT_EQ(value, 0x00U);
223     value = masm.GetU8(current++);
224     ASSERT_EQ(value, 0x00U);
225     value = masm.GetU8(current++);
226     ASSERT_EQ(value, 0x00U);
227     value = masm.GetU8(current++);
228     ASSERT_EQ(value, 0x00U);
229     value = masm.GetU8(current++);
230     ASSERT_EQ(value, 0x00U);
231     value = masm.GetU8(current++);
232     ASSERT_EQ(value, 0x00U);
233 
234     __ Movq(0x5, rdx);
235     value = masm.GetU8(current++);
236     ASSERT_EQ(value, 0xBAU);
237     value = masm.GetU8(current++);
238     ASSERT_EQ(value, 0x05U);
239     value = masm.GetU8(current++);
240     ASSERT_EQ(value, 0x00U);
241     value = masm.GetU8(current++);
242     ASSERT_EQ(value, 0x00U);
243     value = masm.GetU8(current++);
244     ASSERT_EQ(value, 0x00U);
245 
246     // 49 89 e0        mov    %rsp,%r8
247     __ Movq(rsp, r8);
248     value = masm.GetU8(current++);
249     ASSERT_EQ(value, 0x49U);
250     value = masm.GetU8(current++);
251     ASSERT_EQ(value, 0x89U);
252     value = masm.GetU8(current++);
253     ASSERT_EQ(value, 0xE0U);
254 
255     ecmascript::kungfu::LLVMAssembler::Disassemble(nullptr, TARGET_X64,
256                                                    masm.GetBegin(), masm.GetCurrentPosition());
257 }
258 
HWTEST_F_L0(AssemblerX64Test,Emit2)259 HWTEST_F_L0(AssemblerX64Test, Emit2)
260 {
261     x64::AssemblerX64 masm(chunk_);
262 
263     size_t current = 0;
264     // 81 fa ff ff ff 09       cmpl    $0x9ffffff,%edx
265     __ Cmpl(0x9FFFFFF, rdx);
266     uint32_t value = masm.GetU8(current++);
267     ASSERT_EQ(value, 0x81U);
268     value = masm.GetU8(current++);
269     ASSERT_EQ(value, 0xFAU);
270     value = masm.GetU8(current++);
271     ASSERT_EQ(value, 0xFFU);
272     value = masm.GetU8(current++);
273     ASSERT_EQ(value, 0xFFU);
274     value = masm.GetU8(current++);
275     ASSERT_EQ(value, 0xFFU);
276     value = masm.GetU8(current++);
277     ASSERT_EQ(value, 0x09U);
278 
279     // 39 cb   cmpl    %ecx,%ebx
280     __ Cmpl(rcx, rbx);
281     value = masm.GetU8(current++);
282     ASSERT_EQ(value, 0x39U);
283     value = masm.GetU8(current++);
284     ASSERT_EQ(value, 0xCBU);
285 
286     // 48 83 fa 00     cmp    $0x0,%rdx
287     __ Cmp(0x0, rdx);
288     value = masm.GetU8(current++);
289     ASSERT_EQ(value, 0x48U);
290     value = masm.GetU8(current++);
291     ASSERT_EQ(value, 0x83U);
292     value = masm.GetU8(current++);
293     ASSERT_EQ(value, 0xFAU);
294     value = masm.GetU8(current++);
295     ASSERT_EQ(value, 0x00U);
296 
297     // 4c 39 D8 cmpq    %r11, %rax
298     __ Cmpq(r11, rax);
299     value = masm.GetU8(current++);
300     ASSERT_EQ(value, 0x4CU);
301     value = masm.GetU8(current++);
302     ASSERT_EQ(value, 0x39U);
303     value = masm.GetU8(current++);
304     ASSERT_EQ(value, 0xD8U);
305 
306 
307     // 0f ba e0 08     bt     $0x8,%eax
308     __ Btl(0x8, rax);
309     value = masm.GetU8(current++);
310     ASSERT_EQ(value, 0x0FU);
311     value = masm.GetU8(current++);
312     ASSERT_EQ(value, 0xBAU);
313     value = masm.GetU8(current++);
314     ASSERT_EQ(value, 0xE0U);
315     value = masm.GetU8(current++);
316     ASSERT_EQ(value, 0x08U);
317     ecmascript::kungfu::LLVMAssembler::Disassemble(nullptr, TARGET_X64,
318                                                    masm.GetBegin(), masm.GetCurrentPosition());
319 }
320 
HWTEST_F_L0(AssemblerX64Test,Emit3)321 HWTEST_F_L0(AssemblerX64Test, Emit3)
322 {
323     x64::AssemblerX64 masm(chunk_);
324     size_t current = 0;
325 
326     // cmovbe  %ebx, %ecx
327     __ CMovbe(rbx, rcx);
328     uint32_t value = masm.GetU8(current++);
329 
330     ASSERT_EQ(value, 0x0FU);
331     value = masm.GetU8(current++);
332     ASSERT_EQ(value, 0x46U);
333     value = masm.GetU8(current++);
334     ASSERT_EQ(value, 0xCBU);
335 
336     // testb   $0x1, %r14b
337     __ Testb(0x1, r14);
338     value = masm.GetU8(current++);
339     ASSERT_EQ(value, 0x41U);
340     value = masm.GetU8(current++);
341     ASSERT_EQ(value, 0xF6U);
342     value = masm.GetU8(current++);
343     ASSERT_EQ(value, 0xC6U);
344     value = masm.GetU8(current++);
345     ASSERT_EQ(value, 0x01U);
346 
347     // 48 f6 c4 0f testq   $15, %rsp
348     __ Testq(15, rsp);
349     value = masm.GetU8(current++);
350     ASSERT_EQ(value, 0x40U);
351     value = masm.GetU8(current++);
352     ASSERT_EQ(value, 0xF6U);
353     value = masm.GetU8(current++);
354     ASSERT_EQ(value, 0xC4U);
355     value = masm.GetU8(current++);
356     ASSERT_EQ(value, 0x0FU);
357 
358     // andq    $ASM_JS_METHOD_NUM_VREGS_MASK, %r11
359     __ Andq(0xfffffff, r11);
360     value = masm.GetU8(current++);
361     ASSERT_EQ(value, 0x49U);
362     value = masm.GetU8(current++);
363     ASSERT_EQ(value, 0x81U);
364     value = masm.GetU8(current++);
365     ASSERT_EQ(value, 0xE3U);
366     value = masm.GetU8(current++);
367     ASSERT_EQ(value, 0xFFU);
368     value = masm.GetU8(current++);
369     ASSERT_EQ(value, 0xFFU);
370     value = masm.GetU8(current++);
371     ASSERT_EQ(value, 0xFFU);
372     value = masm.GetU8(current++);
373     ASSERT_EQ(value, 0x0FU);
374 
375     // andl 0xfffffff, %eax
376     __ Andl(0xfffffff, rax);
377     value = masm.GetU8(current++);
378     ASSERT_EQ(value, 0x25U);
379     value = masm.GetU8(current++);
380     ASSERT_EQ(value, 0xFFU);
381     value = masm.GetU8(current++);
382     ASSERT_EQ(value, 0xFFU);
383     value = masm.GetU8(current++);
384     ASSERT_EQ(value, 0xFFU);
385     value = masm.GetU8(current++);
386     ASSERT_EQ(value, 0x0FU);
387 
388     // and     %rax, %rdx
389     __ And(rax, rdx);
390     value = masm.GetU8(current++);
391     ASSERT_EQ(value, 0x48U);
392     value = masm.GetU8(current++);
393     ASSERT_EQ(value, 0x21U);
394     value = masm.GetU8(current++);
395     ASSERT_EQ(value, 0xC2U);
396     ecmascript::kungfu::LLVMAssembler::Disassemble(nullptr, TARGET_X64,
397                                                    masm.GetBegin(), masm.GetCurrentPosition());
398 }
399 
HWTEST_F_L0(AssemblerX64Test,Emit4)400 HWTEST_F_L0(AssemblerX64Test, Emit4)
401 {
402     x64::AssemblerX64 masm(chunk_);
403     size_t current = 0;
404 
405     // 4a 8d 0c f5 00 00 00 00 leaq    0x0(,%r14,8),%rcx
406     __ Leaq(Operand(r14, Scale::Times8, 0), rcx);
407     uint32_t value = masm.GetU8(current++);
408     ASSERT_EQ(value, 0x4AU);
409     value = masm.GetU8(current++);
410     ASSERT_EQ(value, 0x8DU);
411     value = masm.GetU8(current++);
412     ASSERT_EQ(value, 0x0CU);
413     value = masm.GetU8(current++);
414     ASSERT_EQ(value, 0xF5U);
415     value = masm.GetU8(current++);
416     ASSERT_EQ(value, 0x00U);
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 
424     // 8d 90 ff ff ff fc       leal    -0x3000001(%rax),%edx
425     __ Leal(Operand(rax, -50331649), rdx);
426     value = masm.GetU8(current++);
427     ASSERT_EQ(value, 0x8DU);
428     value = masm.GetU8(current++);
429     ASSERT_EQ(value, 0x90U);
430     value = masm.GetU8(current++);
431     ASSERT_EQ(value, 0xFFU);
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, 0xFCU);
438 
439     // c1 e0 18        shl    $0x18,%eax
440     __ Shll(0x18, rax);
441     value = masm.GetU8(current++);
442     ASSERT_EQ(value, 0xC1U);
443     value = masm.GetU8(current++);
444     ASSERT_EQ(value, 0xE0U);
445     value = masm.GetU8(current++);
446     ASSERT_EQ(value, 0x18U);
447 
448     // shrq    $ASM_JS_METHOD_NUM_ARGS_START_BIT(32), %r11
449     __ Shrq(32, r11);
450     value = masm.GetU8(current++);
451     ASSERT_EQ(value, 0x49U);
452     value = masm.GetU8(current++);
453     ASSERT_EQ(value, 0xC1U);
454     value = masm.GetU8(current++);
455     ASSERT_EQ(value, 0xEBU);
456     value = masm.GetU8(current++);
457     ASSERT_EQ(value, 0x20U);
458 
459     // int3
460     __ Int3();
461     value = masm.GetU8(current++);
462     ASSERT_EQ(value, 0xCCU);
463     ecmascript::kungfu::LLVMAssembler::Disassemble(nullptr, TARGET_X64,
464                                                    masm.GetBegin(), masm.GetCurrentPosition());
465 }
466 #undef __
467 }  // namespace panda::test
468