2 // A short test program with which to experiment with the assembler.
4 //satisfies CPU(X86_64)
5 //#define WTF_CPU_X86_64
7 // satisfies ENABLE(ASSEMBLER)
8 #define ENABLE_ASSEMBLER 1
10 // satisfies ENABLE(JIT)
13 #define USE_SYSTEM_MALLOC 1
14 // leads to FORCE_SYSTEM_MALLOC in wtf/FastMalloc.cpp
16 #include <jit/ExecutableAllocator.h>
17 #include <assembler/LinkBuffer.h>
18 #include <assembler/CodeLocation.h>
19 #include <assembler/RepatchBuffer.h>
21 #include <assembler/MacroAssembler.h>
25 /////////////////////////////////////////////////////////////////
26 // Temporary scaffolding for selecting the arch
31 #if defined(__APPLE__) && defined(__i386__)
33 #elif defined(__APPLE__) && defined(__x86_64__)
35 #elif defined(__linux__) && defined(__i386__)
37 #elif defined(__linux__) && defined(__x86_64__)
39 #elif defined(__linux__) && defined(__arm__)
41 #elif defined(_MSC_VER) && defined(_M_IX86)
44 /////////////////////////////////////////////////////////////////
46 // just somewhere convenient to put a breakpoint, before
49 __attribute__((noinline))
51 void pre_run ( void ) { }
53 /////////////////////////////////////////////////////////////////
54 //// test1 (simple straight line code)
59 printf("\n------------ Test 1 (straight line code) ------------\n\n" );
61 // Create new assembler
62 JSC::MacroAssembler* am = new JSC::MacroAssembler();
64 #if defined(ARCH_amd64)
65 JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15;
66 // dump some instructions into it
71 am->xorPtr(areg,areg);
72 am->addPtr(JSC::MacroAssembler::Imm32(123), areg);
73 am->addPtr(JSC::MacroAssembler::Imm32(321), areg);
78 JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi;
79 // dump some instructions into it
84 am->xorPtr(areg,areg);
85 am->addPtr(JSC::MacroAssembler::Imm32(123), areg);
86 am->addPtr(JSC::MacroAssembler::Imm32(321), areg);
91 JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8;
93 // adds r8, r8, #123 ; 0x7b
94 // mov r3, #256 ; 0x100
95 // orr r3, r3, #65 ; 0x41
98 am->xorPtr(areg,areg);
99 am->addPtr(JSC::MacroAssembler::Imm32(123), areg);
100 am->addPtr(JSC::MacroAssembler::Imm32(321), areg);
104 // prepare a link buffer, into which we can copy the completed insns
105 JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator();
107 // intermediate step .. get the pool suited for the size of code in 'am'
108 //WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() );
109 JSC::ExecutablePool* ep = eal->poolForSize( am->size() );
111 // constructor for LinkBuffer asks ep to allocate r-x memory,
112 // then copies it there.
113 JSC::LinkBuffer patchBuffer(am, ep);
116 JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode();
118 // cr now holds a pointer to the final runnable code.
119 void* entry = cr.m_code.executableAddress();
121 printf("disas %p %p\n",
122 entry, (char*)entry + cr.m_size);
125 unsigned long result = 0x55555555;
127 #if defined(ARCH_amd64)
128 // call the generated piece of code. It puts its result in r15.
129 __asm__ __volatile__(
131 "movq %%r15, %0" "\n"
132 :/*out*/ "=r"(result)
134 :/*trash*/ "r15","cc"
137 #if defined(ARCH_x86)
138 // call the generated piece of code. It puts its result in edi.
139 __asm__ __volatile__(
141 "movl %%edi, %0" "\n"
142 :/*out*/ "=r"(result)
144 :/*trash*/ "edi","cc"
147 #if defined(ARCH_arm)
148 // call the generated piece of code. It puts its result in r8.
149 __asm__ __volatile__(
152 :/*out*/ "=r"(result)
159 printf("value computed is %lu (expected 444)\n", result);
166 #endif /* WTF_COMPILER_GCC */
168 /////////////////////////////////////////////////////////////////
169 //// test2 (a simple counting-down loop)
174 printf("\n------------ Test 2 (mini loop) ------------\n\n" );
176 // Create new assembler
177 JSC::MacroAssembler* am = new JSC::MacroAssembler();
179 #if defined(ARCH_amd64)
180 JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15;
187 // jne 0x7ff6d3e6a00e
189 // so r15 always winds up being zero
190 am->xorPtr(areg,areg);
191 am->addPtr(JSC::MacroAssembler::Imm32(123), areg);
192 am->addPtr(JSC::MacroAssembler::Imm32(321), areg);
194 JSC::MacroAssembler::Label loopHeadLabel(am);
195 am->subPtr(JSC::MacroAssembler::Imm32(1), areg);
197 JSC::MacroAssembler::Jump j
198 = am->branchPtr(JSC::MacroAssembler::NotEqual,
199 areg, JSC::MacroAssembler::ImmPtr(0));
200 j.linkTo(loopHeadLabel, am);
205 #if defined(ARCH_x86)
206 JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi;
214 // so edi always winds up being zero
215 am->xorPtr(areg,areg);
216 am->addPtr(JSC::MacroAssembler::Imm32(123), areg);
217 am->addPtr(JSC::MacroAssembler::Imm32(321), areg);
219 JSC::MacroAssembler::Label loopHeadLabel(am);
220 am->subPtr(JSC::MacroAssembler::Imm32(1), areg);
222 JSC::MacroAssembler::Jump j
223 = am->branchPtr(JSC::MacroAssembler::NotEqual,
224 areg, JSC::MacroAssembler::ImmPtr(0));
225 j.linkTo(loopHeadLabel, am);
230 #if defined(ARCH_arm)
231 JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8;
233 // adds r8, r8, #123 ; 0x7b
234 // mov r3, #256 ; 0x100
235 // orr r3, r3, #65 ; 0x41
237 // subs r8, r8, #1 ; 0x1
238 // ldr r3, [pc, #8] ; 0x40026028
242 // andeq r0, r0, r0 // DATA (0)
243 // andeq r0, r0, r4, lsl r0 // DATA (?? what's this for?)
244 // so r8 always winds up being zero
245 am->xorPtr(areg,areg);
246 am->addPtr(JSC::MacroAssembler::Imm32(123), areg);
247 am->addPtr(JSC::MacroAssembler::Imm32(321), areg);
249 JSC::MacroAssembler::Label loopHeadLabel(am);
250 am->subPtr(JSC::MacroAssembler::Imm32(1), areg);
252 JSC::MacroAssembler::Jump j
253 = am->branchPtr(JSC::MacroAssembler::NotEqual,
254 areg, JSC::MacroAssembler::ImmPtr(0));
255 j.linkTo(loopHeadLabel, am);
260 // prepare a link buffer, into which we can copy the completed insns
261 JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator();
263 // intermediate step .. get the pool suited for the size of code in 'am'
264 //WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() );
265 JSC::ExecutablePool* ep = eal->poolForSize( am->size() );
267 // constructor for LinkBuffer asks ep to allocate r-x memory,
268 // then copies it there.
269 JSC::LinkBuffer patchBuffer(am, ep);
272 JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode();
274 // cr now holds a pointer to the final runnable code.
275 void* entry = cr.m_code.executableAddress();
277 printf("disas %p %p\n",
278 entry, (char*)entry + cr.m_size);
281 unsigned long result = 0x55555555;
283 #if defined(ARCH_amd64)
284 // call the generated piece of code. It puts its result in r15.
285 __asm__ __volatile__(
287 "movq %%r15, %0" "\n"
288 :/*out*/ "=r"(result)
290 :/*trash*/ "r15","cc"
293 #if defined(ARCH_x86)
294 // call the generated piece of code. It puts its result in edi.
295 __asm__ __volatile__(
297 "movl %%edi, %0" "\n"
298 :/*out*/ "=r"(result)
300 :/*trash*/ "edi","cc"
303 #if defined(ARCH_arm)
304 // call the generated piece of code. It puts its result in r8.
305 __asm__ __volatile__(
308 :/*out*/ "=r"(result)
315 printf("value computed is %lu (expected 0)\n", result);
322 #endif /* WTF_COMPILER_GCC */
324 /////////////////////////////////////////////////////////////////
325 //// test3 (if-then-else)
330 printf("\n------------ Test 3 (if-then-else) ------------\n\n" );
332 // Create new assembler
333 JSC::MacroAssembler* am = new JSC::MacroAssembler();
335 #if defined(ARCH_amd64)
336 JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15;
340 // jne 0x7ff6d3e6a024
342 // jmpq 0x7ff6d3e6a02a
345 // so r15 ends up being 4
347 // put a value in reg
348 am->move(JSC::MacroAssembler::Imm32(100), areg);
350 // test, and conditionally jump to 'else' branch
351 JSC::MacroAssembler::Jump jToElse
352 = am->branchPtr(JSC::MacroAssembler::NotEqual,
353 areg, JSC::MacroAssembler::ImmPtr(0));
356 am->move(JSC::MacroAssembler::Imm32(64), areg);
357 JSC::MacroAssembler::Jump jToAfter
361 JSC::MacroAssembler::Label elseLbl(am);
362 am->move(JSC::MacroAssembler::Imm32(4), areg);
365 JSC::MacroAssembler::Label afterLbl(am);
370 #if defined(ARCH_x86)
371 JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi;
379 // so edi ends up being 4
381 // put a value in reg
382 am->move(JSC::MacroAssembler::Imm32(100), areg);
384 // test, and conditionally jump to 'else' branch
385 JSC::MacroAssembler::Jump jToElse
386 = am->branchPtr(JSC::MacroAssembler::NotEqual,
387 areg, JSC::MacroAssembler::ImmPtr(0));
390 am->move(JSC::MacroAssembler::Imm32(64), areg);
391 JSC::MacroAssembler::Jump jToAfter
395 JSC::MacroAssembler::Label elseLbl(am);
396 am->move(JSC::MacroAssembler::Imm32(4), areg);
399 JSC::MacroAssembler::Label afterLbl(am);
404 #if defined(ARCH_arm)
405 JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8;
406 // mov r8, #100 ; 0x64
407 // ldr r3, [pc, #20] ; 0x40026020
410 // mov r8, #64 ; 0x40
414 // andeq r0, r0, r0 // DATA
415 // andeq r0, r0, r8, lsl r0 // DATA
416 // andeq r0, r0, r12, lsl r0 // DATA
417 // ldr r3, [r3, -r3] // DATA
418 // so r8 ends up being 4
420 // put a value in reg
421 am->move(JSC::MacroAssembler::Imm32(100), areg);
423 // test, and conditionally jump to 'else' branch
424 JSC::MacroAssembler::Jump jToElse
425 = am->branchPtr(JSC::MacroAssembler::NotEqual,
426 areg, JSC::MacroAssembler::ImmPtr(0));
429 am->move(JSC::MacroAssembler::Imm32(64), areg);
430 JSC::MacroAssembler::Jump jToAfter
434 JSC::MacroAssembler::Label elseLbl(am);
435 am->move(JSC::MacroAssembler::Imm32(4), areg);
438 JSC::MacroAssembler::Label afterLbl(am);
443 // set branch targets appropriately
444 jToElse.linkTo(elseLbl, am);
445 jToAfter.linkTo(afterLbl, am);
447 // prepare a link buffer, into which we can copy the completed insns
448 JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator();
450 // intermediate step .. get the pool suited for the size of code in 'am'
451 //WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() );
452 JSC::ExecutablePool* ep = eal->poolForSize( am->size() );
454 // constructor for LinkBuffer asks ep to allocate r-x memory,
455 // then copies it there.
456 JSC::LinkBuffer patchBuffer(am, ep);
459 JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode();
461 // cr now holds a pointer to the final runnable code.
462 void* entry = cr.m_code.executableAddress();
464 printf("disas %p %p\n",
465 entry, (char*)entry + cr.m_size);
468 unsigned long result = 0x55555555;
470 #if defined(ARCH_amd64)
471 // call the generated piece of code. It puts its result in r15.
472 __asm__ __volatile__(
474 "movq %%r15, %0" "\n"
475 :/*out*/ "=r"(result)
477 :/*trash*/ "r15","cc"
480 #if defined(ARCH_x86)
481 // call the generated piece of code. It puts its result in edi.
482 __asm__ __volatile__(
484 "movl %%edi, %0" "\n"
485 :/*out*/ "=r"(result)
487 :/*trash*/ "edi","cc"
490 #if defined(ARCH_arm)
491 // call the generated piece of code. It puts its result in r8.
492 __asm__ __volatile__(
495 :/*out*/ "=r"(result)
502 printf("value computed is %lu (expected 4)\n", result);
509 #endif /* WTF_COMPILER_GCC */
511 /////////////////////////////////////////////////////////////////
512 //// test4 (callable function)
516 printf("\n------------ Test 4 (callable fn) ------------\n\n" );
518 // Create new assembler
519 JSC::MacroAssembler* am = new JSC::MacroAssembler();
521 #if defined(ARCH_amd64)
522 // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function
541 // callable as a normal function, returns 444
543 JSC::X86Registers::RegisterID rreg = JSC::X86Registers::eax;
544 am->push(JSC::X86Registers::ebp);
545 am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp);
546 am->push(JSC::X86Registers::ebx);
547 am->push(JSC::X86Registers::r12);
548 am->push(JSC::X86Registers::r13);
549 am->push(JSC::X86Registers::r14);
550 am->push(JSC::X86Registers::r15);
552 am->xorPtr(rreg,rreg);
553 am->addPtr(JSC::MacroAssembler::Imm32(123), rreg);
554 am->addPtr(JSC::MacroAssembler::Imm32(321), rreg);
556 am->pop(JSC::X86Registers::r15);
557 am->pop(JSC::X86Registers::r14);
558 am->pop(JSC::X86Registers::r13);
559 am->pop(JSC::X86Registers::r12);
560 am->pop(JSC::X86Registers::ebx);
561 am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp);
562 am->pop(JSC::X86Registers::ebp);
566 #if defined(ARCH_x86)
567 // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function
582 // callable as a normal function, returns 444
584 JSC::X86Registers::RegisterID rreg = JSC::X86Registers::eax;
586 am->push(JSC::X86Registers::ebp);
587 am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp);
588 am->push(JSC::X86Registers::ebx);
589 am->push(JSC::X86Registers::esi);
590 am->push(JSC::X86Registers::edi);
592 am->xorPtr(rreg,rreg);
593 am->addPtr(JSC::MacroAssembler::Imm32(123), rreg);
594 am->addPtr(JSC::MacroAssembler::Imm32(321), rreg);
596 am->pop(JSC::X86Registers::edi);
597 am->pop(JSC::X86Registers::esi);
598 am->pop(JSC::X86Registers::ebx);
599 am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp);
600 am->pop(JSC::X86Registers::ebp);
604 #if defined(ARCH_arm)
605 // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function
606 // push {r4} ; (str r4, [sp, #-4]!)
607 // push {r5} ; (str r5, [sp, #-4]!)
608 // push {r6} ; (str r6, [sp, #-4]!)
609 // push {r7} ; (str r7, [sp, #-4]!)
610 // push {r8} ; (str r8, [sp, #-4]!)
611 // push {r9} ; (str r9, [sp, #-4]!)
612 // push {r10} ; (str r10, [sp, #-4]!)
613 // push {r11} ; (str r11, [sp, #-4]!)
615 // adds r0, r0, #123 ; 0x7b
616 // mov r3, #256 ; 0x100
617 // orr r3, r3, #65 ; 0x41
619 // pop {r11} ; (ldr r11, [sp], #4)
620 // pop {r10} ; (ldr r10, [sp], #4)
621 // pop {r9} ; (ldr r9, [sp], #4)
622 // pop {r8} ; (ldr r8, [sp], #4)
623 // pop {r7} ; (ldr r7, [sp], #4)
624 // pop {r6} ; (ldr r6, [sp], #4)
625 // pop {r5} ; (ldr r5, [sp], #4)
626 // pop {r4} ; (ldr r4, [sp], #4)
628 // callable as a normal function, returns 444
630 JSC::ARMRegisters::RegisterID rreg = JSC::ARMRegisters::r0;
632 am->push(JSC::ARMRegisters::r4);
633 am->push(JSC::ARMRegisters::r5);
634 am->push(JSC::ARMRegisters::r6);
635 am->push(JSC::ARMRegisters::r7);
636 am->push(JSC::ARMRegisters::r8);
637 am->push(JSC::ARMRegisters::r9);
638 am->push(JSC::ARMRegisters::r10);
639 am->push(JSC::ARMRegisters::r11);
641 am->xorPtr(rreg,rreg);
642 am->addPtr(JSC::MacroAssembler::Imm32(123), rreg);
643 am->addPtr(JSC::MacroAssembler::Imm32(321), rreg);
645 am->pop(JSC::ARMRegisters::r11);
646 am->pop(JSC::ARMRegisters::r10);
647 am->pop(JSC::ARMRegisters::r9);
648 am->pop(JSC::ARMRegisters::r8);
649 am->pop(JSC::ARMRegisters::r7);
650 am->pop(JSC::ARMRegisters::r6);
651 am->pop(JSC::ARMRegisters::r5);
652 am->pop(JSC::ARMRegisters::r4);
657 // prepare a link buffer, into which we can copy the completed insns
658 JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator();
660 // intermediate step .. get the pool suited for the size of code in 'am'
661 //WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() );
662 JSC::ExecutablePool* ep = eal->poolForSize( am->size() );
664 // constructor for LinkBuffer asks ep to allocate r-x memory,
665 // then copies it there.
666 JSC::LinkBuffer patchBuffer(am, ep);
668 // now fix up any branches/calls
669 //JSC::FunctionPtr target = JSC::FunctionPtr::FunctionPtr( &cube );
672 JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode();
674 // cr now holds a pointer to the final runnable code.
675 void* entry = cr.m_code.executableAddress();
677 printf("disas %p %p\n",
678 entry, (char*)entry + cr.m_size);
682 unsigned long (*fn)(void) = (unsigned long (*)())entry;
683 unsigned long result = fn();
686 printf("value computed is %lu (expected 444)\n", result);
694 /////////////////////////////////////////////////////////////////
695 //// test5 (call in, out, repatch)
697 // a function which we will call from the JIT generated code
698 unsigned long cube ( unsigned long x ) { return x * x * x; }
699 unsigned long square ( unsigned long x ) { return x * x; }
703 printf("\n--------- Test 5 (call in, out, repatch) ---------\n\n" );
705 // Create new assembler
706 JSC::MacroAssembler* am = new JSC::MacroAssembler();
707 JSC::MacroAssembler::Call cl;
708 ptrdiff_t offset_of_call_insn;
710 #if defined(ARCH_amd64)
711 // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function
712 // and then call a non-JIT-generated helper from within
722 // mov $0x40187e,%r11
732 JSC::MacroAssembler::Label startOfFnLbl(am);
733 am->push(JSC::X86Registers::ebp);
734 am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp);
735 am->push(JSC::X86Registers::ebx);
736 am->push(JSC::X86Registers::r12);
737 am->push(JSC::X86Registers::r13);
738 am->push(JSC::X86Registers::r14);
739 am->push(JSC::X86Registers::r15);
741 // let's compute cube(9). Move $9 to the first arg reg.
742 am->move(JSC::MacroAssembler::Imm32(9), JSC::X86Registers::edi);
743 cl = am->JSC::MacroAssembler::call();
745 // result is now in %rax. Leave it ther and just return.
747 am->pop(JSC::X86Registers::r15);
748 am->pop(JSC::X86Registers::r14);
749 am->pop(JSC::X86Registers::r13);
750 am->pop(JSC::X86Registers::r12);
751 am->pop(JSC::X86Registers::ebx);
752 am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp);
753 am->pop(JSC::X86Registers::ebp);
757 = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl);
758 if (0) printf("XXXXXXXX offset = %lu\n", offset_of_call_insn);
761 #if defined(ARCH_x86)
762 // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function
763 // and then call a non-JIT-generated helper from within
771 // call 0x80490e9 <_Z4cubem>
779 JSC::MacroAssembler::Label startOfFnLbl(am);
780 am->push(JSC::X86Registers::ebp);
781 am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp);
782 am->push(JSC::X86Registers::ebx);
783 am->push(JSC::X86Registers::esi);
784 am->push(JSC::X86Registers::edi);
786 // let's compute cube(9). Push $9 on the stack.
787 am->push(JSC::MacroAssembler::Imm32(9));
788 cl = am->JSC::MacroAssembler::call();
789 am->addPtr(JSC::MacroAssembler::Imm32(4), JSC::X86Registers::esp);
790 // result is now in %eax. Leave it there and just return.
792 am->pop(JSC::X86Registers::edi);
793 am->pop(JSC::X86Registers::esi);
794 am->pop(JSC::X86Registers::ebx);
795 am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp);
796 am->pop(JSC::X86Registers::ebp);
800 = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl);
801 if (0) printf("XXXXXXXX offset = %lu\n",
802 (unsigned long)offset_of_call_insn);
805 #if defined(ARCH_arm)
806 // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function
807 // push {r4} ; (str r4, [sp, #-4]!)
808 // push {r5} ; (str r5, [sp, #-4]!)
809 // push {r6} ; (str r6, [sp, #-4]!)
810 // push {r7} ; (str r7, [sp, #-4]!)
811 // push {r8} ; (str r8, [sp, #-4]!)
812 // push {r9} ; (str r9, [sp, #-4]!)
813 // push {r10} ; (str r10, [sp, #-4]!)
814 // push {r11} ; (str r11, [sp, #-4]!)
816 // adds r0, r0, #123 ; 0x7b
817 // mov r3, #256 ; 0x100
818 // orr r3, r3, #65 ; 0x41
820 // pop {r11} ; (ldr r11, [sp], #4)
821 // pop {r10} ; (ldr r10, [sp], #4)
822 // pop {r9} ; (ldr r9, [sp], #4)
823 // pop {r8} ; (ldr r8, [sp], #4)
824 // pop {r7} ; (ldr r7, [sp], #4)
825 // pop {r6} ; (ldr r6, [sp], #4)
826 // pop {r5} ; (ldr r5, [sp], #4)
827 // pop {r4} ; (ldr r4, [sp], #4)
829 // callable as a normal function, returns 444
830 JSC::MacroAssembler::Label startOfFnLbl(am);
831 am->push(JSC::ARMRegisters::r4);
832 am->push(JSC::ARMRegisters::r5);
833 am->push(JSC::ARMRegisters::r6);
834 am->push(JSC::ARMRegisters::r7);
835 am->push(JSC::ARMRegisters::r8);
836 am->push(JSC::ARMRegisters::r9);
837 am->push(JSC::ARMRegisters::r10);
838 am->push(JSC::ARMRegisters::r11);
839 am->push(JSC::ARMRegisters::lr);
841 // let's compute cube(9). Get $9 into r0.
842 am->move(JSC::MacroAssembler::Imm32(9), JSC::ARMRegisters::r0);
843 cl = am->JSC::MacroAssembler::call();
844 // result is now in r0. Leave it there and just return.
846 am->pop(JSC::ARMRegisters::lr);
847 am->pop(JSC::ARMRegisters::r11);
848 am->pop(JSC::ARMRegisters::r10);
849 am->pop(JSC::ARMRegisters::r9);
850 am->pop(JSC::ARMRegisters::r8);
851 am->pop(JSC::ARMRegisters::r7);
852 am->pop(JSC::ARMRegisters::r6);
853 am->pop(JSC::ARMRegisters::r5);
854 am->pop(JSC::ARMRegisters::r4);
858 = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl);
859 if (0) printf("XXXXXXXX offset = %lu\n",
860 (unsigned long)offset_of_call_insn);
863 // prepare a link buffer, into which we can copy the completed insns
864 JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator();
866 // intermediate step .. get the pool suited for the size of code in 'am'
867 //WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() );
868 JSC::ExecutablePool* ep = eal->poolForSize( am->size() );
870 // constructor for LinkBuffer asks ep to allocate r-x memory,
871 // then copies it there.
872 JSC::LinkBuffer patchBuffer(am, ep);
874 // now fix up any branches/calls
875 JSC::FunctionPtr target = JSC::FunctionPtr::FunctionPtr( &cube );
876 patchBuffer.link(cl, target);
878 JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode();
880 // cr now holds a pointer to the final runnable code.
881 void* entry = cr.m_code.executableAddress();
883 printf("disas %p %p\n",
884 entry, (char*)entry + cr.m_size);
891 unsigned long (*fn)() = (unsigned long(*)())entry;
892 unsigned long result = fn();
894 printf("value computed is %lu (expected 729)\n", result);
897 // now repatch the call in the JITted code to go elsewhere
898 JSC::JITCode jc = JSC::JITCode::JITCode(entry, cr.m_size);
899 JSC::CodeBlock cb = JSC::CodeBlock::CodeBlock(jc);
901 // the address of the call insn, that we want to prod
902 JSC::MacroAssemblerCodePtr cp
903 = JSC::MacroAssemblerCodePtr( ((char*)entry) + offset_of_call_insn );
905 JSC::RepatchBuffer repatchBuffer(&cb);
906 repatchBuffer.relink( JSC::CodeLocationCall(cp),
907 JSC::FunctionPtr::FunctionPtr( &square ));
910 printf("value computed is %lu (expected 81)\n", result);
917 /////////////////////////////////////////////////////////////////