Handling stack overflow is a critical requirement for most Virtual Machines. For .NET Compact framework (NETCF) it is more important because it runs on embedded devices with very little memory and hence little stack space.
The .NETCF Execution Engine (EE) needs to detect stack overflows and report it via StackOverflowException. To do this it uses some logic which we internally refer to as StackCheck (that will be covered in a later post). The algorithm needs fair prediction of stack usage for system APIs (e.g. Win32 APIs or for Symbian OS, S60 APIs).
Each time we target a new platform we do some measurements in addition to referring to specs :) to find it's stack characteristics. As we are currently making the NETCF work on Symbian OS we are doing these measurements again. So I thought of sharing how we are going about measuring stack usage using simple watermarking.
The technique
Step:1
On method Entry store the two current and max stack values. This typically available via system APIs which in case of Symbian is available over the TThreadStackInfo class (iBase, iLimit and other members).
+---------------+
| |
| |
| |
current stack ------> +---------------+
| |
| Available |
| Stack |
| |
| |
| |
| |
Stack limit ---------> +---------------+
| |
| |
. .
. .
. .
Step :2
Get a pointer on to the current stack pointer. How to get the pointer will vary based on the target platform. Options include system APIs, de-referencing stack pointer register (e.g. ESP register on x86) or simply creating a local variable on the stack and getting it's pointer.
Then Memset the whole region from current stack to the total available with some known pattern, e.g. 0xDEAD (a larger signature is a better approach to ensure there is no accidental match)
+---------------+
| |
| |
| |
current stack ------> +---------------+
| DEAD |
| DEAD |
| DEAD |
| DEAD |
| DEAD |
| DEAD |
| DEAD |
| DEAD |
Stack limit ---------> +---------------+
| |
| |
. .
. .
. .
Step: 3
Make an OS or whatever call you want to measure.
+---------------+
| |
| |
| |
current stack ------> +---------------+
| 1231 | --+
| 1231 | |
| D433 | +--> Stack usage
| D324 | |
| 3453 | --+
| DEAD |
| DEAD |
| DEAD |
Stack limit ---------> +---------------+
| |
| |
. .
. .
. .
Step 4:
When the call returns the stack will get modified. Iterate through the memory starting from the current stack pointer looking for the first occurrence of the pattern you’ve set in Step:2. This is the water mark and is the point till which the stack got used by the OS call. Subtract the water mark from the original entry point saved in Step 1 and you have the stack usage.
No comments:
Post a Comment