/* -*- Mode: asm; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
 * Version: MPL 1.1
 *
 * ***** 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 Corp, Inc.
 * Portions created by the Initial Developer are Copyright (C) 2001
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Brendan Eich     <brendan@mozilla.org>
 *   Stuart Parmenter <pavlov@netscape.com>
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either 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 ***** */

/* This code is for MIPS using the O32 ABI. */

#include <sys/regdef.h>
#include <sys/asm.h>

.text
.globl  invoke_count_words
.globl	invoke_copy_to_stack 

# We need a variable number of words allocated from the stack for copies of
# the params, and this space must come between the high frame (where ra, gp,
# and s0 are saved) and the low frame (where a0-a3 are saved by the callee
# functions we invoke). 

LOCALSZ=4		# s0, s1, ra, gp
NARGSAVE=4		# a0, a1, a2, a3
HIFRAMESZ=(LOCALSZ*SZREG)
LOFRAMESZ=(NARGSAVE*SZREG)
FRAMESZ=(HIFRAMESZ+LOFRAMESZ+ALSZ)&ALMASK

# XXX these 2*SZREG, etc. are very magic -- we *know* that ALSZ&ALMASK cause
# FRAMESZ to be 0 mod 8, in this case to be 16 and not 12.
RAOFF=FRAMESZ - (2*SZREG)
GPOFF=FRAMESZ - (3*SZREG)
S0OFF=FRAMESZ - (4*SZREG)
S1OFF=FRAMESZ - (5*SZREG)

# These are not magic -- they are just our argsave slots in the caller frame.
A0OFF=FRAMESZ
A1OFF=FRAMESZ + (1*SZREG)
A2OFF=FRAMESZ + (2*SZREG)
A3OFF=FRAMESZ + (3*SZREG)

	#	
	# _XPTC_InvokeByIndex(that, methodIndex, paramCount, params)
	#                      a0       a1          a2         a3

NESTED(_XPTC_InvokeByIndex, FRAMESZ, ra)

	.set	noreorder
	.cpload	t9
	.set	reorder

	subu	sp, FRAMESZ

	# specify the save register mask -- XXX do we want the a0-a3 here, given
	# our "split" frame where the args are saved below a dynamicly allocated
	# region under the high frame?
	#
	# 10010000000000010000000011110000
	.mask 0x900100F0, -((NARGSAVE+LOCALSZ)*SZREG)

	# thou shalt not use .cprestore if yer frame has variable size...
	# .cprestore GPOFF

	REG_S	ra, RAOFF(sp)

	# this happens automatically with .cprestore, but we cannot use that op...
	REG_S	gp, GPOFF(sp)
	REG_S	s0, S0OFF(sp)
	REG_S	s1, S1OFF(sp)

	REG_S	a0, A0OFF(sp)
	REG_S	a1, A1OFF(sp)
	REG_S	a2, A2OFF(sp)
	REG_S	a3, A3OFF(sp)

	# invoke_count_words(paramCount, params)
	move	a0, a2
	move	a1, a3

	jal	invoke_count_words
	lw	gp, GPOFF(sp)

	# save the old sp so we can pop the param area and any "low frame"
	# needed as an argsave area below the param block for callees that
	# we invoke.
	move	s0, sp

	REG_L	a1, A2OFF(sp)	# a1 = paramCount
	REG_L	a2, A3OFF(sp)	# a2 = params

	# we define a word as 4 bytes, period end of story!
	sll	v0, 2		# 4 bytes * result of invoke_copy_words
	subu	v0, LOFRAMESZ	# but we take back the argsave area built into
				# our stack frame -- SWEET!
	subu	sp, sp, v0	# make room
	move	a0, sp		# a0 = param stack address
	move	s1, a0		# save it for later -- it should be safe here

	# the old sp is still saved in s0, but we now need another argsave
	# area ("low frame") for the invoke_copy_to_stack call.
	subu	sp, sp, LOFRAMESZ

	# copy the param into the stack areas
	# invoke_copy_to_stack(PRUint32* d, PRUint32 paramCount,
	#                      nsXPTCVariant* s)
	jal     invoke_copy_to_stack
	lw  	gp, GPOFF(s0)

	move	sp, s0		# get orig sp back, popping params and argsave

	REG_L	a0, A0OFF(sp)	# a0 = set "that" to be "this"
	REG_L	a1, A1OFF(sp)	# a1 = methodIndex

	# t1 = methodIndex * 4
	# (use shift instead of mult)
	sll	t1, a1, 2

	# calculate the function we need to jump to,
	# which must then be saved in t9
	lw	t9, 0(a0)
	addu	t9, t9, t1
	lw	t9, 8(t9)

	# a1..a3 and f13..f14 should now be set to what
	# invoke_copy_to_stack told us. skip a0 and f12
	# because that is the "this" pointer

	REG_L	a1, 1*SZREG(s1)
	REG_L	a2, 2*SZREG(s1)
	REG_L	a3, 3*SZREG(s1)

	l.d	$f13, 8(s1)
	l.d	$f14, 16(s1)

	# Create the stack pointer for the function, which must have 4 words
	# of space for callee-saved args.  invoke_count_words allocated space
        # for a0 starting at s1, so we just move s1 into sp.
	move	sp, s1

	jalr	ra, t9
	lw	gp, GPOFF(s0)

	move	sp, s0

	REG_L	ra, RAOFF(sp)
	REG_L	s0, S0OFF(sp)
	addu	sp, FRAMESZ
	j	ra
.end _XPTC_InvokeByIndex
