[llvm-commits] [llvm] r57846 - in /llvm/trunk: include/llvm/System/Memory.h lib/System/Unix/Memory.inc lib/System/Win32/Memory.inc lib/Target/ARM/ARMJITInfo.cpp

Evan Cheng evan.cheng at apple.com
Mon Oct 20 22:42:46 PDT 2008


On Oct 20, 2008, at 2:39 PM, Jim Grosbach wrote:

Thanks Jim. Good job getting this working. It's a big step.

>
> +    // Save caller saved registers since they may contain stuff
> +    // for the real target function right now. We have to act as if  
> this
> +    // whole compilation callback doesn't exist as far as the  
> caller is
> +    // concerned, so we can't just preserve the callee saved regs.
> +    "push {r0, r1, r2, r3, lr}\n"

Is this code Mac OS X specific? Is "push" accepted by all the  
assemblers?

>
> +    // The LR contains the address of the stub function on entry.
> +    // pass it as the argument to the C part of the callback
> +    "mov  r0, lr\n"
> +    "sub  sp, sp, #4\n"
> +    // Call the C portion of the callback
> +    "bl   " ASMPREFIX "ARMCompilationCallbackC\n"
> +    "add  sp, sp, #4\n"
> +    // Restoring the LR to the return address of the function that  
> invoked
> +    // the stub and de-allocating the stack space for it requires  
> us to
> +    // swap the two saved LR values on the stack, as they're  
> backwards
> +    // for what we need since the pop instruction has a pre- 
> determined
> +    // order for the registers.
> +    //      +--------+
> +    //   0  | LR     | Original return address
> +    //      +--------+
> +    //   1  | LR     | Stub address (start of stub)
> +    // 2-5  | R3..R0 | Saved registers (we need to preserve all regs)
> +    //      +--------+
> +    //
> +    //      We need to exchange the values in slots 0 and 1 so we can
> +    //      return to the address in slot 1 with the address in  
> slot 0
> +    //      restored to the LR.
> +    "ldr  r0, [sp,#20]\n"
> +    "ldr  r1, [sp,#16]\n"
> +    "str  r1, [sp,#20]\n"
> +    "str  r0, [sp,#16]\n"
> +    // Return to the (newly modified) stub to invoke the real  
> function.
> +    // The above twiddling of the saved return addresses allows us to
> +    // deallocate everything, including the LR the stub saved, all  
> in one
> +    // pop instruction.
> +    "pop  {r0, r1, r2, r3, lr, pc}\n"
>       );
> #else  // Not an ARM host
>   void ARMCompilationCallback() {
> @@ -85,31 +97,37 @@
> #endif
> }
>
> -/// ARMCompilationCallbackC - This is the target-specific function  
> invoked by the
> -/// function stub when we did not know the real target of a call.   
> This function
> -/// must locate the start of the stub or call site and pass it into  
> the JIT
> -/// compiler function.
> -extern "C" void ARMCompilationCallbackC(intptr_t *StackPtr,  
> intptr_t RetAddr) {
> -  intptr_t *RetAddrLoc = &StackPtr[-1];
> -
> -  assert(*RetAddrLoc == RetAddr &&
> -         "Could not find return address on the stack!");
> -#if 0
> -  DOUT << "In callback! Addr=" << (void*)RetAddr
> -       << " FP=" << (void*)StackPtr
> -       << ": Resolving call to function: "
> -       << TheVM->getFunctionReferencedName((void*)RetAddr) << "\n";
> -#endif
> -  intptr_t Addr = RetAddr - 4;
> -
> -  intptr_t NewVal = (intptr_t)JITCompilerFunction((void*)Addr);
> +/// ARMCompilationCallbackC - This is the target-specific function  
> invoked
> +/// by the function stub when we did not know the real target of a  
> call.
> +/// This function must locate the start of the stub or call site  
> and pass
> +/// it into the JIT compiler function.
> +extern "C" void ARMCompilationCallbackC(intptr_t StubAddr) {
> +  // Get the address of the compiled code for this function.
> +  intptr_t NewVal = (intptr_t)JITCompilerFunction((void*)StubAddr);
>
>   // Rewrite the call target... so that we don't end up here every  
> time we
> -  // execute the call.
> -  *(intptr_t *)Addr = NewVal;
> -
> -  // Change the return address to reexecute the branch and link  
> instruction...
> -  *RetAddrLoc -= 12;
> +  // execute the call. We're replacing the first two instructions  
> of the
> +  // stub with:
> +  //   ldr pc, [pc,#-4]
> +  //   <addr>
> +#if defined(__APPLE__)
> +  bool ok = sys::Memory::setRangeWritable ((void*)StubAddr, 8);

This works. But it's probably somewhat inefficient. Do you have any  
ideas for improving the efficiency? I have some ideas, we should talk  
about it.

Thanks,

Evan

>
> +  if (!ok)
> +    {
> +      cerr << "ERROR: Unable to mark stub writable\n";
> +      abort();
> +    }
> +#endif
> +  *(intptr_t *)StubAddr = 0xe51ff004;
> +  *(intptr_t *)(StubAddr+4) = NewVal;
> +#if defined(__APPLE__)
> +  ok = sys::Memory::setRangeExecutable ((void*)StubAddr, 8);
> +  if (!ok)
> +    {
> +      cerr << "ERROR: Unable to mark stub executable\n";
> +      abort();
> +    }
> +#endif
> }
>
> TargetJITInfo::LazyResolverFn
> @@ -127,17 +145,27 @@
>     // branch to the corresponding function addr
>     // the stub is 8-byte size and 4-aligned
>     MCE.startFunctionStub(F, 8, 4);
> -    MCE.emitWordLE(0xE51FF004); // LDR PC, [PC,#-4]
> +    MCE.emitWordLE(0xe51ff004); // LDR PC, [PC,#-4]
>     MCE.emitWordLE(addr);       // addr of function
>   } else {
> -    // branch and link to the corresponding function addr
> -    // the stub is 20-byte size and 4-aligned
> -    MCE.startFunctionStub(F, 20, 4);
> -    MCE.emitWordLE(0xE92D4800); // STMFD SP!, [R11, LR]
> -    MCE.emitWordLE(0xE28FE004); // ADD LR, PC, #4
> -    MCE.emitWordLE(0xE51FF004); // LDR PC, [PC,#-4]
> -    MCE.emitWordLE(addr);       // addr of function
> -    MCE.emitWordLE(0xE8BD8800); // LDMFD SP!, [R11, PC]
> +    // The compilation callback will overwrite the first two words  
> of this
> +    // stub with indirect branch instructions targeting the  
> compiled code.
> +    // This stub sets the return address to restart the stub, so that
> +    // the new branch will be invoked when we come back.
> +    //
> +    // branch and link to the compilation callback.
> +    // the stub is 16-byte size and 4-byte aligned.
> +    MCE.startFunctionStub(F, 16, 4);
> +    // Save LR so the callback can determine which stub called it.
> +    // The compilation callback is responsible for popping this prior
> +    // to returning.
> +    MCE.emitWordLE(0xe92d4000); // PUSH {lr}
> +    // Set the return address to go back to the start of this stub
> +    MCE.emitWordLE(0xe24fe00c); // SUB LR, PC, #12
> +    // Invoke the compilation callback
> +    MCE.emitWordLE(0xe51ff004); // LDR PC, [PC,#-4]
> +    // The address of the compilation callback
> +    MCE.emitWordLE((intptr_t)ARMCompilationCallback);
>   }
>
>   return MCE.finishFunctionStub(F);
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits




More information about the llvm-commits mailing list