Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the stack limit of 5287 in AS3 variable or predefined?

I ran a test just now:

function overflow(stack:int = 0):void
{
    if(stack < 5290)
    {
        trace(stack);
        overflow(stack + 1);
    }
}

overflow();

This always throws a StackOverflow error after 5287 calls.

Error #1023: Stack overflow occurred.

Is this limit variable (depending on machine specs, environment, etc) or is that a flat value defined somewhere? If I change the if statement to less than 5287, I don't get the error.

like image 604
Marty Avatar asked Mar 04 '13 00:03

Marty


2 Answers

Obviously it's variable. Since all the calculations you really do are located in stack (disassembly report codes show pushbyte instructions and other stuff that's working with stack, as non-operand arithmetics), this value only reports how many function contexts can be put into the stack until it overflows.

I have decided to run some tests for recursion thresholds as based on this article that was referenced in baris's comment. The results were pretty embarrassing. Test environment: FlashDevelop 3.3.4 RTM, Flash player debugger 10.1.53.64, flash compile mode: release. "Debug" mode didn't change numbers cardinally, checked that too.

Locals number     Iterations (static int)       Iterations (Math.random())   
0                 5306                          
1                 4864                          4856
2                 4850                          4471
3                 4474                          4149
4                 4153                          3870
5                 3871                          3868
6                 3869                          3621
7                 3620                          3404
8                 3403                          3217
9                 3210                          3214
10                3214                          3042
11                3042                          3045
10 mixed          3042     1 value was assigned Math.random() and 9 - static int
10 advancedRandom 2890     1 value was assigned a custom random with 1 parameter

Note, all of these values vary within a margin of ten between subsequent executions. The "static int" and "Math.random()" are designations of what is assigned to locals wihin the recursively called function. This, however, leads me to assume the following:

  1. Including function calls into the recursive function adds to function context
  2. Memory for locals is assigned along with its type, in chunks of more than 8 bytes, because adding a local does not always decrease recursion limit
  3. Adding more than one call to a certain function does not add more memory to function context
  4. The "memory chunk" is most likely 16 bytes long, because this value is 2^N, an addition of one int or Number local does not always decrease recursion, and this is more than 8, as a raw value of a Number variable takes 8 bytes, being a double-precision floating-point.
  5. Assuming #4 is correct, the best value for function context size appeared to be 172 bytes, with total stack size being 912632 bytes. This largely confirms my initial assumption that the stack size is actually 1 megabyte in Flash 10. Flash 11 showed me a bit higher numbers when I have tried opening the test SWF in its debugger, but I didn't make extensive tests with it.
like image 116
Vesper Avatar answered Oct 27 '22 11:10

Vesper


Hm, this is interesting. I took a look at the link that Barış gave. It seems like it might be to be with 'method complexity' after all, but I am not sure how to further test it. I am using Flash CS5, publishing for Flash Player 10, Actionscript 3 (of course).

Original:

function overflow(stack:int = 0):void {
    if(stack < 5290){
        trace(stack);
        overflow(stack + 1);
    }
}
// gives 5287

Now adding a single Math.random() call to the overflow() method:

function overflow(stack:int = 0):void {
    Math.random();
    if(stack < 5290){
        trace(stack);
        overflow(stack + 1);
    }
}
// gives 4837

Adding multiple Math.random() calls make no difference, nor does storing it in a local variable or adding another parameter to the overflow() method to 'carry' that random generated value

function overflow(stack:int = 0):void {
    Math.random();
    Math.random();
    if(stack < 5290){
        trace(stack);
        overflow(stack + 1);
    }
}
// still gives 4837

At this point I tried different Math calls, such as:

// just the change to that 1 line:
Math.pow() // gives 4457
Math.random(), Math.sqrt(), Math.tan(), Math.log() // gives 4837

Interestingly, it doesn't seem to matter what you pass in to the Math class, but it remains constant:

Math.sqrt(5) vs Math.sqrt(Math.random()) // gives 4837
Math.tan(5) vs Math.tan(Math.random()) // gives 4837
Math.pow(5, 7) vs Math.pow(Math.random(), Math.random()) // 4457

Until I chained 3 of them:

Math.tan(Math.log(Math.random())); // gives 4457

It looks like two Math calls from that 'group' is "equal" to one Math.pow() call? =b Mixing Math.pow() and something else doesn't seem to decrease the value though:

Math.pow(Math.random(), Math.random()); // gives 4457

However, chaining two Math.pow()'s:

Math.pow(Math.pow(Math.random(), Math.random()), Math.random()); // 4133

I could go on and on, but I wonder if there is some pattern:

Results:   5287, 4837, 4457, 4133
Differences:  450   380   324
like image 41
mitim Avatar answered Oct 27 '22 13:10

mitim