Page 1 of 1

[Windows] Sub / EndSub / Call Macros

Posted: Thu Apr 26, 2012 11:08 am
by Danilo
Just some codes to call parameter-less SubRoutines inside and outside of Procedures.

The codes were developed in the thread: MACRO: variable evaluation ?
I am not quite sure if those Macros could be useful for anyone except charvista,
but i put it here anyway for conservation.

With those Macro's you can create and call SubRoutines in a specific program scope.

If you put a Sub in a Procedure, it can only be used local within this procedure.
The Sub has access to the same variables as the procedure.

If you put a Sub in the global scope (main code, outside procedures), it has access to the variables in the global scope.

Sub's require unique names, like labels and procedures.

The main difference to PureBasic's Gosub/Return is, you can call Sub's from within Procedures.

The following is not allowed in PB 4.60:

Code: Select all

Procedure proc1()
    Gosub sub1
EndProcedure

proc1()

End

sub1:
    ; do something
Return
With Sub/EndSub it is allowed to call SubRoutines outside and inside Procedures:

Code: Select all

XIncludeFile "Sub.pbi"

Procedure proc1()
    a = 12         ; local variable a
    Call(sub1)
    Debug a
    Call(sub2)
    Debug a

    Sub(sub2)
        a = 200    ; access variable a in procedure scope
    EndSub

EndProcedure

a = 1              ; variable a in main scope

proc1()

Debug a

Sub(sub1)
    a = 500        ; access variable a in main scope
EndSub


There are 3 includes:

Sub_SingleCall.pbi
- fastest call, but does not allow nested Sub calls and is not thread-safe.

Sub.pbi
- general version, does allow nested calls to other Subs. Not thread-safe.

Sub_ThreadSafe.pbi
- Allows nested calls to other Subs. Special thread-safe version.



DOWNLOAD all Includes: Sub.zip (4k)



Sub_SingleCall.pbi

Code: Select all

;--------------------------------------------------------------------------------------------------------
;
; START INCLUDE "Sub_SingleCall.pbi"
;
;--------------------------------------------------------------------------------------------------------

Threaded *__Sub_ReturnAddress__

Macro Sub(_name_)
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x86 Or #PB_Compiler_Processor = #PB_Processor_x64
        !EndSub_Name equ __EndSub_#_name_
        !  JMP EndSub_Name
        !_sub_#_name_:
    CompilerElse
        CompilerError "Macro Sub(): unsupported processor"
    CompilerEndIf
EndMacro

Macro ExitSub
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x86 Or #PB_Compiler_Processor = #PB_Processor_x64
        !  JMP [p___Sub_ReturnAddress__]
    CompilerElse
        CompilerError "Macro ExitSub: unsupported processor"
    CompilerEndIf
EndMacro

Macro EndSub
    ExitSub
    !EndSub_Name:
EndMacro

Macro Call(_name_)
    CompilerSelect #PB_Compiler_Processor
        CompilerCase #PB_Processor_x86
            !  MOV dword [p___Sub_ReturnAddress__],@f
            !  JMP _sub_#_name_
            !@@:
        CompilerCase #PB_Processor_x64
            !  MOV RAX, @f
            !  MOV qword [p___Sub_ReturnAddress__],RAX
            !  JMP _sub_#_name_
            !@@:
        CompilerDefault
            CompilerError "Macro Call(): unsupported processor"
    CompilerEndSelect
EndMacro


;--------------------------------------------------------------------------------------------------------
;
; END INCLUDE "Sub_SingleCall.pbi"
;
;--------------------------------------------------------------------------------------------------------
Sub.pbi

Code: Select all

;--------------------------------------------------------------------------------------------------------
;
; START INCLUDE "Sub.pbi"
;
;--------------------------------------------------------------------------------------------------------

#SUB_STACKSIZE = 100000

;--------------------------------------------------------------------------------------------------------

