To conform to the Windows programming conventions, PowerBASIC must provide a "safe" environment for the range of functions that are available. This is achieved by transparently preserving the three volatile registers at the start of each Sub/Function, and restoring these same registers before exit from the Sub/Function. The following example shows approximately how PowerBASIC constructs the entry and exit of a Sub/Function to preserve these registers:
! PUSH EBX ' Automatically added by PowerBASIC
! PUSH ESI ' --"---
! PUSH EDI ' --"---
' the actual SUB code is placed here
! POP EDI ' Automatically added by PowerBASIC
! POP ESI ' --"---
! POP EBX ' --"---
When writing a Sub or Function in PowerBASIC, we can safely predict that the EBX, ESI, and EDI registers will be automatically saved upon entry and restored upon exit from a Sub/Function.
The virtue of code that observes these conventions is that it allows the programmer to safely assume that a call to any other Sub/Function or API function is certain to follow the same register preservation rules for the EBX, ESI, and EDI registers. This helps ensure that writing Inline Assembler code in PowerBASIC will result in reliable and completely predictable code execution in terms of register use when calling PowerBASIC and API Subs/Functions.
The PowerBASIC compiler is also very efficient in the way it calls API system functions. For example, the following BASIC statement which calls the SendMessage API:
CALL SendMessage(hWnd&, %WM_COMMAND, 50, 100)
…is translated into assembly code in the compiled program, to resemble something like this:
This direct low level translation is one of the main reasons why PowerBASIC programmers can easily mix API code and assembler code. However, when it comes to intermixing assembler and BASIC code within a Sub/Function, the programmer must take additional care.
The Inline Assembler
Using ESP and EBP
Saving the FPU registers
Tricks in preserving registers