michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: // A short test program with which to experiment with the assembler. michael@0: michael@0: //satisfies CPU(X86_64) michael@0: //#define WTF_CPU_X86_64 michael@0: michael@0: // satisfies ENABLE(ASSEMBLER) michael@0: #define ENABLE_ASSEMBLER 1 michael@0: michael@0: // satisfies ENABLE(JIT) michael@0: #define ENABLE_JIT 1 michael@0: michael@0: #define USE_SYSTEM_MALLOC 1 michael@0: // leads to FORCE_SYSTEM_MALLOC in wtf/FastMalloc.cpp michael@0: michael@0: #include "assembler/jit/ExecutableAllocator.h" michael@0: #include "assembler/assembler/LinkBuffer.h" michael@0: #include "assembler/assembler/CodeLocation.h" michael@0: #include "assembler/assembler/RepatchBuffer.h" michael@0: michael@0: #include "assembler/assembler/MacroAssembler.h" michael@0: michael@0: #include michael@0: michael@0: ///////////////////////////////////////////////////////////////// michael@0: // Temporary scaffolding for selecting the arch michael@0: #undef ARCH_x86 michael@0: #undef ARCH_amd64 michael@0: #undef ARCH_arm michael@0: michael@0: #if defined(__APPLE__) && defined(__i386__) michael@0: # define ARCH_x86 1 michael@0: #elif defined(__APPLE__) && defined(__x86_64__) michael@0: # define ARCH_amd64 1 michael@0: #elif defined(__linux__) && defined(__i386__) michael@0: # define ARCH_x86 1 michael@0: #elif defined(__linux__) && defined(__x86_64__) michael@0: # define ARCH_amd64 1 michael@0: #elif defined(__linux__) && defined(__arm__) michael@0: # define ARCH_arm 1 michael@0: #elif defined(_MSC_VER) && defined(_M_IX86) michael@0: # define ARCH_x86 1 michael@0: #endif michael@0: ///////////////////////////////////////////////////////////////// michael@0: michael@0: // just somewhere convenient to put a breakpoint, before michael@0: // running gdb michael@0: #if WTF_COMPILER_GCC michael@0: __attribute__((noinline)) michael@0: #endif michael@0: void pre_run ( void ) { } michael@0: michael@0: ///////////////////////////////////////////////////////////////// michael@0: //// test1 (simple straight line code) michael@0: #if WTF_COMPILER_GCC michael@0: michael@0: void test1 ( void ) michael@0: { michael@0: printf("\n------------ Test 1 (straight line code) ------------\n\n" ); michael@0: michael@0: // Create new assembler michael@0: JSC::MacroAssembler* am = new JSC::MacroAssembler(); michael@0: michael@0: #if defined(ARCH_amd64) michael@0: JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15; michael@0: // dump some instructions into it michael@0: // xor %r15,%r15 michael@0: // add $0x7b,%r15 michael@0: // add $0x141,%r15 michael@0: // retq michael@0: am->xorPtr(areg,areg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(123), areg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(321), areg); michael@0: am->ret(); michael@0: #endif michael@0: michael@0: #if defined(ARCH_x86) michael@0: JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi; michael@0: // dump some instructions into it michael@0: // xor %edi,%edi michael@0: // add $0x7b,%edi michael@0: // add $0x141,%edi michael@0: // ret michael@0: am->xorPtr(areg,areg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(123), areg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(321), areg); michael@0: am->ret(); michael@0: #endif michael@0: michael@0: #if defined(ARCH_arm) michael@0: JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8; michael@0: // eors r8, r8, r8 michael@0: // adds r8, r8, #123 ; 0x7b michael@0: // mov r3, #256 ; 0x100 michael@0: // orr r3, r3, #65 ; 0x41 michael@0: // adds r8, r8, r3 michael@0: // mov pc, lr michael@0: am->xorPtr(areg,areg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(123), areg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(321), areg); michael@0: am->ret(); michael@0: #endif michael@0: michael@0: // prepare a link buffer, into which we can copy the completed insns michael@0: JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); michael@0: michael@0: // intermediate step .. get the pool suited for the size of code in 'am' michael@0: //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); michael@0: JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); michael@0: michael@0: // constructor for LinkBuffer asks ep to allocate r-x memory, michael@0: // then copies it there. michael@0: JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); michael@0: michael@0: // finalize michael@0: JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); michael@0: michael@0: // cr now holds a pointer to the final runnable code. michael@0: void* entry = cr.m_code.executableAddress(); michael@0: michael@0: printf("disas %p %p\n", michael@0: entry, (char*)entry + cr.m_size); michael@0: pre_run(); michael@0: michael@0: unsigned long result = 0x55555555; michael@0: michael@0: #if defined(ARCH_amd64) michael@0: // call the generated piece of code. It puts its result in r15. michael@0: __asm__ __volatile__( michael@0: "callq *%1" "\n\t" michael@0: "movq %%r15, %0" "\n" michael@0: :/*out*/ "=r"(result) michael@0: :/*in*/ "r"(entry) michael@0: :/*trash*/ "r15","cc" michael@0: ); michael@0: #endif michael@0: #if defined(ARCH_x86) michael@0: // call the generated piece of code. It puts its result in edi. michael@0: __asm__ __volatile__( michael@0: "calll *%1" "\n\t" michael@0: "movl %%edi, %0" "\n" michael@0: :/*out*/ "=r"(result) michael@0: :/*in*/ "r"(entry) michael@0: :/*trash*/ "edi","cc" michael@0: ); michael@0: #endif michael@0: #if defined(ARCH_arm) michael@0: // call the generated piece of code. It puts its result in r8. michael@0: __asm__ __volatile__( michael@0: "blx %1" "\n\t" michael@0: "mov %0, %%r8" "\n" michael@0: :/*out*/ "=r"(result) michael@0: :/*in*/ "r"(entry) michael@0: :/*trash*/ "r8","cc" michael@0: ); michael@0: #endif michael@0: michael@0: printf("\n"); michael@0: printf("value computed is %lu (expected 444)\n", result); michael@0: printf("\n"); michael@0: michael@0: delete eal; michael@0: delete am; michael@0: } michael@0: michael@0: #endif /* WTF_COMPILER_GCC */ michael@0: michael@0: ///////////////////////////////////////////////////////////////// michael@0: //// test2 (a simple counting-down loop) michael@0: #if WTF_COMPILER_GCC michael@0: michael@0: void test2 ( void ) michael@0: { michael@0: printf("\n------------ Test 2 (mini loop) ------------\n\n" ); michael@0: michael@0: // Create new assembler michael@0: JSC::MacroAssembler* am = new JSC::MacroAssembler(); michael@0: michael@0: #if defined(ARCH_amd64) michael@0: JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15; michael@0: // xor %r15,%r15 michael@0: // add $0x7b,%r15 michael@0: // add $0x141,%r15 michael@0: // sub $0x1,%r15 michael@0: // mov $0x0,%r11 michael@0: // cmp %r11,%r15 michael@0: // jne 0x7ff6d3e6a00e michael@0: // retq michael@0: // so r15 always winds up being zero michael@0: am->xorPtr(areg,areg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(123), areg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(321), areg); michael@0: michael@0: JSC::MacroAssembler::Label loopHeadLabel(am); michael@0: am->subPtr(JSC::MacroAssembler::Imm32(1), areg); michael@0: michael@0: JSC::MacroAssembler::Jump j michael@0: = am->branchPtr(JSC::MacroAssembler::NotEqual, michael@0: areg, JSC::MacroAssembler::ImmPtr(0)); michael@0: j.linkTo(loopHeadLabel, am); michael@0: michael@0: am->ret(); michael@0: #endif michael@0: michael@0: #if defined(ARCH_x86) michael@0: JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi; michael@0: // xor %edi,%edi michael@0: // add $0x7b,%edi michael@0: // add $0x141,%edi michael@0: // sub $0x1,%edi michael@0: // test %edi,%edi michael@0: // jne 0xf7f9700b michael@0: // ret michael@0: // so edi always winds up being zero michael@0: am->xorPtr(areg,areg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(123), areg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(321), areg); michael@0: michael@0: JSC::MacroAssembler::Label loopHeadLabel(am); michael@0: am->subPtr(JSC::MacroAssembler::Imm32(1), areg); michael@0: michael@0: JSC::MacroAssembler::Jump j michael@0: = am->branchPtr(JSC::MacroAssembler::NotEqual, michael@0: areg, JSC::MacroAssembler::ImmPtr(0)); michael@0: j.linkTo(loopHeadLabel, am); michael@0: michael@0: am->ret(); michael@0: #endif michael@0: michael@0: #if defined(ARCH_arm) michael@0: JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8; michael@0: // eors r8, r8, r8 michael@0: // adds r8, r8, #123 ; 0x7b michael@0: // mov r3, #256 ; 0x100 michael@0: // orr r3, r3, #65 ; 0x41 michael@0: // adds r8, r8, r3 michael@0: // subs r8, r8, #1 ; 0x1 michael@0: // ldr r3, [pc, #8] ; 0x40026028 michael@0: // cmp r8, r3 michael@0: // bne 0x40026014 michael@0: // mov pc, lr michael@0: // andeq r0, r0, r0 // DATA (0) michael@0: // andeq r0, r0, r4, lsl r0 // DATA (?? what's this for?) michael@0: // so r8 always winds up being zero michael@0: am->xorPtr(areg,areg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(123), areg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(321), areg); michael@0: michael@0: JSC::MacroAssembler::Label loopHeadLabel(am); michael@0: am->subPtr(JSC::MacroAssembler::Imm32(1), areg); michael@0: michael@0: JSC::MacroAssembler::Jump j michael@0: = am->branchPtr(JSC::MacroAssembler::NotEqual, michael@0: areg, JSC::MacroAssembler::ImmPtr(0)); michael@0: j.linkTo(loopHeadLabel, am); michael@0: michael@0: am->ret(); michael@0: #endif michael@0: michael@0: // prepare a link buffer, into which we can copy the completed insns michael@0: JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); michael@0: michael@0: // intermediate step .. get the pool suited for the size of code in 'am' michael@0: //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); michael@0: JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); michael@0: michael@0: // constructor for LinkBuffer asks ep to allocate r-x memory, michael@0: // then copies it there. michael@0: JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); michael@0: michael@0: // finalize michael@0: JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); michael@0: michael@0: // cr now holds a pointer to the final runnable code. michael@0: void* entry = cr.m_code.executableAddress(); michael@0: michael@0: printf("disas %p %p\n", michael@0: entry, (char*)entry + cr.m_size); michael@0: pre_run(); michael@0: michael@0: unsigned long result = 0x55555555; michael@0: michael@0: #if defined(ARCH_amd64) michael@0: // call the generated piece of code. It puts its result in r15. michael@0: __asm__ __volatile__( michael@0: "callq *%1" "\n\t" michael@0: "movq %%r15, %0" "\n" michael@0: :/*out*/ "=r"(result) michael@0: :/*in*/ "r"(entry) michael@0: :/*trash*/ "r15","cc" michael@0: ); michael@0: #endif michael@0: #if defined(ARCH_x86) michael@0: // call the generated piece of code. It puts its result in edi. michael@0: __asm__ __volatile__( michael@0: "calll *%1" "\n\t" michael@0: "movl %%edi, %0" "\n" michael@0: :/*out*/ "=r"(result) michael@0: :/*in*/ "r"(entry) michael@0: :/*trash*/ "edi","cc" michael@0: ); michael@0: #endif michael@0: #if defined(ARCH_arm) michael@0: // call the generated piece of code. It puts its result in r8. michael@0: __asm__ __volatile__( michael@0: "blx %1" "\n\t" michael@0: "mov %0, %%r8" "\n" michael@0: :/*out*/ "=r"(result) michael@0: :/*in*/ "r"(entry) michael@0: :/*trash*/ "r8","cc" michael@0: ); michael@0: #endif michael@0: michael@0: printf("\n"); michael@0: printf("value computed is %lu (expected 0)\n", result); michael@0: printf("\n"); michael@0: michael@0: delete eal; michael@0: delete am; michael@0: } michael@0: michael@0: #endif /* WTF_COMPILER_GCC */ michael@0: michael@0: ///////////////////////////////////////////////////////////////// michael@0: //// test3 (if-then-else) michael@0: #if WTF_COMPILER_GCC michael@0: michael@0: void test3 ( void ) michael@0: { michael@0: printf("\n------------ Test 3 (if-then-else) ------------\n\n" ); michael@0: michael@0: // Create new assembler michael@0: JSC::MacroAssembler* am = new JSC::MacroAssembler(); michael@0: michael@0: #if defined(ARCH_amd64) michael@0: JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15; michael@0: // mov $0x64,%r15d michael@0: // mov $0x0,%r11 michael@0: // cmp %r11,%r15 michael@0: // jne 0x7ff6d3e6a024 michael@0: // mov $0x40,%r15d michael@0: // jmpq 0x7ff6d3e6a02a michael@0: // mov $0x4,%r15d michael@0: // retq michael@0: // so r15 ends up being 4 michael@0: michael@0: // put a value in reg michael@0: am->move(JSC::MacroAssembler::Imm32(100), areg); michael@0: michael@0: // test, and conditionally jump to 'else' branch michael@0: JSC::MacroAssembler::Jump jToElse michael@0: = am->branchPtr(JSC::MacroAssembler::NotEqual, michael@0: areg, JSC::MacroAssembler::ImmPtr(0)); michael@0: michael@0: // 'then' branch michael@0: am->move(JSC::MacroAssembler::Imm32(64), areg); michael@0: JSC::MacroAssembler::Jump jToAfter michael@0: = am->jump(); michael@0: michael@0: // 'else' branch michael@0: JSC::MacroAssembler::Label elseLbl(am); michael@0: am->move(JSC::MacroAssembler::Imm32(4), areg); michael@0: michael@0: // after michael@0: JSC::MacroAssembler::Label afterLbl(am); michael@0: michael@0: am->ret(); michael@0: #endif michael@0: michael@0: #if defined(ARCH_x86) michael@0: JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi; michael@0: // mov $0x64,%edi michael@0: // test %edi,%edi michael@0: // jne 0xf7f22017 michael@0: // mov $0x40,%edi michael@0: // jmp 0xf7f2201c michael@0: // mov $0x4,%edi michael@0: // ret michael@0: // so edi ends up being 4 michael@0: michael@0: // put a value in reg michael@0: am->move(JSC::MacroAssembler::Imm32(100), areg); michael@0: michael@0: // test, and conditionally jump to 'else' branch michael@0: JSC::MacroAssembler::Jump jToElse michael@0: = am->branchPtr(JSC::MacroAssembler::NotEqual, michael@0: areg, JSC::MacroAssembler::ImmPtr(0)); michael@0: michael@0: // 'then' branch michael@0: am->move(JSC::MacroAssembler::Imm32(64), areg); michael@0: JSC::MacroAssembler::Jump jToAfter michael@0: = am->jump(); michael@0: michael@0: // 'else' branch michael@0: JSC::MacroAssembler::Label elseLbl(am); michael@0: am->move(JSC::MacroAssembler::Imm32(4), areg); michael@0: michael@0: // after michael@0: JSC::MacroAssembler::Label afterLbl(am); michael@0: michael@0: am->ret(); michael@0: #endif michael@0: michael@0: #if defined(ARCH_arm) michael@0: JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8; michael@0: // mov r8, #100 ; 0x64 michael@0: // ldr r3, [pc, #20] ; 0x40026020 michael@0: // cmp r8, r3 michael@0: // bne 0x40026018 michael@0: // mov r8, #64 ; 0x40 michael@0: // b 0x4002601c michael@0: // mov r8, #4 ; 0x4 michael@0: // mov pc, lr michael@0: // andeq r0, r0, r0 // DATA michael@0: // andeq r0, r0, r8, lsl r0 // DATA michael@0: // andeq r0, r0, r12, lsl r0 // DATA michael@0: // ldr r3, [r3, -r3] // DATA michael@0: // so r8 ends up being 4 michael@0: michael@0: // put a value in reg michael@0: am->move(JSC::MacroAssembler::Imm32(100), areg); michael@0: michael@0: // test, and conditionally jump to 'else' branch michael@0: JSC::MacroAssembler::Jump jToElse michael@0: = am->branchPtr(JSC::MacroAssembler::NotEqual, michael@0: areg, JSC::MacroAssembler::ImmPtr(0)); michael@0: michael@0: // 'then' branch michael@0: am->move(JSC::MacroAssembler::Imm32(64), areg); michael@0: JSC::MacroAssembler::Jump jToAfter michael@0: = am->jump(); michael@0: michael@0: // 'else' branch michael@0: JSC::MacroAssembler::Label elseLbl(am); michael@0: am->move(JSC::MacroAssembler::Imm32(4), areg); michael@0: michael@0: // after michael@0: JSC::MacroAssembler::Label afterLbl(am); michael@0: michael@0: am->ret(); michael@0: #endif michael@0: michael@0: // set branch targets appropriately michael@0: jToElse.linkTo(elseLbl, am); michael@0: jToAfter.linkTo(afterLbl, am); michael@0: michael@0: // prepare a link buffer, into which we can copy the completed insns michael@0: JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); michael@0: michael@0: // intermediate step .. get the pool suited for the size of code in 'am' michael@0: //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); michael@0: JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); michael@0: michael@0: // constructor for LinkBuffer asks ep to allocate r-x memory, michael@0: // then copies it there. michael@0: JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); michael@0: michael@0: // finalize michael@0: JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); michael@0: michael@0: // cr now holds a pointer to the final runnable code. michael@0: void* entry = cr.m_code.executableAddress(); michael@0: michael@0: printf("disas %p %p\n", michael@0: entry, (char*)entry + cr.m_size); michael@0: pre_run(); michael@0: michael@0: unsigned long result = 0x55555555; michael@0: michael@0: #if defined(ARCH_amd64) michael@0: // call the generated piece of code. It puts its result in r15. michael@0: __asm__ __volatile__( michael@0: "callq *%1" "\n\t" michael@0: "movq %%r15, %0" "\n" michael@0: :/*out*/ "=r"(result) michael@0: :/*in*/ "r"(entry) michael@0: :/*trash*/ "r15","cc" michael@0: ); michael@0: #endif michael@0: #if defined(ARCH_x86) michael@0: // call the generated piece of code. It puts its result in edi. michael@0: __asm__ __volatile__( michael@0: "calll *%1" "\n\t" michael@0: "movl %%edi, %0" "\n" michael@0: :/*out*/ "=r"(result) michael@0: :/*in*/ "r"(entry) michael@0: :/*trash*/ "edi","cc" michael@0: ); michael@0: #endif michael@0: #if defined(ARCH_arm) michael@0: // call the generated piece of code. It puts its result in r8. michael@0: __asm__ __volatile__( michael@0: "blx %1" "\n\t" michael@0: "mov %0, %%r8" "\n" michael@0: :/*out*/ "=r"(result) michael@0: :/*in*/ "r"(entry) michael@0: :/*trash*/ "r8","cc" michael@0: ); michael@0: #endif michael@0: michael@0: printf("\n"); michael@0: printf("value computed is %lu (expected 4)\n", result); michael@0: printf("\n"); michael@0: michael@0: delete eal; michael@0: delete am; michael@0: } michael@0: michael@0: #endif /* WTF_COMPILER_GCC */ michael@0: michael@0: ///////////////////////////////////////////////////////////////// michael@0: //// test4 (callable function) michael@0: michael@0: void test4 ( void ) michael@0: { michael@0: printf("\n------------ Test 4 (callable fn) ------------\n\n" ); michael@0: michael@0: // Create new assembler michael@0: JSC::MacroAssembler* am = new JSC::MacroAssembler(); michael@0: michael@0: #if defined(ARCH_amd64) michael@0: // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function michael@0: // push %rbp michael@0: // mov %rsp,%rbp michael@0: // push %rbx michael@0: // push %r12 michael@0: // push %r13 michael@0: // push %r14 michael@0: // push %r15 michael@0: // xor %rax,%rax michael@0: // add $0x7b,%rax michael@0: // add $0x141,%rax michael@0: // pop %r15 michael@0: // pop %r14 michael@0: // pop %r13 michael@0: // pop %r12 michael@0: // pop %rbx michael@0: // mov %rbp,%rsp michael@0: // pop %rbp michael@0: // retq michael@0: // callable as a normal function, returns 444 michael@0: michael@0: JSC::X86Registers::RegisterID rreg = JSC::X86Registers::eax; michael@0: am->push(JSC::X86Registers::ebp); michael@0: am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); michael@0: am->push(JSC::X86Registers::ebx); michael@0: am->push(JSC::X86Registers::r12); michael@0: am->push(JSC::X86Registers::r13); michael@0: am->push(JSC::X86Registers::r14); michael@0: am->push(JSC::X86Registers::r15); michael@0: michael@0: am->xorPtr(rreg,rreg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(123), rreg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(321), rreg); michael@0: michael@0: am->pop(JSC::X86Registers::r15); michael@0: am->pop(JSC::X86Registers::r14); michael@0: am->pop(JSC::X86Registers::r13); michael@0: am->pop(JSC::X86Registers::r12); michael@0: am->pop(JSC::X86Registers::ebx); michael@0: am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); michael@0: am->pop(JSC::X86Registers::ebp); michael@0: am->ret(); michael@0: #endif michael@0: michael@0: #if defined(ARCH_x86) michael@0: // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function michael@0: // push %ebp michael@0: // mov %esp,%ebp michael@0: // push %ebx michael@0: // push %esi michael@0: // push %edi michael@0: // xor %eax,%eax michael@0: // add $0x7b,%eax michael@0: // add $0x141,%eax michael@0: // pop %edi michael@0: // pop %esi michael@0: // pop %ebx michael@0: // mov %ebp,%esp michael@0: // pop %ebp michael@0: // ret michael@0: // callable as a normal function, returns 444 michael@0: michael@0: JSC::X86Registers::RegisterID rreg = JSC::X86Registers::eax; michael@0: michael@0: am->push(JSC::X86Registers::ebp); michael@0: am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); michael@0: am->push(JSC::X86Registers::ebx); michael@0: am->push(JSC::X86Registers::esi); michael@0: am->push(JSC::X86Registers::edi); michael@0: michael@0: am->xorPtr(rreg,rreg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(123), rreg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(321), rreg); michael@0: michael@0: am->pop(JSC::X86Registers::edi); michael@0: am->pop(JSC::X86Registers::esi); michael@0: am->pop(JSC::X86Registers::ebx); michael@0: am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); michael@0: am->pop(JSC::X86Registers::ebp); michael@0: am->ret(); michael@0: #endif michael@0: michael@0: #if defined(ARCH_arm) michael@0: // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function michael@0: // push {r4} ; (str r4, [sp, #-4]!) michael@0: // push {r5} ; (str r5, [sp, #-4]!) michael@0: // push {r6} ; (str r6, [sp, #-4]!) michael@0: // push {r7} ; (str r7, [sp, #-4]!) michael@0: // push {r8} ; (str r8, [sp, #-4]!) michael@0: // push {r9} ; (str r9, [sp, #-4]!) michael@0: // push {r10} ; (str r10, [sp, #-4]!) michael@0: // push {r11} ; (str r11, [sp, #-4]!) michael@0: // eors r0, r0, r0 michael@0: // adds r0, r0, #123 ; 0x7b michael@0: // mov r3, #256 ; 0x100 michael@0: // orr r3, r3, #65 ; 0x41 michael@0: // adds r0, r0, r3 michael@0: // pop {r11} ; (ldr r11, [sp], #4) michael@0: // pop {r10} ; (ldr r10, [sp], #4) michael@0: // pop {r9} ; (ldr r9, [sp], #4) michael@0: // pop {r8} ; (ldr r8, [sp], #4) michael@0: // pop {r7} ; (ldr r7, [sp], #4) michael@0: // pop {r6} ; (ldr r6, [sp], #4) michael@0: // pop {r5} ; (ldr r5, [sp], #4) michael@0: // pop {r4} ; (ldr r4, [sp], #4) michael@0: // mov pc, lr michael@0: // callable as a normal function, returns 444 michael@0: michael@0: JSC::ARMRegisters::RegisterID rreg = JSC::ARMRegisters::r0; michael@0: michael@0: am->push(JSC::ARMRegisters::r4); michael@0: am->push(JSC::ARMRegisters::r5); michael@0: am->push(JSC::ARMRegisters::r6); michael@0: am->push(JSC::ARMRegisters::r7); michael@0: am->push(JSC::ARMRegisters::r8); michael@0: am->push(JSC::ARMRegisters::r9); michael@0: am->push(JSC::ARMRegisters::r10); michael@0: am->push(JSC::ARMRegisters::r11); michael@0: michael@0: am->xorPtr(rreg,rreg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(123), rreg); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(321), rreg); michael@0: michael@0: am->pop(JSC::ARMRegisters::r11); michael@0: am->pop(JSC::ARMRegisters::r10); michael@0: am->pop(JSC::ARMRegisters::r9); michael@0: am->pop(JSC::ARMRegisters::r8); michael@0: am->pop(JSC::ARMRegisters::r7); michael@0: am->pop(JSC::ARMRegisters::r6); michael@0: am->pop(JSC::ARMRegisters::r5); michael@0: am->pop(JSC::ARMRegisters::r4); michael@0: michael@0: am->ret(); michael@0: #endif michael@0: michael@0: // prepare a link buffer, into which we can copy the completed insns michael@0: JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); michael@0: michael@0: // intermediate step .. get the pool suited for the size of code in 'am' michael@0: //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); michael@0: JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); michael@0: michael@0: // constructor for LinkBuffer asks ep to allocate r-x memory, michael@0: // then copies it there. michael@0: JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); michael@0: michael@0: // now fix up any branches/calls michael@0: //JSC::FunctionPtr target = JSC::FunctionPtr::FunctionPtr( &cube ); michael@0: michael@0: // finalize michael@0: JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); michael@0: michael@0: // cr now holds a pointer to the final runnable code. michael@0: void* entry = cr.m_code.executableAddress(); michael@0: michael@0: printf("disas %p %p\n", michael@0: entry, (char*)entry + cr.m_size); michael@0: pre_run(); michael@0: michael@0: // call the function michael@0: unsigned long (*fn)(void) = (unsigned long (*)())entry; michael@0: unsigned long result = fn(); michael@0: michael@0: printf("\n"); michael@0: printf("value computed is %lu (expected 444)\n", result); michael@0: printf("\n"); michael@0: michael@0: delete eal; michael@0: delete am; michael@0: } michael@0: michael@0: michael@0: ///////////////////////////////////////////////////////////////// michael@0: //// test5 (call in, out, repatch) michael@0: michael@0: // a function which we will call from the JIT generated code michael@0: unsigned long cube ( unsigned long x ) { return x * x * x; } michael@0: unsigned long square ( unsigned long x ) { return x * x; } michael@0: michael@0: void test5 ( void ) michael@0: { michael@0: printf("\n--------- Test 5 (call in, out, repatch) ---------\n\n" ); michael@0: michael@0: // Create new assembler michael@0: JSC::MacroAssembler* am = new JSC::MacroAssembler(); michael@0: JSC::MacroAssembler::Call cl; michael@0: ptrdiff_t offset_of_call_insn; michael@0: michael@0: #if defined(ARCH_amd64) michael@0: // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function michael@0: // and then call a non-JIT-generated helper from within michael@0: // this code michael@0: // push %rbp michael@0: // mov %rsp,%rbp michael@0: // push %rbx michael@0: // push %r12 michael@0: // push %r13 michael@0: // push %r14 michael@0: // push %r15 michael@0: // mov $0x9,%edi michael@0: // mov $0x40187e,%r11 michael@0: // callq *%r11 michael@0: // pop %r15 michael@0: // pop %r14 michael@0: // pop %r13 michael@0: // pop %r12 michael@0: // pop %rbx michael@0: // mov %rbp,%rsp michael@0: // pop %rbp michael@0: // retq michael@0: JSC::MacroAssembler::Label startOfFnLbl(am); michael@0: am->push(JSC::X86Registers::ebp); michael@0: am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); michael@0: am->push(JSC::X86Registers::ebx); michael@0: am->push(JSC::X86Registers::r12); michael@0: am->push(JSC::X86Registers::r13); michael@0: am->push(JSC::X86Registers::r14); michael@0: am->push(JSC::X86Registers::r15); michael@0: michael@0: // let's compute cube(9). Move $9 to the first arg reg. michael@0: am->move(JSC::MacroAssembler::Imm32(9), JSC::X86Registers::edi); michael@0: cl = am->JSC::MacroAssembler::call(); michael@0: michael@0: // result is now in %rax. Leave it ther and just return. michael@0: michael@0: am->pop(JSC::X86Registers::r15); michael@0: am->pop(JSC::X86Registers::r14); michael@0: am->pop(JSC::X86Registers::r13); michael@0: am->pop(JSC::X86Registers::r12); michael@0: am->pop(JSC::X86Registers::ebx); michael@0: am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); michael@0: am->pop(JSC::X86Registers::ebp); michael@0: am->ret(); michael@0: michael@0: offset_of_call_insn michael@0: = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl); michael@0: if (0) printf("XXXXXXXX offset = %lu\n", offset_of_call_insn); michael@0: #endif michael@0: michael@0: #if defined(ARCH_x86) michael@0: // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function michael@0: // and then call a non-JIT-generated helper from within michael@0: // this code michael@0: // push %ebp michael@0: // mov %esp,%ebp michael@0: // push %ebx michael@0: // push %esi michael@0: // push %edi michael@0: // push $0x9 michael@0: // call 0x80490e9 <_Z4cubem> michael@0: // add $0x4,%esp michael@0: // pop %edi michael@0: // pop %esi michael@0: // pop %ebx michael@0: // mov %ebp,%esp michael@0: // pop %ebp michael@0: // ret michael@0: JSC::MacroAssembler::Label startOfFnLbl(am); michael@0: am->push(JSC::X86Registers::ebp); michael@0: am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); michael@0: am->push(JSC::X86Registers::ebx); michael@0: am->push(JSC::X86Registers::esi); michael@0: am->push(JSC::X86Registers::edi); michael@0: michael@0: // let's compute cube(9). Push $9 on the stack. michael@0: am->push(JSC::MacroAssembler::Imm32(9)); michael@0: cl = am->JSC::MacroAssembler::call(); michael@0: am->addPtr(JSC::MacroAssembler::Imm32(4), JSC::X86Registers::esp); michael@0: // result is now in %eax. Leave it there and just return. michael@0: michael@0: am->pop(JSC::X86Registers::edi); michael@0: am->pop(JSC::X86Registers::esi); michael@0: am->pop(JSC::X86Registers::ebx); michael@0: am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); michael@0: am->pop(JSC::X86Registers::ebp); michael@0: am->ret(); michael@0: michael@0: offset_of_call_insn michael@0: = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl); michael@0: if (0) printf("XXXXXXXX offset = %lu\n", michael@0: (unsigned long)offset_of_call_insn); michael@0: #endif michael@0: michael@0: #if defined(ARCH_arm) michael@0: // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function michael@0: // push {r4} ; (str r4, [sp, #-4]!) michael@0: // push {r5} ; (str r5, [sp, #-4]!) michael@0: // push {r6} ; (str r6, [sp, #-4]!) michael@0: // push {r7} ; (str r7, [sp, #-4]!) michael@0: // push {r8} ; (str r8, [sp, #-4]!) michael@0: // push {r9} ; (str r9, [sp, #-4]!) michael@0: // push {r10} ; (str r10, [sp, #-4]!) michael@0: // push {r11} ; (str r11, [sp, #-4]!) michael@0: // eors r0, r0, r0 michael@0: // adds r0, r0, #123 ; 0x7b michael@0: // mov r3, #256 ; 0x100 michael@0: // orr r3, r3, #65 ; 0x41 michael@0: // adds r0, r0, r3 michael@0: // pop {r11} ; (ldr r11, [sp], #4) michael@0: // pop {r10} ; (ldr r10, [sp], #4) michael@0: // pop {r9} ; (ldr r9, [sp], #4) michael@0: // pop {r8} ; (ldr r8, [sp], #4) michael@0: // pop {r7} ; (ldr r7, [sp], #4) michael@0: // pop {r6} ; (ldr r6, [sp], #4) michael@0: // pop {r5} ; (ldr r5, [sp], #4) michael@0: // pop {r4} ; (ldr r4, [sp], #4) michael@0: // mov pc, lr michael@0: // callable as a normal function, returns 444 michael@0: JSC::MacroAssembler::Label startOfFnLbl(am); michael@0: am->push(JSC::ARMRegisters::r4); michael@0: am->push(JSC::ARMRegisters::r5); michael@0: am->push(JSC::ARMRegisters::r6); michael@0: am->push(JSC::ARMRegisters::r7); michael@0: am->push(JSC::ARMRegisters::r8); michael@0: am->push(JSC::ARMRegisters::r9); michael@0: am->push(JSC::ARMRegisters::r10); michael@0: am->push(JSC::ARMRegisters::r11); michael@0: am->push(JSC::ARMRegisters::lr); michael@0: michael@0: // let's compute cube(9). Get $9 into r0. michael@0: am->move(JSC::MacroAssembler::Imm32(9), JSC::ARMRegisters::r0); michael@0: cl = am->JSC::MacroAssembler::call(); michael@0: // result is now in r0. Leave it there and just return. michael@0: michael@0: am->pop(JSC::ARMRegisters::lr); michael@0: am->pop(JSC::ARMRegisters::r11); michael@0: am->pop(JSC::ARMRegisters::r10); michael@0: am->pop(JSC::ARMRegisters::r9); michael@0: am->pop(JSC::ARMRegisters::r8); michael@0: am->pop(JSC::ARMRegisters::r7); michael@0: am->pop(JSC::ARMRegisters::r6); michael@0: am->pop(JSC::ARMRegisters::r5); michael@0: am->pop(JSC::ARMRegisters::r4); michael@0: am->ret(); michael@0: michael@0: offset_of_call_insn michael@0: = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl); michael@0: if (0) printf("XXXXXXXX offset = %lu\n", michael@0: (unsigned long)offset_of_call_insn); michael@0: #endif michael@0: michael@0: // prepare a link buffer, into which we can copy the completed insns michael@0: JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); michael@0: michael@0: // intermediate step .. get the pool suited for the size of code in 'am' michael@0: //WTF::PassRefPtr ep = eal->poolForSize( am->size() ); michael@0: JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); michael@0: michael@0: // constructor for LinkBuffer asks ep to allocate r-x memory, michael@0: // then copies it there. michael@0: JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); michael@0: michael@0: // now fix up any branches/calls michael@0: JSC::FunctionPtr target = JSC::FunctionPtr::FunctionPtr( &cube ); michael@0: patchBuffer.link(cl, target); michael@0: michael@0: JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); michael@0: michael@0: // cr now holds a pointer to the final runnable code. michael@0: void* entry = cr.m_code.executableAddress(); michael@0: michael@0: printf("disas %p %p\n", michael@0: entry, (char*)entry + cr.m_size); michael@0: michael@0: michael@0: pre_run(); michael@0: michael@0: printf("\n"); michael@0: michael@0: unsigned long (*fn)() = (unsigned long(*)())entry; michael@0: unsigned long result = fn(); michael@0: michael@0: printf("value computed is %lu (expected 729)\n", result); michael@0: printf("\n"); michael@0: michael@0: // now repatch the call in the JITted code to go elsewhere michael@0: JSC::JITCode jc = JSC::JITCode::JITCode(entry, cr.m_size); michael@0: JSC::CodeBlock cb = JSC::CodeBlock::CodeBlock(jc); michael@0: michael@0: // the address of the call insn, that we want to prod michael@0: JSC::MacroAssemblerCodePtr cp michael@0: = JSC::MacroAssemblerCodePtr( ((char*)entry) + offset_of_call_insn ); michael@0: michael@0: JSC::RepatchBuffer repatchBuffer(&cb); michael@0: repatchBuffer.relink( JSC::CodeLocationCall(cp), michael@0: JSC::FunctionPtr::FunctionPtr( &square )); michael@0: michael@0: result = fn(); michael@0: printf("value computed is %lu (expected 81)\n", result); michael@0: printf("\n\n"); michael@0: michael@0: delete eal; michael@0: delete am; michael@0: } michael@0: michael@0: ///////////////////////////////////////////////////////////////// michael@0: michael@0: int main ( void ) michael@0: { michael@0: #if WTF_COMPILER_GCC michael@0: test1(); michael@0: test2(); michael@0: test3(); michael@0: #endif michael@0: test4(); michael@0: test5(); michael@0: return 0; michael@0: }