<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META content="text/html; charset=utf-8" http-equiv=Content-Type><!-- flashmail style begin -->
<STYLE type=text/css>
body {border-width:0;margin:0}
img {border:0;margin:0;padding:0}
</STYLE>
<BASE target=_blank><!-- flashmail style end -->
<META name=GENERATOR content="MSHTML 11.00.9600.18525"></HEAD>
<BODY 
style="BORDER-LEFT-WIDTH: 0px; FONT-SIZE: 10.5pt; FONT-FAMILY: 微软雅黑; BORDER-RIGHT-WIDTH: 0px; BORDER-BOTTOM-WIDTH: 0px; COLOR: #000000; MARGIN: 12px; LINE-HEIGHT: 1.5; BORDER-TOP-WIDTH: 0px" 
marginheight="0" marginwidth="0">
<DIV> </DIV>
<DIV> </DIV>
<DIV style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; COLOR: #c0c0c0" 
align=left>2016-12-14 
<HR id=SignNameHR 
style="BORDER-TOP: #c0c0c0 1px solid; HEIGHT: 1px; BORDER-RIGHT: 0px; WIDTH: 122px; BORDER-BOTTOM: 0px; BORDER-LEFT: 0px" 
align=left>
<SPAN id=_FlashSignName>MR.WANGYOUCHU</SPAN> </DIV>
<HR 
style="BORDER-TOP: #c0c0c0 1px solid; HEIGHT: 1px; BORDER-RIGHT: 0px; BORDER-BOTTOM: 0px; BORDER-LEFT: 0px">

