On Fri, Jul 13, 2012 at 9:12 AM, Michael Goffioul
<address@hidden> wrote:
I also tried the complex test:
a = b = 1+1i;
for ii=1:5
a = a + b;
endfor
unfortunately it generates a segmentation fault (works fine without JIT). If the goal is to enforce calling convention, then I suggest you use the appropriate modifiers instead of extern "C". If you want I can give it a quick try here.
No luck, still crashing (I replaced all 'extern "C"' in pt-jit.cc with __cdecl equivalent). Debuggin shows it's crashing in octave_jit_cast_complex_any, when trying to access obv. It looks like obv is not a valid pointer, indicating a potential stack corruption.
I'm not sure this is related, but did you know that even with __cdecl, there's an ABI difference between MSVC and GCC when returning aggregate objects larger than 8 bytes (typically returning a double complex object). The object to return is provided through a hidden pointer pushed on the stack, but MSVC assumes the caller pops the hidden argument, while GCC assumes the callee pops it (note: this has been fixed in gcc-4.7.0, which is now compatible with MSVC). Another source of problems is stack-alignment, although I don't whether it's relevant in this case (MSVC aligns the stack on 4 bytes, GCC aligns it on 16 bytes).
I have no idea how the JIT is working, but if binary code is compiled on the fly for functions returning a large aggregate object, maybe the wrong ABI is being used, leading to stack corruption.
I did some more debugging to analyze what's going on and there's something wrong in the assembly code that is calling octave_jit_cast_complex_any. I've attached a screenshot of the disassembled code: function starts at 02CB00E0 and ends at 02CB010E, you can recognize the standard prologue and epilogue of x86.
If you inspect how the stack is constructed before calling octave_jit_cast_complex_any, you can see that:
- 24 bytes are allocated on the stack (02CB00E9, that's 3 double's, let's call them d1, d2 and d3)
- EAX is copied at the top of the stack, at this point EAX is the "octave_base_value* obv" argument, so it's basically the first argument of the function; it occupies the location d1 on the stack
- after octave_jit_cast_complex_any call, results are pulled from the stack at location d2 and d3
This does not correspond to the ABI MSVC is using. Instead of pushing a hidden pointer on the top of the stack (as it should do), it allocates the memory for the returned complex value on the stack and *after* the regular function arguments. Of course, when octave_jit_cast_complex_any tries to access obv, it points to invalid memory and crashes.
What kind of ABI is this?
Michael.