;*********************************************************************
;                                                                     
;                           Objective Caml                            
;
;            Xavier Leroy, projet Cristal, INRIA Rocquencourt         
;
;  Copyright 1996 Institut National de Recherche en Informatique et   
;  Automatique.  Distributed only by permission.                      
;
;*********************************************************************

; $Id: i386nt.asm,v 1.6 1997/03/17 10:17:30 xleroy Exp $

; Asm part of the runtime system, Intel 386 processor, Intel syntax

	.386
	.MODEL FLAT

        EXTERN  _garbage_collection: PROC
        EXTERN  _mlraise: PROC
        EXTERN  _caml_apply2: PROC
        EXTERN  _caml_apply3: PROC
        EXTERN  _caml_program: PROC
        EXTERN  _young_limit: DWORD
        EXTERN  _young_ptr: DWORD

        PUBLIC	_gc_entry_regs
        PUBLIC	_caml_bottom_of_stack
        PUBLIC	_caml_top_of_stack
        PUBLIC	_caml_last_return_address
	PUBLIC	_caml_exception_pointer

	.DATA
	ALIGN	4

_gc_entry_regs			DWORD 7 DUP(?)
_caml_bottom_of_stack		DWORD 0
_caml_top_of_stack		DWORD 0
_caml_last_return_address	DWORD 0
_caml_exception_pointer		DWORD 0

; Allocation 

        .CODE
        PUBLIC  _caml_alloc1
        PUBLIC  _caml_alloc2
        PUBLIC  _caml_alloc3
        PUBLIC  _caml_alloc
	PUBLIC  _caml_call_gc

_caml_call_gc:
    ; Record lowest stack address and return address 
        mov	eax, [esp]
        mov     _caml_last_return_address, eax
        lea     eax, [esp+4]
        mov     _caml_bottom_of_stack, eax
    ; Save all regs used by the code generator 
L105:   mov	_gc_entry_regs + 4, ebx
        mov	_gc_entry_regs + 8, ecx
        mov	_gc_entry_regs + 12, edx
        mov	_gc_entry_regs + 16, esi
        mov	_gc_entry_regs + 20, edi
        mov	_gc_entry_regs + 24, ebp
    ; Call the garbage collector 
        call	_garbage_collection
    ; Restore all regs used by the code generator 
        mov	ebx, _gc_entry_regs + 4
        mov	ecx, _gc_entry_regs + 8
        mov	edx, _gc_entry_regs + 12
        mov	esi, _gc_entry_regs + 16
        mov	edi, _gc_entry_regs + 20
        mov	ebp, _gc_entry_regs + 24
    ; Return to caller 
        ret	

        ALIGN  4
_caml_alloc1:
        mov	eax, _young_ptr
        sub	eax, 8
        mov	_young_ptr, eax
        cmp	eax, _young_limit
        jb	L100
        ret	
L100:   mov	eax, [esp]
        mov     _caml_last_return_address, eax
        lea     eax, [esp+4]
        mov     _caml_bottom_of_stack, eax
        call    L105
        jmp     _caml_alloc1

        ALIGN  4
_caml_alloc2:
        mov	eax, _young_ptr
        sub	eax, 12
        mov	_young_ptr, eax
        cmp	eax, _young_limit
        jb	L101
        ret	
L101:   mov	eax, [esp]
        mov     _caml_last_return_address, eax
        lea     eax, [esp+4]
        mov     _caml_bottom_of_stack, eax
        call    L105
        jmp     _caml_alloc2

        ALIGN  4
_caml_alloc3:
        mov	eax, _young_ptr
        sub	eax, 16
        mov	_young_ptr, eax
        cmp	eax, _young_limit
        jb	L102
        ret	
L102:   mov	eax, [esp]
        mov     _caml_last_return_address, eax
        lea     eax, [esp+4]
        mov     _caml_bottom_of_stack, eax
        call    L105
        jmp     _caml_alloc3

        ALIGN  4
_caml_alloc:
        sub     eax, _young_ptr         ; eax = size - young_ptr
        neg     eax                     ; eax = young_ptr - size
        cmp     eax, _young_limit
        jb      L103
        mov     _young_ptr, eax
        ret
