michael@0: /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // Implement shared vtbl methods. michael@0: michael@0: #include "xptcprivate.h" michael@0: #include "xptiprivate.h" michael@0: michael@0: // The Linux/PPC ABI (aka PPC/SYSV ABI) passes the first 8 integral michael@0: // parameters and the first 8 floating point parameters in registers michael@0: // (r3-r10 and f1-f8), no stack space is allocated for these by the michael@0: // caller. The rest of the parameters are passed in the callers stack michael@0: // area. The stack pointer has to retain 16-byte alignment, longlongs michael@0: // and doubles are aligned on 8-byte boundaries. michael@0: #ifndef __NO_FPRS__ michael@0: #define PARAM_BUFFER_COUNT 16 michael@0: #define GPR_COUNT 8 michael@0: #define FPR_COUNT 8 michael@0: #else michael@0: #define PARAM_BUFFER_COUNT 8 michael@0: #define GPR_COUNT 8 michael@0: #endif michael@0: // PrepareAndDispatch() is called by SharedStub() and calls the actual method. michael@0: // michael@0: // - 'args[]' contains the arguments passed on stack michael@0: // - 'gprData[]' contains the arguments passed in integer registers michael@0: // - 'fprData[]' contains the arguments passed in floating point registers michael@0: // michael@0: // The parameters are mapped into an array of type 'nsXPTCMiniVariant' michael@0: // and then the method gets called. michael@0: michael@0: extern "C" nsresult ATTRIBUTE_USED michael@0: PrepareAndDispatch(nsXPTCStubBase* self, michael@0: uint32_t methodIndex, michael@0: uint32_t* args, michael@0: uint32_t *gprData, michael@0: double *fprData) michael@0: { michael@0: nsXPTCMiniVariant paramBuffer[PARAM_BUFFER_COUNT]; michael@0: nsXPTCMiniVariant* dispatchParams = nullptr; michael@0: const nsXPTMethodInfo* info = nullptr; michael@0: uint32_t paramCount; michael@0: uint32_t i; michael@0: nsresult result = NS_ERROR_FAILURE; michael@0: michael@0: NS_ASSERTION(self,"no self"); michael@0: michael@0: self->mEntry->GetMethodInfo(uint16_t(methodIndex), &info); michael@0: NS_ASSERTION(info,"no method info"); michael@0: if (! info) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: paramCount = info->GetParamCount(); michael@0: michael@0: // setup variant array pointer michael@0: if(paramCount > PARAM_BUFFER_COUNT) michael@0: dispatchParams = new nsXPTCMiniVariant[paramCount]; michael@0: else michael@0: dispatchParams = paramBuffer; michael@0: michael@0: NS_ASSERTION(dispatchParams,"no place for params"); michael@0: if (! dispatchParams) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: uint32_t* ap = args; michael@0: uint32_t gpr = 1; // skip one GPR register michael@0: #ifndef __NO_FPRS__ michael@0: uint32_t fpr = 0; michael@0: #endif michael@0: uint32_t tempu32; michael@0: uint64_t tempu64; michael@0: michael@0: for(i = 0; i < paramCount; i++) { michael@0: const nsXPTParamInfo& param = info->GetParam(i); michael@0: const nsXPTType& type = param.GetType(); michael@0: nsXPTCMiniVariant* dp = &dispatchParams[i]; michael@0: michael@0: if (!param.IsOut() && type == nsXPTType::T_DOUBLE) { michael@0: #ifndef __NO_FPRS__ michael@0: if (fpr < FPR_COUNT) michael@0: dp->val.d = fprData[fpr++]; michael@0: #else michael@0: if (gpr & 1) michael@0: gpr++; michael@0: if (gpr + 1 < GPR_COUNT) { michael@0: dp->val.d = *(double*) &gprData[gpr]; michael@0: gpr += 2; michael@0: } michael@0: #endif michael@0: else { michael@0: if ((uint32_t) ap & 4) ap++; // doubles are 8-byte aligned on stack michael@0: dp->val.d = *(double*) ap; michael@0: ap += 2; michael@0: } michael@0: continue; michael@0: } michael@0: else if (!param.IsOut() && type == nsXPTType::T_FLOAT) { michael@0: #ifndef __NO_FPRS__ michael@0: if (fpr < FPR_COUNT) michael@0: dp->val.f = (float) fprData[fpr++]; // in registers floats are passed as doubles michael@0: #else michael@0: if (gpr < GPR_COUNT) michael@0: dp->val.f = *(float*) &gprData[gpr++]; michael@0: #endif michael@0: else michael@0: dp->val.f = *(float*) ap++; michael@0: continue; michael@0: } michael@0: else if (!param.IsOut() && (type == nsXPTType::T_I64 michael@0: || type == nsXPTType::T_U64)) { michael@0: if (gpr & 1) gpr++; // longlongs are aligned in odd/even register pairs, eg. r5/r6 michael@0: if ((gpr + 1) < GPR_COUNT) { michael@0: tempu64 = *(uint64_t*) &gprData[gpr]; michael@0: gpr += 2; michael@0: } michael@0: else { michael@0: if ((uint32_t) ap & 4) ap++; // longlongs are 8-byte aligned on stack michael@0: tempu64 = *(uint64_t*) ap; michael@0: ap += 2; michael@0: } michael@0: } michael@0: else { michael@0: if (gpr < GPR_COUNT) michael@0: tempu32 = gprData[gpr++]; michael@0: else michael@0: tempu32 = *ap++; michael@0: } michael@0: michael@0: if(param.IsOut() || !type.IsArithmetic()) { michael@0: dp->val.p = (void*) tempu32; michael@0: continue; michael@0: } michael@0: michael@0: switch(type) { michael@0: case nsXPTType::T_I8: dp->val.i8 = (int8_t) tempu32; break; michael@0: case nsXPTType::T_I16: dp->val.i16 = (int16_t) tempu32; break; michael@0: case nsXPTType::T_I32: dp->val.i32 = (int32_t) tempu32; break; michael@0: case nsXPTType::T_I64: dp->val.i64 = (int64_t) tempu64; break; michael@0: case nsXPTType::T_U8: dp->val.u8 = (uint8_t) tempu32; break; michael@0: case nsXPTType::T_U16: dp->val.u16 = (uint16_t) tempu32; break; michael@0: case nsXPTType::T_U32: dp->val.u32 = (uint32_t) tempu32; break; michael@0: case nsXPTType::T_U64: dp->val.u64 = (uint64_t) tempu64; break; michael@0: case nsXPTType::T_BOOL: dp->val.b = (bool) tempu32; break; michael@0: case nsXPTType::T_CHAR: dp->val.c = (char) tempu32; break; michael@0: case nsXPTType::T_WCHAR: dp->val.wc = (wchar_t) tempu32; break; michael@0: michael@0: default: michael@0: NS_ERROR("bad type"); michael@0: break; michael@0: } michael@0: } michael@0: michael@0: result = self->mOuter->CallMethod((uint16_t)methodIndex, michael@0: info, michael@0: dispatchParams); michael@0: michael@0: if (dispatchParams != paramBuffer) michael@0: delete [] dispatchParams; michael@0: michael@0: return result; michael@0: } michael@0: michael@0: // Load r11 with the constant 'n' and branch to SharedStub(). michael@0: // michael@0: // XXX Yes, it's ugly that we're relying on gcc's name-mangling here; michael@0: // however, it's quick, dirty, and'll break when the ABI changes on michael@0: // us, which is what we want ;-). michael@0: michael@0: // gcc-3 version michael@0: // michael@0: // As G++3 ABI contains the length of the functionname in the mangled michael@0: // name, it is difficult to get a generic assembler mechanism like michael@0: // in the G++ 2.95 case. michael@0: // Create names would be like: michael@0: // _ZN14nsXPTCStubBase5Stub1Ev michael@0: // _ZN14nsXPTCStubBase6Stub12Ev michael@0: // _ZN14nsXPTCStubBase7Stub123Ev michael@0: // _ZN14nsXPTCStubBase8Stub1234Ev michael@0: // etc. michael@0: // Use assembler directives to get the names right... michael@0: michael@0: # define STUB_ENTRY(n) \ michael@0: __asm__ ( \ michael@0: ".align 2 \n\t" \ michael@0: ".if "#n" < 10 \n\t" \ michael@0: ".globl _ZN14nsXPTCStubBase5Stub"#n"Ev \n\t" \ michael@0: ".type _ZN14nsXPTCStubBase5Stub"#n"Ev,@function \n\n" \ michael@0: "_ZN14nsXPTCStubBase5Stub"#n"Ev: \n\t" \ michael@0: \ michael@0: ".elseif "#n" < 100 \n\t" \ michael@0: ".globl _ZN14nsXPTCStubBase6Stub"#n"Ev \n\t" \ michael@0: ".type _ZN14nsXPTCStubBase6Stub"#n"Ev,@function \n\n" \ michael@0: "_ZN14nsXPTCStubBase6Stub"#n"Ev: \n\t" \ michael@0: \ michael@0: ".elseif "#n" < 1000 \n\t" \ michael@0: ".globl _ZN14nsXPTCStubBase7Stub"#n"Ev \n\t" \ michael@0: ".type _ZN14nsXPTCStubBase7Stub"#n"Ev,@function \n\n" \ michael@0: "_ZN14nsXPTCStubBase7Stub"#n"Ev: \n\t" \ michael@0: \ michael@0: ".else \n\t" \ michael@0: ".err \"stub number "#n" >= 1000 not yet supported\"\n" \ michael@0: ".endif \n\t" \ michael@0: \ michael@0: "li 11,"#n" \n\t" \ michael@0: "b SharedStub@local \n" \ michael@0: ); michael@0: michael@0: #define SENTINEL_ENTRY(n) \ michael@0: nsresult nsXPTCStubBase::Sentinel##n() \ michael@0: { \ michael@0: NS_ERROR("nsXPTCStubBase::Sentinel called"); \ michael@0: return NS_ERROR_NOT_IMPLEMENTED; \ michael@0: } michael@0: michael@0: #include "xptcstubsdef.inc"