actionscript-3bytecodeavm2

What is initscopedepth in ActionScript bytecode AVM2? Why getlocal_0 and pushscope?


I have looked into the AVM2 Overview document (chapter 4.11, page 33) and found the following about init_scope_depth:

init_scope_depth
The init_scope_depth field defines the minimum scope depth, relative to max_scope_depth, that may be accessed within the method.
max_scope_depth
The max_scope_depth field defines the maximum scope depth that may be accessed within the method. The difference between max_scope_depth and init_scope_depth determines the size of the local scope stack.

I have also came across a citation on the ActionScript 3.0 Bible book about the scope chain, which I believe to be related to init_scope_depth, and says:

The scope chain, shown in figure 2-1, is an internal device that is created to manage variable scope during function execution.
When a variable is referenced, the Flash Player starts with the most recent function called and checks for variable declarations. If the value isn't found in the most local scope, it moves up one level to the parent function that called the function and checks there. This process continues until the scope chain has been checked all the way up to the global scope.

Figure2-1

As shown in the figure, we have the scope order being, from top to bottom:

function scope -> parent function(s) scope (if any) -> instance of the class calling the function -> static instance of the class calling the function -> global scope

Notice also that the scope chain can have more levels depending on class inheritance.

Now here comes my question:

I've been playing with JPEXS Free Flash Decompiler and RABCDAsm, and I have a class called Global in a package called Data. The class does not extend any other classes, but implements one interface. Within this class, there are normal methods and static methods. I have noticed that the static methods have initscopedepth set to 3 and the normal methods have initscopedepth set to 4. (Note: these values were set by the compiler, as explained in the AVM2 Overview document, chapter 4.11).

My guess is that the initial scope is:

method -> instance of class -> static instance of class (static variables) -> global

But I am not sure and was wondering if anyone could confirm this.

This also leads me to another question. All the methods code block, both normal and static, start with the code:

getlocal_0
pushscope

(Note: After these 2 instructions comes whatever instruction the method starts with.) Could it be because, for normal objects it is pushing the this onto the scope stack, and for static methods it is pushing the static instance of the class onto the scope stack? If so, why is this necessary?


Solution

  • All right, I believe that I've figured out the answer after some more research and thinking. The key to the puzzle was figuring out two more things.

    1. All classes extend the Object class by default, as explained in this book.
    2. On method entry, the scope stack is empty and has room for max_scope_stack values, as explained in chapter 3.3.3 of AVM2 Overview.

    Therefore, the initial scope depth is: global -> Object class -> MyClass class (static instance)

    And thus, the initial scope depth in this case is 3. I have noticed that functions outside classes have initial scope depth of 1 (the global scope only). And methods that are not static have initial scope depth of 4 (they also have MyClass object).

    Because the scope stack is empty when we enter a method, and because register 0 holds the this object (which is the static instance, in the case of static methods, or the class itself if you prefer), we must push this object onto the scope stack so that we can access all the variables and methods on its scope chain. We have of course the scope of the method itself, which makes the max scope depth to be 4.