Global __Sub_ReturnAddress__.s{(#SUB_STACKSIZE+1)*(SizeOf(Integer)/SizeOf(character))}
Global __Sub_ReturnIndex.i

Macro Sub(_name_)
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x86 Or #PB_Compiler_Processor = #PB_Processor_x64
        !EndSub_Name equ __EndSub_#_name_
        !  JMP EndSub_Name
        !_sub_#_name_:
    CompilerElse
        CompilerError "Macro Sub(): unsupported processor"
    CompilerEndIf
EndMacro

Macro ExitSub
    CompilerSelect #PB_Compiler_Processor
        CompilerCase #PB_Processor_x86
            !  MOV dword EAX, v___Sub_ReturnAddress__
            !  MOV dword EDX, [v___Sub_ReturnIndex]
            !  JMP dword [EAX+EDX*4]
        CompilerCase #PB_Processor_x64
            !  MOV RAX, v___Sub_ReturnAddress__
            !  MOV R8, [v___Sub_ReturnIndex]
            !  JMP qword [RAX+R8*8]
        CompilerDefault
            CompilerError "Macro ExitSub: unsupported processor"
    CompilerEndSelect
EndMacro

Macro EndSub
    ExitSub
    !EndSub_Name:
EndMacro

Macro Call(_name_)
    CompilerSelect #PB_Compiler_Processor
        CompilerCase #PB_Processor_x86
            !  INC dword [v___Sub_ReturnIndex]
            !  MOV dword EAX, v___Sub_ReturnAddress__
            !  MOV dword EDX, [v___Sub_ReturnIndex]
            !  MOV dword [EAX+EDX*4], @f
            !  JMP _sub_#_name_
            !@@:
            !  DEC dword [v___Sub_ReturnIndex]
        CompilerCase #PB_Processor_x64
            !  INC qword [v___Sub_ReturnIndex]
            !  MOV R9, @f
            !  MOV RAX, v___Sub_ReturnAddress__
            !  MOV R8, [v___Sub_ReturnIndex]
            !  MOV qword [RAX+R8*8],R9
            !  JMP _sub_#_name_
            !@@:
            !  DEC qword [v___Sub_ReturnIndex]
        CompilerDefault
            CompilerError "Macro Call(): unsupported processor"
    CompilerEndSelect
EndMacro


;--------------------------------------------------------------------------------------------------------
;
; END INCLUDE "Sub.pbi"
;
;--------------------------------------------------------------------------------------------------------
Sub_ThreadSafe.pbi

Code: Select all

;--------------------------------------------------------------------------------------------------------
;
; START INCLUDE "Sub_ThreadSafe.pbi"
;
;--------------------------------------------------------------------------------------------------------

#SUB_STACKSIZE = 100000

;--------------------------------------------------------------------------------------------------------

Global __Sub_ThreadLocalStorage.l = TlsAlloc_()

If __Sub_ThreadLocalStorage = #TLS_OUT_OF_INDEXES
    ; FatalError(#ThreadLocalStorage_Alloc_failed) ; shouldn't happen
EndIf


Procedure __Sub_Allocate_ThreadLocalStorage()
    Protected mem.i = AllocateMemory(#SUB_STACKSIZE*SizeOf(Integer))
    If Not mem
        ; FatalError(#Out_of_Memory)
    EndIf
    ;Debug "Allocating new ThreadLocalStorage for Sub/EndSub Call()"
    TlsSetValue_(__Sub_ThreadLocalStorage,mem)
    ProcedureReturn mem
EndProcedure

Macro Sub(_name_)
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x86 Or #PB_Compiler_Processor = #PB_Processor_x64
        !EndSub_Name equ __EndSub_#_name_
        !  JMP EndSub_Name
        !_sub_#_name_:
    CompilerElse
        CompilerError "Macro Sub(): unsupported processor"
    CompilerEndIf
EndMacro

Macro ExitSub
    CompilerSelect #PB_Compiler_Processor
        CompilerCase #PB_Processor_x86
            TlsGetValue_(__Sub_ThreadLocalStorage)
            !  MOV dword EDX, [EAX]
            !  JMP dword [EAX+EDX*4]
        CompilerCase #PB_Processor_x64
            TlsGetValue_(__Sub_ThreadLocalStorage)
            !  MOV R8, qword [RAX]
            !  JMP qword [RAX+R8*8]
        CompilerDefault
            CompilerError "Macro ExitSub: unsupported processor"
    CompilerEndSelect
EndMacro

Macro EndSub
   ExitSub
   !EndSub_Name:
EndMacro


Macro Call(_name_)
    CompilerSelect #PB_Compiler_Processor
        CompilerCase #PB_Processor_x86
            TlsGetValue_(__Sub_ThreadLocalStorage)
            !  OR  dword EAX, EAX
            !  JNZ @f
            __Sub_Allocate_ThreadLocalStorage()
            !@@:
            !  INC dword [EAX]
            !  MOV dword EDX, [EAX]
            !  MOV dword [EAX+EDX*4], @f
            !  JMP _sub_#_name_
            !@@:
            TlsGetValue_(__Sub_ThreadLocalStorage)
            !  DEC dword [EAX]
        CompilerCase #PB_Processor_x64
            TlsGetValue_(__Sub_ThreadLocalStorage)
            !  OR  qword RAX, RAX
            !  JNZ @f
            __Sub_Allocate_ThreadLocalStorage()
            !@@:
            !  INC qword [RAX]
            !  MOV R9, @f
            !  MOV R8, [RAX]
            !  MOV qword [RAX+R8*8],R9
            !  JMP _sub_#_name_
            !@@:
            TlsGetValue_(__Sub_ThreadLocalStorage)
            !  DEC qword [RAX]
        CompilerDefault
            CompilerError "Macro Call(): unsupported processor"
    CompilerEndSelect
EndMacro


;--------------------------------------------------------------------------------------------------------
;
; END INCLUDE "Sub_ThreadSafe.pbi"
;
;--------------------------------------------------------------------------------------------------------

Re: [Windows] Sub / EndSub / Call Macros

Posted: Fri Apr 27, 2012 11:12 am
by Kwai chang caine
Then here !!!!!! there are not word for explain my admiration :shock:
Since a long time we are several members to reclaim that (A "Procedure" into another) :(

Is it possible a day to can return value of this SUB ??
I know in normal time a SUB not return value..but perhaps you can create a day a "SUPER SUB" with return :D

When i see how you modify PB...you have much works, for do all the numerous dreams of the members :lol:

Thanks a lot DANILO for this jewel code 8)

Re: [Windows] Sub / EndSub / Call Macros

Posted: Fri Apr 27, 2012 7:01 pm
by Danilo
Kwaï chang caïne wrote:Is it possible a day to can return value of this SUB ??
No, you have to use variables.

Code: Select all

XIncludeFile "Sub.pbi"

Global sub1_result

Procedure proc1()

    Call(sub1)
    Debug sub1_result

    Call(sub2)
    Debug sub2_result

    Sub(sub2)
        sub2_result = 200
    EndSub

EndProcedure

proc1()

Sub(sub1)
    sub1_result = 500
EndSub

Re: [Windows] Sub / EndSub / Call Macros

Posted: Sat Apr 28, 2012 11:28 pm
by Kwai chang caine
Ok thanks again DANILO 8)