mirror of
				https://github.com/termux/termux-packages.git
				synced 2025-11-04 00:08:54 +00:00 
			
		
		
		
	- Switch source URL to https://github.com/eeTools/SimulIDE-dev - official new development location by the same developers - Software has been relicensed to AGPL-V3 - Convert all source code with `dos2unix` before patching - Remove `src-gpsim-protocol.cc.patch` - no longer necessary - Remove `enable-pie.patch`: upstreamed ina0ad4593ee- `angelscript-restore-arm-callfunc.patch`: restores the necessary code to the vendored angelscript to build for 32-bit ARM - by copying and pasting it from upstream angelscript, here: -ec94f25441/sdk/angelscript/source/as_callfunc_arm_gcc.S-ec94f25441/sdk/angelscript/source/as_callfunc_arm.cpp- `use_posix_ipc.patch`: Copy and paste Termux-specific implementation of `shm_open()` found in other Termux packages like `qt5-qtbase` - More information: https://github.com/eeTools/SimulIDE-dev/issues/68 - Provide icon and `.desktop` file - Tested launching using the `.desktop` file and a little bit of basic functionality on Samsung Galaxy A70 SM-A705FN, appears to be working
		
			
				
	
	
		
			1470 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			1470 lines
		
	
	
		
			51 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
Restore missing angelscript source files for 32-bit ARM
 | 
						||
copied and pasted from
 | 
						||
https://github.com/anjo76/angelscript/blob/ec94f25441e8ccbba1d8968c0418ed5c195e4b81/sdk/angelscript/source/as_callfunc_arm_gcc.S
 | 
						||
https://github.com/anjo76/angelscript/blob/ec94f25441e8ccbba1d8968c0418ed5c195e4b81/sdk/angelscript/source/as_callfunc_arm.cpp
 | 
						||
 | 
						||
--- a/SimulIDE.pri
 | 
						||
+++ b/SimulIDE.pri
 | 
						||
@@ -117,6 +117,10 @@ macx {
 | 
						||
     QMAKE_LINK = /usr/local/Cellar/gcc@7/7.5.0_4/bin/g++-7
 | 
						||
 }
 | 
						||
 
 | 
						||
+contains( QMAKE_HOST.arch, arm.* ) | contains( QMAKE_CC, .*arm.* ){
 | 
						||
+    SOURCES += $$PWD/src/angel/src/as_callfunc_arm_gcc.S
 | 
						||
+}
 | 
						||
+
 | 
						||
 contains( QMAKE_HOST.arch, arm64|aarch64 ) | contains( QMAKE_CC, .*aarch64.* ){
 | 
						||
     SOURCES += $$PWD/src/angel/src/as_callfunc_arm64_gcc.S
 | 
						||
 }
 | 
						||
diff --git a/src/angel/src/as_callfunc_arm_gcc.S b/src/angel/src/as_callfunc_arm_gcc.S
 | 
						||
new file mode 100644
 | 
						||
index 00000000..69423f95
 | 
						||
--- /dev/null
 | 
						||
+++ b/src/angel/src/as_callfunc_arm_gcc.S
 | 
						||
@@ -0,0 +1,742 @@
 | 
						||
+/*
 | 
						||
+  AngelCode Scripting Library
 | 
						||
+  Copyright (c) 2003-2025 Andreas Jonsson
 | 
						||
+
 | 
						||
+  This software is provided 'as-is', without any express or implied
 | 
						||
+  warranty. In no event will the authors be held liable for any
 | 
						||
+  damages arising from the use of this software.
 | 
						||
+
 | 
						||
+  Permission is granted to anyone to use this software for any
 | 
						||
+  purpose, including commercial applications, and to alter it and
 | 
						||
+  redistribute it freely, subject to the following restrictions:
 | 
						||
+
 | 
						||
+  1. The origin of this software must not be misrepresented; you
 | 
						||
+     must not claim that you wrote the original software. If you use
 | 
						||
+     this software in a product, an acknowledgment in the product
 | 
						||
+     documentation would be appreciated but is not required.
 | 
						||
+
 | 
						||
+  2. Altered source versions must be plainly marked as such, and
 | 
						||
+     must not be misrepresented as being the original software.
 | 
						||
+
 | 
						||
+  3. This notice may not be removed or altered from any source
 | 
						||
+     distribution.
 | 
						||
+
 | 
						||
+  The original version of this library can be located at:
 | 
						||
+  http://www.angelcode.com/angelscript/
 | 
						||
+
 | 
						||
+  Andreas Jonsson
 | 
						||
+  andreas@angelcode.com
 | 
						||
+*/
 | 
						||
+
 | 
						||
+/*
 | 
						||
+   Assembly routines for the ARM call convention
 | 
						||
+   Written by Fredrik Ehnbom in June 2009
 | 
						||
+
 | 
						||
+   Adapted to GNUC by darktemplar216 in September 2009
 | 
						||
+
 | 
						||
+   Modified by Lasse Oorni for 8-byte stack alignment in May 2012
 | 
						||
+
 | 
						||
+   The assembler routines for Linux were written by Carlos Luna in December 2012
 | 
						||
+*/
 | 
						||
+
 | 
						||
+#if !defined(AS_MAX_PORTABILITY)
 | 
						||
+
 | 
						||
+#if defined(__arm__) || defined(__ARM__) || defined(I3D_ARCH_ARM)
 | 
						||
+
 | 
						||
+#if !defined(__linux__) || defined(__ANDROID__) || defined(ANDROID) || defined(__SOFTFP__) || defined(__ARM_PCS)
 | 
						||
+
 | 
						||
+/* iOS, Android, Marmalade, and Linux with soft-float ABI goes here */
 | 
						||
+
 | 
						||
+.global armFunc
 | 
						||
+.global armFuncR0
 | 
						||
+.global armFuncR0R1
 | 
						||
+.global armFuncObjLast
 | 
						||
+.global armFuncR0ObjLast
 | 
						||
+
 | 
						||
+.type armFunc, %function
 | 
						||
+.type armFuncR0, %function
 | 
						||
+.type armFuncR0R1, %function
 | 
						||
+.type armFuncObjLast, %function
 | 
						||
+.type armFuncR0ObjLast, %function
 | 
						||
+
 | 
						||
+/* --------------------------------------------------------------------------------------------*/
 | 
						||
+armFunc:
 | 
						||
+    stmdb   sp!, {r4-r8, lr}
 | 
						||
+    mov     r6, r0  /* arg table */
 | 
						||
+    movs    r7, r1  /* arg size (also set the condition code flags so that we detect if there are no arguments) */
 | 
						||
+    mov     r4, r2  /* function address */
 | 
						||
+    mov     r8, #0
 | 
						||
+
 | 
						||
+    beq     nomoreargs
 | 
						||
+
 | 
						||
+    /* Load the first 4 arguments into r0-r3 */
 | 
						||
+    cmp     r7, #4
 | 
						||
+    ldrge   r0, [r6],#4
 | 
						||
+    cmp     r7, #2*4
 | 
						||
+    ldrge   r1, [r6],#4
 | 
						||
+    cmp     r7, #3*4
 | 
						||
+    ldrge   r2, [r6],#4
 | 
						||
+    cmp     r7, #4*4
 | 
						||
+    ldrge   r3, [r6],#4
 | 
						||
+    ble     nomoreargs
 | 
						||
+
 | 
						||
+    /* Load the rest of the arguments onto the stack */
 | 
						||
+    sub     r7, r7, #4*4      /* skip the 4 registers already loaded into r0-r3 */
 | 
						||
+    add     r8, r7, #4        /* ensure 8-byte stack alignment */
 | 
						||
+    bic     r8, r8, #4
 | 
						||
+    sub     sp, sp, r8
 | 
						||
+    mov     r12, sp           /* copy size != frame size, so store frame start sp */
 | 
						||
+stackargsloop:
 | 
						||
+    ldr     r5, [r6], #4
 | 
						||
+    str     r5, [sp], #4
 | 
						||
+    subs    r7, r7, #4
 | 
						||
+    bne     stackargsloop
 | 
						||
+    mov     sp, r12
 | 
						||
+nomoreargs:
 | 
						||
+#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
 | 
						||
+    mov    lr, pc   /* older ARM didn't support blx */
 | 
						||
+    mov    pc, r4
 | 
						||
+#else
 | 
						||
+    blx     r4
 | 
						||
+#endif
 | 
						||
+    add     sp, sp, r8
 | 
						||
+    ldmia   sp!, {r4-r8, pc}
 | 
						||
+
 | 
						||
+/* --------------------------------------------------------------------------------------------*/
 | 
						||
+armFuncObjLast:
 | 
						||
+    stmdb   sp!, {r4-r8, lr}
 | 
						||
+    mov     r6, r0  /* arg table */
 | 
						||
+    movs    r7, r1  /* arg size (also set the condition code flags so that we detect if there are no arguments) */
 | 
						||
+    mov     r4, r2  /* function address */
 | 
						||
+    mov     r8, #0
 | 
						||
+
 | 
						||
+    mov     r0, r3          /* objlast. might get overwritten */
 | 
						||
+    mov     r5, r3          /* objlast to temp reg */
 | 
						||
+
 | 
						||
+    beq     nomoreargsarmFuncObjLast
 | 
						||
+
 | 
						||
+    /* Load the first 4 arguments into r0-r3 */
 | 
						||
+    cmp     r7, #4
 | 
						||
+    ldrge   r0, [r6],#4
 | 
						||
+    cmp     r7, #2*4
 | 
						||
+    ldrge   r1, [r6],#4
 | 
						||
+    movlt   r1, r5
 | 
						||
+    cmp     r7, #3*4
 | 
						||
+    ldrge   r2, [r6],#4
 | 
						||
+    movlt   r2, r5
 | 
						||
+    cmp     r7, #4*4
 | 
						||
+    ldrge   r3, [r6],#4
 | 
						||
+    movlt   r3, r5
 | 
						||
+    blt     nomoreargsarmFuncObjLast
 | 
						||
+
 | 
						||
+    /* Load the rest of the arguments onto the stack */
 | 
						||
+    sub     r7, r7, #4*4    /* skip the 4 registers already loaded into r0-r3 */
 | 
						||
+    add     r8, r7, #8      /* account for the objlast pointer, ensure 8-byte stack alignment */
 | 
						||
+    bic     r8, r8, #4
 | 
						||
