2

我查看了AVM2 概述文档(第 4.11 章,第 33 页)并发现以下内容init_scope_depth

init_scope_depth
init_scope_depth 字段定义了max_scope_depth可以在方法内访问的相对于 的最小范围深度。
max_scope_depth
max_scope_depth 字段定义了可以在方法内访问的最大范围深度。max_scope_depth和之间的差异init_scope_depth决定了本地范围堆栈的大小。

我还在ActionScript 3.0 Bible book上看到了关于范围链的引用,我认为它与 相关init_scope_depth,并说:

作用域链,如图 2-1 所示,是一个内部设备,用于在函数执行期间管理变量作用域。
引用变量时,Flash Player 会从最近调用的函数开始并检查变量声明。如果在最本地范围内找不到该值,它会向上移动一级到调用该函数的父函数并在那里检查。这个过程一直持续到作用域链一直被检查到全局作用域。

图2-1

如图所示,我们的范围顺序是,从上到下:

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

另请注意,范围链可以根据类继承具有更多级别。

现在我的问题来了:

我一直在玩 JPEXS Free Flash Decompiler 和 RABCDAsm,我Global在一个名为Data. 该类不扩展任何其他类,但实现了一个接口。在这个类中,有普通方法和静态方法。我注意到静态方法已initscopedepth设置为 3,而普通方法已initscopedepth设置为 4。(注意:这些值由编译器设置,如AVM2 概述文档第 4.11 章中所述)。

我的猜测是初始范围是:

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

但我不确定,想知道是否有人可以证实这一点。

这也引出了我另一个问题。所有的方法code块,无论是普通的还是静态的,都从代码开始:

getlocal_0
pushscope

(注意:在这两条指令之后是方法开始的任何指令。)可能是因为,对于普通对象,它将 推this入作用域堆栈,而对于静态方法,它将类的静态实例推入作用域堆栈? 如果是这样,为什么有必要这样做?

4

1 回答 1

1

好吧,我相信经过更多的研究和思考,我已经找到了答案。谜题的关键是弄清楚另外两件事。

  1. 正如本书Object中所解释的那样,所有类默认扩展该类。
  2. 在方法入口时,作用域堆栈是空的,并且有max_scope_stack值的空间,如 AVM2 概述的第 3.3.3 章所述。

因此,初始范围深度为: global -> Object class -> MyClass class (static instance)

因此,在这种情况下,初始作用域深度为 3。我注意到类外的函数的初始作用域深度为 1(仅限全局作用域)。非静态方法的初始范围深度为 4(它们也有 MyClass 对象)。

因为当我们进入一个方法时作用域堆栈是空的,并且因为寄存器 0 保存了this对象(在静态方法的情况下是静态实例,或者如果您愿意,也可以是类本身),我们必须将此对象推送到作用域上堆栈,以便我们可以访问其作用域链上的所有变量和方法。我们当然有方法本身的范围,这使得最大范围深度为 4。

于 2020-07-05T17:52:37.443 回答