PageRenderTime 44ms CodeModel.GetById 14ms app.highlight 25ms RepoModel.GetById 1ms app.codeStats 0ms

/xbmc/visualizations/Vortex/angelscript/angelscript/source/as_callfunc_sh4.cpp

http://github.com/xbmc/xbmc
C++ | 517 lines | 375 code | 60 blank | 82 comment | 65 complexity | b10ad81834371ded448edc4488577459 MD5 | raw file
  1/*
  2   AngelCode Scripting Library
  3   Copyright (c) 2003-2009 Andreas Jonsson
  4
  5   This software is provided 'as-is', without any express or implied 
  6   warranty. In no event will the authors be held liable for any 
  7   damages arising from the use of this software.
  8
  9   Permission is granted to anyone to use this software for any 
 10   purpose, including commercial applications, and to alter it and 
 11   redistribute it freely, subject to the following restrictions:
 12
 13   1. The origin of this software must not be misrepresented; you 
 14      must not claim that you wrote the original software. If you use
 15      this software in a product, an acknowledgment in the product 
 16      documentation would be appreciated but is not required.
 17
 18   2. Altered source versions must be plainly marked as such, and 
 19      must not be misrepresented as being the original software.
 20
 21   3. This notice may not be removed or altered from any source 
 22      distribution.
 23
 24   The original version of this library can be located at:
 25   http://www.angelcode.com/angelscript/
 26
 27   Andreas Jonsson
 28   andreas@angelcode.com
 29*/
 30
 31
 32//
 33// as_callfunc_sh4.cpp
 34//
 35// These functions handle the actual calling of system functions
 36//
 37// This version is SH4 specific and was originally written
 38// by Fredrik Ehnbom in May, 2004
 39// Later updated for angelscript 2.0.0 by Fredrik Ehnbom in Jan, 2005
 40
 41// References:
 42// * http://www.renesas.com/avs/resource/japan/eng/pdf/mpumcu/e602156_sh4.pdf
 43// * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcechp40/html/_callsh4_SH_4_Calling_Standard.asp
 44
 45
 46#include "as_config.h"
 47
 48#ifndef MAX_PORTABILITY
 49#ifdef AS_SH4
 50
 51#include "as_callfunc.h"
 52#include "as_scriptengine.h"
 53#include "as_texts.h"
 54#include "as_tokendef.h"
 55
 56#include <stdio.h>
 57#include <stdlib.h>
 58
 59BEGIN_AS_NAMESPACE
 60
 61#define AS_SH4_MAX_ARGS 32
 62// The array used to send values to the correct places.
 63// first 0-4 regular values to load into the r4-r7 registers
 64// then 0-8 float values to load into the fr4-fr11 registers
 65// then (AS_SH4_MAX_ARGS - 12) values to load onto the stack
 66// the +1 is for when CallThis (object methods) is used
 67// extra +1 when returning in memory
 68extern "C" {
 69static asDWORD sh4Args[AS_SH4_MAX_ARGS + 1 + 1];
 70}
 71
 72// Loads all data into the correct places and calls the function.
 73// intArgSize is the size in bytes for how much data to put in int registers
 74// floatArgSize is the size in bytes for how much data to put in float registers
 75// stackArgSize is the size in bytes for how much data to put on the callstack
 76extern "C" asQWORD sh4Func(int intArgSize, int floatArgSize, int stackArgSize, asDWORD func);
 77
 78asm(""
 79"	.align 4\n"
 80"	.global _sh4Func\n"
 81"_sh4Func:\n"
 82"	mov.l	r14,@-r15\n"
 83"	mov.l	r13,@-r15\n"
 84"	mov.l	r12,@-r15\n"
 85"	sts.l	pr,@-r15\n"		// must be saved since we call a subroutine
 86"	mov	r7, r14\n"		// func
 87"	mov	r6, r13\n"		// stackArgSize
 88"	mov.l	r5,@-r15\n"		// floatArgSize
 89"	mov.l	sh4Args,r0\n"
 90"	pref	@r0\n"
 91"	mov	r4, r1\n"		// intArgsize
 92"	mov	#33*4,r2\n"
 93"	extu.b	r2,r2\n"		// make unsigned (33*4 = 132 => 128)
 94"	mov.l	@(r0,r2), r2\n"		// r2 has adress for when returning in memory
 95"_sh4f_intarguments:\n"			// copy all the int arguments to the respective registers
 96"	mov	#4*2*2,r3\n"		// calculate how many bytes to skip
 97"	sub	r1,r3\n"
 98"	braf	r3\n"
 99"	add	#-4,r1\n"		// we are indexing the array backwards, so subtract one (delayed slot)
100"	mov.l	@(r0,r1),r7\n"		// 4 arguments
101"	add	#-4,r1\n"
102"	mov.l	@(r0,r1),r6\n"		// 3 arguments
103"	add	#-4,r1\n"
104"	mov.l	@(r0,r1),r5\n"		// 2 arguments
105"	add	#-4,r1\n"
106"	mov.l	@(r0,r1),r4\n"		// 1 argument
107"	nop\n"
108"_sh4f_floatarguments:\n"		// copy all the float arguments to the respective registers
109"	add	#4*4, r0\n"
110"	mov.l	@r15+,r1\n"		// floatArgSize
111"	mov	#8*2*2,r3\n"		// calculate how many bytes to skip
112"	sub	r1,r3\n"
113"	braf	r3\n"
114"	add	#-4,r1\n"		// we are indexing the array backwards, so subtract one (delayed slot)
115"	fmov.s	@(r0,r1),fr11\n"	// 8 arguments
116"	add	#-4,r1\n"
117"	fmov.s	@(r0,r1),fr10\n"	// 7 arguments
118"	add	#-4,r1\n"
119"	fmov.s	@(r0,r1),fr9\n"		// 6 arguments
120"	add	#-4,r1\n"
121"	fmov.s	@(r0,r1),fr8\n"		// 5 arguments
122"	add	#-4,r1\n"
123"	fmov.s	@(r0,r1),fr7\n"		// 4 arguments
124"	add	#-4,r1\n"
125"	fmov.s	@(r0,r1),fr6\n"		// 3 arguments
126"	add	#-4,r1\n"
127"	fmov.s	@(r0,r1),fr5\n"		// 2 arguments
128"	add	#-4,r1\n"
129"	fmov.s	@(r0,r1),fr4\n"		// 1 argument
130"	nop\n"
131"_sh4f_stackarguments:\n"		// copy all the stack argument onto the stack
132"	add	#8*4, r0\n"
133"	mov	r0, r1\n"
134"	mov	#0, r0\n"		// init position counter (also used as a 0-check on the line after)
135"	cmp/eq	r0, r13\n"
136"	bt	_sh4f_functioncall\n"	// no arguments to push onto the stack
137"	mov	r13, r3\n"		// stackArgSize
138"	sub	r3,r15\n"		// "allocate" space on the stack
139"	shlr2	r3\n"			// make into a counter
140"_sh4f_stackloop:\n"
141"	mov.l	@r1+, r12\n"
142"	mov.l	r12, @(r0, r15)\n"
143"	add	#4, r0\n"
144"	dt	r3\n"
145"	bf	_sh4f_stackloop\n"
146"_sh4f_functioncall:\n"
147"	jsr	@r14\n"			// no arguments
148"	nop\n"
149"	add	r13, r15\n"		// restore stack position
150"	lds.l	@r15+,pr\n"
151"	mov.l	@r15+, r12\n"
152"	mov.l	@r15+, r13\n"
153"	rts\n"
154"	mov.l	@r15+, r14\n"		// delayed slot
155"\n"
156"	.align 4\n"
157"sh4Args:\n"
158"	.long	_sh4Args\n"
159);
160
161// puts the arguments in the correct place in the sh4Args-array. See comments above.
162// This could be done better.
163inline void splitArgs(const asDWORD *args, int argNum, int &numRegIntArgs, int &numRegFloatArgs, int &numRestArgs, int hostFlags) {
164	int i;
165
166	int argBit = 1;
167	for (i = 0; i < argNum; i++) {
168		if (hostFlags & argBit) {
169			if (numRegFloatArgs < 12 - 4) {
170				// put in float register
171				sh4Args[4 + numRegFloatArgs] = args[i];
172				numRegFloatArgs++;
173			} else {
174				// put in stack
175				sh4Args[4 + 8 + numRestArgs] = args[i];
176				numRestArgs++;
177			}
178		} else {
179			if (numRegIntArgs < 8 - 4) {
180				// put in int register
181				sh4Args[numRegIntArgs] = args[i];
182				numRegIntArgs++;
183			} else {
184				// put in stack
185				sh4Args[4 + 8 + numRestArgs] = args[i];
186				numRestArgs++;
187			}
188		}
189		argBit <<= 1;
190	}
191}
192asQWORD CallCDeclFunction(const asDWORD *args, int argSize, asDWORD func, int flags)
193{
194	int argNum = argSize >> 2;
195
196	int intArgs = 0;
197	int floatArgs = 0;
198	int restArgs = 0;
199
200	// put the arguments in the correct places in the sh4Args array
201	if (argNum > 0)
202		splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags);
203
204	return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func);
205}
206
207// This function is identical to CallCDeclFunction, with the only difference that
208// the value in the first parameter is the object
209asQWORD CallThisCallFunction(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags)
210{
211	int argNum = argSize >> 2;
212
213	int intArgs = 1;
214	int floatArgs = 0;
215	int restArgs = 0;
216
217	sh4Args[0] = (asDWORD) obj;
218	
219	// put the arguments in the correct places in the sh4Args array
220	if (argNum >= 1)
221		splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags);
222
223	return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func);
224}
225// This function is identical to CallCDeclFunction, with the only difference that
226// the value in the last parameter is the object
227asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags)
228{
229	int argNum = argSize >> 2;
230
231	int intArgs = 0;
232	int floatArgs = 0;
233	int restArgs = 0;
234
235
236	// put the arguments in the correct places in the sh4Args array
237	if (argNum >= 1)
238		splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags);
239
240	if (intArgs < 4) {
241		sh4Args[intArgs] = (asDWORD) obj;
242		intArgs++;
243	} else {
244		sh4Args[4 + 8 + restArgs] = (asDWORD) obj;
245		restArgs++;
246	}
247	
248
249	return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func);
250}
251
252asDWORD GetReturnedFloat()
253{
254	asDWORD f;
255
256	asm("fmov.s	fr0, %0\n" : "=m"(f));
257
258	return f;
259}
260
261// sizeof(double) == 4 with sh-elf-gcc (3.4.0) -m4
262// so this isn't really used...
263asQWORD GetReturnedDouble()
264{
265	asQWORD d;
266
267	asm("fmov	dr0, %0\n" : "=m"(d));
268
269	return d;
270}
271
272int CallSystemFunction(int id, asCContext *context, void *objectPointer)
273{
274	asCScriptEngine *engine = context->engine;
275	asSSystemFunctionInterface *sysFunc = engine->scriptFunctions[id]->sysFuncIntf;
276	int callConv = sysFunc->callConv;
277	if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD )
278		return context->CallGeneric(id, objectPointer);
279
280	asQWORD retQW = 0;
281
282	asCScriptFunction *descr = engine->scriptFunctions[id];
283
284	void    *func              = (void*)sysFunc->func;
285	int      paramSize         = sysFunc->paramSize;
286	asDWORD *args              = context->regs.stackPointer;
287	void    *retPointer = 0;
288	void    *obj = 0;
289	asDWORD *vftable;
290	int      popSize           = paramSize;
291
292	context->regs.objectType = descr->returnType.GetObjectType();
293	if( descr->returnType.IsObject() && !descr->returnType.IsReference() && !descr->returnType.IsObjectHandle() )
294	{
295		// Allocate the memory for the object
296		retPointer = engine->CallAlloc(descr->returnType.GetObjectType());
297		sh4Args[AS_SH4_MAX_ARGS+1] = (asDWORD) retPointer;
298
299		if( sysFunc->hostReturnInMemory )
300		{
301			// The return is made in memory
302			callConv++;
303		}
304	}
305
306	if( callConv >= ICC_THISCALL )
307	{
308		if( objectPointer )
309		{
310			obj = objectPointer;
311		}
312		else
313		{
314			// The object pointer should be popped from the context stack
315			popSize++;
316
317			// Check for null pointer
318			obj = (void*)*(args + paramSize);
319			if( obj == 0 )
320			{	
321				context->SetInternalException(TXT_NULL_POINTER_ACCESS);
322				if( retPointer )
323					engine->CallFree(retPointer);
324				return 0;
325			}
326
327			// Add the base offset for multiple inheritance
328			obj = (void*)(int(obj) + sysFunc->baseOffset);
329		}
330	}
331	asASSERT(descr->parameterTypes.GetLength() <= 32);
332
333	// mark all float arguments
334	int argBit = 1;
335	int hostFlags = 0;
336	int intArgs = 0;
337	for( int a = 0; a < descr->parameterTypes.GetLength(); a++ ) {
338		if (descr->parameterTypes[a].IsFloatType()) {
339			hostFlags |= argBit;
340		} else intArgs++;
341		argBit <<= 1;
342	}
343
344	asDWORD paramBuffer[64];
345	if( sysFunc->takesObjByVal )
346	{
347		paramSize = 0;
348		int spos = 0;
349		int dpos = 1;
350		for( int n = 0; n < descr->parameterTypes.GetLength(); n++ )
351		{
352			if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
353			{
354#ifdef COMPLEX_OBJS_PASSED_BY_REF
355				if( descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK )
356				{
357					paramBuffer[dpos++] = args[spos++];
358					paramSize++;
359				}
360				else
361#endif
362				{
363					// Copy the object's memory to the buffer
364					memcpy(&paramBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
365					// Delete the original memory
366					engine->CallFree(*(char**)(args+spos));
367					spos++;
368					dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
369					paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
370				}
371			}
372			else
373			{
374				// Copy the value directly
375				paramBuffer[dpos++] = args[spos++];
376				if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
377					paramBuffer[dpos++] = args[spos++];
378				paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
379			}
380		}
381		// Keep a free location at the beginning
382		args = &paramBuffer[1];
383	}
384
385	context->isCallingSystemFunction = true;
386	switch( callConv )
387	{
388	case ICC_CDECL:
389	case ICC_CDECL_RETURNINMEM:
390	case ICC_STDCALL:
391	case ICC_STDCALL_RETURNINMEM:
392		retQW = CallCDeclFunction(args, paramSize<<2, (asDWORD)func, hostFlags);
393		break;
394	case ICC_THISCALL:
395	case ICC_THISCALL_RETURNINMEM:
396		retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags);
397		break;
398	case ICC_VIRTUAL_THISCALL:
399	case ICC_VIRTUAL_THISCALL_RETURNINMEM:
400		// Get virtual function table from the object pointer
401		vftable = *(asDWORD**)obj;
402		retQW = CallThisCallFunction(obj, args, paramSize<<2, vftable[asDWORD(func)>>2], hostFlags);
403		break;
404	case ICC_CDECL_OBJLAST:
405	case ICC_CDECL_OBJLAST_RETURNINMEM:
406		retQW = CallThisCallFunction_objLast(obj, args, paramSize<<2, (asDWORD)func, hostFlags);
407		break;
408	case ICC_CDECL_OBJFIRST:
409	case ICC_CDECL_OBJFIRST_RETURNINMEM:
410		retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags);
411		break;
412	default:
413		context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
414	}
415	context->isCallingSystemFunction = false;
416
417#ifdef COMPLEX_OBJS_PASSED_BY_REF
418	if( sysFunc->takesObjByVal )
419	{
420		// Need to free the complex objects passed by value
421		args = context->regs.stackPointer;
422		if( callConv >= ICC_THISCALL && !objectPointer )
423		    args++;
424
425		int spos = 0;
426		for( int n = 0; n < descr->parameterTypes.GetLength(); n++ )
427		{
428			if( descr->parameterTypes[n].IsObject() && 
429				!descr->parameterTypes[n].IsReference() &&
430				(descr->parameterTypes[n].GetObjectType()->flags & COMPLEX_MASK) )
431			{
432				void *obj = (void*)args[spos++];
433				asSTypeBehaviour *beh = &descr->parameterTypes[n].GetObjectType()->beh;
434				if( beh->destruct )
435					engine->CallObjectMethod(obj, beh->destruct);
436
437				engine->CallFree(obj);
438			}
439			else
440				spos += descr->parameterTypes[n].GetSizeInMemoryDWords();
441		}
442	}
443#endif
444
445	// Store the returned value in our stack
446	if( descr->returnType.IsObject() && !descr->returnType.IsReference() )
447	{
448		if( descr->returnType.IsObjectHandle() )
449		{
450			context->regs.objectRegister = (void*)(asDWORD)retQW;
451
452			if( sysFunc->returnAutoHandle && context->regs.objectRegister )
453				engine->CallObjectMethod(context->regs.objectRegister, descr->returnType.GetObjectType()->beh.addref);
454		}
455		else
456		{
457			if( !sysFunc->hostReturnInMemory )
458			{
459				// Copy the returned value to the pointer sent by the script engine
460				if( sysFunc->hostReturnSize == 1 )
461					*(asDWORD*)retPointer = (asDWORD)retQW;
462				else
463					*(asQWORD*)retPointer = retQW;
464			}
465
466			// Store the object in the register
467			context->regs.objectRegister = retPointer;
468		}
469	}
470	else
471	{
472		// Store value in valueRegister
473		if( sysFunc->hostReturnFloat )
474		{
475			if( sysFunc->hostReturnSize == 1 )
476				*(asDWORD*)&context->regs.valueRegister = GetReturnedFloat();
477			else
478				context->regs.valueRegister = GetReturnedDouble();
479		}
480		else if( sysFunc->hostReturnSize == 1 )
481			*(asDWORD*)&context->regs.valueRegister = (asDWORD)retQW;
482		else
483			context->regs.valueRegister = retQW;
484	}
485
486	if( sysFunc->hasAutoHandles )
487	{
488		args = context->regs.stackPointer;
489		if( callConv >= ICC_THISCALL && !objectPointer )
490			args++;
491
492		int spos = 0;
493		for( int n = 0; n < descr->parameterTypes.GetLength(); n++ )
494		{
495			if( sysFunc->paramAutoHandles[n] && args[spos] )
496			{
497				// Call the release method on the type
498				engine->CallObjectMethod((void*)args[spos], descr->parameterTypes[n].GetObjectType()->beh.release);
499				args[spos] = 0;
500			}
501
502			if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
503				spos++;
504			else
505				spos += descr->parameterTypes[n].GetSizeOnStackDWords();
506		}
507	}
508
509	return popSize;
510}
511
512END_AS_NAMESPACE
513
514#endif // AS_SH4
515#endif // AS_MAX_PORTABILITY
516
517