Back to index

lightning-sunbird  0.9+nobinonly
xptcinvoke_unixish_x86.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Mark Mentovai <mark@moxienet.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 
00039 /* Platform specific code to invoke XPCOM methods on native objects */
00040 
00041 #include "xptcprivate.h"
00042 #include "xptc_platforms_unixish_x86.h"
00043 
00044 extern "C" {
00045 
00046 static void
00047 invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint32* d)
00048 {
00049     for(PRUint32 i = paramCount; i >0; i--, d++, s++)
00050     {
00051         if(s->IsPtrData())
00052         {
00053             *((void**)d) = s->ptr;
00054             continue;
00055         }
00056 
00057 /* XXX: the following line is here (rather than as the default clause in
00058  *      the following switch statement) so that the Sun native compiler
00059  *      will generate the correct assembly code on the Solaris Intel
00060  *      platform. See the comments in bug #28817 for more details.
00061  */
00062 
00063         *((void**)d) = s->val.p;
00064 
00065         switch(s->type)
00066         {
00067         case nsXPTType::T_I64    : *((PRInt64*) d) = s->val.i64; d++;    break;
00068         case nsXPTType::T_U64    : *((PRUint64*)d) = s->val.u64; d++;    break;
00069         case nsXPTType::T_DOUBLE : *((double*)  d) = s->val.d;   d++;    break;
00070         }
00071     }
00072 }
00073 
00074 }
00075 
00076 XPTC_PUBLIC_API(nsresult)
00077 XPTC_InvokeByIndex(nsISupports* that, PRUint32 methodIndex,
00078                    PRUint32 paramCount, nsXPTCVariant* params)
00079 {
00080 #ifdef __GNUC__            /* Gnu compiler. */
00081   PRUint32 result;
00082   /* Each param takes at most 2, 4-byte words
00083      It doesn't matter if we push too many words, and calculating the exact
00084      amount takes time. */
00085   PRUint32 n = paramCount << 3;
00086   void (*fn_copy) (unsigned int, nsXPTCVariant *, PRUint32 *) = invoke_copy_to_stack;
00087   int temp1, temp2;
00088  
00089   /* These are only significant when KEEP_STACK_16_BYTE_ALIGNED is
00090      defined.  Otherwise, they're just placeholders to keep the parameter
00091      indices the same for aligned and unaligned users in the inline asm
00092      block. */
00093   unsigned int saved_esp;
00094   
00095  __asm__ __volatile__(
00096 #ifdef KEEP_STACK_16_BYTE_ALIGNED
00097     "movl  %%esp, %3\n\t"
00098 #endif
00099     "subl  %8, %%esp\n\t" /* make room for params */
00100 #ifdef KEEP_STACK_16_BYTE_ALIGNED
00101     /* For the second CALL, there will be one parameter before the ones
00102        copied by invoke_copy_to_stack.  Make sure that the stack will be
00103        aligned for that CALL. */
00104     "subl  $4, %%esp\n\t"
00105     "andl  $0xfffffff0, %%esp\n\t"
00106     /* For the first CALL, there are three parameters.  Leave padding to
00107        ensure alignment. */
00108     "subl  $4, %%esp\n\t"
00109     /* The third parameter to invoke_copy_to_stack is the destination pointer.
00110        It needs to point into the parameter area prepared for the second CALL,
00111        leaving room for the |that| parameter.  This reuses |n|, which was
00112        the stack space to reserve, but that's OK because it's no longer needed
00113        if the stack is being kept aligned. */
00114     "leal  8(%%esp), %8\n\t"
00115     "pushl %8\n\t"
00116 #else
00117     "pushl %%esp\n\t"
00118 #endif
00119     "pushl %7\n\t"
00120     "pushl %6\n\t"
00121     "call  *%9\n\t"       /* copy params */
00122 #ifdef KEEP_STACK_16_BYTE_ALIGNED
00123     /* The stack is still aligned from the first CALL.  Keep it aligned for
00124        the next one by popping past the parameters from the first CALL and
00125        leaving space for the first (|that|) parameter for the second CALL. */
00126     "addl  $0x14, %%esp\n\t"
00127 #else
00128     "addl  $0xc, %%esp\n\t"
00129 #endif
00130     "movl  %4, %%ecx\n\t"
00131 #ifdef CFRONT_STYLE_THIS_ADJUST
00132     "movl  (%%ecx), %%edx\n\t"
00133     "movl  %5, %%eax\n\t"   /* function index */
00134     "shl   $3, %%eax\n\t"   /* *= 8 */
00135     "addl  $8, %%eax\n\t"   /* += 8 skip first entry */
00136     "addl  %%eax, %%edx\n\t"
00137     "movswl (%%edx), %%eax\n\t" /* 'this' offset */
00138     "addl  %%eax, %%ecx\n\t"
00139     "pushl %%ecx\n\t"
00140     "addl  $4, %%edx\n\t"   /* += 4, method pointer */
00141 #else /* THUNK_BASED_THIS_ADJUST */
00142     "pushl %%ecx\n\t"
00143     "movl  (%%ecx), %%edx\n\t"
00144     "movl  %5, %%eax\n\t"   /* function index */
00145 #if defined(__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100 /* G++ V3 ABI */
00146     "leal  (%%edx,%%eax,4), %%edx\n\t"
00147 #else /* not G++ V3 ABI  */
00148     "leal  8(%%edx,%%eax,4), %%edx\n\t"
00149 #endif /* G++ V3 ABI */
00150 #endif
00151     "call  *(%%edx)\n\t"    /* safe to not cleanup esp */
00152 #ifdef KEEP_STACK_16_BYTE_ALIGNED
00153     "movl  %3, %%esp\n\t"
00154 #else
00155     "addl  $4, %%esp\n\t"
00156     "addl  %8, %%esp"
00157 #endif
00158     : "=a" (result),        /* %0 */
00159       "=c" (temp1),         /* %1 */
00160       "=d" (temp2),         /* %2 */
00161 #ifdef KEEP_STACK_16_BYTE_ALIGNED
00162       "=&g" (saved_esp)     /* %3 */
00163 #else
00164       /* Don't waste a register, this isn't used if alignment is unimportant */
00165       "=m" (saved_esp)      /* %3 */
00166 #endif
00167     : "g" (that),           /* %4 */
00168       "g" (methodIndex),    /* %5 */
00169       "1" (paramCount),     /* %6 */
00170       "2" (params),         /* %7 */
00171 #ifdef KEEP_STACK_16_BYTE_ALIGNED
00172       /* Must be in a register, it's the target of an LEA instruction */
00173       "r" (n),              /* %8 */
00174 #else
00175       "g" (n),              /* %8 */
00176 #endif
00177       "0" (fn_copy)         /* %9 */
00178     : "memory"
00179     );
00180     
00181   return result;
00182 
00183 #else
00184 #error "can't find a compiler to use"
00185 #endif /* __GNUC__ */
00186 
00187 }