Yes, it should be mentioned that although you can declare LOCAL vars, you should never try to use them with this type of construct.
It has been pointed out elsewhere by Bob Zale that Basic just works that way. It's better not to even try Hutch's trick if you're uncomfortable or unsure about this.
I agree that it's probably only safe to use globals and inline assembler.
Peter.
------------------
[email protected]
Announcement
Collapse
No announcement yet.
DIRTYCALL convention 2
Collapse
X
-
I agree with both comments, the calling code must have #REGISTER NONE set
otherwise there can be a register conflict with any register variables
that are used by the compiler.
Working outside a stack frame can be risky and in most instances, the normal
sub/function method of calling remote code is the best way to do it. The
purpose of bypassing the normal method was to avoid the stack overhead for
highly recursive calls where the overhead slowed down the execution.
The use of GLOBAL variables is safe as it does not use the stack and there
should be no difference from making a CALL/RET within a normal function, the
address of the label in the DLL function does not change so the call is just
another in memory jump with the return value on the stack like normal.
Still, its an interesting way of sneaking some extra performance with highly
recursive calls in a language that has enough grunt to actually do it.
Regards,
[email protected]
------------------
Leave a comment:
-
-
The problem here is that PowerBASIC code requires the stack to be set up
properly. It is likely to be safe to use DIRTYCALL if the called function
is entirely in assembly language. If you use any BASIC code, you run the
risk that some runtime routine will overwrite the stack at a location it
expected to be able to use.
------------------
Tom Hanlin
PowerBASIC Staff
Leave a comment:
-
-
I tested the same approach in EXE.
Results are nice, but how safety is it ?
With Register None - probably, yes; without - very doubt.
Code:#Compile Exe #Register None #Dim All #Include "Win32Api.Inc" %WithCode = %False %cntr = 10000000 Global var1 As Long Global var2 As Long Global var3 As Long Global var4 As Long Global retv As Long Sub No1 LoadHere: $If %WithCode ! mov edx, [eax] ! mov var1, edx ! mov edx, [eax+4] ! mov var2, edx ! mov edx, [eax+8] ! mov var3, edx ! mov edx, [eax+12] ! mov var4, edx retv = var1 + var2 + var3 + var4 $EndIf ! ret ' ---------------------------- End Sub Sub No2(rc As RECT) $If %WithCode var1 = rc.nLeft var2 = rc.nRight var3 = rc.nTop var4 = rc.nBottom retv = var1 + var2 + var3 + var4 $EndIf End Sub Function PbMain Dim TheProc As Dword, rc As RECT, tc As Long, tc1 As Long, cntr As Long ! LEA EAX, LoadHere ! MOV TheProc, EAX Rc.nLeft = 1 Rc.nTop = 2 Rc.nRight = 3 Rc.nBottom = 4 tc = getTickCount() cntr = %cntr lbl1: ! lea eax, Rc ; load EAX with address of structure RECT ! call TheProc ! dec cntr ! jnz lbl1 tc1 = GetTickCount() MessageBox 0, Format$(0.001 * (tc1 - tc), "#.##"), "PassStruct", %MB_OK Or %MB_ICONINFORMATION tc = getTickCount() cntr = %cntr Dim i As Long For i = 1 To cntr Call No2(rc) Next tc1 = GetTickCount() MessageBox 0, Format$(0.001 * (tc1 - tc), "#.##"), "PassStruct", %MB_OK Or %MB_ICONINFORMATION End Function
------------------
E-MAIL: [email protected]
Leave a comment:
-
-
DIRTYCALL convention 2
Here is version 2 of DIRTYCALL with a comparison in time to using the
normal DLL calling technique through the stack. The times show that
DIRTYCALL is more than twice as fast, even though it has to manually
dereference the addresses and load 4 global variables with the
results.
The speed difference is due to DIRTYCALL having no stack overhead, even
though it manually converts the values.
Regards,
[email protected]
Code:The calling code. Case 51 TheProc& = PassStruct Rct.nLeft = 1 Rct.nTop = 2 Rct.nRight = 3 Rct.nBottom = 4 tc& = getTickCount() cntr& = 100000000 lbl1: ! lea eax, Rct ; load EAX with address of structure RECT ! call TheProc& ! dec cntr& ! jnz lbl1 tc1& = GetTickCount() - tc& MessageBox hWin,ByCopy str$(tc1&),"PassStruct", _ %MB_OK or %MB_ICONINFORMATION Case 52 tc& = getTickCount() cntr& = 100000000 lbl2: NormalCall 1,2,3,4 ! dec cntr& ! jnz lbl2 tc1& = GetTickCount() - tc& MessageBox hWin,ByCopy str$(tc1&),"NormalCall", _ %MB_OK or %MB_ICONINFORMATION The two DLL functions for comparison. '########################################################################## FUNCTION PassStruct ALIAS "PassStruct" () EXPORT as LONG ! jmp over_it ' ---------------------------- ' struct address in EAX ' ---------------------------- LandHere: GLOBAL var1 as LONG GLOBAL var2 as LONG GLOBAL var3 as LONG GLOBAL var4 as LONG GLOBAL retv as LONG ! mov edx, [eax] ! mov var1, edx ! mov edx, [eax+4] ! mov var2, edx ! mov edx, [eax+8] ! mov var3, edx ! mov edx, [eax+12] ! mov var4, edx ' ------------------------------------ ' commented out to test calling speed ' ------------------------------------ ' retv = (var1 * var2) ^ (var3 + var4) ' ! mov eax, retv ! ret ' ---------------------------- over_it: FUNCTION = CodePtr(LandHere) END FUNCTION ' ######################################################################### FUNCTION NormalCall ALIAS "NormalCall" (ByVal a as LONG, _ ByVal b as LONG, _ ByVal c as LONG, _ ByVal d as LONG) EXPORT as LONG ' ------------------------------------- ' empty function to test calling speed ' ------------------------------------- FUNCTION = 0 END FUNCTION ' #########################################################################
Tags: None
-
Leave a comment: