Bug 684659 - Remove xptcinvoke_unixish_x86.cpp. r=bsmedberg.

This patch:
* Modifies the linux version so that both calls are aligned and can be used by the OS X assembler.
* Removes KEEP_STACK_16_BYTE_ALIGNED, since it is cheap to do it always and the linux implementation was already doing.
* Define MOZ_NEED_LEADING_UNDERSCOR on OS X
* Move users of xptcinvoke_unixish_x86.cpp to xptcinvoke_gcc_x86_unix.cpp (and the stubs file too)

--HG--
extra : rebase_source : 11eac139b33ddfe60af96690e0c54aec77db82c9
This commit is contained in:
Rafael Ávila de Espíndola 2011-09-16 14:34:09 -07:00
Родитель a7981da69c
Коммит 7c62c3c039
5 изменённых файлов: 43 добавлений и 387 удалений

Просмотреть файл

@ -64,22 +64,6 @@ NO_PROFILE_GUIDED_OPTIMIZE = 1
endif
endif
ifeq (Darwin,$(OS_ARCH))
ifeq (86,$(findstring 86,$(OS_TEST)))
ifneq (x86_64,$(OS_TEST))
# If we compile xptcinvoke_unixish_x86.cpp with -fomit-frame-pointer
# we end up crashing on startup. This is because
# "movl %5, %%eax\n\t" /* function index */
# becomes
# mov 0x1c(%esp),%eax
# but we have modified esp.
# NOTE: MOZ_FRAMEPTR_FLAGS must be set before including config.mk
# FIXME: change the file instead of using this hack.
MOZ_FRAMEPTR_FLAGS=-fno-omit-frame-pointer
endif
endif
endif
include $(topsrcdir)/config/config.mk
######################################################################
@ -94,15 +78,15 @@ ifeq (86,$(findstring 86,$(OS_TEST)))
ifeq (x86_64,$(OS_TEST))
CPPSRCS := xptcinvoke_x86_64_unix.cpp xptcstubs_x86_64_darwin.cpp
else
DEFINES += -DKEEP_STACK_16_BYTE_ALIGNED
CPPSRCS := xptcinvoke_unixish_x86.cpp xptcstubs_unixish_x86.cpp
DEFINES += -DMOZ_NEED_LEADING_UNDERSCORE
CPPSRCS := xptcinvoke_gcc_x86_unix.cpp xptcstubs_gcc_x86_unix.cpp
endif
endif
endif
ifneq (,$(filter NetBSD OpenBSD BSD_OS GNU,$(OS_ARCH)))
ifeq (86,$(findstring 86,$(OS_TEST)))
CPPSRCS := xptcinvoke_unixish_x86.cpp xptcstubs_unixish_x86.cpp
CPPSRCS := xptcinvoke_gcc_x86_unix.cpp xptcstubs_gcc_x86_unix.cpp
endif
endif
#
@ -137,7 +121,7 @@ endif
#
ifeq ($(OS_TARGET),NTO)
ifeq ($(OS_TEST),x86)
CPPSRCS := xptcinvoke_unixish_x86.cpp xptcstubs_unixish_x86.cpp
CPPSRCS := xptcinvoke_gcc_x86_unix.cpp xptcstubs_gcc_x86_unix.cpp
endif
ifeq ($(OS_TEST),arm)
CPPSRCS := xptcinvoke_nto_arm.cpp xptcstubs_nto_arm.cpp

Просмотреть файл

@ -20,6 +20,7 @@
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Mentovai <mark@moxienet.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -103,25 +104,23 @@ __asm__ (
/* alignment here seems unimportant here; this was 16, now it's 2 which
is what xptcstubs uses. */
".align 2\n\t"
#if defined(XP_WIN32) || defined(XP_OS2)
".globl " SYMBOL_UNDERSCORE "_NS_InvokeByIndex_P\n\t"
SYMBOL_UNDERSCORE "_NS_InvokeByIndex_P:\n\t"
#else
".globl " SYMBOL_UNDERSCORE "NS_InvokeByIndex_P\n\t"
#if !defined(XP_WIN32) && !defined(XP_OS2) && !defined(XP_MACOSX)
".type " SYMBOL_UNDERSCORE "NS_InvokeByIndex_P,@function\n"
SYMBOL_UNDERSCORE "NS_InvokeByIndex_P:\n\t"
#endif
SYMBOL_UNDERSCORE "NS_InvokeByIndex_P:\n\t"
"pushl %ebp\n\t"
"movl %esp, %ebp\n\t"
"movl 0x10(%ebp), %eax\n\t"
"leal 0(,%eax,8),%edx\n\t"
"movl %esp, %ecx\n\t"
"subl %edx, %ecx\n\t"
/* set up call frame for method. */
"subl %edx, %esp\n\t" /* make room for params. */
/* Align to maximum x86 data size: 128 bits == 16 bytes == XMM register size.
* This is to avoid protection faults where SSE+ alignment of stack pointer
* is assumed and required, e.g. by GCC4's -ftree-vectorize option.
*/
"andl $0xfffffff0, %ecx\n\t" /* drop(?) stack ptr to 128-bit align */
"andl $0xfffffff0, %esp\n\t" /* drop(?) stack ptr to 128-bit align */
/* $esp should be aligned to a 16-byte boundary here (note we include an
* additional 4 bytes in a later push instruction). This will ensure $ebp
* in the function called below is aligned to a 0x8 boundary. SSE instructions
@ -129,12 +128,14 @@ __asm__ (
* boundary. The GCC compiler will generate the memory operand using $ebp
* with an 8-byte offset.
*/
"subl $0xc, %ecx\n\t" /* lower again; push/call below will re-align */
"movl %ecx, %esp\n\t" /* make stack space */
"subl $0xc, %esp\n\t" /* lower again; push/call below will re-align */
"movl %esp, %ecx\n\t" /* ecx = d */
"movl 8(%ebp), %edx\n\t" /* edx = this */
"pushl %edx\n\t" /* push this. esp % 16 == 0 */
"movl 0x14(%ebp), %edx\n\t"
"call " SYMBOL_UNDERSCORE "invoke_copy_to_stack\n\t"
"movl 0x08(%ebp), %ecx\n\t" /* 'that' */
"pushl %ecx\n\t"
"movl (%ecx), %edx\n\t"
"movl 0x0c(%ebp), %eax\n\t" /* function index */
"leal (%edx,%eax,4), %edx\n\t"
@ -142,7 +143,7 @@ __asm__ (
"movl %ebp, %esp\n\t"
"popl %ebp\n\t"
"ret\n"
#if !defined(XP_WIN32) && !defined(XP_OS2)
#if !defined(XP_WIN32) && !defined(XP_OS2) && !defined(XP_MACOSX)
".size " SYMBOL_UNDERSCORE "NS_InvokeByIndex_P, . -" SYMBOL_UNDERSCORE "NS_InvokeByIndex_P\n\t"
#endif
);

Просмотреть файл

@ -1,176 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mark Mentovai <mark@moxienet.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* Platform specific code to invoke XPCOM methods on native objects */
#include "xptcprivate.h"
extern "C" {
static void
invoke_copy_to_stack(PRUint32 paramCount, nsXPTCVariant* s, PRUint32* d)
{
for(PRUint32 i = paramCount; i >0; i--, d++, s++)
{
if(s->IsPtrData())
{
*((void**)d) = s->ptr;
continue;
}
/* XXX: the following line is here (rather than as the default clause in
* the following switch statement) so that the Sun native compiler
* will generate the correct assembly code on the Solaris Intel
* platform. See the comments in bug #28817 for more details.
*/
*((void**)d) = s->val.p;
switch(s->type)
{
case nsXPTType::T_I64 : *((PRInt64*) d) = s->val.i64; d++; break;
case nsXPTType::T_U64 : *((PRUint64*)d) = s->val.u64; d++; break;
case nsXPTType::T_DOUBLE : *((double*) d) = s->val.d; d++; break;
}
}
}
}
EXPORT_XPCOM_API(nsresult)
NS_InvokeByIndex_P(nsISupports* that, PRUint32 methodIndex,
PRUint32 paramCount, nsXPTCVariant* params)
{
PRUint32 result;
/* Each param takes at most 2, 4-byte words
It doesn't matter if we push too many words, and calculating the exact
amount takes time. */
PRUint32 n = paramCount << 3;
void (*fn_copy) (unsigned int, nsXPTCVariant *, PRUint32 *) = invoke_copy_to_stack;
int temp1, temp2;
/* These are only significant when KEEP_STACK_16_BYTE_ALIGNED is
defined. Otherwise, they're just placeholders to keep the parameter
indices the same for aligned and unaligned users in the inline asm
block. */
unsigned int saved_esp;
__asm__ __volatile__(
#ifdef KEEP_STACK_16_BYTE_ALIGNED
"movl %%esp, %3\n\t"
#endif
"subl %8, %%esp\n\t" /* make room for params */
#ifdef KEEP_STACK_16_BYTE_ALIGNED
/* For the second CALL, there will be one parameter before the ones
copied by invoke_copy_to_stack. Make sure that the stack will be
aligned for that CALL. */
"subl $4, %%esp\n\t"
"andl $0xfffffff0, %%esp\n\t"
/* For the first CALL, there are three parameters. Leave padding to
ensure alignment. */
"subl $4, %%esp\n\t"
/* The third parameter to invoke_copy_to_stack is the destination pointer.
It needs to point into the parameter area prepared for the second CALL,
leaving room for the |that| parameter. This reuses |n|, which was
the stack space to reserve, but that's OK because it's no longer needed
if the stack is being kept aligned. */
"leal 8(%%esp), %8\n\t"
"pushl %8\n\t"
#else
"pushl %%esp\n\t"
#endif
"pushl %7\n\t"
"pushl %6\n\t"
"call *%9\n\t" /* copy params */
#ifdef KEEP_STACK_16_BYTE_ALIGNED
/* The stack is still aligned from the first CALL. Keep it aligned for
the next one by popping past the parameters from the first CALL and
leaving space for the first (|that|) parameter for the second CALL. */
"addl $0x14, %%esp\n\t"
#else
"addl $0xc, %%esp\n\t"
#endif
"movl %4, %%ecx\n\t"
#ifdef CFRONT_STYLE_THIS_ADJUST
"movl (%%ecx), %%edx\n\t"
"movl %5, %%eax\n\t" /* function index */
"shl $3, %%eax\n\t" /* *= 8 */
"addl $8, %%eax\n\t" /* += 8 skip first entry */
"addl %%eax, %%edx\n\t"
"movswl (%%edx), %%eax\n\t" /* 'this' offset */
"addl %%eax, %%ecx\n\t"
"pushl %%ecx\n\t"
"addl $4, %%edx\n\t" /* += 4, method pointer */
#else /* THUNK_BASED_THIS_ADJUST */
"pushl %%ecx\n\t"
"movl (%%ecx), %%edx\n\t"
"movl %5, %%eax\n\t" /* function index */
"leal (%%edx,%%eax,4), %%edx\n\t"
#endif
"call *(%%edx)\n\t" /* safe to not cleanup esp */
#ifdef KEEP_STACK_16_BYTE_ALIGNED
"movl %3, %%esp\n\t"
#else
"addl $4, %%esp\n\t"
"addl %8, %%esp"
#endif
: "=a" (result), /* %0 */
"=c" (temp1), /* %1 */
"=d" (temp2), /* %2 */
#ifdef KEEP_STACK_16_BYTE_ALIGNED
"=&g" (saved_esp) /* %3 */
#else
/* Don't waste a register, this isn't used if alignment is unimportant */
"=m" (saved_esp) /* %3 */
#endif
: "g" (that), /* %4 */
"g" (methodIndex), /* %5 */
"1" (paramCount), /* %6 */
"2" (params), /* %7 */
#ifdef KEEP_STACK_16_BYTE_ALIGNED
/* Must be in a register, it's the target of an LEA instruction */
"r" (n), /* %8 */
#else
"g" (n), /* %8 */
#endif
"0" (fn_copy) /* %9 */
: "memory"
);
return result;
}

Просмотреть файл

@ -98,24 +98,35 @@ PrepareAndDispatch(uint32 methodIndex, nsXPTCStubBase* self, PRUint32* args)
}
} // extern "C"
#if !defined(XP_MACOSX)
#define STUB_HEADER(a, b) ".hidden " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase" #a "Stub" #b "Ev\n\t" \
".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase" #a "Stub" #b "Ev,@function\n"
#define STUB_SIZE(a, b) ".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase" #a "Stub" #b "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase" #a "Stub" #b "Ev\n\t"
#else
#define STUB_HEADER(a, b)
#define STUB_SIZE(a, b)
#endif
// gcc3 mangling tends to insert the length of the method name
#define STUB_ENTRY(n) \
asm(".text\n\t" \
".align 2\n\t" \
".if " #n " < 10\n\t" \
".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \
".hidden " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \
".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev,@function\n" \
STUB_HEADER(5, n) \
SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev:\n\t" \
".elseif " #n " < 100\n\t" \
".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \
".hidden " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \
".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev,@function\n" \
STUB_HEADER(6, n) \
SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev:\n\t" \
".elseif " #n " < 1000\n\t" \
".globl " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \
".hidden " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \
".type " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev,@function\n" \
STUB_HEADER(7, n) \
SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev:\n\t" \
".else\n\t" \
".err \"stub number " #n " >= 1000 not yet supported\"\n\t" \
@ -123,22 +134,27 @@ asm(".text\n\t" \
"movl $" #n ", %eax\n\t" \
"jmp " SYMBOL_UNDERSCORE "SharedStub\n\t" \
".if " #n " < 10\n\t" \
".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase5Stub" #n "Ev\n\t" \
STUB_SIZE(5, n) \
".elseif " #n " < 100\n\t" \
".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase6Stub" #n "Ev\n\t" \
STUB_SIZE(6, n) \
".else\n\t" \
".size " SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev,.-" SYMBOL_UNDERSCORE "_ZN14nsXPTCStubBase7Stub" #n "Ev\n\t" \
STUB_SIZE(7, n) \
".endif");
// static nsresult SharedStub(PRUint32 methodIndex) __attribute__((regparm(1)))
asm(".text\n\t"
".align 2\n\t"
#if !defined(XP_MACOSX)
".type " SYMBOL_UNDERSCORE "SharedStub,@function\n\t"
#endif
SYMBOL_UNDERSCORE "SharedStub:\n\t"
"leal 0x08(%esp), %ecx\n\t"
"movl 0x04(%esp), %edx\n\t"
"jmp " SYMBOL_UNDERSCORE "PrepareAndDispatch\n\t"
".size " SYMBOL_UNDERSCORE "SharedStub,.-" SYMBOL_UNDERSCORE "SharedStub");
#if !defined(XP_MACOSX)
".size " SYMBOL_UNDERSCORE "SharedStub,.-" SYMBOL_UNDERSCORE "SharedStub"
#endif
);
#define SENTINEL_ENTRY(n) \
nsresult nsXPTCStubBase::Sentinel##n() \

Просмотреть файл

@ -1,169 +0,0 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1999
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
/* Implement shared vtbl methods. */
#include "xptcprivate.h"
#include "xptiprivate.h"
static nsresult
PrepareAndDispatch(nsXPTCStubBase* self, uint32 methodIndex, PRUint32* args)
{
#define PARAM_BUFFER_COUNT 16
nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT];
nsXPTCMiniVariant* dispatchParams = NULL;
const nsXPTMethodInfo* info;
PRUint8 paramCount;
PRUint8 i;
nsresult result = NS_ERROR_FAILURE;
NS_ASSERTION(self,"no self");
self->mEntry->GetMethodInfo(PRUint16(methodIndex), &info);
NS_ASSERTION(info,"no interface info");
paramCount = info->GetParamCount();
// setup variant array pointer
if(paramCount > PARAM_BUFFER_COUNT)
dispatchParams = new nsXPTCMiniVariant[paramCount];
else
dispatchParams = paramBuffer;
NS_ASSERTION(dispatchParams,"no place for params");
PRUint32* ap = args;
for(i = 0; i < paramCount; i++, ap++)
{
const nsXPTParamInfo& param = info->GetParam(i);
const nsXPTType& type = param.GetType();
nsXPTCMiniVariant* dp = &dispatchParams[i];
if(param.IsOut() || !type.IsArithmetic())
{
dp->val.p = (void*) *ap;
continue;
}
// else
dp->val.p = (void*) *ap;
switch(type)
{
case nsXPTType::T_I64 : dp->val.i64 = *((PRInt64*) ap); ap++; break;
case nsXPTType::T_U64 : dp->val.u64 = *((PRUint64*)ap); ap++; break;
case nsXPTType::T_DOUBLE : dp->val.d = *((double*) ap); ap++; break;
}
}
result = self->mOuter->
CallMethod((PRUint16)methodIndex, info, dispatchParams);
if(dispatchParams != paramBuffer)
delete [] dispatchParams;
return result;
}
#ifdef KEEP_STACK_16_BYTE_ALIGNED
/* Make sure the stack is 16-byte aligned. Do that by aligning to 16 bytes and
* then subtracting 4 so the three subsequent pushes result in a 16-byte aligned
* stack. */
#define ALIGN_STACK_DECL \
unsigned int saved_esp;
#define ALIGN_STACK_SAVE \
"movl %%esp, %3\n\t"
#define ALIGN_STACK_ALIGN \
"addl $0x4, %%esp\n\t" \
"andl $0xfffffff0, %%esp\n\t" \
"subl $0x4, %%esp\n\t"
#define STACK_RESTORE \
"movl %3, %%esp\n"
#define ALIGN_STACK_REGS_IN \
, "=r"(saved_esp) /* 3 */
#define ALIGN_STACK_REGS_OUT \
, "3"(saved_esp)
#else
#define ALIGN_STACK_DECL
#define ALIGN_STACK_SAVE
#define ALIGN_STACK_ALIGN
#define STACK_RESTORE \
"addl $12, %%esp\n"
#define ALIGN_STACK_REGS_IN
#define ALIGN_STACK_REGS_OUT
#endif
#define STUB_ENTRY(n) \
nsresult nsXPTCStubBase::Stub##n() \
{ \
register nsresult (*method) (nsXPTCStubBase *, uint32, PRUint32 *) = PrepareAndDispatch; \
int temp0, temp1; \
register nsresult result; \
ALIGN_STACK_DECL \
__asm__ __volatile__( \
ALIGN_STACK_SAVE \
ALIGN_STACK_ALIGN \
"leal 0x0c(%%ebp), %%ecx\n\t" /* args */ \
"pushl %%ecx\n\t" \
"pushl $"#n"\n\t" /* method index */ \
"movl 0x08(%%ebp), %%ecx\n\t" /* this */ \
"pushl %%ecx\n\t" \
"call *%%edx\n\t" /* PrepareAndDispatch */ \
STACK_RESTORE /* "addl $12, %%esp" or restore saved */ \
: "=a" (result), /* %0 */ \
"=&c" (temp0), /* %1 */ \
"=d" (temp1) /* %2 */ \
ALIGN_STACK_REGS_IN \
: "2" (method) /* %2 */ \
ALIGN_STACK_REGS_OUT \
: "memory" \
); \
return result; \
}
#define SENTINEL_ENTRY(n) \
nsresult nsXPTCStubBase::Sentinel##n() \
{ \
NS_ERROR("nsXPTCStubBase::Sentinel called"); \
return NS_ERROR_NOT_IMPLEMENTED; \
}
#include "xptcstubsdef.inc"