+    str     r5, [sp,#-4]    /* store the objlast on stack, twice in case we adjusted alignment */
 | 
						||
+    str     r5, [sp,#-8]
 | 
						||
+    sub     sp, sp, r8      /* adjust frame */
 | 
						||
+    cmp     r7, #0          /* we may also have come here with no extra params */
 | 
						||
+    beq     nomoreargsarmFuncObjLast
 | 
						||
+    mov     r12, sp         /* copy size != frame size, so store frame start sp */
 | 
						||
+stackargslooparmFuncObjLast:
 | 
						||
+    ldr     r5, [r6], #4
 | 
						||
+    str     r5, [sp], #4
 | 
						||
+    subs    r7, r7, #4
 | 
						||
+    bne     stackargslooparmFuncObjLast
 | 
						||
+    mov     sp, r12
 | 
						||
+nomoreargsarmFuncObjLast:
 | 
						||
+#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
 | 
						||
+    mov    lr, pc   /* older ARM didn't support blx */
 | 
						||
+    mov    pc, r4
 | 
						||
+#else
 | 
						||
+    blx     r4
 | 
						||
+#endif
 | 
						||
+    add     sp, sp, r8
 | 
						||
+    ldmia   sp!, {r4-r8, pc}
 | 
						||
+
 | 
						||
+/* --------------------------------------------------------------------------------------------*/
 | 
						||
+armFuncR0ObjLast:
 | 
						||
+    stmdb   sp!, {r4-r8, lr}
 | 
						||
+    ldr     r5, [sp,#6*4]   /* objlast to temp reg */
 | 
						||
+
 | 
						||
+    mov     r6, r0  /* arg table */
 | 
						||
+    movs    r7, r1  /* arg size (also set the condition code flags so that we detect if there are no arguments) */
 | 
						||
+    mov     r4, r2  /* function address */
 | 
						||
+    mov     r8, #0
 | 
						||
+
 | 
						||
+    mov     r0, r3      /* r0 explicitly set */
 | 
						||
+    mov     r1, r5      /* objlast.  might get overwritten */
 | 
						||
+
 | 
						||
+    beq     nomoreargsarmFuncR0ObjLast
 | 
						||
+
 | 
						||
+    /* Load the first 3 arguments into r1-r3 */
 | 
						||
+    cmp     r7, #1*4
 | 
						||
+    ldrge   r1, [r6],#4
 | 
						||
+    cmp     r7, #2*4
 | 
						||
+    ldrge   r2, [r6],#4
 | 
						||
+    movlt   r2, r5
 | 
						||
+    cmp     r7, #3*4
 | 
						||
+    ldrge   r3, [r6],#4
 | 
						||
+    movlt   r3, r5
 | 
						||
+    blt     nomoreargsarmFuncR0ObjLast
 | 
						||
+
 | 
						||
+    /* Load the rest of the arguments onto the stack */
 | 
						||
+    sub     r7, r7, #3*4    /* skip the 3 registers already loaded into r1-r3 */
 | 
						||
+    add     r8, r7, #8      /* account for the objlast pointer, ensure 8-byte stack alignment */
 | 
						||
+    bic     r8, r8, #4
 | 
						||
+    str     r5, [sp,#-4]    /* store the objlast on stack, twice in case we adjusted alignment */
 | 
						||
+    str     r5, [sp,#-8]
 | 
						||
+    sub     sp, sp, r8      /* adjust frame */
 | 
						||
+    cmp     r7, #0          /* we may also have come here with no extra params */
 | 
						||
+    beq     nomoreargsarmFuncR0ObjLast
 | 
						||
+    mov     r12, sp         /* copy size != frame size, so store frame start sp */
 | 
						||
+stackargslooparmFuncR0ObjLast:
 | 
						||
+    ldr     r5, [r6], #4
 | 
						||
+    str     r5, [sp], #4
 | 
						||
+    subs    r7, r7, #4
 | 
						||
+    bne     stackargslooparmFuncR0ObjLast
 | 
						||
+    mov     sp, r12
 | 
						||
+nomoreargsarmFuncR0ObjLast:
 | 
						||
+#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
 | 
						||
+    mov    lr, pc   /* older ARM didn't support blx */
 | 
						||
+    mov    pc, r4
 | 
						||
+#else
 | 
						||
+    blx     r4
 | 
						||
+#endif
 | 
						||
+    add     sp, sp, r8
 | 
						||
+    ldmia   sp!, {r4-r8, pc}
 | 
						||
+
 | 
						||
+/* --------------------------------------------------------------------------------------------*/
 | 
						||
+armFuncR0:
 | 
						||
+    stmdb   sp!, {r4-r8, lr}
 | 
						||
+    mov     r6, r0  /* arg table */
 | 
						||
+    movs    r7, r1  /* arg size (also set the condition code flags so that we detect if there are no arguments) */
 | 
						||
+    mov     r4, r2  /* function address */
 | 
						||
+    mov     r8, #0
 | 
						||
+
 | 
						||
+    mov     r0, r3  /* r0 explicitly set */
 | 
						||
+
 | 
						||
+    beq     nomoreargsarmFuncR0
 | 
						||
+
 | 
						||
+    /* Load the first 3 arguments into r1-r3 */
 | 
						||
+    cmp     r7, #1*4
 | 
						||
+    ldrge   r1, [r6],#4
 | 
						||
+    cmp     r7, #2*4
 | 
						||
+    ldrge   r2, [r6],#4
 | 
						||
+    cmp     r7, #3*4
 | 
						||
+    ldrge   r3, [r6],#4
 | 
						||
+    ble     nomoreargsarmFuncR0
 | 
						||
+
 | 
						||
+    /* Load the rest of the arguments onto the stack */
 | 
						||
+    sub     r7, r7, #3*4    /* skip the 3 registers already loaded into r1-r3 */
 | 
						||
+    add     r8, r7, #4      /* ensure 8-byte stack alignment */
 | 
						||
+    bic     r8, r8, #4
 | 
						||
+    sub     sp, sp, r8
 | 
						||
+    mov     r12, sp         /* copy size != frame size, so store frame start sp */
 | 
						||
+stackargslooparmFuncR0:
 | 
						||
+    ldr     r5, [r6], #4
 | 
						||
+    str     r5, [sp], #4
 | 
						||
+    subs    r7, r7, #4
 | 
						||
+    bne     stackargslooparmFuncR0
 | 
						||
+    mov     sp, r12
 | 
						||
+nomoreargsarmFuncR0:
 | 
						||
+#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
 | 
						||
+    mov    lr, pc   /* older ARM didn't support blx */
 | 
						||
+    mov    pc, r4
 | 
						||
+#else
 | 
						||
+    blx     r4
 | 
						||
+#endif
 | 
						||
+    add     sp, sp, r8
 | 
						||
+    ldmia   sp!, {r4-r8, pc}
 | 
						||
+
 | 
						||
+/* --------------------------------------------------------------------------------------------*/
 | 
						||
+armFuncR0R1:
 | 
						||
+    stmdb   sp!, {r4-r8, lr}
 | 
						||
+    mov     r6, r0  /* arg table */
 | 
						||
+    movs    r7, r1  /* arg size (also set the condition code flags so that we detect if there are no arguments) */
 | 
						||
+    mov     r4, r2  /* function address */
 | 
						||
+    mov     r8, #0
 | 
						||
+
 | 
						||
+    mov     r0, r3          /* r0 explicitly set */
 | 
						||
+    ldr     r1, [sp, #6*4]  /* r1 explicitly set too */
 | 
						||
+
 | 
						||
+    beq     nomoreargsarmFuncR0R1
 | 
						||
+
 | 
						||
+    /* Load the first 2 arguments into r2-r3 */
 | 
						||
+    cmp     r7, #1*4
 | 
						||
+    ldrge   r2, [r6],#4
 | 
						||
+    cmp     r7, #2*4
 | 
						||
+    ldrge   r3, [r6],#4
 | 
						||
+    ble     nomoreargsarmFuncR0R1
 | 
						||
+
 | 
						||
+    /* Load the rest of the arguments onto the stack */
 | 
						||
+    sub     r7, r7, #2*4    /* skip the 2 registers already loaded into r2-r3 */
 | 
						||
+    add     r8, r7, #4      /* ensure 8-byte stack alignment */
 | 
						||
+    bic     r8, r8, #4
 | 
						||
+    sub     sp, sp, r8
 | 
						||
+    mov     r12, sp         /* copy size != frame size, so store frame start sp */
 | 
						||
+stackargslooparmFuncR0R1:
 | 
						||
+    ldr     r5, [r6], #4
 | 
						||
+    str     r5, [sp], #4
 | 
						||
+    subs    r7, r7, #4
 | 
						||
+    bne     stackargslooparmFuncR0R1
 | 
						||
+    mov     sp, r12
 | 
						||
+nomoreargsarmFuncR0R1:
 | 
						||
+#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
 | 
						||
+    mov    lr, pc   /* older ARM didn't support blx */
 | 
						||
+    mov    pc, r4
 | 
						||
+#else
 | 
						||
+    blx     r4
 | 
						||
+#endif
 | 
						||
+    add     sp, sp, r8
 | 
						||
+    ldmia   sp!, {r4-r8, pc}
 | 
						||
+
 | 
						||
+/* --------------------------------------------------------------------------------------------*/
 | 
						||
+#elif defined(__linux__) && !defined(__SOFTFP__) && !defined(__ARM_PCS)
 | 
						||
+
 | 
						||
+/* The Linux with hard-float ABI code goes here */
 | 
						||
+
 | 
						||
+
 | 
						||
+/* These codes are suitable for armeabi + vfp  / armeabihf */
 | 
						||
+/* when using armeabi + vfp, please set C_FLAGS -mfloat-abi=softfp -mfpu=vfp */
 | 
						||
+/* using armeabihf, please set C_FLAGS -mfloat-abi=hard -mfpu=vfpv3-d16 */
 | 
						||
+
 | 
						||
+/* if you prefer to run in ARM mode, please add -marm to C_FLAGS */
 | 
						||
+/* while using thumb mode, please add -mthumb -Wa,-mimplicit-it=thumb */
 | 
						||
+
 | 
						||
+
 | 
						||
+/* SP is a multiple of 8 when control first enters a program.*/
 | 
						||
+/* This places an obligation on authors of low level OS, RTOS, and runtime library code to align SP at all points */
 | 
						||
+/* at which control first enters a body of (AAPCS-conforming) code. (please read "ARM IHI 0046B" document)*/
 | 
						||
+
 | 
						||
+
 | 
						||
+.section .text
 | 
						||
+
 | 
						||
+    .align 2        /* Align the function code to a 4-byte (2^n) word boundary. */
 | 
						||
+#if defined(__thumb__) || defined(__thumb2__)
 | 
						||
+    .thumb
 | 
						||
+    .syntax unified
 | 
						||
+#else
 | 
						||
+    .arm            /* Use ARM instructions instead of Thumb.*/
 | 
						||
+#endif
 | 
						||
+    .globl armFunc  /* Make the function globally accessible.*/
 | 
						||
+    .type armFunc, %function
 | 
						||
+armFunc:
 | 
						||
+    push    {r4-r8, r10, r11, lr}   /* sp must be 8-byte alignment for ABI compliance, so the pushed registers must be even */
 | 
						||
+
 | 
						||
+    mov     r6, r0  /* arg table */
 | 
						||
+    movs    r7, r1  /* arg size (also set the condition code flags so that we detect if there are no arguments) */
 | 
						||
+    mov     r4, r2  /* function address */
 | 
						||
+
 | 
						||
+    /* Load float and double args into d0-d7 and s0-s15 */
 | 
						||
+    add       r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */
 | 
						||
+    mov       r8, #0
 | 
						||
+    vldmia.64 r10, {d0-d7}  /* Load contents starting at r10 into registers d0-d7 */
 | 
						||
+
 | 
						||
+    /* If there are no arguments to set into r0-r3 */
 | 
						||
+    /* go check if there are arguments for the stack */
 | 
						||
+    beq     stackargs
 | 
						||
+
 | 
						||
+    /* Load the first 4 arguments into r0-r3 */
 | 
						||
+    cmp     r7, #4
 | 
						||
+    ldrge   r0, [r6]
 | 
						||
+    cmp     r7, #8
 | 
						||
+    ldrge   r1, [r6, #4]
 | 
						||
+    cmp     r7, #12
 | 
						||
+    ldrge   r2, [r6, #8]
 | 
						||
+    cmp     r7, #16
 | 
						||
+    ldrge   r3, [r6, #12]
 | 
						||
+
 | 
						||
+stackargs:
 | 
						||
+    ldr     r5, [r6, #268]  /* Load stack size into r5 */
 | 
						||
+    movs    r7, r5          /* Load stack size into r7, checking for 0 args */
 | 
						||
+
 | 
						||
+    /* If there are no args for the stack, branch */
 | 
						||
+    beq     nomoreargs
 | 
						||
+
 | 
						||
+    /* Load the rest of the arguments onto the stack */
 | 
						||
+    /* Ensure 8-byte stack alignment */
 | 
						||
+    mov     r8, sp
 | 
						||
+    sub     sp, sp, r7
 | 
						||
+    add     r6, r6, #16     /* Set r6 to point to the first arg to be placed on the stack */
 | 
						||
+
 | 
						||
+    sub     r12, sp, #8
 | 
						||
+    bic     r12, r12, #7    /* thumb mode couldn't support "bic  sp, sp, #7" instruction */
 | 
						||
+    sub     r8, r8, r12
 | 
						||
+    mov     sp, r12         /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */
 | 
						||
+
 | 
						||
+stackargsloop:
 | 
						||
+    ldr     r5, [r6], #4
 | 
						||
+    subs    r7, r7, #4
 | 
						||
+    str     r5, [sp], #4
 | 
						||
+    bne     stackargsloop
 | 
						||
+    mov     sp, r12
 | 
						||
+
 | 
						||
+nomoreargs:
 | 
						||
+#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
 | 
						||
+    mov    lr, pc   /* older ARM didn't support blx */
 | 
						||
+    mov    pc, r4
 | 
						||
+#else
 | 
						||
+    blx     r4
 | 
						||
+#endif
 | 
						||
+    add     sp, sp, r8
 | 
						||
+    vstmia.64 r10, {d0-d7}   /* Copy contents of registers d0-d7 to the address stored in r10 */
 | 
						||
+
 | 
						||
+    pop {r4-r8, r10, r11, pc}
 | 
						||
+
 | 
						||
+/* --------------------------------------------------------------------------------------------*/
 | 
						||
+    .align 2        /* Align the function code to a 4-byte (2^n) word boundary. */
 | 
						||
+#if defined(__thumb__) || defined(__thumb2__)
 | 
						||
+    .thumb
 | 
						||
+    .syntax unified
 | 
						||
+#else
 | 
						||
+    .arm            /* Use ARM instructions instead of Thumb.*/
 | 
						||
+#endif
 | 
						||
+    .globl armFuncObjLast       /* Make the function globally accessible.*/
 | 
						||
+    .type armFuncObjLast, %function
 | 
						||
+armFuncObjLast:
 | 
						||
+    push {r4-r8, r10, r11, lr}  /* We're storing r11 just to keep the stack aligned to an 8 byte boundary */
 | 
						||
+
 | 
						||
+    mov     r6, r0  /* arg table */
 | 
						||
+    movs    r7, r1  /* arg size (also set the condition code flags so that we detect if there are no arguments) */
 | 
						||
+    mov     r4, r2  /* function address */
 | 
						||
+
 | 
						||
+    mov     r0, r3          /* objlast. might get overwritten */
 | 
						||
+    mov     r5, #0          /* This will hold an offset of #4 only if objlast couldn't be placed into an "r" register */
 | 
						||
+
 | 
						||
+    /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */
 | 
						||
+    add     r10, r6, #272   /* r10 (r6 + 272) points to the first value for the VFP registers */
 | 
						||
+    mov     r8, #0
 | 
						||
+    vldmia.64 r10, {d0-d7}  /* Load contents starting at r10 into registers d0-d7 */
 | 
						||
+
 | 
						||
+    /* If there are no arguments to set into r0-r3 */
 | 
						||
+    /* go check if there are arguments for the stack */
 | 
						||
+    beq     stackargsFuncObjLast
 | 
						||
+
 | 
						||
+    mov     r5, r3          /* store objlast in r5 temporarily */
 | 
						||
+
 | 
						||
+    /* Load the first 4 arguments into r0-r3 */
 | 
						||
+    cmp     r7, #4
 | 
						||
+    ldrge   r0, [r6]
 | 
						||
+    cmp     r7, #8
 | 
						||
+    ldrge   r1, [r6,#4]
 | 
						||
+    movlt   r1, r5
 | 
						||
+    cmp     r7, #12
 | 
						||
+    ldrge   r2, [r6,#8]
 | 
						||
+    movlt   r2, r5
 | 
						||
+    cmp     r7, #16
 | 
						||
+    ldrge   r3, [r6,#12]
 | 
						||
+    movlt   r3, r5
 | 
						||
+    movlt   r5, #0                  /* If objlast got placed into a register, r5 = 0 */
 | 
						||
+    blt     stackargsFuncObjLast    /* If objlast got placed into a register, go to stackargsFuncObjLast */
 | 
						||
+
 | 
						||
+    str     r5, [r6, #12]           /* Put objlast in r6 + 12 */
 | 
						||
+    mov     r5, #4                  /* Set r5 with an offset of #4, so objlast can be loaded into the stack */
 | 
						||
+
 | 
						||
+stackargsFuncObjLast:
 | 
						||
+    ldr     r7, [r6, #268]  /* Load stack size into r7 */
 | 
						||
+    add     r7, r7, r5      /* Add the offset placed in r5 (could be #0 or #4) */
 | 
						||
+    cmp     r7, #0          /* Check for 0 args */
 | 
						||
+
 | 
						||
+    /* If there are no args for the stack, branch */
 | 
						||
+    beq     nomoreargsarmFuncObjLast
 | 
						||
+
 | 
						||
+    /* Load the rest of the arguments onto the stack */
 | 
						||
+    /* Ensure 8-byte stack alignment */
 | 
						||
+    mov     r8, sp
 | 
						||
+    sub     sp, sp, r7
 | 
						||
+    add     r6, r6, #16     /* Set r6 to point to the first arg to be placed on the stack */
 | 
						||
+
 | 
						||
+    sub     r12, sp, #8
 | 
						||
+    sub     r6, r6, r5      /* r6 = r6 - r5 (r5 can be #0 or #4) */
 | 
						||
+    bic     r12, r12, #7    /* thumb mode couldn't support "bic  sp, sp, #7" instruction */
 | 
						||
+    sub     r8, r8, r12
 | 
						||
+    mov     sp, r12         /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */
 | 
						||
+
 | 
						||
+stackargslooparmFuncObjLast:
 | 
						||
+    ldr     r5, [r6], #4
 | 
						||
+    subs    r7, r7, #4
 | 
						||
+    str     r5, [sp], #4
 | 
						||
+    bne     stackargslooparmFuncObjLast
 | 
						||
+    mov     sp, r12
 | 
						||
+
 | 
						||
+nomoreargsarmFuncObjLast:
 | 
						||
+#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
 | 
						||
+    mov    lr, pc   /* older ARM didn't support blx */
 | 
						||
+    mov    pc, r4
 | 
						||
+#else
 | 
						||
+    blx     r4
 | 
						||
+#endif
 | 
						||
+    add     sp, sp, r8
 | 
						||
+    vstmia.64   r10, {d0-d7}    /* Copy contents of registers d0-d10 to the address stored in r10 */
 | 
						||
+
 | 
						||
+    pop   {r4-r8, r10,r11, pc}
 | 
						||
+
 | 
						||
+/* ------------------------------------------------------------------------------------------- */
 | 
						||
+    .align 2        /* Align the function code to a 4-byte (2^n) word boundary. */
 | 
						||
+#if defined(__thumb__) || defined(__thumb2__)
 | 
						||
+    .thumb
 | 
						||
+    .syntax unified
 | 
						||
+#else
 | 
						||
+    .arm            /* Use ARM instructions instead of Thumb.*/
 | 
						||
+#endif
 | 
						||
+    .globl armFuncR0ObjLast     /* Make the function globally accessible.*/
 | 
						||
+    .type armFuncR0ObjLast, %function
 | 
						||
+armFuncR0ObjLast:
 | 
						||
+    push    {r4-r8, r10, r11, lr}
 | 
						||
+
 | 
						||
+    ldr     r5, [sp,#32]   /* objlast to temp reg */
 | 
						||
+
 | 
						||
+    mov     r6, r0  /* arg table */
 | 
						||
+    movs    r7, r1  /* arg size (also set the condition code flags so that we detect if there are no arguments) */
 | 
						||
+    mov     r4, r2  /* function address */
 | 
						||
+
 | 
						||
+    mov     r0, r3      /* r0 explicitly set */
 | 
						||
+    mov     r1, r5      /* objlast.  might get overwritten */
 | 
						||
+    mov     r5, #0      /* This will hold an offset of #4 or #8 if objlast or one arg couldn't be placed into an "r" register */
 | 
						||
+
 | 
						||
+    /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */
 | 
						||
+    add     r10, r6, #272   /* r10 (r6 + 272) points to the first value for the VFP registers */
 | 
						||
+    mov     r8, #0
 | 
						||
+    vldmia.64 r10, {d0-d7}  /* Load contents starting at r10 into registers d0-d7 */
 | 
						||
+
 | 
						||
+    /* If there are no arguments to set into r0-r3 */
 | 
						||
+    /* go check if there are arguments for the stack */
 | 
						||
+    beq     stackargsFuncR0ObjLast
 | 
						||
+
 | 
						||
+    mov     r5, r1          /* store objlast in r5 temporarily */
 | 
						||
+
 | 
						||
+    /* Load the first 3 arguments into r1-r3 */
 | 
						||
+    cmp     r7, #4
 | 
						||
+    ldrge   r1, [r6]
 | 
						||
+    cmp     r7, #8
 | 
						||
+    ldrge   r2, [r6,#4]
 | 
						||
+    movlt   r2, r5
 | 
						||
+    cmp     r7, #12
 | 
						||
+    ldrge   r3, [r6,#8]
 | 
						||
+    movlt   r3, r5
 | 
						||
+    movlt   r5, #0                  /* If objlast got placed into a register, r5 = 0 */
 | 
						||
+    blt     stackargsFuncR0ObjLast  /* If objlast got placed into a register, go to stackargsFuncR0ObjLast */
 | 
						||
+
 | 
						||
+    cmp     r7, #16                 /* Else if we have one last arg set the offset accordingly and store the arg in the array */
 | 
						||
+    ldrge   r7, [r6, #12]
 | 
						||
+    strge   r7, [r6, #8]
 | 
						||
+
 | 
						||
+    str     r5, [r6, #12]           /* Put objlast in r6 + 12 */
 | 
						||
+    mov     r5, #0
 | 
						||
+
 | 
						||
+    movge   r5, #4                  /* Set r5 with an offset of #4 if there's one last arg that couldn't be placed in r registers */
 | 
						||
+    add     r5, r5, #4              /* Set r5 with an offset of + #4, so objlast can be loaded into the stack */
 | 
						||
+
 | 
						||
+stackargsFuncR0ObjLast:
 | 
						||
+    ldr     r7, [r6, #268]  /* Load stack size into r7 */
 | 
						||
+    add     r7, r7, r5      /* Add the offset placed in r5 (could be #0 or #4) */
 | 
						||
+    cmp     r7, #0          /* Check for 0 args */
 | 
						||
+
 | 
						||
+    /* If there are no args for the stack, branch */
 | 
						||
+    beq     nomoreargsarmFuncR0ObjLast
 | 
						||
+
 | 
						||
+    /* Load the rest of the arguments onto the stack */
 | 
						||
+    /* Ensure 8-byte stack alignment */
 | 
						||
+    mov     r8, sp
 | 
						||
+    sub     sp, sp, r7
 | 
						||
+    add     r6, r6, #16     /* Set r6 to point to the first arg to be placed on the stack */
 | 
						||
+
 | 
						||
+    sub     r12, sp, #8
 | 
						||
+    sub     r6, r6, r5      /* r6 = r6 - r5 (r5 can be #0 or #4) */
 | 
						||
+    bic     r12, r12, #7    /* thumb mode couldn't support "bic  sp, sp, #7" instruction */
 | 
						||
+    sub     r8, r8, r12
 | 
						||
+    mov     sp, r12         /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */
 | 
						||
+
 | 
						||
+stackargslooparmFuncR0ObjLast:
 | 
						||
+    ldr     r5, [r6], #4
 | 
						||
+    subs    r7, r7, #4
 | 
						||
+    str     r5, [sp], #4
 | 
						||
+    bne     stackargslooparmFuncR0ObjLast
 | 
						||
+    mov     sp, r12
 | 
						||
+
 | 
						||
+nomoreargsarmFuncR0ObjLast:
 | 
						||
+#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
 | 
						||
+    mov    lr, pc   /* older ARM didn't support blx */
 | 
						||
+    mov    pc, r4
 | 
						||
+#else
 | 
						||
+    blx     r4
 | 
						||
+#endif
 | 
						||
+    add     sp, sp, r8
 | 
						||
+    vstmia.64   r10, {d0-d7}    /* Copy contents of registers d0-d10 to the address stored in r10 */
 | 
						||
+
 | 
						||
+    pop {r4-r8, r10, r11, pc}
 | 
						||
+
 | 
						||
+/* ------------------------------------------------------------------------------------------- */
 | 
						||
+    .align 2        /* Align the function code to a 4-byte (2^n) word boundary. */
 | 
						||
+#if defined(__thumb__) || defined(__thumb2__)
 | 
						||
+    .thumb
 | 
						||
+    .syntax unified
 | 
						||
+#else
 | 
						||
+    .arm            /* Use ARM instructions instead of Thumb.*/
 | 
						||
+#endif
 | 
						||
+    .globl armFuncR0        /* Make the function globally accessible.*/
 | 
						||
+    .type armFuncR0, %function
 | 
						||
+armFuncR0:
 | 
						||
+    push {r4-r8, r10, r11, lr}
 | 
						||
+
 | 
						||
+    mov     r6, r0  /* arg table */
 | 
						||
+    movs    r7, r1  /* arg size (also set the condition code flags so that we detect if there are no arguments) */
 | 
						||
+    mov     r4, r2  /* function address */
 | 
						||
+    mov     r11, #0 /* This will hold an offset of #4 only if the last arg that should have been placed into an "r" reg needs to go to the stack */
 | 
						||
+    mov     r0, r3  /* r0 explicitly set */
 | 
						||
+
 | 
						||
+    /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */
 | 
						||
+    add     r10, r6, #272   /* r10 (r6 + 272) points to the first value for the VFP registers */
 | 
						||
+    mov     r8, #0
 | 
						||
+    vldmia.64 r10, {d0-d7}  /* Load contents starting at r10 into registers d0-d7 */
 | 
						||
+
 | 
						||
+    /* If there are no arguments to set into r0-r3 */
 | 
						||
+    /* go check if there are arguments for the stack */
 | 
						||
+    beq     stackargsarmFuncR0
 | 
						||
+
 | 
						||
+    /* Load the first 3 arguments into r1-r3 */
 | 
						||
+    cmp     r7, #4
 | 
						||
+    ldrge   r1, [r6]
 | 
						||
+    cmp     r7, #8
 | 
						||
+    ldrge   r2, [r6, #4]
 | 
						||
+    cmp     r7, #12
 | 
						||
+    ldrge   r3, [r6, #8]
 | 
						||
+    cmp     r7, #16
 | 
						||
+    movge   r11, #4         /* If there is still one arg to be placed, set the offset in r11 to #4 */
 | 
						||
+
 | 
						||
+stackargsarmFuncR0:
 | 
						||
+    ldr     r5, [r6, #268]  /* Load stack size into r5 */
 | 
						||
+    add     r5, r11         /* Add the offset placed in r11 (could be #0 or #4) */
 | 
						||
+    movs    r7, r5          /* Load stack size into r7, checking for 0 args */
 | 
						||
+
 | 
						||
+    /* If there are no args for the stack, branch */
 | 
						||
+    beq     nomoreargsarmFuncR0
 | 
						||
+
 | 
						||
+    /* Load the rest of the arguments onto the stack */
 | 
						||
+    /* Ensure 8-byte stack alignment */
 | 
						||
+    mov     r8, sp
 | 
						||
+    sub     sp, sp, r7
 | 
						||
+    add     r6, r6, #16     /* Set r6 to point to the first arg to be placed on the stack */
 | 
						||
+
 | 
						||
+    sub     r12, sp, #8
 | 
						||
+    sub     r6, r6, r11     /* r6 = r6 - r11 (r11 can be #0 or #4) */
 | 
						||
+    bic     r12, r12, #7    /* thumb mode couldn't support "bic  sp, sp, #7" instruction */
 | 
						||
+    sub     r8, r8, r12
 | 
						||
+    mov     sp, r12         /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */
 | 
						||
+
 | 
						||
+stackargslooparmFuncR0:
 | 
						||
+    ldr     r5, [r6], #4
 | 
						||
+    subs    r7, r7, #4
 | 
						||
+    str     r5, [sp], #4
 | 
						||
+    bne     stackargslooparmFuncR0
 | 
						||
+    mov     sp, r12
 | 
						||
+
 | 
						||
+nomoreargsarmFuncR0:
 | 
						||
+#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
 | 
						||
+    mov    lr, pc   /* older ARM didn't support blx */
 | 
						||
+    mov    pc, r4
 | 
						||
+#else
 | 
						||
+    blx     r4
 | 
						||
+#endif
 | 
						||
+    add     sp, sp, r8
 | 
						||
+    vstmia.64   r10, {d0-d7}    /* Copy contents of registers d0-d10 to the address stored in r10 */
 | 
						||
+
 | 
						||
+    pop {r4-r8, r10, r11, pc}
 | 
						||
+
 | 
						||
+/* ------------------------------------------------------------------------------------------- */
 | 
						||
+    .align 2        /* Align the function code to a 4-byte (2^n) word boundary. */
 | 
						||
+#if defined(__thumb__) || defined(__thumb2__)
 | 
						||
+    .thumb
 | 
						||
+    .syntax unified
 | 
						||
+#else
 | 
						||
+    .arm            /* Use ARM instructions instead of Thumb.*/
 | 
						||
+#endif
 | 
						||
+    .globl armFuncR0R1      /* Make the function globally accessible.*/
 | 
						||
+    .type armFuncR0R1, %function
 | 
						||
+armFuncR0R1:
 | 
						||
+    push {r4-r8, r10, r11, lr}
 | 
						||
+
 | 
						||
+    mov     r6, r0  /* arg table */
 | 
						||
+    movs    r7, r1  /* arg size (also set the condition code flags so that we detect if there are no arguments) */
 | 
						||
+    mov     r4, r2  /* function address */
 | 
						||
+    mov     r11, #0 /* This will hold an offset of #4 or #8 only if the last arg (or last 2 args) that should have been placed into "r" regs need to go to the stack */
 | 
						||
+
 | 
						||
+    mov     r0, r3          /* r0 explicitly set */
 | 
						||
+    ldr     r1, [sp, #32]   /* r1 explicitly set too */
 | 
						||
+
 | 
						||
+    /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */
 | 
						||
+    add     r10, r6, #272   /* r10 (r6 + 272) points to the first value for the VFP registers */
 | 
						||
+    mov     r8, #0
 | 
						||
+    vldmia.64 r10, {d0-d7}  /* Load contents starting at r10 into registers d0-d7 */
 | 
						||
+
 | 
						||
+    /* If there are no arguments to set into r2-r3 */
 | 
						||
+    /* go check if there are arguments for the stack */
 | 
						||
+    beq     stackargsarmFuncR0R1
 | 
						||
+
 | 
						||
+    /* Load the first 2 arguments into r2-r3 */
 | 
						||
+    cmp     r7, #4
 | 
						||
+    ldrge   r2, [r6]
 | 
						||
+    cmp     r7, #8
 | 
						||
+    ldrge   r3, [r6, #4]
 | 
						||
+    cmp     r7, #12
 | 
						||
+    movge   r11, #4         /* If there is a third arg to be placed, set the offset in r11 to #4 */
 | 
						||
+    cmp     r7, #16
 | 
						||
+    movge   r11, #8         /* If there is a fourth arg to be placed, set the offset in r11 to #8 */
 | 
						||
+    ldrlt   r7, [r6, #8]    /* Else copy the third arg to the correct place in the array */
 | 
						||
+    strlt   r7, [r6, #12]
 | 
						||
+
 | 
						||
+stackargsarmFuncR0R1:
 | 
						||
+    ldr     r5, [r6, #268]  /* Load stack size into r5 */
 | 
						||
+    add     r5, r11         /* Add the offset placed in r11 (could be #0 or #4 or #8) */
 | 
						||
+    movs    r7, r5          /* Load stack size into r7, checking for 0 args */
 | 
						||
+
 | 
						||
+    /* If there are no args for the stack, branch */
 | 
						||
+    beq     nomoreargsarmFuncR0R1
 | 
						||
+
 | 
						||
+    /* Load the rest of the arguments onto the stack */
 | 
						||
+    /* Ensure 8-byte stack alignment */
 | 
						||
+    mov     r8, sp
 | 
						||
+    sub     sp, sp, r7
 | 
						||
+    add     r6, r6, #16     /* Set r6 to point to the first arg to be placed on the stack */
 | 
						||
+
 | 
						||
+    sub     r12, sp, #8
 | 
						||
+    sub     r6, r6, r11     /* r6 = r6 - r11 (r11 can be #0 or #4 or #8) */
 | 
						||
+    bic     r12, r12, #7    /* thumb mode couldn't support "bic  sp, sp, #7" instruction */
 | 
						||
+    sub     r8, r8, r12
 | 
						||
+    mov     sp, r12         /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */
 | 
						||
+
 | 
						||
+stackargslooparmFuncR0R1:
 | 
						||
+    ldr     r5, [r6], #4
 | 
						||
+    subs    r7, r7, #4
 | 
						||
+    str     r5, [sp], #4
 | 
						||
+    bne     stackargslooparmFuncR0R1
 | 
						||
+    mov     sp, r12
 | 
						||
+
 | 
						||
+nomoreargsarmFuncR0R1:
 | 
						||
+#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__)
 | 
						||
+    mov    lr, pc   /* older ARM didn't support blx */
 | 
						||
+    mov    pc, r4
 | 
						||
+#else
 | 
						||
+    blx     r4
 | 
						||
+#endif
 | 
						||
+    add     sp, sp, r8
 | 
						||
+    vstmia.64   r10, {d0-d7}    /* Copy contents of registers d0-d10 to the address stored in r10 */
 | 
						||
+
 | 
						||
+    pop {r4-r8, r10, r11, pc}
 | 
						||
+
 | 
						||
+#endif /* hard float abi */
 | 
						||
+
 | 
						||
+#endif /* arm */
 | 
						||
+
 | 
						||
+#if defined(__linux__) && defined(__ELF__)
 | 
						||
+/* ref: http://hardened.gentoo.org/gnu-stack.xml 
 | 
						||
+   ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart */
 | 
						||
+.section .note.GNU-stack,"",%progbits
 | 
						||
+#endif
 | 
						||
+
 | 
						||
+#endif /* !AS_MAX_PORTABILITY */
 | 
						||
+
 | 
						||
+
 | 
						||
+
 | 
						||
diff --git a/src/angel/src/as_callfunc_arm.cpp b/src/angel/src/as_callfunc_arm.cpp
 | 
						||
new file mode 100644
 | 
						||
index 00000000..c30db60b
 | 
						||
--- /dev/null
 | 
						||
+++ b/src/angel/src/as_callfunc_arm.cpp
 | 
						||
@@ -0,0 +1,697 @@
 | 
						||
+/*
 | 
						||
+   AngelCode Scripting Library
 | 
						||
+   Copyright (c) 2003-2025 Andreas Jonsson
 | 
						||
+
 | 
						||
+   This software is provided 'as-is', without any express or implied
 | 
						||
+   warranty. In no event will the authors be held liable for any
 | 
						||
+   damages arising from the use of this software.
 | 
						||
+
 | 
						||
+   Permission is granted to anyone to use this software for any
 | 
						||
+   purpose, including commercial applications, and to alter it and
 | 
						||
+   redistribute it freely, subject to the following restrictions:
 | 
						||
+
 | 
						||
+   1. The origin of this software must not be misrepresented; you
 | 
						||
+      must not claim that you wrote the original software. If you use
 | 
						||
+      this software in a product, an acknowledgment in the product
 | 
						||
+      documentation would be appreciated but is not required.
 | 
						||
+
 | 
						||
+   2. Altered source versions must be plainly marked as such, and
 | 
						||
+      must not be misrepresented as being the original software.
 | 
						||
+
 | 
						||
+   3. This notice may not be removed or altered from any source
 | 
						||
+      distribution.
 | 
						||
+
 | 
						||
+   The original version of this library can be located at:
 | 
						||
+   http://www.angelcode.com/angelscript/
 | 
						||
+
 | 
						||
+   Andreas Jonsson
 | 
						||
+   andreas@angelcode.com
 | 
						||
+*/
 | 
						||
+
 | 
						||
+
 | 
						||
+//
 | 
						||
+// as_callfunc_arm.cpp
 | 
						||
+//
 | 
						||
+// These functions handle the actual calling of system functions on the arm platform
 | 
						||
+//
 | 
						||
+// Written by Fredrik Ehnbom in June 2009, based on as_callfunc_x86.cpp
 | 
						||
+//
 | 
						||
+// The code was complemented to support Linux with ARM by Carlos Luna in December, 2012.
 | 
						||
+//
 | 
						||
+// Added support for functor methods by Jordi Oliveras Rovira in April, 2014.
 | 
						||
+
 | 
						||
+
 | 
						||
+// This code has to conform to both AAPCS and the modified ABI for iOS
 | 
						||
+//
 | 
						||
+// Reference:
 | 
						||
+//
 | 
						||
+// AAPCS: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf
 | 
						||
+// iOS: http://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/iPhoneOSABIReference.pdf
 | 
						||
+
 | 
						||
+#include "as_config.h"
 | 
						||
+
 | 
						||
+#ifndef AS_MAX_PORTABILITY
 | 
						||
+#ifdef AS_ARM
 | 
						||
+
 | 
						||
+#include "as_callfunc.h"
 | 
						||
+#include "as_scriptengine.h"
 | 
						||
+#include "as_texts.h"
 | 
						||
+#include "as_tokendef.h"
 | 
						||
+#include "as_context.h"
 | 
						||
+
 | 
						||
+#if defined(AS_SOFTFP)
 | 
						||
+
 | 
						||
+// This code supports the soft-float ABI, i.e. g++ -mfloat-abi=softfp
 | 
						||
+//
 | 
						||
+// The code for iOS, Android, Marmalade and Windows Phone goes here
 | 
						||
+
 | 
						||
+BEGIN_AS_NAMESPACE
 | 
						||
+
 | 
						||
+extern "C" asQWORD armFunc          (const asDWORD *, int, asFUNCTION_t);
 | 
						||
+extern "C" asQWORD armFuncR0        (const asDWORD *, int, asFUNCTION_t, asDWORD r0);
 | 
						||
+extern "C" asQWORD armFuncR0R1      (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD r1);
 | 
						||
+extern "C" asQWORD armFuncObjLast   (const asDWORD *, int, asFUNCTION_t, asDWORD obj);
 | 
						||
+extern "C" asQWORD armFuncR0ObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD obj);
 | 
						||
+
 | 
						||
+asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject)
 | 
						||
+{
 | 
						||
+	asCScriptEngine *engine = context->m_engine;
 | 
						||
+	asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
 | 
						||
+	int callConv = sysFunc->callConv;
 | 
						||
+
 | 
						||
+	asQWORD       retQW     = 0;
 | 
						||
+	asFUNCTION_t  func      = sysFunc->func;
 | 
						||
+	int           paramSize = sysFunc->paramSize;
 | 
						||
+	asFUNCTION_t *vftable;
 | 
						||
+
 | 
						||
+	if( sysFunc->hostReturnInMemory )
 | 
						||
+	{
 | 
						||
+		// The return is made in memory
 | 
						||
+		callConv++;
 | 
						||
+	}
 | 
						||
+	bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST;
 | 
						||
+
 | 
						||
+
 | 
						||
+	asDWORD paramBuffer[64+2];
 | 
						||
+	// Android & Linux needs to align 64bit types on even registers, but this isn't done on iOS or Windows Phone
 | 
						||
+	// TODO: optimize runtime: There should be a check for this in PrepareSystemFunction() so this 
 | 
						||
+	//                         doesn't have to be done for functions that don't have any 64bit types
 | 
						||
+#if !defined(AS_ANDROID) && !defined(AS_LINUX)
 | 
						||
+	// In cases of thiscall methods, the callstack is configured as a standard thiscall
 | 
						||
+	// adding the secondObject as first or last element in callstack
 | 
						||
+	if( sysFunc->takesObjByVal || isThisCallMethod )
 | 
						||
+#endif
 | 
						||
+	{
 | 
						||
+#if defined(AS_ANDROID) || defined(AS_LINUX)
 | 
						||
+		// mask is used as a toggler to skip uneven registers.
 | 
						||
+		int mask = 1;
 | 
						||
+
 | 
						||
+		if( isThisCallMethod )
 | 
						||
+		{
 | 
						||
+			mask = 0;
 | 
						||
+		}
 | 
						||
+		else
 | 
						||
+		{
 | 
						||
+			// Check for object pointer as first argument
 | 
						||
+			switch( callConv )
 | 
						||
+			{
 | 
						||
+				case ICC_THISCALL:
 | 
						||
+				case ICC_CDECL_OBJFIRST:
 | 
						||
+				case ICC_VIRTUAL_THISCALL:
 | 
						||
+				case ICC_THISCALL_RETURNINMEM:
 | 
						||
+				case ICC_CDECL_OBJFIRST_RETURNINMEM:
 | 
						||
+				case ICC_VIRTUAL_THISCALL_RETURNINMEM:
 | 
						||
+					mask = 0;
 | 
						||
+					break;
 | 
						||
+				default:
 | 
						||
+					break;
 | 
						||
+			}
 | 
						||
+		}
 | 
						||
+
 | 
						||
+		// Check for hidden address in case of return by value
 | 
						||
+		if( sysFunc->hostReturnInMemory )
 | 
						||
+			mask = !mask;
 | 
						||
+#endif
 | 
						||
+		paramSize = 0;
 | 
						||
+		int spos = 0;
 | 
						||
+		int dpos = 2;
 | 
						||
+
 | 
						||
+		if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJFIRST &&
 | 
						||
+			callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) )
 | 
						||
+		{
 | 
						||
+			// Add the object pointer as the first parameter
 | 
						||
+			paramBuffer[dpos++] = (asDWORD)secondObject;
 | 
						||
+			paramSize++;
 | 
						||
+		}
 | 
						||
+
 | 
						||
+		for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
 | 
						||
+		{
 | 
						||
+			// TODO: runtime optimize: Declare a reference to descr->parameterTypes[n] so the array doesn't have to be access all the time
 | 
						||
+			if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() )
 | 
						||
+			{
 | 
						||
+#ifdef COMPLEX_OBJS_PASSED_BY_REF
 | 
						||
+				if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
 | 
						||
+				{
 | 
						||
+					paramBuffer[dpos++] = args[spos++];
 | 
						||
+					paramSize++;
 | 
						||
+				}
 | 
						||
+				else
 | 
						||
+#endif
 | 
						||
+				{
 | 
						||
+#if defined(AS_ANDROID) || defined(AS_LINUX)
 | 
						||
+					if( (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) &&
 | 
						||
+						((dpos & 1) == mask) )
 | 
						||
+					{
 | 
						||
+						// 64 bit value align
 | 
						||
+						dpos++;
 | 
						||
+						paramSize++;
 | 
						||
+					}
 | 
						||
+#endif
 | 
						||
+					// Copy the object's memory to the buffer
 | 
						||
+					memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
 | 
						||
+
 | 
						||
+					// Delete the original memory
 | 
						||
+					engine->CallFree(*(char**)(args+spos));
 | 
						||
+					spos++;
 | 
						||
+					dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
 | 
						||
+					paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
 | 
						||
+				}
 | 
						||
+			}
 | 
						||
+			else
 | 
						||
+			{
 | 
						||
+#if defined(AS_ANDROID) || defined(AS_LINUX)
 | 
						||
+				// Should an alignment be performed?
 | 
						||
+				if( !descr->parameterTypes[n].IsObjectHandle() && 
 | 
						||
+					!descr->parameterTypes[n].IsReference() && 
 | 
						||
+					descr->parameterTypes[n].GetSizeOnStackDWords() == 2 && 
 | 
						||
+					((dpos & 1) == mask) )
 | 
						||
+				{
 | 
						||
+					// 64 bit value align
 | 
						||
+					dpos++;
 | 
						||
+					paramSize++;
 | 
						||
+				}
 | 
						||
+#endif
 | 
						||
+
 | 
						||
+				// Copy the value directly
 | 
						||
+				paramBuffer[dpos++] = args[spos++];
 | 
						||
+				if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
 | 
						||
+					paramBuffer[dpos++] = args[spos++];
 | 
						||
+				paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
 | 
						||
+			}
 | 
						||
+		}
 | 
						||
+
 | 
						||
+		if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJLAST &&
 | 
						||
+			callConv <= ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) )
 | 
						||
+		{
 | 
						||
+			// Add the object pointer as the last parameter
 | 
						||
+			paramBuffer[dpos++] = (asDWORD)secondObject;
 | 
						||
+			paramSize++;
 | 
						||
+		}
 | 
						||
+
 | 
						||
+		// Keep a free location at the beginning
 | 
						||
+		args = ¶mBuffer[2];
 | 
						||
+	}
 | 
						||
+
 | 
						||
+	switch( callConv )
 | 
						||
+	{
 | 
						||
+	case ICC_CDECL_RETURNINMEM:     // fall through
 | 
						||
+	case ICC_STDCALL_RETURNINMEM:
 | 
						||
+		retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)retPointer);
 | 
						||
+		break;
 | 
						||
+	case ICC_CDECL:     // fall through
 | 
						||
+	case ICC_STDCALL:
 | 
						||
+		retQW = armFunc(args, paramSize<<2, func);
 | 
						||
+		break;
 | 
						||
+	case ICC_THISCALL:  // fall through
 | 
						||
+	case ICC_CDECL_OBJFIRST:
 | 
						||
+	case ICC_THISCALL_OBJFIRST:
 | 
						||
+	case ICC_THISCALL_OBJLAST:
 | 
						||
+		retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)obj);
 | 
						||
+		break;
 | 
						||
+	case ICC_THISCALL_RETURNINMEM:
 | 
						||
+	case ICC_THISCALL_OBJFIRST_RETURNINMEM:
 | 
						||
+	case ICC_THISCALL_OBJLAST_RETURNINMEM:
 | 
						||
+#ifdef __GNUC__
 | 
						||
+		// On GNUC the address where the return value will be placed should be put in R0
 | 
						||
+		retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
 | 
						||
+#else
 | 
						||
+		// On Windows the R0 should always hold the object pointer, and the address for the return value comes after
 | 
						||
+		retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)obj, (asDWORD)retPointer);
 | 
						||
+#endif
 | 
						||
+		break;
 | 
						||
+	case ICC_CDECL_OBJFIRST_RETURNINMEM:
 | 
						||
+		retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
 | 
						||
+		break;
 | 
						||
+	case ICC_VIRTUAL_THISCALL:
 | 
						||
+	case ICC_VIRTUAL_THISCALL_OBJFIRST:
 | 
						||
+	case ICC_VIRTUAL_THISCALL_OBJLAST:
 | 
						||
+		// Get virtual function table from the object pointer
 | 
						||
+		vftable = *(asFUNCTION_t**)obj;
 | 
						||
+		retQW = armFuncR0(args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)obj);
 | 
						||
+		break;
 | 
						||
+	case ICC_VIRTUAL_THISCALL_RETURNINMEM:
 | 
						||
+	case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM:
 | 
						||
+	case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM:
 | 
						||
+		// Get virtual function table from the object pointer
 | 
						||
+		vftable = *(asFUNCTION_t**)obj;
 | 
						||
+#ifdef __GNUC__
 | 
						||
+		// On GNUC the address where the return value will be placed should be put in R0
 | 
						||
+		retQW = armFuncR0R1(args, (paramSize+1)<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)retPointer, (asDWORD)obj);
 | 
						||
+#else
 | 
						||
+		// On Windows the R0 should always hold the object pointer, and the address for the return value comes after
 | 
						||
+		retQW = armFuncR0R1(args, (paramSize+1)<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)obj, (asDWORD)retPointer);
 | 
						||
+#endif
 | 
						||
+		break;
 | 
						||
+	case ICC_CDECL_OBJLAST:
 | 
						||
+		retQW = armFuncObjLast(args, paramSize<<2, func, (asDWORD)obj);
 | 
						||
+		break;
 | 
						||
+	case ICC_CDECL_OBJLAST_RETURNINMEM:
 | 
						||
+		retQW = armFuncR0ObjLast(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
 | 
						||
+		break;
 | 
						||
+	default:
 | 
						||
+		context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
 | 
						||
+	}
 | 
						||
+
 | 
						||
+	return retQW;
 | 
						||
+}
 | 
						||
+
 | 
						||
+END_AS_NAMESPACE
 | 
						||
+
 | 
						||
+#elif !defined(AS_SOFTFP)
 | 
						||
+
 | 
						||
+// This code supports the hard-float ABI, i.e. g++ -mfloat-abi=hard
 | 
						||
+// The main difference is that the floating point values are passed in the fpu registers
 | 
						||
+
 | 
						||
+#define VFP_OFFSET 70
 | 
						||
+#define STACK_OFFSET 6
 | 
						||
+#define PARAM_BUFFER_SIZE 104
 | 
						||
+
 | 
						||
+BEGIN_AS_NAMESPACE
 | 
						||
+
 | 
						||
+extern "C" asQWORD armFunc          (const asDWORD *, int, asFUNCTION_t);
 | 
						||
+extern "C" asQWORD armFuncR0        (const asDWORD *, int, asFUNCTION_t, asDWORD r0);
 | 
						||
+extern "C" asQWORD armFuncR0R1      (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD r1);
 | 
						||
+extern "C" asQWORD armFuncObjLast   (const asDWORD *, int, asFUNCTION_t, asDWORD obj);
 | 
						||
+extern "C" asQWORD armFuncR0ObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD obj);
 | 
						||
+
 | 
						||
+asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2, void *secondObject)
 | 
						||
+{
 | 
						||
+	asCScriptEngine *engine = context->m_engine;
 | 
						||
+	asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf;
 | 
						||
+	int callConv = sysFunc->callConv;
 | 
						||
+
 | 
						||
+	asQWORD       retQW     = 0;
 | 
						||
+	asFUNCTION_t  func      = sysFunc->func;
 | 
						||
+	int           paramSize = sysFunc->paramSize;
 | 
						||
+	asFUNCTION_t *vftable;
 | 
						||
+
 | 
						||
+	//---------------------------------------------------------------------------- RPi
 | 
						||
+	int freeFloatSlot	= VFP_OFFSET;
 | 
						||
+	int freeDoubleSlot	= VFP_OFFSET;
 | 
						||
+	int stackPos		= STACK_OFFSET;
 | 
						||
+	int stackSize		= 0;
 | 
						||
+	//----------------------------------------------------------------------------
 | 
						||
+
 | 
						||
+	//---------------------------------------------------------------------------- RPi
 | 
						||
+	// We<57>ll divide paramBuffer into several segments:
 | 
						||
+	//
 | 
						||
+	// 0-1							Unused
 | 
						||
+	// 2-5		(+8   / +0   asm)	values that should be placed in R0 - R3
 | 
						||
+	// 6-67		(+24  / +16  asm)	values that should be placed on the stack
 | 
						||
+	// 68		(+272 / +264 asm)	number of values stored in r registers (R0 - R3)
 | 
						||
+	// 69		(+276 / +268 asm)	number of args stored on the stack
 | 
						||
+	// 70-85	(+280 / +272 asm)	values that should be placed in VFP registers (16)
 | 
						||
+	// 86-87	(+344 / +336 asm)	sp original value - sp final value - for debugging
 | 
						||
+	// 88-103	(+352 / +344 asm)	Check area for free-used VFP registers
 | 
						||
+	//
 | 
						||
+	// Total number of elements: 104
 | 
						||
+	//
 | 
						||
+	// When passing the paramBuffer to the asm routines via the args pointer we are
 | 
						||
+	// offsetting the start of the array to being at element # 2. That<61>s why in asm
 | 
						||
+	// all addresses must have an offset of -2 words (-8 bytes).
 | 
						||
+	//---------------------------------------------------------------------------- RPi
 | 
						||
+
 | 
						||
+	asDWORD paramBuffer[PARAM_BUFFER_SIZE];
 | 
						||
+	memset(paramBuffer, 0, sizeof(asDWORD) * PARAM_BUFFER_SIZE);
 | 
						||
+
 | 
						||
+	if( sysFunc->hostReturnInMemory )
 | 
						||
+	{
 | 
						||
+		// TODO: runtime optimize: This check should be done in PrepareSystemFunction
 | 
						||
+		if ( !( descr->returnType.GetTypeInfo()->flags & COMPLEX_RETURN_MASK )		&&
 | 
						||
+			  ( descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS )	&&
 | 
						||
+			    descr->returnType.GetSizeInMemoryBytes() <= 16 )
 | 
						||
+			callConv--;
 | 
						||
+		
 | 
						||
+		// The return is made in memory
 | 
						||
+		callConv++;
 | 
						||
+	}
 | 
						||
+
 | 
						||
+	bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST;
 | 
						||
+
 | 
						||
+	// Linux needs to align 64bit types on even registers, but this isn't done on iOS or Windows Phone
 | 
						||
+	// TODO: optimize runtime: There should be a check for this in PrepareSystemFunction() so this 
 | 
						||
+	//                         doesn't have to be done for functions that don't have any 64bit types
 | 
						||
+	{
 | 
						||
+		// mask is used as a toggler to skip uneven registers.
 | 
						||
+		int mask = 1;
 | 
						||
+
 | 
						||
+		if( isThisCallMethod )
 | 
						||
+		{
 | 
						||
+			mask = 0;
 | 
						||
+		}
 | 
						||
+		else
 | 
						||
+		{
 | 
						||
+			// Check for object pointer as first argument
 | 
						||
+			switch( callConv )
 | 
						||
+			{
 | 
						||
+				case ICC_THISCALL:
 | 
						||
+				case ICC_CDECL_OBJFIRST:
 | 
						||
+				case ICC_VIRTUAL_THISCALL:
 | 
						||
+				case ICC_THISCALL_RETURNINMEM:
 | 
						||
+				case ICC_CDECL_OBJFIRST_RETURNINMEM:
 | 
						||
+				case ICC_VIRTUAL_THISCALL_RETURNINMEM:
 | 
						||
+					mask = 0;
 | 
						||
+					break;
 | 
						||
+				default:
 | 
						||
+					break;
 | 
						||
+			}
 | 
						||
+		}
 | 
						||
+		// Check for hidden address in case of return by value
 | 
						||
+		if( sysFunc->hostReturnInMemory )
 | 
						||
+			mask = !mask;
 | 
						||
+
 | 
						||
+		paramSize = 0;
 | 
						||
+		int spos = 0;
 | 
						||
+		int dpos = 2;
 | 
						||
+
 | 
						||
+		if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJFIRST &&
 | 
						||
+			callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) )
 | 
						||
+		{
 | 
						||
+			// Add the object pointer as the first parameter
 | 
						||
+			paramBuffer[dpos++] = (asDWORD)secondObject;
 | 
						||
+			paramSize++;
 | 
						||
+		}
 | 
						||
+
 | 
						||
+		for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ )
 | 
						||
+		{
 | 
						||
+			// TODO: runtime optimize: Declare a reference to descr->parameterTypes[n] so the array doesn't have to be access all the time
 | 
						||
+			if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() &&
 | 
						||
+				!(descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_ARRAY) )
 | 
						||
+			{
 | 
						||
+#ifdef COMPLEX_OBJS_PASSED_BY_REF
 | 
						||
+				if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK )
 | 
						||
+				{
 | 
						||
+					paramBuffer[dpos++] = args[spos++];
 | 
						||
+					paramSize++;
 | 
						||
+				}
 | 
						||
+				else
 | 
						||
+#endif
 | 
						||
+				{
 | 
						||
+					if( (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) )
 | 
						||
+					{
 | 
						||
+						if ( (dpos & 1) == mask )
 | 
						||
+						{
 | 
						||
+							// 64 bit value align
 | 
						||
+							dpos++;
 | 
						||
+							paramSize++;
 | 
						||
+						}
 | 
						||
+
 | 
						||
+						if ( (stackPos & 1) == mask )
 | 
						||
+						{
 | 
						||
+							// 64 bit value align
 | 
						||
+							stackPos++;
 | 
						||
+							stackSize++;
 | 
						||
+						}
 | 
						||
+					}
 | 
						||
+
 | 
						||
+					// Copy the object's memory to the buffer
 | 
						||
+					if (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS)
 | 
						||
+					{
 | 
						||
+						int target = (freeFloatSlot > freeDoubleSlot) ? freeFloatSlot : freeDoubleSlot;
 | 
						||
+
 | 
						||
+						if ( descr->parameterTypes[n].GetSizeInMemoryDWords() <= ( (VFP_OFFSET + 16) - target) )
 | 
						||
+						{
 | 
						||
+							memcpy(¶mBuffer[target], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
 | 
						||
+							memset(¶mBuffer[target + 18], (asDWORD)1, descr->parameterTypes[n].GetSizeInMemoryDWords());
 | 
						||
+							target += descr->parameterTypes[n].GetSizeInMemoryDWords();
 | 
						||
+							freeFloatSlot = freeDoubleSlot = target;
 | 
						||
+						}
 | 
						||
+						else
 | 
						||
+						{
 | 
						||
+							memcpy(¶mBuffer[stackPos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
 | 
						||
+							stackPos += descr->parameterTypes[n].GetSizeInMemoryDWords();
 | 
						||
+							stackSize += descr->parameterTypes[n].GetSizeOnStackDWords();
 | 
						||
+						}
 | 
						||
+					}
 | 
						||
+					else
 | 
						||
+					{
 | 
						||
+						memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes());
 | 
						||
+						dpos += descr->parameterTypes[n].GetSizeInMemoryDWords();
 | 
						||
+						paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords();
 | 
						||
+					}
 | 
						||
+
 | 
						||
+					// Delete the original memory
 | 
						||
+					engine->CallFree(*(char**)(args+spos));
 | 
						||
+					spos++;					
 | 
						||
+				}
 | 
						||
+
 | 
						||
+				continue;
 | 
						||
+			}
 | 
						||
+			else if( descr->parameterTypes[n].IsFloatType() && !descr->parameterTypes[n].IsReference() )
 | 
						||
+			{
 | 
						||
+				// Are there any "s" registers available?
 | 
						||
+				if ( freeFloatSlot < (VFP_OFFSET + 16) )
 | 
						||
+				{
 | 
						||
+					if (freeFloatSlot == freeDoubleSlot)
 | 
						||
+						freeDoubleSlot += 2;
 | 
						||
+
 | 
						||
+					paramBuffer[freeFloatSlot + 18] = (asDWORD)1;
 | 
						||
+					paramBuffer[freeFloatSlot++] = args[spos++];
 | 
						||
+
 | 
						||
+					while(freeFloatSlot < (VFP_OFFSET + 16) && paramBuffer[freeFloatSlot + 18] != 0)
 | 
						||
+						freeFloatSlot++;
 | 
						||
+				}
 | 
						||
+				// If not, then store the float arg in the stack area
 | 
						||
+				else
 | 
						||
+				{
 | 
						||
+					paramBuffer[stackPos++] = args[spos++];
 | 
						||
+					stackSize++;
 | 
						||
+				}
 | 
						||
+
 | 
						||
+				continue;
 | 
						||
+			}
 | 
						||
+			else if( descr->parameterTypes[n].IsDoubleType() && !descr->parameterTypes[n].IsReference() )
 | 
						||
+			{
 | 
						||
+				// Are there any "d" registers available?
 | 
						||
+				if ( freeDoubleSlot < (VFP_OFFSET + 15) )
 | 
						||
+				{
 | 
						||
+					if (freeFloatSlot == freeDoubleSlot)
 | 
						||
+						freeFloatSlot += 2;
 | 
						||
+
 | 
						||
+					// Copy two dwords for the double
 | 
						||
+					paramBuffer[freeDoubleSlot + 18] = (asDWORD)1;
 | 
						||
+					paramBuffer[freeDoubleSlot + 19] = (asDWORD)1;
 | 
						||
+					paramBuffer[freeDoubleSlot++] = args[spos++];
 | 
						||
+					paramBuffer[freeDoubleSlot++] = args[spos++];
 | 
						||
+
 | 
						||
+					while(freeDoubleSlot < (VFP_OFFSET + 15) && paramBuffer[freeDoubleSlot + 18] != 0)
 | 
						||
+						freeDoubleSlot += 2;
 | 
						||
+				}
 | 
						||
+				// If not, then store the double arg in the stack area
 | 
						||
+				else
 | 
						||
+				{
 | 
						||
+					if ( (stackPos & 1) == mask )
 | 
						||
+					{
 | 
						||
+						// 64 bit value align
 | 
						||
+						stackPos++;
 | 
						||
+						stackSize++;
 | 
						||
+					}
 | 
						||
+
 | 
						||
+					paramBuffer[stackPos++] = args[spos++];
 | 
						||
+					paramBuffer[stackPos++] = args[spos++];
 | 
						||
+					stackSize += 2;
 | 
						||
+				}
 | 
						||
+				
 | 
						||
+				continue;
 | 
						||
+			}
 | 
						||
+			else if (descr->parameterTypes[n].GetTokenType() == ttQuestion)
 | 
						||
+			{
 | 
						||
+				// Copy the reference and the type id as two separate arguments
 | 
						||
+				// Copy the value directly to "r" registers or the stack, checking for alignment
 | 
						||
+				
 | 
						||
+				// First the reference...
 | 
						||
+				if (paramSize < 4)
 | 
						||
+				{
 | 
						||
+					paramBuffer[dpos++] = args[spos++];
 | 
						||
+					paramSize += 1;
 | 
						||
+				}
 | 
						||
+				else
 | 
						||
+				{
 | 
						||
+					paramBuffer[stackPos++] = args[spos++];
 | 
						||
+					stackSize += 1;
 | 
						||
+				}
 | 
						||
+
 | 
						||
+				// ...then the type id
 | 
						||
+				if (paramSize < 4)
 | 
						||
+				{
 | 
						||
+					paramBuffer[dpos++] = args[spos++];
 | 
						||
+					paramSize += 1;
 | 
						||
+				}
 | 
						||
+				else
 | 
						||
+				{
 | 
						||
+					paramBuffer[stackPos++] = args[spos++];
 | 
						||
+					stackSize += 1;
 | 
						||
+				}
 | 
						||
+			}
 | 
						||
+			else
 | 
						||
+			{
 | 
						||
+				// Copy the value directly to "r" registers or the stack, checking for alignment
 | 
						||
+				if (paramSize < 4)
 | 
						||
+				{
 | 
						||
+					// Should an alignment be performed?
 | 
						||
+					if( (dpos & 1) == mask && descr->parameterTypes[n].GetSizeOnStackDWords() == 2 && 
 | 
						||
+						!descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() &&
 | 
						||
+						!descr->parameterTypes[n].IsAnyType() )
 | 
						||
+					{
 | 
						||
+						// 64 bit value align
 | 
						||
+						dpos++;
 | 
						||
+						paramSize++;
 | 
						||
+					}
 | 
						||
+
 | 
						||
+					paramBuffer[dpos++] = args[spos++];
 | 
						||
+					paramSize += descr->parameterTypes[n].GetSizeOnStackDWords();
 | 
						||
+				}
 | 
						||
+				else
 | 
						||
+				{
 | 
						||
+					// Should an alignment be performed?
 | 
						||
+					if( (stackPos & 1) == mask && descr->parameterTypes[n].GetSizeOnStackDWords() == 2 &&
 | 
						||
+						!descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() &&
 | 
						||
+						!descr->parameterTypes[n].IsAnyType() )
 | 
						||
+					{
 | 
						||
+						// 64 bit value align
 | 
						||
+						stackPos++;
 | 
						||
+						stackSize++;
 | 
						||
+					}
 | 
						||
+
 | 
						||
+					paramBuffer[stackPos++] = args[spos++];
 | 
						||
+					stackSize += descr->parameterTypes[n].GetSizeOnStackDWords();
 | 
						||
+				}
 | 
						||
+
 | 
						||
+				if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 )
 | 
						||
+				{
 | 
						||
+					if (paramSize < 5)
 | 
						||
+						paramBuffer[dpos++] = args[spos++];
 | 
						||
+					else
 | 
						||
+						paramBuffer[stackPos++] = args[spos++];
 | 
						||
+				}
 | 
						||
+			}// else...
 | 
						||
+		}// Loop
 | 
						||
+
 | 
						||
+		if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJLAST &&
 | 
						||
+			callConv <= ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) )
 | 
						||
+		{
 | 
						||
+			if (paramSize < 4)
 | 
						||
+			{
 | 
						||
+				paramBuffer[dpos++] = (asDWORD)secondObject;
 | 
						||
+				paramSize++;
 | 
						||
+			}
 | 
						||
+			else
 | 
						||
+			{
 | 
						||
+				paramBuffer[stackPos++] = (asDWORD)secondObject;
 | 
						||
+				stackSize++;
 | 
						||
+			}
 | 
						||
+		}
 | 
						||
+
 | 
						||
+		// Keep a free location at the beginning
 | 
						||
+		args = ¶mBuffer[2];
 | 
						||
+	}
 | 
						||
+
 | 
						||
+	paramBuffer[69] = static_cast<asDWORD>(stackSize<<2);
 | 
						||
+
 | 
						||
+	switch( callConv )
 | 
						||
+	{
 | 
						||
+	case ICC_CDECL_RETURNINMEM:     // fall through
 | 
						||
+	case ICC_STDCALL_RETURNINMEM:
 | 
						||
+		retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)retPointer);
 | 
						||
+		break;
 | 
						||
+	case ICC_CDECL:     // fall through
 | 
						||
+	case ICC_STDCALL:
 | 
						||
+		retQW = armFunc(args, paramSize<<2, func);
 | 
						||
+		break;
 | 
						||
+	case ICC_THISCALL:  // fall through
 | 
						||
+	case ICC_CDECL_OBJFIRST:
 | 
						||
+	case ICC_THISCALL_OBJFIRST:
 | 
						||
+	case ICC_THISCALL_OBJLAST:
 | 
						||
+		retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)obj);
 | 
						||
+		break;
 | 
						||
+	case ICC_THISCALL_RETURNINMEM:
 | 
						||
+	case ICC_THISCALL_OBJFIRST_RETURNINMEM:
 | 
						||
+	case ICC_THISCALL_OBJLAST_RETURNINMEM:
 | 
						||
+		// On GNUC the address where the return value will be placed should be put in R0
 | 
						||
+		retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
 | 
						||
+		break;
 | 
						||
+	case ICC_CDECL_OBJFIRST_RETURNINMEM:
 | 
						||
+		retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
 | 
						||
+		break;
 | 
						||
+	case ICC_VIRTUAL_THISCALL:
 | 
						||
+	case ICC_VIRTUAL_THISCALL_OBJFIRST:
 | 
						||
+	case ICC_VIRTUAL_THISCALL_OBJLAST:
 | 
						||
+		// Get virtual function table from the object pointer
 | 
						||
+		vftable = *(asFUNCTION_t**)obj;
 | 
						||
+		retQW = armFuncR0(args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)obj);
 | 
						||
+		break;
 | 
						||
+	case ICC_VIRTUAL_THISCALL_RETURNINMEM:
 | 
						||
+	case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM:
 | 
						||
+	case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM:
 | 
						||
+		// Get virtual function table from the object pointer
 | 
						||
+		vftable = *(asFUNCTION_t**)obj;
 | 
						||
+		// On GNUC the address where the return value will be placed should be put in R0
 | 
						||
+		retQW = armFuncR0R1(args, (paramSize+1)<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)retPointer, (asDWORD)obj);
 | 
						||
+		break;
 | 
						||
+	case ICC_CDECL_OBJLAST:
 | 
						||
+		retQW = armFuncObjLast(args, paramSize<<2, func, (asDWORD)obj);
 | 
						||
+		break;
 | 
						||
+	case ICC_CDECL_OBJLAST_RETURNINMEM:
 | 
						||
+		retQW = armFuncR0ObjLast(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj);
 | 
						||
+		break;
 | 
						||
+	default:
 | 
						||
+		context->SetInternalException(TXT_INVALID_CALLING_CONVENTION);
 | 
						||
+	}
 | 
						||
+
 | 
						||
+	// On Linux with arm the float and double values are returns in the 
 | 
						||
+	// floating point registers, s0 and s1. Objects that contain only 
 | 
						||
+	// float types and are not considered complex are also returned in the
 | 
						||
+	// floating point registers.
 | 
						||
+	if( sysFunc->hostReturnFloat )
 | 
						||
+	{
 | 
						||
+		retQW = paramBuffer[VFP_OFFSET];
 | 
						||
+
 | 
						||
+		if ( sysFunc->hostReturnSize > 1 )
 | 
						||
+			retQW = *( (asQWORD*)¶mBuffer[VFP_OFFSET] );
 | 
						||
+		if (sysFunc->hostReturnSize > 2)
 | 
						||
+			retQW2 = *((asQWORD*)¶mBuffer[VFP_OFFSET + 2]);
 | 
						||
+	}
 | 
						||
+	else if ( descr->returnType.IsObject() )
 | 
						||
+	{
 | 
						||
+		// TODO: runtime optimize: This should be identified with a flag determined in PrepareSystemFunction
 | 
						||
+		if ( !descr->returnType.IsObjectHandle()									&&
 | 
						||
+			 !descr->returnType.IsReference()										&&
 | 
						||
+			 !(descr->returnType.GetTypeInfo()->flags & COMPLEX_RETURN_MASK)		&&
 | 
						||
+			 (descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) )
 | 
						||
+			memcpy( retPointer, ¶mBuffer[VFP_OFFSET], descr->returnType.GetSizeInMemoryBytes() );
 | 
						||
+	}
 | 
						||
+
 | 
						||
+	return retQW;
 | 
						||
+}
 | 
						||
+
 | 
						||
+END_AS_NAMESPACE
 | 
						||
+
 | 
						||
+#endif // AS_LINUX
 | 
						||
+
 | 
						||
+#endif // AS_ARM
 | 
						||
+#endif // AS_MAX_PORTABILITY
 | 
						||
+
 | 
						||
+
 | 
						||
+
 | 
						||
+
 | 
						||
+
 |