/***********************************************************************/ /* */ /* OCaml */ /* */ /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */ /* */ /* Copyright 1998 Institut National de Recherche en Informatique et */ /* en Automatique. All rights reserved. This file is distributed */ /* under the terms of the GNU Library General Public License, with */ /* the special exception on linking described in file ../LICENSE. */ /* */ /***********************************************************************/ /* $Id$ */ /* Asm part of the runtime system, ARM processor */ trap_ptr .req r11 alloc_ptr .req r8 alloc_limit .req r10 .text /* Allocation functions and GC interface */ .globl caml_call_gc caml_call_gc: /* Record return address and desired size */ /* Can use alloc_limit as a temporary since it will be reloaded by invoke_gc */ ldr alloc_limit, .Lcaml_last_return_address str lr, [alloc_limit, #0] ldr alloc_limit, .Lcaml_requested_size str r12, [alloc_limit, #0] /* Branch to shared GC code */ bl .Linvoke_gc /* Finish allocation */ ldr r12, .Lcaml_requested_size ldr r12, [r12, #0] sub alloc_ptr, alloc_ptr, r12 bx lr .globl caml_alloc1 caml_alloc1: sub alloc_ptr, alloc_ptr, #8 cmp alloc_ptr, alloc_limit movcs pc, lr /* Return if alloc_ptr >= alloc_limit */ /* Record return address */ ldr r12, .Lcaml_last_return_address str lr, [r12, #0] /* Invoke GC */ bl .Linvoke_gc /* Try again */ b caml_alloc1 .globl caml_alloc2 caml_alloc2: sub alloc_ptr, alloc_ptr, #12 cmp alloc_ptr, alloc_limit movcs pc, lr /* Return if alloc_ptr >= alloc_limit */ /* Record return address */ ldr r12, .Lcaml_last_return_address str lr, [r12, #0] /* Invoke GC */ bl .Linvoke_gc /* Try again */ b caml_alloc2 .globl caml_alloc3 caml_alloc3: sub alloc_ptr, alloc_ptr, #16 cmp alloc_ptr, alloc_limit movcs pc, lr /* Return if alloc_ptr >= alloc_limit */ /* Record return address */ ldr r12, .Lcaml_last_return_address str lr, [r12, #0] /* Invoke GC */ bl .Linvoke_gc /* Try again */ b caml_alloc3 .globl caml_allocN caml_allocN: sub alloc_ptr, alloc_ptr, r12 cmp alloc_ptr, alloc_limit movcs pc, lr /* Return if alloc_ptr >= alloc_limit */ /* Record return address and desired size */ /* Can use alloc_limit as a temporary since it will be reloaded by invoke_gc */ ldr alloc_limit, .Lcaml_last_return_address str lr, [alloc_limit, #0] ldr alloc_limit, .Lcaml_requested_size str r12, [alloc_limit, #0] /* Invoke GC */ bl .Linvoke_gc /* Try again */ ldr r12, .Lcaml_requested_size ldr r12, [r12, #0] b caml_allocN /* Shared code to invoke the GC */ .Linvoke_gc: /* Record lowest stack address */ ldr r12, .Lcaml_bottom_of_stack str sp, [r12, #0] /* Save integer registers and return address on stack */ stmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r12,lr} /* Store pointer to saved integer registers in caml_gc_regs */ ldr r12, .Lcaml_gc_regs str sp, [r12, #0] /* Save current allocation pointer for debugging purposes */ ldr r12, .Lcaml_young_ptr str alloc_ptr, [r12, #0] /* Save trap pointer in case an exception is raised during GC */ ldr r12, .Lcaml_exception_pointer str trap_ptr, [r12, #0] /* Call the garbage collector */ bl caml_garbage_collection /* Restore the registers from the stack */ ldmfd sp!, {r0,r1,r2,r3,r4,r5,r6,r7,r12} /* Reload return address */ ldr r12, .Lcaml_last_return_address ldr lr, [r12, #0] /* Reload new allocation pointer and allocation limit */ ldr r12, .Lcaml_young_ptr ldr alloc_ptr, [r12, #0] ldr r12, .Lcaml_young_limit ldr alloc_limit, [r12, #0] /* Return to caller */ ldr r12, [sp], #4 bx r12 /* Call a C function from Caml */ /* Function to call is in r12 */ .globl caml_c_call caml_c_call: /* Preserve return address in callee-save register r4 */ mov r4, lr /* Record lowest stack address and return address */ ldr r5, .Lcaml_last_return_address ldr r6, .Lcaml_bottom_of_stack str lr, [r5, #0] str sp, [r6, #0] /* Make the exception handler and alloc ptr available to the C code */ ldr r6, .Lcaml_young_ptr ldr r7, .Lcaml_exception_pointer str alloc_ptr, [r6, #0] str trap_ptr, [r7, #0] /* Call the function */ mov lr, pc bx r12 /* Reload alloc ptr and alloc limit */ ldr r5, .Lcaml_young_limit ldr alloc_ptr, [r6, #0] /* r6 still points to caml_young_ptr */ ldr alloc_limit, [r5, #0] /* Return */ bx r4 /* Start the Caml program */ .globl caml_start_program caml_start_program: ldr r12, .Lcaml_program /* Code shared with caml_callback* */ /* Address of Caml code to call is in r12 */ /* Arguments to the Caml code are in r0...r3 */ .Ljump_to_caml: /* Save return address and callee-save registers */ stmfd sp!, {r4,r5,r6,r7,r8,r10,r11,lr} /* 8-alignment */ /* Setup a callback link on the stack */ sub sp, sp, #4*4 /* 8-alignment */ ldr r4, .Lcaml_bottom_of_stack ldr r4, [r4, #0] str r4, [sp, #0] ldr r4, .Lcaml_last_return_address ldr r4, [r4, #0] str r4, [sp, #4] ldr r4, .Lcaml_gc_regs ldr r4, [r4, #0] str r4, [sp, #8] /* Setup a trap frame to catch exceptions escaping the Caml code */ sub sp, sp, #4*2 ldr r4, .Lcaml_exception_pointer ldr r4, [r4, #0] str r4, [sp, #0] ldr r4, .LLtrap_handler str r4, [sp, #4] mov trap_ptr, sp /* Reload allocation pointers */ ldr r4, .Lcaml_young_ptr ldr alloc_ptr, [r4, #0] ldr r4, .Lcaml_young_limit ldr alloc_limit, [r4, #0] /* Call the Caml code */ mov lr, pc bx r12 .Lcaml_retaddr: /* Pop the trap frame, restoring caml_exception_pointer */ ldr r4, .Lcaml_exception_pointer ldr r5, [sp, #0] str r5, [r4, #0] add sp, sp, #2 * 4 /* Pop the callback link, restoring the global variables */ .Lreturn_result: ldr r4, .Lcaml_bottom_of_stack ldr r5, [sp, #0] str r5, [r4, #0] ldr r4, .Lcaml_last_return_address ldr r5, [sp, #4] str r5, [r4, #0] ldr r4, .Lcaml_gc_regs ldr r5, [sp, #8] str r5, [r4, #0] add sp, sp, #4*4 /* Update allocation pointer */ ldr r4, .Lcaml_young_ptr str alloc_ptr, [r4, #0] /* Reload callee-save registers and return */ ldmfd sp!, {r4,r5,r6,r7,r8,r10,r11,lr} bx lr /* The trap handler */ .Ltrap_handler: /* Save exception pointer */ ldr r4, .Lcaml_exception_pointer str trap_ptr, [r4, #0] /* Encode exception bucket as an exception result */ orr r0, r0, #2 /* Return it */ b .Lreturn_result /* Raise an exception from C */ .globl caml_raise_exception caml_raise_exception: /* Reload Caml allocation pointers */ ldr r12, .Lcaml_young_ptr ldr alloc_ptr, [r12, #0] ldr r12, .Lcaml_young_limit ldr alloc_limit, [r12, #0] /* Cut stack at current trap handler */ ldr r12, .Lcaml_exception_pointer ldr sp, [r12, #0] /* Pop previous handler and addr of trap, and jump to it */ ldmfd sp!, {trap_ptr, pc} /* Callback from C to Caml */ .globl caml_callback_exn caml_callback_exn: /* Initial shuffling of arguments (r0 = closure, r1 = first arg) */ mov r12, r0 mov r0, r1 /* r0 = first arg */ mov r1, r12 /* r1 = closure environment */ ldr r12, [r12, #0] /* code pointer */ b .Ljump_to_caml .globl caml_callback2_exn caml_callback2_exn: /* Initial shuffling of arguments (r0 = closure, r1 = arg1, r2 = arg2) */ mov r12, r0 mov r0, r1 /* r0 = first arg */ mov r1, r2 /* r1 = second arg */ mov r2, r12 /* r2 = closure environment */ ldr r12, .Lcaml_apply2 b .Ljump_to_caml .globl caml_callback3_exn caml_callback3_exn: /* Initial shuffling of arguments */ /* (r0 = closure, r1 = arg1, r2 = arg2, r3 = arg3) */ mov r12, r0 mov r0, r1 /* r0 = first arg */ mov r1, r2 /* r1 = second arg */ mov r2, r3 /* r2 = third arg */ mov r3, r12 /* r3 = closure environment */ ldr r12, .Lcaml_apply3 b .Ljump_to_caml .globl caml_ml_array_bound_error caml_ml_array_bound_error: /* Load address of [caml_array_bound_error] in r12 */ ldr r12, .Lcaml_array_bound_error /* Call that function */ b caml_c_call /* Global references */ .Lcaml_last_return_address: .word caml_last_return_address .Lcaml_bottom_of_stack: .word caml_bottom_of_stack .Lcaml_gc_regs: .word caml_gc_regs .Lcaml_young_ptr: .word caml_young_ptr .Lcaml_young_limit: .word caml_young_limit .Lcaml_exception_pointer: .word caml_exception_pointer .Lcaml_program: .word caml_program .LLtrap_handler: .word .Ltrap_handler .Lcaml_apply2: .word caml_apply2 .Lcaml_apply3: .word caml_apply3 .Lcaml_array_bound_error: .word caml_array_bound_error .Lcaml_requested_size: .word caml_requested_size .data caml_requested_size: .word 0 /* GC roots for callback */ .data .globl caml_system__frametable caml_system__frametable: .word 1 /* one descriptor */ .word .Lcaml_retaddr /* return address into callback */ .short -1 /* negative frame size => use callback link */ .short 0 /* no roots */ .align 2