1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/src/assembler/TestMain.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,933 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 + 1.9 +// A short test program with which to experiment with the assembler. 1.10 + 1.11 +//satisfies CPU(X86_64) 1.12 +//#define WTF_CPU_X86_64 1.13 + 1.14 +// satisfies ENABLE(ASSEMBLER) 1.15 +#define ENABLE_ASSEMBLER 1 1.16 + 1.17 +// satisfies ENABLE(JIT) 1.18 +#define ENABLE_JIT 1 1.19 + 1.20 +#define USE_SYSTEM_MALLOC 1 1.21 +// leads to FORCE_SYSTEM_MALLOC in wtf/FastMalloc.cpp 1.22 + 1.23 +#include "assembler/jit/ExecutableAllocator.h" 1.24 +#include "assembler/assembler/LinkBuffer.h" 1.25 +#include "assembler/assembler/CodeLocation.h" 1.26 +#include "assembler/assembler/RepatchBuffer.h" 1.27 + 1.28 +#include "assembler/assembler/MacroAssembler.h" 1.29 + 1.30 +#include <stdio.h> 1.31 + 1.32 +///////////////////////////////////////////////////////////////// 1.33 +// Temporary scaffolding for selecting the arch 1.34 +#undef ARCH_x86 1.35 +#undef ARCH_amd64 1.36 +#undef ARCH_arm 1.37 + 1.38 +#if defined(__APPLE__) && defined(__i386__) 1.39 +# define ARCH_x86 1 1.40 +#elif defined(__APPLE__) && defined(__x86_64__) 1.41 +# define ARCH_amd64 1 1.42 +#elif defined(__linux__) && defined(__i386__) 1.43 +# define ARCH_x86 1 1.44 +#elif defined(__linux__) && defined(__x86_64__) 1.45 +# define ARCH_amd64 1 1.46 +#elif defined(__linux__) && defined(__arm__) 1.47 +# define ARCH_arm 1 1.48 +#elif defined(_MSC_VER) && defined(_M_IX86) 1.49 +# define ARCH_x86 1 1.50 +#endif 1.51 +///////////////////////////////////////////////////////////////// 1.52 + 1.53 +// just somewhere convenient to put a breakpoint, before 1.54 +// running gdb 1.55 +#if WTF_COMPILER_GCC 1.56 +__attribute__((noinline)) 1.57 +#endif 1.58 +void pre_run ( void ) { } 1.59 + 1.60 +///////////////////////////////////////////////////////////////// 1.61 +//// test1 (simple straight line code) 1.62 +#if WTF_COMPILER_GCC 1.63 + 1.64 +void test1 ( void ) 1.65 +{ 1.66 + printf("\n------------ Test 1 (straight line code) ------------\n\n" ); 1.67 + 1.68 + // Create new assembler 1.69 + JSC::MacroAssembler* am = new JSC::MacroAssembler(); 1.70 + 1.71 +#if defined(ARCH_amd64) 1.72 + JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15; 1.73 + // dump some instructions into it 1.74 + // xor %r15,%r15 1.75 + // add $0x7b,%r15 1.76 + // add $0x141,%r15 1.77 + // retq 1.78 + am->xorPtr(areg,areg); 1.79 + am->addPtr(JSC::MacroAssembler::Imm32(123), areg); 1.80 + am->addPtr(JSC::MacroAssembler::Imm32(321), areg); 1.81 + am->ret(); 1.82 +#endif 1.83 + 1.84 +#if defined(ARCH_x86) 1.85 + JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi; 1.86 + // dump some instructions into it 1.87 + // xor %edi,%edi 1.88 + // add $0x7b,%edi 1.89 + // add $0x141,%edi 1.90 + // ret 1.91 + am->xorPtr(areg,areg); 1.92 + am->addPtr(JSC::MacroAssembler::Imm32(123), areg); 1.93 + am->addPtr(JSC::MacroAssembler::Imm32(321), areg); 1.94 + am->ret(); 1.95 +#endif 1.96 + 1.97 +#if defined(ARCH_arm) 1.98 + JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8; 1.99 + // eors r8, r8, r8 1.100 + // adds r8, r8, #123 ; 0x7b 1.101 + // mov r3, #256 ; 0x100 1.102 + // orr r3, r3, #65 ; 0x41 1.103 + // adds r8, r8, r3 1.104 + // mov pc, lr 1.105 + am->xorPtr(areg,areg); 1.106 + am->addPtr(JSC::MacroAssembler::Imm32(123), areg); 1.107 + am->addPtr(JSC::MacroAssembler::Imm32(321), areg); 1.108 + am->ret(); 1.109 +#endif 1.110 + 1.111 + // prepare a link buffer, into which we can copy the completed insns 1.112 + JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); 1.113 + 1.114 + // intermediate step .. get the pool suited for the size of code in 'am' 1.115 + //WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() ); 1.116 + JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); 1.117 + 1.118 + // constructor for LinkBuffer asks ep to allocate r-x memory, 1.119 + // then copies it there. 1.120 + JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); 1.121 + 1.122 + // finalize 1.123 + JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); 1.124 + 1.125 + // cr now holds a pointer to the final runnable code. 1.126 + void* entry = cr.m_code.executableAddress(); 1.127 + 1.128 + printf("disas %p %p\n", 1.129 + entry, (char*)entry + cr.m_size); 1.130 + pre_run(); 1.131 + 1.132 + unsigned long result = 0x55555555; 1.133 + 1.134 +#if defined(ARCH_amd64) 1.135 + // call the generated piece of code. It puts its result in r15. 1.136 + __asm__ __volatile__( 1.137 + "callq *%1" "\n\t" 1.138 + "movq %%r15, %0" "\n" 1.139 + :/*out*/ "=r"(result) 1.140 + :/*in*/ "r"(entry) 1.141 + :/*trash*/ "r15","cc" 1.142 + ); 1.143 +#endif 1.144 +#if defined(ARCH_x86) 1.145 + // call the generated piece of code. It puts its result in edi. 1.146 + __asm__ __volatile__( 1.147 + "calll *%1" "\n\t" 1.148 + "movl %%edi, %0" "\n" 1.149 + :/*out*/ "=r"(result) 1.150 + :/*in*/ "r"(entry) 1.151 + :/*trash*/ "edi","cc" 1.152 + ); 1.153 +#endif 1.154 +#if defined(ARCH_arm) 1.155 + // call the generated piece of code. It puts its result in r8. 1.156 + __asm__ __volatile__( 1.157 + "blx %1" "\n\t" 1.158 + "mov %0, %%r8" "\n" 1.159 + :/*out*/ "=r"(result) 1.160 + :/*in*/ "r"(entry) 1.161 + :/*trash*/ "r8","cc" 1.162 + ); 1.163 +#endif 1.164 + 1.165 + printf("\n"); 1.166 + printf("value computed is %lu (expected 444)\n", result); 1.167 + printf("\n"); 1.168 + 1.169 + delete eal; 1.170 + delete am; 1.171 +} 1.172 + 1.173 +#endif /* WTF_COMPILER_GCC */ 1.174 + 1.175 +///////////////////////////////////////////////////////////////// 1.176 +//// test2 (a simple counting-down loop) 1.177 +#if WTF_COMPILER_GCC 1.178 + 1.179 +void test2 ( void ) 1.180 +{ 1.181 + printf("\n------------ Test 2 (mini loop) ------------\n\n" ); 1.182 + 1.183 + // Create new assembler 1.184 + JSC::MacroAssembler* am = new JSC::MacroAssembler(); 1.185 + 1.186 +#if defined(ARCH_amd64) 1.187 + JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15; 1.188 + // xor %r15,%r15 1.189 + // add $0x7b,%r15 1.190 + // add $0x141,%r15 1.191 + // sub $0x1,%r15 1.192 + // mov $0x0,%r11 1.193 + // cmp %r11,%r15 1.194 + // jne 0x7ff6d3e6a00e 1.195 + // retq 1.196 + // so r15 always winds up being zero 1.197 + am->xorPtr(areg,areg); 1.198 + am->addPtr(JSC::MacroAssembler::Imm32(123), areg); 1.199 + am->addPtr(JSC::MacroAssembler::Imm32(321), areg); 1.200 + 1.201 + JSC::MacroAssembler::Label loopHeadLabel(am); 1.202 + am->subPtr(JSC::MacroAssembler::Imm32(1), areg); 1.203 + 1.204 + JSC::MacroAssembler::Jump j 1.205 + = am->branchPtr(JSC::MacroAssembler::NotEqual, 1.206 + areg, JSC::MacroAssembler::ImmPtr(0)); 1.207 + j.linkTo(loopHeadLabel, am); 1.208 + 1.209 + am->ret(); 1.210 +#endif 1.211 + 1.212 +#if defined(ARCH_x86) 1.213 + JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi; 1.214 + // xor %edi,%edi 1.215 + // add $0x7b,%edi 1.216 + // add $0x141,%edi 1.217 + // sub $0x1,%edi 1.218 + // test %edi,%edi 1.219 + // jne 0xf7f9700b 1.220 + // ret 1.221 + // so edi always winds up being zero 1.222 + am->xorPtr(areg,areg); 1.223 + am->addPtr(JSC::MacroAssembler::Imm32(123), areg); 1.224 + am->addPtr(JSC::MacroAssembler::Imm32(321), areg); 1.225 + 1.226 + JSC::MacroAssembler::Label loopHeadLabel(am); 1.227 + am->subPtr(JSC::MacroAssembler::Imm32(1), areg); 1.228 + 1.229 + JSC::MacroAssembler::Jump j 1.230 + = am->branchPtr(JSC::MacroAssembler::NotEqual, 1.231 + areg, JSC::MacroAssembler::ImmPtr(0)); 1.232 + j.linkTo(loopHeadLabel, am); 1.233 + 1.234 + am->ret(); 1.235 +#endif 1.236 + 1.237 +#if defined(ARCH_arm) 1.238 + JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8; 1.239 + // eors r8, r8, r8 1.240 + // adds r8, r8, #123 ; 0x7b 1.241 + // mov r3, #256 ; 0x100 1.242 + // orr r3, r3, #65 ; 0x41 1.243 + // adds r8, r8, r3 1.244 + // subs r8, r8, #1 ; 0x1 1.245 + // ldr r3, [pc, #8] ; 0x40026028 1.246 + // cmp r8, r3 1.247 + // bne 0x40026014 1.248 + // mov pc, lr 1.249 + // andeq r0, r0, r0 // DATA (0) 1.250 + // andeq r0, r0, r4, lsl r0 // DATA (?? what's this for?) 1.251 + // so r8 always winds up being zero 1.252 + am->xorPtr(areg,areg); 1.253 + am->addPtr(JSC::MacroAssembler::Imm32(123), areg); 1.254 + am->addPtr(JSC::MacroAssembler::Imm32(321), areg); 1.255 + 1.256 + JSC::MacroAssembler::Label loopHeadLabel(am); 1.257 + am->subPtr(JSC::MacroAssembler::Imm32(1), areg); 1.258 + 1.259 + JSC::MacroAssembler::Jump j 1.260 + = am->branchPtr(JSC::MacroAssembler::NotEqual, 1.261 + areg, JSC::MacroAssembler::ImmPtr(0)); 1.262 + j.linkTo(loopHeadLabel, am); 1.263 + 1.264 + am->ret(); 1.265 +#endif 1.266 + 1.267 + // prepare a link buffer, into which we can copy the completed insns 1.268 + JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); 1.269 + 1.270 + // intermediate step .. get the pool suited for the size of code in 'am' 1.271 + //WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() ); 1.272 + JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); 1.273 + 1.274 + // constructor for LinkBuffer asks ep to allocate r-x memory, 1.275 + // then copies it there. 1.276 + JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); 1.277 + 1.278 + // finalize 1.279 + JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); 1.280 + 1.281 + // cr now holds a pointer to the final runnable code. 1.282 + void* entry = cr.m_code.executableAddress(); 1.283 + 1.284 + printf("disas %p %p\n", 1.285 + entry, (char*)entry + cr.m_size); 1.286 + pre_run(); 1.287 + 1.288 + unsigned long result = 0x55555555; 1.289 + 1.290 +#if defined(ARCH_amd64) 1.291 + // call the generated piece of code. It puts its result in r15. 1.292 + __asm__ __volatile__( 1.293 + "callq *%1" "\n\t" 1.294 + "movq %%r15, %0" "\n" 1.295 + :/*out*/ "=r"(result) 1.296 + :/*in*/ "r"(entry) 1.297 + :/*trash*/ "r15","cc" 1.298 + ); 1.299 +#endif 1.300 +#if defined(ARCH_x86) 1.301 + // call the generated piece of code. It puts its result in edi. 1.302 + __asm__ __volatile__( 1.303 + "calll *%1" "\n\t" 1.304 + "movl %%edi, %0" "\n" 1.305 + :/*out*/ "=r"(result) 1.306 + :/*in*/ "r"(entry) 1.307 + :/*trash*/ "edi","cc" 1.308 + ); 1.309 +#endif 1.310 +#if defined(ARCH_arm) 1.311 + // call the generated piece of code. It puts its result in r8. 1.312 + __asm__ __volatile__( 1.313 + "blx %1" "\n\t" 1.314 + "mov %0, %%r8" "\n" 1.315 + :/*out*/ "=r"(result) 1.316 + :/*in*/ "r"(entry) 1.317 + :/*trash*/ "r8","cc" 1.318 + ); 1.319 +#endif 1.320 + 1.321 + printf("\n"); 1.322 + printf("value computed is %lu (expected 0)\n", result); 1.323 + printf("\n"); 1.324 + 1.325 + delete eal; 1.326 + delete am; 1.327 +} 1.328 + 1.329 +#endif /* WTF_COMPILER_GCC */ 1.330 + 1.331 +///////////////////////////////////////////////////////////////// 1.332 +//// test3 (if-then-else) 1.333 +#if WTF_COMPILER_GCC 1.334 + 1.335 +void test3 ( void ) 1.336 +{ 1.337 + printf("\n------------ Test 3 (if-then-else) ------------\n\n" ); 1.338 + 1.339 + // Create new assembler 1.340 + JSC::MacroAssembler* am = new JSC::MacroAssembler(); 1.341 + 1.342 +#if defined(ARCH_amd64) 1.343 + JSC::X86Registers::RegisterID areg = JSC::X86Registers::r15; 1.344 + // mov $0x64,%r15d 1.345 + // mov $0x0,%r11 1.346 + // cmp %r11,%r15 1.347 + // jne 0x7ff6d3e6a024 1.348 + // mov $0x40,%r15d 1.349 + // jmpq 0x7ff6d3e6a02a 1.350 + // mov $0x4,%r15d 1.351 + // retq 1.352 + // so r15 ends up being 4 1.353 + 1.354 + // put a value in reg 1.355 + am->move(JSC::MacroAssembler::Imm32(100), areg); 1.356 + 1.357 + // test, and conditionally jump to 'else' branch 1.358 + JSC::MacroAssembler::Jump jToElse 1.359 + = am->branchPtr(JSC::MacroAssembler::NotEqual, 1.360 + areg, JSC::MacroAssembler::ImmPtr(0)); 1.361 + 1.362 + // 'then' branch 1.363 + am->move(JSC::MacroAssembler::Imm32(64), areg); 1.364 + JSC::MacroAssembler::Jump jToAfter 1.365 + = am->jump(); 1.366 + 1.367 + // 'else' branch 1.368 + JSC::MacroAssembler::Label elseLbl(am); 1.369 + am->move(JSC::MacroAssembler::Imm32(4), areg); 1.370 + 1.371 + // after 1.372 + JSC::MacroAssembler::Label afterLbl(am); 1.373 + 1.374 + am->ret(); 1.375 +#endif 1.376 + 1.377 +#if defined(ARCH_x86) 1.378 + JSC::X86Registers::RegisterID areg = JSC::X86Registers::edi; 1.379 + // mov $0x64,%edi 1.380 + // test %edi,%edi 1.381 + // jne 0xf7f22017 1.382 + // mov $0x40,%edi 1.383 + // jmp 0xf7f2201c 1.384 + // mov $0x4,%edi 1.385 + // ret 1.386 + // so edi ends up being 4 1.387 + 1.388 + // put a value in reg 1.389 + am->move(JSC::MacroAssembler::Imm32(100), areg); 1.390 + 1.391 + // test, and conditionally jump to 'else' branch 1.392 + JSC::MacroAssembler::Jump jToElse 1.393 + = am->branchPtr(JSC::MacroAssembler::NotEqual, 1.394 + areg, JSC::MacroAssembler::ImmPtr(0)); 1.395 + 1.396 + // 'then' branch 1.397 + am->move(JSC::MacroAssembler::Imm32(64), areg); 1.398 + JSC::MacroAssembler::Jump jToAfter 1.399 + = am->jump(); 1.400 + 1.401 + // 'else' branch 1.402 + JSC::MacroAssembler::Label elseLbl(am); 1.403 + am->move(JSC::MacroAssembler::Imm32(4), areg); 1.404 + 1.405 + // after 1.406 + JSC::MacroAssembler::Label afterLbl(am); 1.407 + 1.408 + am->ret(); 1.409 +#endif 1.410 + 1.411 +#if defined(ARCH_arm) 1.412 + JSC::ARMRegisters::RegisterID areg = JSC::ARMRegisters::r8; 1.413 + // mov r8, #100 ; 0x64 1.414 + // ldr r3, [pc, #20] ; 0x40026020 1.415 + // cmp r8, r3 1.416 + // bne 0x40026018 1.417 + // mov r8, #64 ; 0x40 1.418 + // b 0x4002601c 1.419 + // mov r8, #4 ; 0x4 1.420 + // mov pc, lr 1.421 + // andeq r0, r0, r0 // DATA 1.422 + // andeq r0, r0, r8, lsl r0 // DATA 1.423 + // andeq r0, r0, r12, lsl r0 // DATA 1.424 + // ldr r3, [r3, -r3] // DATA 1.425 + // so r8 ends up being 4 1.426 + 1.427 + // put a value in reg 1.428 + am->move(JSC::MacroAssembler::Imm32(100), areg); 1.429 + 1.430 + // test, and conditionally jump to 'else' branch 1.431 + JSC::MacroAssembler::Jump jToElse 1.432 + = am->branchPtr(JSC::MacroAssembler::NotEqual, 1.433 + areg, JSC::MacroAssembler::ImmPtr(0)); 1.434 + 1.435 + // 'then' branch 1.436 + am->move(JSC::MacroAssembler::Imm32(64), areg); 1.437 + JSC::MacroAssembler::Jump jToAfter 1.438 + = am->jump(); 1.439 + 1.440 + // 'else' branch 1.441 + JSC::MacroAssembler::Label elseLbl(am); 1.442 + am->move(JSC::MacroAssembler::Imm32(4), areg); 1.443 + 1.444 + // after 1.445 + JSC::MacroAssembler::Label afterLbl(am); 1.446 + 1.447 + am->ret(); 1.448 +#endif 1.449 + 1.450 + // set branch targets appropriately 1.451 + jToElse.linkTo(elseLbl, am); 1.452 + jToAfter.linkTo(afterLbl, am); 1.453 + 1.454 + // prepare a link buffer, into which we can copy the completed insns 1.455 + JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); 1.456 + 1.457 + // intermediate step .. get the pool suited for the size of code in 'am' 1.458 + //WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() ); 1.459 + JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); 1.460 + 1.461 + // constructor for LinkBuffer asks ep to allocate r-x memory, 1.462 + // then copies it there. 1.463 + JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); 1.464 + 1.465 + // finalize 1.466 + JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); 1.467 + 1.468 + // cr now holds a pointer to the final runnable code. 1.469 + void* entry = cr.m_code.executableAddress(); 1.470 + 1.471 + printf("disas %p %p\n", 1.472 + entry, (char*)entry + cr.m_size); 1.473 + pre_run(); 1.474 + 1.475 + unsigned long result = 0x55555555; 1.476 + 1.477 +#if defined(ARCH_amd64) 1.478 + // call the generated piece of code. It puts its result in r15. 1.479 + __asm__ __volatile__( 1.480 + "callq *%1" "\n\t" 1.481 + "movq %%r15, %0" "\n" 1.482 + :/*out*/ "=r"(result) 1.483 + :/*in*/ "r"(entry) 1.484 + :/*trash*/ "r15","cc" 1.485 + ); 1.486 +#endif 1.487 +#if defined(ARCH_x86) 1.488 + // call the generated piece of code. It puts its result in edi. 1.489 + __asm__ __volatile__( 1.490 + "calll *%1" "\n\t" 1.491 + "movl %%edi, %0" "\n" 1.492 + :/*out*/ "=r"(result) 1.493 + :/*in*/ "r"(entry) 1.494 + :/*trash*/ "edi","cc" 1.495 + ); 1.496 +#endif 1.497 +#if defined(ARCH_arm) 1.498 + // call the generated piece of code. It puts its result in r8. 1.499 + __asm__ __volatile__( 1.500 + "blx %1" "\n\t" 1.501 + "mov %0, %%r8" "\n" 1.502 + :/*out*/ "=r"(result) 1.503 + :/*in*/ "r"(entry) 1.504 + :/*trash*/ "r8","cc" 1.505 + ); 1.506 +#endif 1.507 + 1.508 + printf("\n"); 1.509 + printf("value computed is %lu (expected 4)\n", result); 1.510 + printf("\n"); 1.511 + 1.512 + delete eal; 1.513 + delete am; 1.514 +} 1.515 + 1.516 +#endif /* WTF_COMPILER_GCC */ 1.517 + 1.518 +///////////////////////////////////////////////////////////////// 1.519 +//// test4 (callable function) 1.520 + 1.521 +void test4 ( void ) 1.522 +{ 1.523 + printf("\n------------ Test 4 (callable fn) ------------\n\n" ); 1.524 + 1.525 + // Create new assembler 1.526 + JSC::MacroAssembler* am = new JSC::MacroAssembler(); 1.527 + 1.528 +#if defined(ARCH_amd64) 1.529 + // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function 1.530 + // push %rbp 1.531 + // mov %rsp,%rbp 1.532 + // push %rbx 1.533 + // push %r12 1.534 + // push %r13 1.535 + // push %r14 1.536 + // push %r15 1.537 + // xor %rax,%rax 1.538 + // add $0x7b,%rax 1.539 + // add $0x141,%rax 1.540 + // pop %r15 1.541 + // pop %r14 1.542 + // pop %r13 1.543 + // pop %r12 1.544 + // pop %rbx 1.545 + // mov %rbp,%rsp 1.546 + // pop %rbp 1.547 + // retq 1.548 + // callable as a normal function, returns 444 1.549 + 1.550 + JSC::X86Registers::RegisterID rreg = JSC::X86Registers::eax; 1.551 + am->push(JSC::X86Registers::ebp); 1.552 + am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); 1.553 + am->push(JSC::X86Registers::ebx); 1.554 + am->push(JSC::X86Registers::r12); 1.555 + am->push(JSC::X86Registers::r13); 1.556 + am->push(JSC::X86Registers::r14); 1.557 + am->push(JSC::X86Registers::r15); 1.558 + 1.559 + am->xorPtr(rreg,rreg); 1.560 + am->addPtr(JSC::MacroAssembler::Imm32(123), rreg); 1.561 + am->addPtr(JSC::MacroAssembler::Imm32(321), rreg); 1.562 + 1.563 + am->pop(JSC::X86Registers::r15); 1.564 + am->pop(JSC::X86Registers::r14); 1.565 + am->pop(JSC::X86Registers::r13); 1.566 + am->pop(JSC::X86Registers::r12); 1.567 + am->pop(JSC::X86Registers::ebx); 1.568 + am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); 1.569 + am->pop(JSC::X86Registers::ebp); 1.570 + am->ret(); 1.571 +#endif 1.572 + 1.573 +#if defined(ARCH_x86) 1.574 + // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function 1.575 + // push %ebp 1.576 + // mov %esp,%ebp 1.577 + // push %ebx 1.578 + // push %esi 1.579 + // push %edi 1.580 + // xor %eax,%eax 1.581 + // add $0x7b,%eax 1.582 + // add $0x141,%eax 1.583 + // pop %edi 1.584 + // pop %esi 1.585 + // pop %ebx 1.586 + // mov %ebp,%esp 1.587 + // pop %ebp 1.588 + // ret 1.589 + // callable as a normal function, returns 444 1.590 + 1.591 + JSC::X86Registers::RegisterID rreg = JSC::X86Registers::eax; 1.592 + 1.593 + am->push(JSC::X86Registers::ebp); 1.594 + am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); 1.595 + am->push(JSC::X86Registers::ebx); 1.596 + am->push(JSC::X86Registers::esi); 1.597 + am->push(JSC::X86Registers::edi); 1.598 + 1.599 + am->xorPtr(rreg,rreg); 1.600 + am->addPtr(JSC::MacroAssembler::Imm32(123), rreg); 1.601 + am->addPtr(JSC::MacroAssembler::Imm32(321), rreg); 1.602 + 1.603 + am->pop(JSC::X86Registers::edi); 1.604 + am->pop(JSC::X86Registers::esi); 1.605 + am->pop(JSC::X86Registers::ebx); 1.606 + am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); 1.607 + am->pop(JSC::X86Registers::ebp); 1.608 + am->ret(); 1.609 +#endif 1.610 + 1.611 +#if defined(ARCH_arm) 1.612 + // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function 1.613 + // push {r4} ; (str r4, [sp, #-4]!) 1.614 + // push {r5} ; (str r5, [sp, #-4]!) 1.615 + // push {r6} ; (str r6, [sp, #-4]!) 1.616 + // push {r7} ; (str r7, [sp, #-4]!) 1.617 + // push {r8} ; (str r8, [sp, #-4]!) 1.618 + // push {r9} ; (str r9, [sp, #-4]!) 1.619 + // push {r10} ; (str r10, [sp, #-4]!) 1.620 + // push {r11} ; (str r11, [sp, #-4]!) 1.621 + // eors r0, r0, r0 1.622 + // adds r0, r0, #123 ; 0x7b 1.623 + // mov r3, #256 ; 0x100 1.624 + // orr r3, r3, #65 ; 0x41 1.625 + // adds r0, r0, r3 1.626 + // pop {r11} ; (ldr r11, [sp], #4) 1.627 + // pop {r10} ; (ldr r10, [sp], #4) 1.628 + // pop {r9} ; (ldr r9, [sp], #4) 1.629 + // pop {r8} ; (ldr r8, [sp], #4) 1.630 + // pop {r7} ; (ldr r7, [sp], #4) 1.631 + // pop {r6} ; (ldr r6, [sp], #4) 1.632 + // pop {r5} ; (ldr r5, [sp], #4) 1.633 + // pop {r4} ; (ldr r4, [sp], #4) 1.634 + // mov pc, lr 1.635 + // callable as a normal function, returns 444 1.636 + 1.637 + JSC::ARMRegisters::RegisterID rreg = JSC::ARMRegisters::r0; 1.638 + 1.639 + am->push(JSC::ARMRegisters::r4); 1.640 + am->push(JSC::ARMRegisters::r5); 1.641 + am->push(JSC::ARMRegisters::r6); 1.642 + am->push(JSC::ARMRegisters::r7); 1.643 + am->push(JSC::ARMRegisters::r8); 1.644 + am->push(JSC::ARMRegisters::r9); 1.645 + am->push(JSC::ARMRegisters::r10); 1.646 + am->push(JSC::ARMRegisters::r11); 1.647 + 1.648 + am->xorPtr(rreg,rreg); 1.649 + am->addPtr(JSC::MacroAssembler::Imm32(123), rreg); 1.650 + am->addPtr(JSC::MacroAssembler::Imm32(321), rreg); 1.651 + 1.652 + am->pop(JSC::ARMRegisters::r11); 1.653 + am->pop(JSC::ARMRegisters::r10); 1.654 + am->pop(JSC::ARMRegisters::r9); 1.655 + am->pop(JSC::ARMRegisters::r8); 1.656 + am->pop(JSC::ARMRegisters::r7); 1.657 + am->pop(JSC::ARMRegisters::r6); 1.658 + am->pop(JSC::ARMRegisters::r5); 1.659 + am->pop(JSC::ARMRegisters::r4); 1.660 + 1.661 + am->ret(); 1.662 +#endif 1.663 + 1.664 + // prepare a link buffer, into which we can copy the completed insns 1.665 + JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); 1.666 + 1.667 + // intermediate step .. get the pool suited for the size of code in 'am' 1.668 + //WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() ); 1.669 + JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); 1.670 + 1.671 + // constructor for LinkBuffer asks ep to allocate r-x memory, 1.672 + // then copies it there. 1.673 + JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); 1.674 + 1.675 + // now fix up any branches/calls 1.676 + //JSC::FunctionPtr target = JSC::FunctionPtr::FunctionPtr( &cube ); 1.677 + 1.678 + // finalize 1.679 + JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); 1.680 + 1.681 + // cr now holds a pointer to the final runnable code. 1.682 + void* entry = cr.m_code.executableAddress(); 1.683 + 1.684 + printf("disas %p %p\n", 1.685 + entry, (char*)entry + cr.m_size); 1.686 + pre_run(); 1.687 + 1.688 + // call the function 1.689 + unsigned long (*fn)(void) = (unsigned long (*)())entry; 1.690 + unsigned long result = fn(); 1.691 + 1.692 + printf("\n"); 1.693 + printf("value computed is %lu (expected 444)\n", result); 1.694 + printf("\n"); 1.695 + 1.696 + delete eal; 1.697 + delete am; 1.698 +} 1.699 + 1.700 + 1.701 +///////////////////////////////////////////////////////////////// 1.702 +//// test5 (call in, out, repatch) 1.703 + 1.704 +// a function which we will call from the JIT generated code 1.705 +unsigned long cube ( unsigned long x ) { return x * x * x; } 1.706 +unsigned long square ( unsigned long x ) { return x * x; } 1.707 + 1.708 +void test5 ( void ) 1.709 +{ 1.710 + printf("\n--------- Test 5 (call in, out, repatch) ---------\n\n" ); 1.711 + 1.712 + // Create new assembler 1.713 + JSC::MacroAssembler* am = new JSC::MacroAssembler(); 1.714 + JSC::MacroAssembler::Call cl; 1.715 + ptrdiff_t offset_of_call_insn; 1.716 + 1.717 +#if defined(ARCH_amd64) 1.718 + // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function 1.719 + // and then call a non-JIT-generated helper from within 1.720 + // this code 1.721 + // push %rbp 1.722 + // mov %rsp,%rbp 1.723 + // push %rbx 1.724 + // push %r12 1.725 + // push %r13 1.726 + // push %r14 1.727 + // push %r15 1.728 + // mov $0x9,%edi 1.729 + // mov $0x40187e,%r11 1.730 + // callq *%r11 1.731 + // pop %r15 1.732 + // pop %r14 1.733 + // pop %r13 1.734 + // pop %r12 1.735 + // pop %rbx 1.736 + // mov %rbp,%rsp 1.737 + // pop %rbp 1.738 + // retq 1.739 + JSC::MacroAssembler::Label startOfFnLbl(am); 1.740 + am->push(JSC::X86Registers::ebp); 1.741 + am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); 1.742 + am->push(JSC::X86Registers::ebx); 1.743 + am->push(JSC::X86Registers::r12); 1.744 + am->push(JSC::X86Registers::r13); 1.745 + am->push(JSC::X86Registers::r14); 1.746 + am->push(JSC::X86Registers::r15); 1.747 + 1.748 + // let's compute cube(9). Move $9 to the first arg reg. 1.749 + am->move(JSC::MacroAssembler::Imm32(9), JSC::X86Registers::edi); 1.750 + cl = am->JSC::MacroAssembler::call(); 1.751 + 1.752 + // result is now in %rax. Leave it ther and just return. 1.753 + 1.754 + am->pop(JSC::X86Registers::r15); 1.755 + am->pop(JSC::X86Registers::r14); 1.756 + am->pop(JSC::X86Registers::r13); 1.757 + am->pop(JSC::X86Registers::r12); 1.758 + am->pop(JSC::X86Registers::ebx); 1.759 + am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); 1.760 + am->pop(JSC::X86Registers::ebp); 1.761 + am->ret(); 1.762 + 1.763 + offset_of_call_insn 1.764 + = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl); 1.765 + if (0) printf("XXXXXXXX offset = %lu\n", offset_of_call_insn); 1.766 +#endif 1.767 + 1.768 +#if defined(ARCH_x86) 1.769 + // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function 1.770 + // and then call a non-JIT-generated helper from within 1.771 + // this code 1.772 + // push %ebp 1.773 + // mov %esp,%ebp 1.774 + // push %ebx 1.775 + // push %esi 1.776 + // push %edi 1.777 + // push $0x9 1.778 + // call 0x80490e9 <_Z4cubem> 1.779 + // add $0x4,%esp 1.780 + // pop %edi 1.781 + // pop %esi 1.782 + // pop %ebx 1.783 + // mov %ebp,%esp 1.784 + // pop %ebp 1.785 + // ret 1.786 + JSC::MacroAssembler::Label startOfFnLbl(am); 1.787 + am->push(JSC::X86Registers::ebp); 1.788 + am->move(JSC::X86Registers::esp, JSC::X86Registers::ebp); 1.789 + am->push(JSC::X86Registers::ebx); 1.790 + am->push(JSC::X86Registers::esi); 1.791 + am->push(JSC::X86Registers::edi); 1.792 + 1.793 + // let's compute cube(9). Push $9 on the stack. 1.794 + am->push(JSC::MacroAssembler::Imm32(9)); 1.795 + cl = am->JSC::MacroAssembler::call(); 1.796 + am->addPtr(JSC::MacroAssembler::Imm32(4), JSC::X86Registers::esp); 1.797 + // result is now in %eax. Leave it there and just return. 1.798 + 1.799 + am->pop(JSC::X86Registers::edi); 1.800 + am->pop(JSC::X86Registers::esi); 1.801 + am->pop(JSC::X86Registers::ebx); 1.802 + am->move(JSC::X86Registers::ebp, JSC::X86Registers::esp); 1.803 + am->pop(JSC::X86Registers::ebp); 1.804 + am->ret(); 1.805 + 1.806 + offset_of_call_insn 1.807 + = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl); 1.808 + if (0) printf("XXXXXXXX offset = %lu\n", 1.809 + (unsigned long)offset_of_call_insn); 1.810 +#endif 1.811 + 1.812 +#if defined(ARCH_arm) 1.813 + // ADD FN PROLOGUE/EPILOGUE so as to make a mini-function 1.814 + // push {r4} ; (str r4, [sp, #-4]!) 1.815 + // push {r5} ; (str r5, [sp, #-4]!) 1.816 + // push {r6} ; (str r6, [sp, #-4]!) 1.817 + // push {r7} ; (str r7, [sp, #-4]!) 1.818 + // push {r8} ; (str r8, [sp, #-4]!) 1.819 + // push {r9} ; (str r9, [sp, #-4]!) 1.820 + // push {r10} ; (str r10, [sp, #-4]!) 1.821 + // push {r11} ; (str r11, [sp, #-4]!) 1.822 + // eors r0, r0, r0 1.823 + // adds r0, r0, #123 ; 0x7b 1.824 + // mov r3, #256 ; 0x100 1.825 + // orr r3, r3, #65 ; 0x41 1.826 + // adds r0, r0, r3 1.827 + // pop {r11} ; (ldr r11, [sp], #4) 1.828 + // pop {r10} ; (ldr r10, [sp], #4) 1.829 + // pop {r9} ; (ldr r9, [sp], #4) 1.830 + // pop {r8} ; (ldr r8, [sp], #4) 1.831 + // pop {r7} ; (ldr r7, [sp], #4) 1.832 + // pop {r6} ; (ldr r6, [sp], #4) 1.833 + // pop {r5} ; (ldr r5, [sp], #4) 1.834 + // pop {r4} ; (ldr r4, [sp], #4) 1.835 + // mov pc, lr 1.836 + // callable as a normal function, returns 444 1.837 + JSC::MacroAssembler::Label startOfFnLbl(am); 1.838 + am->push(JSC::ARMRegisters::r4); 1.839 + am->push(JSC::ARMRegisters::r5); 1.840 + am->push(JSC::ARMRegisters::r6); 1.841 + am->push(JSC::ARMRegisters::r7); 1.842 + am->push(JSC::ARMRegisters::r8); 1.843 + am->push(JSC::ARMRegisters::r9); 1.844 + am->push(JSC::ARMRegisters::r10); 1.845 + am->push(JSC::ARMRegisters::r11); 1.846 + am->push(JSC::ARMRegisters::lr); 1.847 + 1.848 + // let's compute cube(9). Get $9 into r0. 1.849 + am->move(JSC::MacroAssembler::Imm32(9), JSC::ARMRegisters::r0); 1.850 + cl = am->JSC::MacroAssembler::call(); 1.851 + // result is now in r0. Leave it there and just return. 1.852 + 1.853 + am->pop(JSC::ARMRegisters::lr); 1.854 + am->pop(JSC::ARMRegisters::r11); 1.855 + am->pop(JSC::ARMRegisters::r10); 1.856 + am->pop(JSC::ARMRegisters::r9); 1.857 + am->pop(JSC::ARMRegisters::r8); 1.858 + am->pop(JSC::ARMRegisters::r7); 1.859 + am->pop(JSC::ARMRegisters::r6); 1.860 + am->pop(JSC::ARMRegisters::r5); 1.861 + am->pop(JSC::ARMRegisters::r4); 1.862 + am->ret(); 1.863 + 1.864 + offset_of_call_insn 1.865 + = am->JSC::MacroAssembler::differenceBetween(startOfFnLbl, cl); 1.866 + if (0) printf("XXXXXXXX offset = %lu\n", 1.867 + (unsigned long)offset_of_call_insn); 1.868 +#endif 1.869 + 1.870 + // prepare a link buffer, into which we can copy the completed insns 1.871 + JSC::ExecutableAllocator* eal = new JSC::ExecutableAllocator(); 1.872 + 1.873 + // intermediate step .. get the pool suited for the size of code in 'am' 1.874 + //WTF::PassRefPtr<JSC::ExecutablePool> ep = eal->poolForSize( am->size() ); 1.875 + JSC::ExecutablePool* ep = eal->poolForSize( am->size() ); 1.876 + 1.877 + // constructor for LinkBuffer asks ep to allocate r-x memory, 1.878 + // then copies it there. 1.879 + JSC::LinkBuffer patchBuffer(am, ep, JSC::METHOD_CODE); 1.880 + 1.881 + // now fix up any branches/calls 1.882 + JSC::FunctionPtr target = JSC::FunctionPtr::FunctionPtr( &cube ); 1.883 + patchBuffer.link(cl, target); 1.884 + 1.885 + JSC::MacroAssemblerCodeRef cr = patchBuffer.finalizeCode(); 1.886 + 1.887 + // cr now holds a pointer to the final runnable code. 1.888 + void* entry = cr.m_code.executableAddress(); 1.889 + 1.890 + printf("disas %p %p\n", 1.891 + entry, (char*)entry + cr.m_size); 1.892 + 1.893 + 1.894 + pre_run(); 1.895 + 1.896 + printf("\n"); 1.897 + 1.898 + unsigned long (*fn)() = (unsigned long(*)())entry; 1.899 + unsigned long result = fn(); 1.900 + 1.901 + printf("value computed is %lu (expected 729)\n", result); 1.902 + printf("\n"); 1.903 + 1.904 + // now repatch the call in the JITted code to go elsewhere 1.905 + JSC::JITCode jc = JSC::JITCode::JITCode(entry, cr.m_size); 1.906 + JSC::CodeBlock cb = JSC::CodeBlock::CodeBlock(jc); 1.907 + 1.908 + // the address of the call insn, that we want to prod 1.909 + JSC::MacroAssemblerCodePtr cp 1.910 + = JSC::MacroAssemblerCodePtr( ((char*)entry) + offset_of_call_insn ); 1.911 + 1.912 + JSC::RepatchBuffer repatchBuffer(&cb); 1.913 + repatchBuffer.relink( JSC::CodeLocationCall(cp), 1.914 + JSC::FunctionPtr::FunctionPtr( &square )); 1.915 + 1.916 + result = fn(); 1.917 + printf("value computed is %lu (expected 81)\n", result); 1.918 + printf("\n\n"); 1.919 + 1.920 + delete eal; 1.921 + delete am; 1.922 +} 1.923 + 1.924 +///////////////////////////////////////////////////////////////// 1.925 + 1.926 +int main ( void ) 1.927 +{ 1.928 +#if WTF_COMPILER_GCC 1.929 + test1(); 1.930 + test2(); 1.931 + test3(); 1.932 +#endif 1.933 + test4(); 1.934 + test5(); 1.935 + return 0; 1.936 +}