<BLOCKQUOTE id=ntes-flashmail-quote 
style="FONT-SIZE: 10pt; FONT-FAMILY: Verdana; PADDING-LEFT: 0px; MARGIN-LEFT: 0px">
  <DIV><STRONG>发件人:</STRONG>vm-dev-request@lists.squeakfoundation.org</DIV>
  <DIV><STRONG>发送时间:</STRONG>2016-12-14 06:13</DIV>
  <DIV><STRONG>主题:</STRONG>Vm-dev Digest, Vol 126, Issue 29</DIV>
  <DIV><STRONG>收件人:</STRONG>"vm-dev"<vm-dev@lists.squeakfoundation.org></DIV>
  <DIV><STRONG>抄送:</STRONG></DIV>
  <DIV> </DIV>
  <DIV>
  <DIV>Send Vm-dev mailing list submissions to </DIV>
  <DIV>    vm-dev@lists.squeakfoundation.org </DIV>
  <DIV> </DIV>
  <DIV>To subscribe or unsubscribe via the World Wide Web, visit </DIV>
  <DIV>    http://lists.squeakfoundation.org/mailman/listinfo/vm-dev </DIV>
  <DIV>or, via email, send a message with subject or body 'help' to </DIV>
  <DIV>    vm-dev-request@lists.squeakfoundation.org </DIV>
  <DIV> </DIV>
  <DIV>You can reach the person managing the list at </DIV>
  <DIV>    vm-dev-owner@lists.squeakfoundation.org </DIV>
  <DIV> </DIV>
  <DIV>When replying, please edit your Subject line so it is more specific </DIV>
  <DIV>than "Re: Contents of Vm-dev digest..." </DIV>
  <DIV> </DIV>
  <DIV> </DIV>
  <DIV>Today's Topics: </DIV>
  <DIV> </DIV>
  <DIV>   1. [OpenSmalltalk/opensmalltalk-vm] 1acd02: Merge commit </DIV>
  <DIV>      '5a949459043392bbc093d78574c2d7c07b10... (GitHub) </DIV>
  <DIV>   2. VM Maker: VMMaker.oscog-nice.2038.mcz (commits@source.squeak.org) </DIV>
  <DIV> </DIV>
  <DIV> </DIV>
  <DIV>---------------------------------------------------------------------- </DIV>
  <DIV> </DIV>
  <DIV>Message: 1 </DIV>
  <DIV>Date: Tue, 13 Dec 2016 10:47:15 -0800 </DIV>
  <DIV>From: GitHub <noreply@github.com> </DIV>
  <DIV>To: vm-dev@lists.squeakfoundation.org </DIV>
  <DIV>Subject: [Vm-dev] [OpenSmalltalk/opensmalltalk-vm] 1acd02: Merge </DIV>
  <DIV>    commit '5a949459043392bbc093d78574c2d7c07b10... </DIV>
  <DIV>Message-ID: </DIV>
  <DIV>    <585042338c44f_42c83fa21117713458182@hookshot-fe5-cp1-prd.iad.github.net.mail> </DIV>
  <DIV>     </DIV>
  <DIV>Content-Type: text/plain; charset="utf-8" </DIV>
  <DIV> </DIV>
  <DIV>  Branch: refs/heads/Cog </DIV>
  <DIV>  Home:   https://github.com/OpenSmalltalk/opensmalltalk-vm </DIV>
  <DIV>  Commit: 1acd02683a9e25936615e0573c712b0ecfd8d06e </DIV>
  <DIV>      https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/1acd02683a9e25936615e0573c712b0ecfd8d06e </DIV>
  <DIV>  Author: Esteban Lorenzano <estebanlm@gmail.com> </DIV>
  <DIV>  Date:   2016-12-09 (Fri, 09 Dec 2016) </DIV>
  <DIV> </DIV>
  <DIV>  Changed paths: </DIV>
  <DIV>    M .gitignore </DIV>
  <DIV>    M build.macos32x86/pharo.stack.spur/plugins.ext </DIV>
  <DIV>    M build.macos32x86/pharo.stack.spur/plugins.int </DIV>
  <DIV>    M nsspur64src/vm/cogit.h </DIV>
  <DIV>    M nsspur64src/vm/cogitX64.c </DIV>
  <DIV>    M nsspur64src/vm/cointerp.c </DIV>
  <DIV>    M nsspur64src/vm/cointerp.h </DIV>
  <DIV>    M nsspur64src/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M nsspursrc/vm/cogit.h </DIV>
  <DIV>    M nsspursrc/vm/cogitARMv5.c </DIV>
  <DIV>    M nsspursrc/vm/cogitIA32.c </DIV>
  <DIV>    M nsspursrc/vm/cogitMIPSEL.c </DIV>
  <DIV>    M nsspursrc/vm/cointerp.c </DIV>
  <DIV>    M nsspursrc/vm/cointerp.h </DIV>
  <DIV>    M nsspursrc/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M nsspurstack64src/vm/gcc3x-interp.c </DIV>
  <DIV>    M nsspurstack64src/vm/interp.c </DIV>
  <DIV>    M nsspurstacksrc/vm/gcc3x-interp.c </DIV>
  <DIV>    M nsspurstacksrc/vm/interp.c </DIV>
  <DIV>    M platforms/iOS/vm/Common/Classes/sqSqueakMainApp.m </DIV>
  <DIV>    M platforms/unix/vm/sqUnixMain.c </DIV>
  <DIV>    M platforms/win32/vm/sqWin32Backtrace.c </DIV>
  <DIV>    M spur64src/vm/cogit.h </DIV>
  <DIV>    M spur64src/vm/cogitX64.c </DIV>
  <DIV>    M spur64src/vm/cointerp.c </DIV>
  <DIV>    M spur64src/vm/cointerp.h </DIV>
  <DIV>    M spur64src/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M spursista64src/vm/cogit.h </DIV>
  <DIV>    M spursista64src/vm/cogitX64.c </DIV>
  <DIV>    M spursista64src/vm/cointerp.c </DIV>
  <DIV>    M spursista64src/vm/cointerp.h </DIV>
  <DIV>    M spursista64src/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M spursistasrc/vm/cogit.h </DIV>
  <DIV>    M spursistasrc/vm/cogitARMv5.c </DIV>
  <DIV>    M spursistasrc/vm/cogitIA32.c </DIV>
  <DIV>    M spursistasrc/vm/cogitMIPSEL.c </DIV>
  <DIV>    M spursistasrc/vm/cointerp.c </DIV>
  <DIV>    M spursistasrc/vm/cointerp.h </DIV>
  <DIV>    M spursistasrc/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M spursrc/vm/cogit.h </DIV>
  <DIV>    M spursrc/vm/cogitARMv5.c </DIV>
  <DIV>    M spursrc/vm/cogitIA32.c </DIV>
  <DIV>    M spursrc/vm/cogitMIPSEL.c </DIV>
  <DIV>    M spursrc/vm/cointerp.c </DIV>
  <DIV>    M spursrc/vm/cointerp.h </DIV>
  <DIV>    M spursrc/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M spurstack64src/vm/gcc3x-interp.c </DIV>
  <DIV>    M spurstack64src/vm/interp.c </DIV>
  <DIV>    M spurstacksrc/vm/gcc3x-interp.c </DIV>
  <DIV>    M spurstacksrc/vm/interp.c </DIV>
  <DIV>    M src/plugins/AsynchFilePlugin/AsynchFilePlugin.c </DIV>
  <DIV>    M src/plugins/B2DPlugin/B2DPlugin.c </DIV>
  <DIV>    M src/plugins/BitBltPlugin/BitBltPlugin.c </DIV>
  <DIV>    M src/plugins/FilePlugin/FilePlugin.c </DIV>
  <DIV>    M src/plugins/MiscPrimitivePlugin/MiscPrimitivePlugin.c </DIV>
  <DIV>    M src/plugins/SqueakFFIPrims/ARM32FFIPlugin.c </DIV>
  <DIV>    M src/plugins/SqueakFFIPrims/IA32FFIPlugin.c </DIV>
  <DIV>    M src/plugins/SqueakFFIPrims/X64SysVFFIPlugin.c </DIV>
  <DIV>    M src/plugins/SqueakFFIPrims/X64Win64FFIPlugin.c </DIV>
  <DIV>    M src/vm/cogit.h </DIV>
  <DIV>    M src/vm/cogitARMv5.c </DIV>
  <DIV>    M src/vm/cogitIA32.c </DIV>
  <DIV>    M src/vm/cogitMIPSEL.c </DIV>
  <DIV>    M src/vm/cointerp.c </DIV>
  <DIV>    M src/vm/cointerp.h </DIV>
  <DIV>    M src/vm/cointerpmt.c </DIV>
  <DIV>    M src/vm/cointerpmt.h </DIV>
  <DIV>    M src/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M src/vm/gcc3x-cointerpmt.c </DIV>
  <DIV>    M stacksrc/vm/gcc3x-interp.c </DIV>
  <DIV>    M stacksrc/vm/interp.c </DIV>
  <DIV> </DIV>
  <DIV>  Log Message: </DIV>
  <DIV>  ----------- </DIV>
  <DIV>  Merge commit '5a949459043392bbc093d78574c2d7c07b10fcb2' </DIV>
  <DIV> </DIV>
  <DIV> </DIV>
  <DIV>  Commit: 7a7283139b72e56572f53caa167cb735a53ba949 </DIV>
  <DIV>      https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/7a7283139b72e56572f53caa167cb735a53ba949 </DIV>
  <DIV>  Author: Esteban Lorenzano <estebanlm@gmail.com> </DIV>
  <DIV>  Date:   2016-12-09 (Fri, 09 Dec 2016) </DIV>
  <DIV> </DIV>
  <DIV>  Changed paths: </DIV>
  <DIV>    M third-party/libpng.spec.win </DIV>
  <DIV> </DIV>
  <DIV>  Log Message: </DIV>
  <DIV>  ----------- </DIV>
  <DIV>  fix appveyor build script to fail when… it fails :) </DIV>
  <DIV>fix png download url. </DIV>
  <DIV> </DIV>
  <DIV> </DIV>
  <DIV>  Commit: c8d42164e557e5107f4452f0d1e6267f6e65feaa </DIV>
  <DIV>      https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/c8d42164e557e5107f4452f0d1e6267f6e65feaa </DIV>
  <DIV>  Author: Esteban Lorenzano <estebanlm@gmail.com> </DIV>
  <DIV>  Date:   2016-12-13 (Tue, 13 Dec 2016) </DIV>
  <DIV> </DIV>
  <DIV>  Changed paths: </DIV>
  <DIV>    M nsspur64src/vm/cogit.h </DIV>
  <DIV>    M nsspur64src/vm/cogitX64.c </DIV>
  <DIV>    M nsspur64src/vm/cointerp.c </DIV>
  <DIV>    M nsspur64src/vm/cointerp.h </DIV>
  <DIV>    M nsspur64src/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M nsspursrc/vm/cogit.h </DIV>
  <DIV>    M nsspursrc/vm/cogitARMv5.c </DIV>
  <DIV>    M nsspursrc/vm/cogitIA32.c </DIV>
  <DIV>    M nsspursrc/vm/cogitMIPSEL.c </DIV>
  <DIV>    M nsspursrc/vm/cointerp.c </DIV>
  <DIV>    M nsspursrc/vm/cointerp.h </DIV>
  <DIV>    M nsspursrc/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M nsspurstack64src/vm/gcc3x-interp.c </DIV>
  <DIV>    M nsspurstack64src/vm/interp.c </DIV>
  <DIV>    M nsspurstacksrc/vm/gcc3x-interp.c </DIV>
  <DIV>    M nsspurstacksrc/vm/interp.c </DIV>
  <DIV>    M spur64src/vm/cogit.h </DIV>
  <DIV>    M spur64src/vm/cogitX64.c </DIV>
  <DIV>    M spur64src/vm/cointerp.c </DIV>
  <DIV>    M spur64src/vm/cointerp.h </DIV>
  <DIV>    M spur64src/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M spursista64src/vm/cogit.h </DIV>
  <DIV>    M spursista64src/vm/cogitX64.c </DIV>
  <DIV>    M spursista64src/vm/cointerp.c </DIV>
  <DIV>    M spursista64src/vm/cointerp.h </DIV>
  <DIV>    M spursista64src/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M spursistasrc/vm/cogit.h </DIV>
  <DIV>    M spursistasrc/vm/cogitARMv5.c </DIV>
  <DIV>    M spursistasrc/vm/cogitIA32.c </DIV>
  <DIV>    M spursistasrc/vm/cogitMIPSEL.c </DIV>
  <DIV>    M spursistasrc/vm/cointerp.c </DIV>
  <DIV>    M spursistasrc/vm/cointerp.h </DIV>
  <DIV>    M spursistasrc/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M spursrc/vm/cogit.h </DIV>
  <DIV>    M spursrc/vm/cogitARMv5.c </DIV>
  <DIV>    M spursrc/vm/cogitIA32.c </DIV>
  <DIV>    M spursrc/vm/cogitMIPSEL.c </DIV>
  <DIV>    M spursrc/vm/cointerp.c </DIV>
  <DIV>    M spursrc/vm/cointerp.h </DIV>
  <DIV>    M spursrc/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M spurstack64src/vm/gcc3x-interp.c </DIV>
  <DIV>    M spurstack64src/vm/interp.c </DIV>
  <DIV>    M spurstacksrc/vm/gcc3x-interp.c </DIV>
  <DIV>    M spurstacksrc/vm/interp.c </DIV>
  <DIV>    M src/vm/cogit.h </DIV>
  <DIV>    M src/vm/cogitARMv5.c </DIV>
  <DIV>    M src/vm/cogitIA32.c </DIV>
  <DIV>    M src/vm/cogitMIPSEL.c </DIV>
  <DIV>    M src/vm/cointerp.c </DIV>
  <DIV>    M src/vm/cointerp.h </DIV>
  <DIV>    M src/vm/cointerpmt.c </DIV>
  <DIV>    M src/vm/cointerpmt.h </DIV>
  <DIV>    M src/vm/gcc3x-cointerp.c </DIV>
  <DIV>    M src/vm/gcc3x-cointerpmt.c </DIV>
  <DIV>    M stacksrc/vm/gcc3x-interp.c </DIV>
  <DIV>    M stacksrc/vm/interp.c </DIV>
  <DIV> </DIV>
  <DIV>  Log Message: </DIV>
  <DIV>  ----------- </DIV>
  <DIV>  Merge commit '8a77b2517d9ec3d467cb0f1ae427e94c4a5eeb10' </DIV>
  <DIV> </DIV>
  <DIV> </DIV>
  <DIV>  Commit: 945fbc37d97f2db5ddcb1abfd14e9a1e7cb55c9c </DIV>
  <DIV>      https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/945fbc37d97f2db5ddcb1abfd14e9a1e7cb55c9c </DIV>
  <DIV>  Author: Esteban Lorenzano <estebanlm@gmail.com> </DIV>
  <DIV>  Date:   2016-12-13 (Tue, 13 Dec 2016) </DIV>
  <DIV> </DIV>
  <DIV>  Changed paths: </DIV>
  <DIV>    M platforms/win32/vm/sqWin32Main.c </DIV>
  <DIV>    M platforms/win32/vm/sqWin32Window.c </DIV>
  <DIV> </DIV>
  <DIV>  Log Message: </DIV>
  <DIV>  ----------- </DIV>
  <DIV>  add double dash for Pharo on windows (the only remaining) </DIV>
  <DIV> </DIV>
  <DIV> </DIV>
  <DIV>  Commit: 99fdc442dc59f3bbe3fc48b2a037c873b9529dcb </DIV>
  <DIV>      https://github.com/OpenSmalltalk/opensmalltalk-vm/commit/99fdc442dc59f3bbe3fc48b2a037c873b9529dcb </DIV>
  <DIV>  Author: Esteban Lorenzano <estebanlm@gmail.com> </DIV>
  <DIV>  Date:   2016-12-13 (Tue, 13 Dec 2016) </DIV>
  <DIV> </DIV>
  <DIV>  Changed paths: </DIV>
  <DIV>    M platforms/win32/vm/sqWin32Main.c </DIV>
  <DIV>    M platforms/win32/vm/sqWin32Window.c </DIV>
  <DIV>    M third-party/libpng.spec.win </DIV>
  <DIV> </DIV>
  <DIV>  Log Message: </DIV>
  <DIV>  ----------- </DIV>
  <DIV>  Merge pull request #107 from estebanlm/Cog </DIV>
  <DIV> </DIV>
  <DIV>add double dash for Pharo on windows (the only remaining) </DIV>
  <DIV> </DIV>
  <DIV> </DIV>
  <DIV>Compare: https://github.com/OpenSmalltalk/opensmalltalk-vm/compare/8a77b2517d9e...99fdc442dc59 </DIV>
  <DIV> </DIV>
  <DIV>------------------------------ </DIV>
  <DIV> </DIV>
  <DIV>Message: 2 </DIV>
  <DIV>Date: Tue, 13 Dec 2016 22:13:18 0000 </DIV>
  <DIV>From: commits@source.squeak.org </DIV>
  <DIV>To: vm-dev@lists.squeakfoundation.org </DIV>
  <DIV>Subject: [Vm-dev] VM Maker: VMMaker.oscog-nice.2038.mcz </DIV>
  <DIV>Message-ID: <E1cGvKe-0003L2-V8@andreas> </DIV>
  <DIV> </DIV>
  <DIV>Nicolas Cellier uploaded a new version of VMMaker to project VM Maker: </DIV>
  <DIV>http://source.squeak.org/VMMaker/VMMaker.oscog-nice.2038.mcz </DIV>
  <DIV> </DIV>
  <DIV>==================== Summary ==================== </DIV>
  <DIV> </DIV>
  <DIV>Name: VMMaker.oscog-nice.2038 </DIV>
  <DIV>Author: nice </DIV>
  <DIV>Time: 13 December 2016, 11:11:51.599692 pm </DIV>
  <DIV>UUID: f98d3e8c-e81d-fb42-b790-8e514777bfff </DIV>
  <DIV>Ancestors: VMMaker.oscog-eem.2037 </DIV>
  <DIV> </DIV>
  <DIV>Revise ALLOCA_LIES_SO_USE_GET_SP </DIV>
  <DIV> </DIV>
  <DIV>The extra space allocated below the value returned by alloca() is used by mingw32 gcc </DIV>
  <DIV>(it is used for marshalling args of sub-functions - those who marshall ffi call args) </DIV>
  <DIV>So we cannot use it for marshalling FFI arguments. </DIV>
  <DIV> </DIV>
  <DIV>Thus we must change the strategy: </DIV>
  <DIV>rather than using getsp() for changing the value returned by alloca() before marshalling args (which will lead to SEGV) </DIV>
  <DIV>we must rather use setsp() for changing the stack pointer before calling the target function. </DIV>
  <DIV> </DIV>
  <DIV>Thus we rename the macro into ALLOCA_LIES_SO_SET_SP_BEFORE_CALL </DIV>
  <DIV> </DIV>
  <DIV>Remind that __clang__'s alloca does not lie. </DIV>
  <DIV>(clang compiler does define __GNUC__) </DIV>
  <DIV> </DIV>
  <DIV>--- </DIV>
  <DIV> </DIV>
  <DIV>Revise FFI stack alignment: </DIV>
  <DIV> </DIV>
  <DIV>1) use STACK_BYTES_ALIGNMENT and getsp() as provided by include file sqCogStackAlignment.h </DIV>
  <DIV>2) use a new macro MUST_ALIGN_STACK that check STACK_BYTES_ALIGNMENT against sizeof(void *) </DIV>
  <DIV>    indeed, some nice STACK_BYTES_ALIGNMENT might be > 0 now, which does not necessarily mean that we must realign the stack </DIV>
  <DIV>    This macro is used both for aligning alloca'ed space before marshalling and for aligning SP before call. </DIV>
  <DIV> </DIV>
  <DIV>It is still questionable whether we must do some further alignment over alloca(), because alloca() should be aware of ABI requirements, but well, if it ain't broken... </DIV>
  <DIV> </DIV>
  <DIV>TO THINK ABOUT: maybe SP should be saved before call/reset after call. By now, this does not seem necessary. </DIV>
  <DIV> </DIV>
  <DIV>--- </DIV>
  <DIV> </DIV>
  <DIV>nuke STACK_OFFSET_BYTES from the preamble since it is unused. </DIV>
  <DIV> </DIV>
  <DIV>--- </DIV>
  <DIV> </DIV>
  <DIV>get rid of registerArgsSlop </DIV>
  <DIV>It was intended for reserving stack space for shadowing register args as mandated by Win64 X64 ABI (and maybe PPC). </DIV>
  <DIV>But this is completely unecessary as this stack space will be reserved by the callout itself (at least on WIN64). </DIV>
  <DIV>For PPC, don't do anything, it's currently unsupported (unmaintained/untested/unnecessary/you name it) </DIV>
  <DIV> </DIV>
  <DIV>--- </DIV>
  <DIV> </DIV>
  <DIV>Let cogit generate remove float args from stack only if more than 0 float args (by symmetry with int args) </DIV>
  <DIV>This was forgotten in a previous commit </DIV>
  <DIV>Note that this is only used by lowcode experiments and still wait to be ported to other architectures than IA32. </DIV>
  <DIV> </DIV>
  <DIV>=============== Diff against VMMaker.oscog-eem.2037 =============== </DIV>
  <DIV> </DIV>
  <DIV>Item was changed: </DIV>
  <DIV>  ----- Method: CogIA32Compiler>>genRemoveNFloatArgsFromStack: (in category 'abi') ----- </DIV>
  <DIV>  genRemoveNFloatArgsFromStack: n  </DIV>
  <DIV>+     n > 0 ifTrue: [cogit AddCq: n * 8 R: ESP]. </DIV>
  <DIV>-     cogit AddCq: n * 8 R: ESP. </DIV>
  <DIV>      ^0! </DIV>
  <DIV> </DIV>
  <DIV>Item was changed: </DIV>
  <DIV>  ----- Method: ThreadedARMFFIPlugin>>ffiCalloutTo:SpecOnStack:in: (in category 'callout support') ----- </DIV>
  <DIV>  ffiCalloutTo: procAddr SpecOnStack: specOnStack in: calloutState </DIV>
  <DIV>      <var: #procAddr type: #'void *'> </DIV>
  <DIV>      <var: #calloutState type: #'CalloutState *'> </DIV>
  <DIV>      <var: #loadFloatRegs declareC: 'extern void loadFloatRegs(double, double, double, double, double, double, double, double)'> </DIV>
  <DIV>      "Go out, call this guy and create the return value.  This *must* be inlined because of </DIV>
  <DIV>       the alloca of the outgoing stack frame in ffiCall:WithFlags:NumArgs:Args:AndTypes:" </DIV>
  <DIV>      | myThreadIndex atomicType floatRet intRet loadFloatRegs oop | </DIV>
  <DIV>      <var: #floatRet type: #double> </DIV>
  <DIV>      <var: #intRet type: #usqLong> </DIV>
  <DIV>      <inline: true> </DIV>
  <DIV>      self cCode: '' inSmalltalk: [loadFloatRegs := #used. loadFloatRegs class]. </DIV>
  <DIV>      self cppIf: COGMTVM ifTrue: </DIV>
  <DIV>      [(calloutState callFlags anyMask: FFICallFlagThreaded) ifTrue: </DIV>
  <DIV>          [myThreadIndex := interpreterProxy disownVM: 0]]. </DIV>
  <DIV>   </DIV>
  <DIV>-     self registerArgsSlop + self cStackAlignment > 0 ifTrue: </DIV>
  <DIV>-         [self setsp: calloutState argVector]. </DIV>
  <DIV>-  </DIV>
  <DIV>      calloutState floatRegisterIndex > 0 ifTrue: </DIV>
  <DIV>          [self  </DIV>
  <DIV>              load: ((self cCoerceSimple: (self addressOf: (calloutState floatRegisters at: 0)) to: 'double *') at: 0) </DIV>
  <DIV>              Flo: ((self cCoerceSimple: (self addressOf: (calloutState floatRegisters at: 2)) to: 'double *') at: 0) </DIV>
  <DIV>              a: ((self cCoerceSimple: (self addressOf: (calloutState floatRegisters at: 4)) to: 'double *') at: 0) </DIV>
  <DIV>              t: ((self cCoerceSimple: (self addressOf: (calloutState floatRegisters at: 6)) to: 'double *') at: 0) </DIV>
  <DIV>              R: ((self cCoerceSimple: (self addressOf: (calloutState floatRegisters at: 8)) to: 'double *') at: 0) </DIV>
  <DIV>              e: ((self cCoerceSimple: (self addressOf: (calloutState floatRegisters at: 10)) to: 'double *') at: 0) </DIV>
  <DIV>              g: ((self cCoerceSimple: (self addressOf: (calloutState floatRegisters at: 12)) to: 'double *') at: 0) </DIV>
  <DIV>              s: ((self cCoerceSimple: (self addressOf: (calloutState floatRegisters at: 14)) to: 'double *') at: 0)]. </DIV>
  <DIV>   </DIV>
  <DIV>+     (self allocaLiesSoSetSpBeforeCall or: [self mustAlignStack]) ifTrue: </DIV>
  <DIV>+         [self setsp: calloutState argVector]. </DIV>
  <DIV>+  </DIV>
  <DIV>      atomicType := self atomicTypeOf: calloutState ffiRetHeader. </DIV>
  <DIV>      (atomicType >> 1) = (FFITypeSingleFloat >> 1) </DIV>
  <DIV>          ifTrue: </DIV>
  <DIV>              [atomicType = FFITypeSingleFloat </DIV>
  <DIV>                  ifTrue: </DIV>
  <DIV>                      [floatRet := self  </DIV>
  <DIV>                          dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)')  </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 0) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 1) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 2) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 3)] </DIV>
  <DIV>                  ifFalse: "atomicType = FFITypeDoubleFloat" </DIV>
  <DIV>                      [floatRet := self  </DIV>
  <DIV>                          dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)')  </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 0) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 1) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 2) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 3)]] </DIV>
  <DIV>          ifFalse: </DIV>
  <DIV>              [intRet := self  </DIV>
  <DIV>                  dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)')  </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 0) </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 1) </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 2) </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 3)]. </DIV>
  <DIV>      "undo any callee argument pops because it may confuse stack management with the alloca." </DIV>
  <DIV>      (self isCalleePopsConvention: calloutState callFlags) ifTrue: </DIV>
  <DIV>          [self setsp: calloutState argVector]. </DIV>
  <DIV>   </DIV>
  <DIV>      self cppIf: COGMTVM ifTrue: </DIV>
  <DIV>      [(calloutState callFlags anyMask: FFICallFlagThreaded) ifTrue: </DIV>
  <DIV>          [interpreterProxy ownVM: myThreadIndex]]. </DIV>
  <DIV>   </DIV>
  <DIV>      (calloutState ffiRetHeader anyMask: FFIFlagPointer+FFIFlagStructure) ifTrue: </DIV>
  <DIV>          ["Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent </DIV>
  <DIV>           'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct." </DIV>
  <DIV>           (calloutState ffiRetHeader anyMask: FFIFlagPointer) </DIV>
  <DIV>              ifTrue: </DIV>
  <DIV>                  [oop := self ffiReturnPointer: intRet ofType: (self ffiReturnType: specOnStack) in: calloutState] </DIV>
  <DIV>              ifFalse: </DIV>
  <DIV>                  [oop := self ffiReturnStruct: intRet ofType: (self ffiReturnType: specOnStack) in: calloutState]. </DIV>
  <DIV>           ^oop]. </DIV>
  <DIV>       </DIV>
  <DIV>      (atomicType >> 1) = (FFITypeSingleFloat >> 1) </DIV>
  <DIV>          ifTrue: </DIV>
  <DIV>              [oop := interpreterProxy floatObjectOf: floatRet] </DIV>
  <DIV>          ifFalse: </DIV>
  <DIV>              [oop := self ffiCreateIntegralResultOop: intRet </DIV>
  <DIV>                          ofAtomicType: atomicType </DIV>
  <DIV>                          in: calloutState]. </DIV>
  <DIV>      ^interpreterProxy methodReturnValue: oop! </DIV>
  <DIV> </DIV>
  <DIV>Item was removed: </DIV>
  <DIV>- ----- Method: ThreadedARMFFIPlugin>>registerArgsSlop (in category 'marshalling') ----- </DIV>
  <DIV>- registerArgsSlop </DIV>
  <DIV>-     "Answer any space needed to prevent the alloca'ed outgoing arguments marshalling area from </DIV>
  <DIV>-      being overwritten by any register arguments during calls during marshalling.  On ARM we </DIV>
  <DIV>-      believe this is zero." </DIV>
  <DIV>-     ^0! </DIV>
  <DIV> </DIV>
  <DIV>Item was changed: </DIV>
  <DIV>  ----- Method: ThreadedFFIPlugin class>>preambleCCode (in category 'translation') ----- </DIV>
  <DIV>  preambleCCode </DIV>
  <DIV>      "For a source of builtin defines grep for builtin_define in a gcc release config directory." </DIV>
  <DIV>      ^' </DIV>
  <DIV>  #include "sqAssert.h" /* for assert */ </DIV>
  <DIV>  #define ThreadedFFIPlugin 1 /* to filter-out unwanted declarations from sqFFI.h */ </DIV>
  <DIV>  #include "sqFFI.h" /* for logging and surface functions */ </DIV>
  <DIV>+ #include "sqCogStackAlignment.h" /* for STACK_ALIGN_BYTES and getsp() */ </DIV>
  <DIV>   </DIV>
  <DIV>  #ifdef _MSC_VER </DIV>
  <DIV>  # define alloca _alloca </DIV>
  <DIV>  #endif </DIV>
  <DIV>  #if defined(__GNUC__) && (defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__)) </DIV>
  <DIV>  # define setsp(sp) asm volatile ("movl %0,%%esp" : : "m"(sp)) </DIV>
  <DIV>- # define getsp() ({ void *esp; asm volatile ("movl %%esp,%0" : "=r"(esp) : ); esp;}) </DIV>
  <DIV>  # elif defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__) ||  defined(__amd64) || defined(__x86_64)) </DIV>
  <DIV>  # define setsp(sp) asm volatile ("movq %0,%%rsp" : : "m"(sp)) </DIV>
  <DIV>- # define getsp() ({ void *rsp; asm volatile ("movq %%rsp,%0" : "=r"(rsp) : ); rsp;}) </DIV>
  <DIV>  # elif defined(__GNUC__) && (defined(__arm__)) </DIV>
  <DIV>  # define setsp(sp) asm volatile ("ldr %%sp, %0" : : "m"(sp)) </DIV>
  <DIV>- # define getsp() ({ void *sp; asm volatile ("mov %0, %%sp" : "=r"(sp) : ); sp;}) </DIV>
  <DIV>  #endif </DIV>
  <DIV>  #if !!defined(getsp) </DIV>
  <DIV>  # define getsp() 0 </DIV>
  <DIV>  #endif  </DIV>
  <DIV>  #if !!defined(setsp) </DIV>
  <DIV>  # define setsp(ignored) 0 </DIV>
  <DIV>  #endif  </DIV>
  <DIV>   </DIV>
  <DIV>  #if !!defined(STACK_ALIGN_BYTES) </DIV>
  <DIV>- # if __APPLE__ && __MACH__ && __i386__ </DIV>
  <DIV>- #  define STACK_ALIGN_BYTES 16 </DIV>
  <DIV>- # elif __linux__ && __i386__ </DIV>
  <DIV>- #  define STACK_ALIGN_BYTES 16 </DIV>
  <DIV>- # elif defined(__amd64__) || defined(__x86_64__) ||  defined(__amd64) || defined(__x86_64) </DIV>
  <DIV>- #  define STACK_ALIGN_BYTES 16 </DIV>
  <DIV>- # elif defined(powerpc) || defined(__powerpc__) || defined(_POWER) || defined(__POWERPC__) || defined(__PPC__) </DIV>
  <DIV>- #  define STACK_ALIGN_BYTES 16 </DIV>
  <DIV>- # elif defined(__sparc64__) || defined(__sparcv9__) || defined(__sparc_v9__) /* must precede 32-bit sparc defs */ </DIV>
  <DIV>- #  define STACK_ALIGN_BYTES 16 </DIV>
  <DIV>- # elif defined(sparc) || defined(__sparc__) || defined(__sparclite__) </DIV>
  <DIV>- #  define STACK_ALIGN_BYTES 8 </DIV>
  <DIV>- # elif defined(__arm__)  </DIV>
  <DIV>- #  define STACK_ALIGN_BYTES 8 </DIV>
  <DIV>- # else </DIV>
  <DIV>  #  define STACK_ALIGN_BYTES 0 </DIV>
  <DIV>- # endif </DIV>
  <DIV>  #endif /* !!defined(STACK_ALIGN_BYTES) */ </DIV>
  <DIV>   </DIV>
  <DIV>+ /* For ABI that require stack alignment greater than natural word size */ </DIV>
  <DIV>+ #define MUST_ALIGN_STACK (STACK_ALIGN_BYTES > sizeof(void*)) </DIV>
  <DIV>- #if !!defined(STACK_OFFSET_BYTES) </DIV>
  <DIV>- # define STACK_OFFSET_BYTES 0 </DIV>
  <DIV>- #endif </DIV>
  <DIV>   </DIV>
  <DIV>  #if defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__) </DIV>
  <DIV>  /* Both Mac OS X x86 and Win32 x86 return structs of a power of two in size </DIV>
  <DIV>   * less than or equal to eight bytes in length in registers. Linux never does so. </DIV>
  <DIV>   */ </DIV>
  <DIV>  # if __linux__ </DIV>
  <DIV>  #    define WIN32_X86_STRUCT_RETURN 0 </DIV>
  <DIV>  # else </DIV>
  <DIV>  #    define WIN32_X86_STRUCT_RETURN 1 </DIV>
  <DIV>  # endif </DIV>
  <DIV>  # if WIN32 </DIV>
  <DIV>  #    define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 1 </DIV>
  <DIV>  # endif </DIV>
  <DIV>  # elif defined(__amd64__) || defined(__x86_64__) ||  defined(__amd64) || defined(__x86_64) </DIV>
  <DIV>  # if WIN32 | WIN64 </DIV>
  <DIV>  #    define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 1 </DIV>
  <DIV>  # endif </DIV>
  <DIV>  #endif /* defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__) */ </DIV>
  <DIV>   </DIV>
  <DIV>+ #if !!defined(ALLOCA_LIES_SO_SETSP_BEFORE_CALL) </DIV>
  <DIV>+ # if defined(__MINGW32__) && !!defined(__clang__) && (__GNUC__ >= 3) && (defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__)) </DIV>
  <DIV>- #if !!defined(ALLOCA_LIES_SO_USE_GETSP) </DIV>
  <DIV>- # if defined(__MINGW32__) && (__GNUC__ >= 3) && (defined(_X86_) || defined(i386) || defined(__i386) || defined(__i386__)) </DIV>
  <DIV>      /* </DIV>
  <DIV>       * cygwin -mno-cygwin (MinGW) gcc 3.4.x''s alloca is a library routine that answers </DIV>
  <DIV>+      * %esp + xx, so the outgoing stack is offset by one or more word if uncorrected. </DIV>
  <DIV>-      * %esp + 4, so the outgoing stack is offset by one word if uncorrected. </DIV>
  <DIV>       * Grab the actual stack pointer to correct. </DIV>
  <DIV>       */ </DIV>
  <DIV>+ #    define ALLOCA_LIES_SO_SETSP_BEFORE_CALL 1 </DIV>
  <DIV>- #    define ALLOCA_LIES_SO_USE_GETSP 1 </DIV>
  <DIV>  # else </DIV>
  <DIV>+ #    define ALLOCA_LIES_SO_SETSP_BEFORE_CALL 0 </DIV>
  <DIV>- #    define ALLOCA_LIES_SO_USE_GETSP 0 </DIV>
  <DIV>  # endif </DIV>
  <DIV>+ #endif /* !!defined(ALLOCA_LIES_SO_SETSP_BEFORE_CALL) */ </DIV>
  <DIV>- #endif /* !!defined(ALLOCA_LIES_SO_USE_GETSP) */ </DIV>
  <DIV>   </DIV>
  <DIV>  #if !!defined(PLATFORM_API_USES_CALLEE_POPS_CONVENTION) </DIV>
  <DIV>  # define PLATFORM_API_USES_CALLEE_POPS_CONVENTION 0 </DIV>
  <DIV>  #endif </DIV>
  <DIV>   </DIV>
  <DIV>  /* The dispatchOn:in:with:with: generates an unwanted call on error.  Just squash it. */ </DIV>
  <DIV>  #define error(foo) 0 </DIV>
  <DIV>  #ifndef SQUEAK_BUILTIN_PLUGIN </DIV>
  <DIV>  /* but print assert failures. */ </DIV>
  <DIV>  void </DIV>
  <DIV>  warning(char *s) { /* Print an error message but don''t exit. */ </DIV>
  <DIV>      printf("\n%s\n", s); </DIV>
  <DIV>  } </DIV>
  <DIV>  #endif </DIV>
  <DIV>   </DIV>
  <DIV>  /* sanitize */ </DIV>
  <DIV>  #ifdef SQUEAK_BUILTIN_PLUGIN </DIV>
  <DIV>  # define EXTERN  </DIV>
  <DIV>  #else </DIV>
  <DIV>  # define EXTERN extern </DIV>
  <DIV>  #endif </DIV>
  <DIV>  '! </DIV>
  <DIV> </DIV>
  <DIV>Item was added: </DIV>
  <DIV>+ ----- Method: ThreadedFFIPlugin>>allocaLiesSoSetSpBeforeCall (in category 'marshalling') ----- </DIV>
  <DIV>+ allocaLiesSoSetSpBeforeCall </DIV>
  <DIV>+     "At least one alloca implementation does not answer the actual top of stack. </DIV>
  <DIV>+      If so we need to reset the actual stack pointer just before the call. </DIV>
  <DIV>+     Answer whether this is necessary." </DIV>
  <DIV>+     <cmacro: '() ALLOCA_LIES_SO_SETSP_BEFORE_CALL'> </DIV>
  <DIV>+     ^false! </DIV>
  <DIV> </DIV>
  <DIV>Item was removed: </DIV>
  <DIV>- ----- Method: ThreadedFFIPlugin>>allocaLiesSoUseGetsp (in category 'marshalling') ----- </DIV>
  <DIV>- allocaLiesSoUseGetsp </DIV>
  <DIV>-     "At least one alloca implementation does not answer the actual top of stack. </DIV>
  <DIV>-      If so we need to get the actual stack pointer.  Answer whether this is necessary." </DIV>
  <DIV>-     <cmacro: '() ALLOCA_LIES_SO_USE_GETSP'> </DIV>
  <DIV>-     ^false! </DIV>
  <DIV> </DIV>
  <DIV>Item was changed: </DIV>
  <DIV>  ----- Method: ThreadedFFIPlugin>>ffiCall:ArgArrayOrNil:NumArgs: (in category 'callout support') ----- </DIV>
  <DIV>  ffiCall: externalFunction ArgArrayOrNil: argArrayOrNil NumArgs: nArgs </DIV>
  <DIV>      "Generic callout. Does the actual work.  If argArrayOrNil is nil it takes args from the stack </DIV>
  <DIV>       and the spec from the method.  If argArrayOrNil is not nil takes args from argArrayOrNil </DIV>
  <DIV>       and the spec from the receiver." </DIV>
  <DIV>      | flags argTypeArray address argType oop argSpec argClass err theCalloutState calloutState requiredStackSize stackSize allocation result | </DIV>
  <DIV>      <inline: true> </DIV>
  <DIV>      <var: #theCalloutState type: #'CalloutState'> </DIV>
  <DIV>      <var: #calloutState type: #'CalloutState *'> </DIV>
  <DIV>      <var: #allocation type: #'char *'> </DIV>
  <DIV>   </DIV>
  <DIV>      (interpreterProxy is: externalFunction KindOfClass: interpreterProxy classExternalFunction) ifFalse: </DIV>
  <DIV>          [^self ffiFail: FFIErrorNotFunction]. </DIV>
  <DIV>      "Load and check the values in the externalFunction before we call out" </DIV>
  <DIV>      flags := interpreterProxy fetchInteger: ExternalFunctionFlagsIndex ofObject: externalFunction. </DIV>
  <DIV>      interpreterProxy failed ifTrue: </DIV>
  <DIV>          [^self ffiFail: FFIErrorBadArgs]. </DIV>
  <DIV>   </DIV>
  <DIV>      "This must come early for compatibility with the old FFIPlugin.  Image-level code </DIV>
  <DIV>       may assume the function pointer is loaded eagerly.  Thanks to Nicolas Cellier." </DIV>
  <DIV>      address := self ffiLoadCalloutAddress: externalFunction. </DIV>
  <DIV>      interpreterProxy failed ifTrue: </DIV>
  <DIV>          [^0 "error code already set by ffiLoadCalloutAddress:"]. </DIV>
  <DIV>       </DIV>
  <DIV>      argTypeArray := interpreterProxy fetchPointer: ExternalFunctionArgTypesIndex ofObject: externalFunction. </DIV>
  <DIV>      "must be array of arg types" </DIV>
  <DIV>      ((interpreterProxy isArray: argTypeArray) </DIV>
  <DIV>      and: [(interpreterProxy slotSizeOf: argTypeArray) = (nArgs + 1)]) ifFalse: </DIV>
  <DIV>          [^self ffiFail: FFIErrorBadArgs]. </DIV>
  <DIV>      "check if the calling convention is supported" </DIV>
  <DIV>      self cppIf: COGMTVM </DIV>
  <DIV>          ifTrue: </DIV>
  <DIV>              [(self ffiSupportsCallingConvention: (flags bitAnd: FFICallTypesMask)) ifFalse: </DIV>
  <DIV>                  [^self ffiFail: FFIErrorCallType]] </DIV>
  <DIV>          ifFalse: "not masking causes threaded calls to fail, which is as they should if the plugin is not threaded." </DIV>
  <DIV>              [(self ffiSupportsCallingConvention: flags) ifFalse: </DIV>
  <DIV>                  [^self ffiFail: FFIErrorCallType]]. </DIV>
  <DIV>           </DIV>
  <DIV>      requiredStackSize := self externalFunctionHasStackSizeSlot </DIV>
  <DIV>                              ifTrue: [interpreterProxy </DIV>
  <DIV>                                          fetchInteger: ExternalFunctionStackSizeIndex </DIV>
  <DIV>                                          ofObject: externalFunction] </DIV>
  <DIV>                              ifFalse: [-1]. </DIV>
  <DIV>      interpreterProxy failed ifTrue: </DIV>
  <DIV>          [^interpreterProxy primitiveFailFor: (argArrayOrNil isNil </DIV>
  <DIV>                                                  ifTrue: [PrimErrBadMethod] </DIV>
  <DIV>                                                  ifFalse: [PrimErrBadReceiver])]. </DIV>
  <DIV>      stackSize := requiredStackSize < 0 ifTrue: [DefaultMaxStackSize] ifFalse: [requiredStackSize]. </DIV>
  <DIV>      self cCode: [] inSmalltalk: [theCalloutState := self class calloutStateClass new]. </DIV>
  <DIV>      calloutState := self addressOf: theCalloutState. </DIV>
  <DIV>      self cCode: [self me: calloutState ms: 0 et: (self sizeof: #CalloutState)]. </DIV>
  <DIV>      calloutState callFlags: flags. </DIV>
  <DIV>      "Fetch return type and args" </DIV>
  <DIV>      argType := interpreterProxy fetchPointer: 0 ofObject: argTypeArray. </DIV>
  <DIV>      argSpec := interpreterProxy fetchPointer: 0 ofObject: argType. </DIV>
  <DIV>      argClass := interpreterProxy fetchPointer: 1 ofObject: argType. </DIV>
  <DIV>      (err := self ffiCheckReturn: argSpec With: argClass in: calloutState) ~= 0 ifTrue: </DIV>
  <DIV>          [^self ffiFail: err]. "cannot return" </DIV>
  <DIV>+     "alloca the outgoing stack frame, leaving room for marshalling args, and including space for the return struct, if any. </DIV>
  <DIV>+     Additional space reserved for saving register args like mandated by Win64 X64 or PPC ABI, will be managed by the call itself" </DIV>
  <DIV>+     allocation := self alloca: stackSize + calloutState structReturnSize + self cStackAlignment. </DIV>
  <DIV>+     self mustAlignStack ifTrue: </DIV>
  <DIV>+         [allocation := self cCoerce: (allocation asUnsignedIntegerPtr bitClear: self cStackAlignment - 1) </DIV>
  <DIV>-     "alloca the outgoing stack frame, leaving room for register args while marshalling, and including space for the return struct, if any." </DIV>
  <DIV>-     allocation := self alloca: stackSize + calloutState structReturnSize + self registerArgsSlop + self cStackAlignment. </DIV>
  <DIV>-     self allocaLiesSoUseGetsp ifTrue: </DIV>
  <DIV>-         [allocation := self getsp]. </DIV>
  <DIV>-     self cStackAlignment ~= 0 ifTrue: </DIV>
  <DIV>-         [allocation := self cCoerce: (allocation asUnsignedInteger bitClear: self cStackAlignment - 1) </DIV>
  <DIV>                          to: #'char *']. </DIV>
  <DIV>      calloutState </DIV>
  <DIV>          argVector: allocation; </DIV>
  <DIV>+         currentArg: allocation; </DIV>
  <DIV>+         limit: allocation + stackSize. </DIV>
  <DIV>-         currentArg: allocation + self registerArgsSlop; </DIV>
  <DIV>-         limit: allocation + stackSize + self registerArgsSlop. </DIV>
  <DIV>      (calloutState structReturnSize > 0 </DIV>
  <DIV>       and: [self nonRegisterStructReturnIsViaImplicitFirstArgument </DIV>
  <DIV>       and: [(self returnStructInRegisters: calloutState structReturnSize) not]]) ifTrue: </DIV>
  <DIV>          [err := self ffiPushPointer: calloutState limit in: calloutState. </DIV>
  <DIV>           err ~= 0 ifTrue: </DIV>
  <DIV>              [self cleanupCalloutState: calloutState. </DIV>
  <DIV>               self cppIf: COGMTVM ifTrue: </DIV>
  <DIV>               [err = PrimErrObjectMayMove negated ifTrue: </DIV>
  <DIV>                  [^PrimErrObjectMayMove]]. "N.B. Do not fail if object may move because caller will GC and retry." </DIV>
  <DIV>               ^self ffiFail: err]]. </DIV>
  <DIV>      1 to: nArgs do: </DIV>
  <DIV>          [:i| </DIV>
  <DIV>          argType := interpreterProxy fetchPointer: i ofObject: argTypeArray. </DIV>
  <DIV>          argSpec := interpreterProxy fetchPointer: 0 ofObject: argType. </DIV>
  <DIV>          argClass := interpreterProxy fetchPointer: 1 ofObject: argType. </DIV>
  <DIV>          oop := argArrayOrNil isNil </DIV>
  <DIV>                  ifTrue: [interpreterProxy stackValue: nArgs - i] </DIV>
  <DIV>                  ifFalse: [interpreterProxy fetchPointer: i - 1 ofObject: argArrayOrNil]. </DIV>
  <DIV>          err := self ffiArgument: oop Spec: argSpec Class: argClass in: calloutState. </DIV>
  <DIV>          err ~= 0 ifTrue: </DIV>
  <DIV>              [self cleanupCalloutState: calloutState. </DIV>
  <DIV>               self cppIf: COGMTVM ifTrue: </DIV>
  <DIV>               [err = PrimErrObjectMayMove negated ifTrue: </DIV>
  <DIV>                  [^PrimErrObjectMayMove]]. "N.B. Do not fail if object may move because caller will GC and retry." </DIV>
  <DIV>               ^self ffiFail: err]]. "coercion failed or out of stack space" </DIV>
  <DIV>      "Failures must be reported back from ffiArgument:Spec:Class:in:. </DIV>
  <DIV>       Should not fail from here on in." </DIV>
  <DIV>      self assert: interpreterProxy failed not. </DIV>
  <DIV>      self ffiLogCallout: externalFunction. </DIV>
  <DIV>      (requiredStackSize < 0 </DIV>
  <DIV>       and: [self externalFunctionHasStackSizeSlot]) ifTrue: </DIV>
  <DIV>          [stackSize := calloutState currentArg - calloutState argVector. </DIV>
  <DIV>           interpreterProxy storeInteger: ExternalFunctionStackSizeIndex ofObject: externalFunction withValue: stackSize]. </DIV>
  <DIV>      "Go out and call this guy" </DIV>
  <DIV>      result := self ffiCalloutTo: address SpecOnStack: argArrayOrNil notNil in: calloutState. </DIV>
  <DIV>      self cleanupCalloutState: calloutState. </DIV>
  <DIV>      ^result! </DIV>
  <DIV> </DIV>
  <DIV>Item was added: </DIV>
  <DIV>+ ----- Method: ThreadedFFIPlugin>>mustAlignStack (in category 'marshalling') ----- </DIV>
  <DIV>+ mustAlignStack </DIV>
  <DIV>+     "Many ABIs mandate a particular stack alignment greater than the natural word size. </DIV>
  <DIV>+      If so, this macro will answer true.  See class-side preambleCCode." </DIV>
  <DIV>+     <cmacro: '() MUST_ALIGN_STACK'> </DIV>
  <DIV>+     ^0! </DIV>
  <DIV> </DIV>
  <DIV>Item was removed: </DIV>
  <DIV>- ----- Method: ThreadedFFIPlugin>>registerArgsSlop (in category 'marshalling') ----- </DIV>
  <DIV>- registerArgsSlop </DIV>
  <DIV>-     "Answer any space needed to prevent the alloca'ed outgoing arguments marshalling area from </DIV>
  <DIV>-      being overwritten by any register arguments during calls during marshalling.  For example, on </DIV>
  <DIV>-      PowerPC, which has 8 register arguments in the calling convention, register arguments are also </DIV>
  <DIV>-      written to the stack.  So unless space is left for them, calls during marshalling prior to the actual </DIV>
  <DIV>-      callout (e.g. to interpreterProxy object manipulation routines) can end up overwriting the </DIV>
  <DIV>-      marshalling stack as register arguments are written to the stack during calls." </DIV>
  <DIV>-     self subclassResponsibility! </DIV>
  <DIV> </DIV>
  <DIV>Item was changed: </DIV>
  <DIV>  ----- Method: ThreadedIA32FFIPlugin>>ffiCalloutTo:SpecOnStack:in: (in category 'callout support') ----- </DIV>
  <DIV>  ffiCalloutTo: procAddr SpecOnStack: specOnStack in: calloutState </DIV>
  <DIV>      <var: #procAddr type: #'void *'> </DIV>
  <DIV>      <var: #calloutState type: #'CalloutState *'> </DIV>
  <DIV>      "Go out, call this guy and create the return value.  This *must* be inlined because of </DIV>
  <DIV>       the alloca of the outgoing stack frame in ffiCall:WithFlags:NumArgs:Args:AndTypes:" </DIV>
  <DIV>      | myThreadIndex atomicType floatRet intRet oop | </DIV>
  <DIV>      <var: #floatRet type: #double> </DIV>
  <DIV>      <var: #intRet type: #usqLong> </DIV>
  <DIV>      <inline: true> </DIV>
  <DIV>      self cppIf: COGMTVM ifTrue: </DIV>
  <DIV>      [(calloutState callFlags anyMask: FFICallFlagThreaded) ifTrue: </DIV>
  <DIV>          [myThreadIndex := interpreterProxy disownVM: 0]]. </DIV>
  <DIV>   </DIV>
  <DIV>+     (self allocaLiesSoSetSpBeforeCall or: [self mustAlignStack]) ifTrue: </DIV>
  <DIV>-     self registerArgsSlop + self cStackAlignment > 0 ifTrue: </DIV>
  <DIV>          [self setsp: calloutState argVector]. </DIV>
  <DIV>   </DIV>
  <DIV>      atomicType := self atomicTypeOf: calloutState ffiRetHeader. </DIV>
  <DIV>      (atomicType >> 1) = (FFITypeSingleFloat >> 1) </DIV>
  <DIV>          ifTrue: </DIV>
  <DIV>              [floatRet := self dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'double (*)()')] </DIV>
  <DIV>          ifFalse: </DIV>
  <DIV>              [intRet := self dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'usqLong (*)()')]. </DIV>
  <DIV>      "undo any callee argument pops because it may confuse stack management with the alloca." </DIV>
  <DIV>      (self isCalleePopsConvention: calloutState callFlags) ifTrue: </DIV>
  <DIV>          [self setsp: calloutState argVector]. </DIV>
  <DIV>   </DIV>
  <DIV>      self cppIf: COGMTVM ifTrue: </DIV>
  <DIV>      [(calloutState callFlags anyMask: FFICallFlagThreaded) ifTrue: </DIV>
  <DIV>          [interpreterProxy ownVM: myThreadIndex]]. </DIV>
  <DIV>   </DIV>
  <DIV>      (calloutState ffiRetHeader anyMask: FFIFlagPointer+FFIFlagStructure) ifTrue: </DIV>
  <DIV>          ["Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent </DIV>
  <DIV>           'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct." </DIV>
  <DIV>           (calloutState ffiRetHeader anyMask: FFIFlagPointer) </DIV>
  <DIV>              ifTrue: </DIV>
  <DIV>                  [oop := self ffiReturnPointer: intRet ofType: (self ffiReturnType: specOnStack) in: calloutState] </DIV>
  <DIV>              ifFalse: </DIV>
  <DIV>                  [oop := self ffiReturnStruct: intRet ofType: (self ffiReturnType: specOnStack) in: calloutState]. </DIV>
  <DIV>           ^oop]. </DIV>
  <DIV>       </DIV>
  <DIV>      (atomicType >> 1) = (FFITypeSingleFloat >> 1) </DIV>
  <DIV>          ifTrue: </DIV>
  <DIV>              [oop := interpreterProxy floatObjectOf: floatRet] </DIV>
  <DIV>          ifFalse: </DIV>
  <DIV>              [oop := self ffiCreateIntegralResultOop: intRet </DIV>
  <DIV>                          ofAtomicType: atomicType </DIV>
  <DIV>                          in: calloutState]. </DIV>
  <DIV>      ^interpreterProxy methodReturnValue: oop! </DIV>
  <DIV> </DIV>
  <DIV>Item was removed: </DIV>
  <DIV>- ----- Method: ThreadedIA32FFIPlugin>>registerArgsSlop (in category 'marshalling') ----- </DIV>
  <DIV>- registerArgsSlop </DIV>
  <DIV>-     "Answer any space needed to prevent the alloca'ed outgoing arguments marshalling area from </DIV>
  <DIV>-      being overwritten by any register arguments during calls during marshalling.  On x86 this is 0" </DIV>
  <DIV>-     ^0! </DIV>
  <DIV> </DIV>
  <DIV>Item was removed: </DIV>
  <DIV>- ----- Method: ThreadedPPCBEFFIPlugin>>registerArgsSlop (in category 'marshalling') ----- </DIV>
  <DIV>- registerArgsSlop </DIV>
  <DIV>-     "Answer any space needed to prevent the alloca'ed outgoing arguments marshalling area from </DIV>
  <DIV>-      being overwritten by any register arguments during calls during marshalling.  On PowerPC, which </DIV>
  <DIV>-      has 8 register arguments in the calling convention, register arguments are also written to the stack. </DIV>
  <DIV>-      So we must leave room for 8 * 4 bytes to avoid overwriting the marshalling stack as register </DIV>
  <DIV>-      arguments are written to the stack during calls to interpreterProxy etc." </DIV>
  <DIV>-     ^32! </DIV>
  <DIV> </DIV>
  <DIV>Item was removed: </DIV>
  <DIV>- ----- Method: ThreadedX64FFIPlugin>>registerArgsSlop (in category 'marshalling') ----- </DIV>
  <DIV>- registerArgsSlop </DIV>
  <DIV>-     "Answer any space needed to prevent the alloca'ed outgoing arguments marshalling area from </DIV>
  <DIV>-      being overwritten by any register arguments during calls during marshalling.  On ARM we </DIV>
  <DIV>-      believe this is zero." </DIV>
  <DIV>-     ^0! </DIV>
  <DIV> </DIV>
  <DIV>Item was changed: </DIV>
  <DIV>  ----- Method: ThreadedX64SysVFFIPlugin>>ffiCalloutTo:SpecOnStack:in: (in category 'callout support') ----- </DIV>
  <DIV>  ffiCalloutTo: procAddr SpecOnStack: specOnStack in: calloutState </DIV>
  <DIV>      <var: #procAddr type: #'void *'> </DIV>
  <DIV>      <var: #calloutState type: #'CalloutState *'> </DIV>
  <DIV>      <var: #loadFloatRegs declareC: 'extern void loadFloatRegs(double, double, double, double, double, double, double, double)'> </DIV>
  <DIV>      "Go out, call this guy and create the return value.  This *must* be inlined because of </DIV>
  <DIV>       the alloca of the outgoing stack frame in ffiCall:WithFlags:NumArgs:Args:AndTypes:" </DIV>
  <DIV>      | myThreadIndex atomicType floatRet intRet loadFloatRegs oop | </DIV>
  <DIV>      <var: #floatRet type: #double> </DIV>
  <DIV>      <var: #intRet type: 'SixteenByteReturn'> </DIV>
  <DIV>      <inline: true> </DIV>
  <DIV>      self cCode: '' inSmalltalk: [loadFloatRegs := #used. loadFloatRegs class]. </DIV>
  <DIV>      self cppIf: COGMTVM ifTrue: </DIV>
  <DIV>      [(calloutState callFlags anyMask: FFICallFlagThreaded) ifTrue: </DIV>
  <DIV>          [myThreadIndex := interpreterProxy disownVM: 0]]. </DIV>
  <DIV>   </DIV>
  <DIV>-     self registerArgsSlop + self cStackAlignment > 0 ifTrue: </DIV>
  <DIV>-         [self setsp: calloutState argVector]. </DIV>
  <DIV>-  </DIV>
  <DIV>      calloutState floatRegisterIndex > 0 ifTrue: </DIV>
  <DIV>          [self  </DIV>
  <DIV>              load: (calloutState floatRegisters at: 0) </DIV>
  <DIV>              Flo: (calloutState floatRegisters at: 1) </DIV>
  <DIV>              a: (calloutState floatRegisters at: 2) </DIV>
  <DIV>              t: (calloutState floatRegisters at: 3) </DIV>
  <DIV>              R: (calloutState floatRegisters at: 4) </DIV>
  <DIV>              e: (calloutState floatRegisters at: 5) </DIV>
  <DIV>              g: (calloutState floatRegisters at: 6) </DIV>
  <DIV>              s: (calloutState floatRegisters at: 7)]. </DIV>
  <DIV>   </DIV>
  <DIV>+     (self allocaLiesSoSetSpBeforeCall or: [self mustAlignStack]) ifTrue: </DIV>
  <DIV>+         [self setsp: calloutState argVector]. </DIV>
  <DIV>+  </DIV>
  <DIV>      atomicType := self atomicTypeOf: calloutState ffiRetHeader. </DIV>
  <DIV>      (atomicType >> 1) = (FFITypeSingleFloat >> 1) </DIV>
  <DIV>          ifTrue: </DIV>
  <DIV>              [atomicType = FFITypeSingleFloat </DIV>
  <DIV>                  ifTrue: </DIV>
  <DIV>                      [floatRet := self  </DIV>
  <DIV>                          dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)')  </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 0) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 1) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 2) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 3) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 4) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 5)] </DIV>
  <DIV>                  ifFalse: "atomicType = FFITypeDoubleFloat" </DIV>
  <DIV>                      [floatRet := self  </DIV>
  <DIV>                          dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)')  </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 0) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 1) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 2) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 3) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 4) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 5)]] </DIV>
  <DIV>          ifFalse: </DIV>
  <DIV>              [intRet := self  </DIV>
  <DIV>                  dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'SixteenByteReturn (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)')  </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 0) </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 1) </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 2) </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 3) </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 4) </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 5)]. </DIV>
  <DIV>      "undo any callee argument pops because it may confuse stack management with the alloca." </DIV>
  <DIV>      (self isCalleePopsConvention: calloutState callFlags) ifTrue: </DIV>
  <DIV>          [self setsp: calloutState argVector]. </DIV>
  <DIV>   </DIV>
  <DIV>      self cppIf: COGMTVM ifTrue: </DIV>
  <DIV>      [(calloutState callFlags anyMask: FFICallFlagThreaded) ifTrue: </DIV>
  <DIV>          [interpreterProxy ownVM: myThreadIndex]]. </DIV>
  <DIV>   </DIV>
  <DIV>      (calloutState ffiRetHeader anyMask: FFIFlagPointer+FFIFlagStructure) ifTrue: </DIV>
  <DIV>          ["Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent </DIV>
  <DIV>           'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct." </DIV>
  <DIV>           (calloutState ffiRetHeader anyMask: FFIFlagPointer) </DIV>
  <DIV>              ifTrue: </DIV>
  <DIV>                  [oop := self ffiReturnPointer: intRet a ofType: (self ffiReturnType: specOnStack) in: calloutState] </DIV>
  <DIV>              ifFalse: </DIV>
  <DIV>                  [oop := self ffiReturnStruct: intRet ofType: (self ffiReturnType: specOnStack) in: calloutState]. </DIV>
  <DIV>           ^oop]. </DIV>
  <DIV>       </DIV>
  <DIV>      (atomicType >> 1) = (FFITypeSingleFloat >> 1) </DIV>
  <DIV>          ifTrue: </DIV>
  <DIV>              [oop := interpreterProxy floatObjectOf: floatRet] </DIV>
  <DIV>          ifFalse: </DIV>
  <DIV>              [oop := self ffiCreateIntegralResultOop: intRet a </DIV>
  <DIV>                          ofAtomicType: atomicType </DIV>
  <DIV>                          in: calloutState]. </DIV>
  <DIV>      ^interpreterProxy methodReturnValue: oop! </DIV>
  <DIV> </DIV>
  <DIV>Item was changed: </DIV>
  <DIV>  ----- Method: ThreadedX64Win64FFIPlugin>>ffiCalloutTo:SpecOnStack:in: (in category 'callout support') ----- </DIV>
  <DIV>  ffiCalloutTo: procAddr SpecOnStack: specOnStack in: calloutState </DIV>
  <DIV>      <var: #procAddr type: #'void *'> </DIV>
  <DIV>      <var: #calloutState type: #'CalloutState *'> </DIV>
  <DIV>      <var: #loadFloatRegs declareC: 'extern void loadFloatRegs(double, double, double, double)'> </DIV>
  <DIV>      "Go out, call this guy and create the return value.  This *must* be inlined because of </DIV>
  <DIV>       the alloca of the outgoing stack frame in ffiCall:WithFlags:NumArgs:Args:AndTypes:" </DIV>
  <DIV>      | myThreadIndex atomicType floatRet intRet loadFloatRegs oop | </DIV>
  <DIV>      <var: #floatRet type: #double> </DIV>
  <DIV>      <var: #intRet type: #usqLong> </DIV>
  <DIV>      <inline: true> </DIV>
  <DIV>      self cCode: '' inSmalltalk: [loadFloatRegs := #used. loadFloatRegs class]. </DIV>
  <DIV>      self cppIf: COGMTVM ifTrue: </DIV>
  <DIV>      [(calloutState callFlags anyMask: FFICallFlagThreaded) ifTrue: </DIV>
  <DIV>          [myThreadIndex := interpreterProxy disownVM: 0]]. </DIV>
  <DIV>   </DIV>
  <DIV>-     self registerArgsSlop + self cStackAlignment > 0 ifTrue: </DIV>
  <DIV>-         [self setsp: calloutState argVector]. </DIV>
  <DIV>-  </DIV>
  <DIV>      calloutState floatRegisterSignature > 0 ifTrue: </DIV>
  <DIV>          [self  </DIV>
  <DIV>              load: (calloutState floatRegisters at: 0) </DIV>
  <DIV>              Flo: (calloutState floatRegisters at: 1) </DIV>
  <DIV>              at: (calloutState floatRegisters at: 2) </DIV>
  <DIV>              Re: (calloutState floatRegisters at: 3) </DIV>
  <DIV>              gs: (calloutState floatRegisters at: 4)]. </DIV>
  <DIV>   </DIV>
  <DIV>+     (self allocaLiesSoSetSpBeforeCall or: [self mustAlignStack]) ifTrue: </DIV>
  <DIV>+         [self setsp: calloutState argVector]. </DIV>
  <DIV>+      </DIV>
  <DIV>      atomicType := self atomicTypeOf: calloutState ffiRetHeader. </DIV>
  <DIV>      (atomicType >> 1) = (FFITypeSingleFloat >> 1) </DIV>
  <DIV>          ifTrue: </DIV>
  <DIV>              [atomicType = FFITypeSingleFloat </DIV>
  <DIV>                  ifTrue: </DIV>
  <DIV>                      [floatRet := self  </DIV>
  <DIV>                          dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'float (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)')  </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 0) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 1) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 2) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 3)] </DIV>
  <DIV>                  ifFalse: "atomicType = FFITypeDoubleFloat" </DIV>
  <DIV>                      [floatRet := self  </DIV>
  <DIV>                          dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'double (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)')  </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 0) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 1) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 2) </DIV>
  <DIV>                          with: (calloutState integerRegisters at: 3)]] </DIV>
  <DIV>          ifFalse: </DIV>
  <DIV>              [intRet := self  </DIV>
  <DIV>                  dispatchFunctionPointer: (self cCoerceSimple: procAddr to: 'usqIntptr_t (*)(sqIntptr_t, sqIntptr_t, sqIntptr_t, sqIntptr_t)')  </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 0) </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 1) </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 2) </DIV>
  <DIV>                  with: (calloutState integerRegisters at: 3)]. </DIV>
  <DIV>      "undo any callee argument pops because it may confuse stack management with the alloca." </DIV>
  <DIV>      (self isCalleePopsConvention: calloutState callFlags) ifTrue: </DIV>
  <DIV>          [self setsp: calloutState argVector]. </DIV>
  <DIV>   </DIV>
  <DIV>      self cppIf: COGMTVM ifTrue: </DIV>
  <DIV>      [(calloutState callFlags anyMask: FFICallFlagThreaded) ifTrue: </DIV>
  <DIV>          [interpreterProxy ownVM: myThreadIndex]]. </DIV>
  <DIV>   </DIV>
  <DIV>      (calloutState ffiRetHeader anyMask: FFIFlagPointer+FFIFlagStructure) ifTrue: </DIV>
  <DIV>          ["Note: Order is important here since FFIFlagPointer + FFIFlagStructure is used to represent </DIV>
  <DIV>           'typedef void* VoidPointer' and VoidPointer must be returned as pointer *not* as struct." </DIV>
  <DIV>           (calloutState ffiRetHeader anyMask: FFIFlagPointer) </DIV>
  <DIV>              ifTrue: </DIV>
  <DIV>                  [oop := self ffiReturnPointer: intRet ofType: (self ffiReturnType: specOnStack) in: calloutState] </DIV>
  <DIV>              ifFalse: </DIV>
  <DIV>                  [oop := self ffiReturnStruct: intRet ofType: (self ffiReturnType: specOnStack) in: calloutState]. </DIV>
  <DIV>           ^oop]. </DIV>
  <DIV>       </DIV>
  <DIV>      (atomicType >> 1) = (FFITypeSingleFloat >> 1) </DIV>
  <DIV>          ifTrue: </DIV>
  <DIV>              [oop := interpreterProxy floatObjectOf: floatRet] </DIV>
  <DIV>          ifFalse: </DIV>
  <DIV>              [oop := self ffiCreateIntegralResultOop: intRet </DIV>
  <DIV>                          ofAtomicType: atomicType </DIV>
  <DIV>                          in: calloutState]. </DIV>
  <DIV>      ^interpreterProxy methodReturnValue: oop! </DIV>
  <DIV> </DIV>
  <DIV> </DIV>
  <DIV> </DIV>
  <DIV>------------------------------ </DIV>
  <DIV> </DIV>
  <DIV>Subject: Digest Footer </DIV>
  <DIV> </DIV>
  <DIV>_______________________________________________ </DIV>
  <DIV>Vm-dev mailing list </DIV>
  <DIV>Vm-dev@lists.squeakfoundation.org </DIV>
  <DIV>http://lists.squeakfoundation.org/mailman/listinfo/vm-dev </DIV>
  <DIV> </DIV>
  <DIV> </DIV>
  <DIV>------------------------------ </DIV>
  <DIV> </DIV>
  <DIV>End of Vm-dev Digest, Vol 126, Issue 29 </DIV>
  <DIV>*************************************** </DIV></DIV></BLOCKQUOTE></BODY></HTML>