[Windows] Sub / EndSub / Call Macros
Posted: Thu Apr 26, 2012 11:08 am
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:
With Sub/EndSub it is allowed to call SubRoutines outside and inside Procedures:
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
Sub.pbi
Sub_ThreadSafe.pbi
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
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"
;
;--------------------------------------------------------------------------------------------------------
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"
;
;--------------------------------------------------------------------------------------------------------
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"
;
;--------------------------------------------------------------------------------------------------------