L103:   sub     eax, _young_ptr         ; eax = - size
        neg     eax                     ; eax = size
        push    eax                     ; save desired size
        sub     _young_ptr, eax         ; must update young_ptr
        mov	eax, [esp+4]
        mov     _caml_last_return_address, eax
        lea     eax, [esp+8]
        mov     _caml_bottom_of_stack, eax
        call    L105
        pop     eax                     ; recover desired size
        jmp     _caml_alloc

; Call a C function from Caml 

        PUBLIC  _caml_c_call
        ALIGN  4
_caml_c_call:
    ; Record lowest stack address and return address 
        mov	edx, [esp]
        mov	_caml_last_return_address, edx
        lea	edx, [esp+4]
        mov	_caml_bottom_of_stack, edx
    ; Call the function (address in %eax) 
        jmp	eax

; Start the Caml program 

        PUBLIC  _caml_start_program
        ALIGN  4
_caml_start_program:
    ; Save callee-save registers 
        push	ebx
        push	esi
        push	edi
        push	ebp
    ; Initial code pointer is caml_program
        mov     esi, offset _caml_program

; Code shared between caml_start_program and callback*

L106:
    ; Build a callback link 
        push	_caml_last_return_address
        push	_caml_bottom_of_stack
    ; Build an exception handler 
        push	L108
        push	_caml_exception_pointer
        mov	_caml_exception_pointer, esp
    ; Call the Caml code 
        call	esi
L107:
    ; Pop the exception handler 
        pop	_caml_exception_pointer
        pop	esi    		; dummy register 
    ; Pop the callback link, restoring the global variables
    ; used by caml_c_call
        pop	_caml_bottom_of_stack
        pop	_caml_last_return_address
    ; Restore callee-save registers.
        pop	ebp
        pop	edi
        pop	esi
        pop	ebx
    ; Return to caller. 
        ret	
L108:
    ; Exception handler
    ; Pop the callback link, restoring the global variables
    ; used by caml_c_call
        pop	_caml_bottom_of_stack
        pop	_caml_last_return_address
    ; Re-raise the exception through mlraise,
    ; so that local C roots are cleaned up correctly.
        push	eax            	; exn bucket is the argument 
        call	_mlraise      	; never returns 

; Raise an exception from C 

        PUBLIC  _raise_caml_exception
        ALIGN  4
_raise_caml_exception:
        mov	eax, [esp+4]
        mov	esp, _caml_exception_pointer
        pop	_caml_exception_pointer
        ret	

; Callback from C to Caml 

        PUBLIC  _callback
        ALIGN  4
_callback:
    ; Save callee-save registers 
        push	ebx
        push	esi
        push	edi
        push	ebp
    ; Initial loading of arguments 
        mov	ebx, [esp+20]   ; closure 
        mov	eax, [esp+24]   ; argument 
        mov	esi, [ebx]      ; code pointer
        jmp     L106

        PUBLIC  _callback2
        ALIGN  4
_callback2:
    ; Save callee-save registers 
        push	ebx
        push	esi
        push	edi
        push	ebp
    ; Initial loading of arguments 
        mov	ecx, [esp+20]   ; closure 
        mov	eax, [esp+24]   ; first argument 
        mov	ebx, [esp+28]   ; second argument 
        mov	esi, offset _caml_apply2   ; code pointer 
        jmp	L106

        PUBLIC  _callback3
        ALIGN	4
_callback3:
    ; Save callee-save registers 
        push	ebx
        push	esi
        push	edi
        push	ebp
    ; Initial loading of arguments 
        mov	edx, [esp+20]   ; closure 
        mov	eax, [esp+24]   ; first argument 
        mov	ebx, [esp+28]   ; second argument 
        mov	ecx, [esp+32]   ; third argument 
        mov	esi, offset _caml_apply3   ; code pointer 
        jmp	L106

        .DATA
        PUBLIC  _system_frametable
_system_frametable LABEL DWORD
        DWORD   1               ; one descriptor 
        DWORD   L107            ; return address into callback 
        WORD    -1              ; negative frame size => use callback link 
        WORD    0               ; no roots here 

        END
