如果你看过 SpiderMonkey 的代码目录,你就发现经常会有名为“ABC-inl.h”的文件与头文件“ABC.h”成对出现。这是 SpiderMonkey 内部组织的一个风格(不知道算不算规范),其目的是为了改善和提高系统内部的模块性。感兴趣的同学可以看看这个 Mozilla 维基页面[1]或者这个 Bugzilla 链接[2]。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
$find ./mozilla-central/js/ -iname '*-inl.h' ./src/frontend/SharedContext-inl.h ./src/frontend/ParseMaps-inl.h ./src/frontend/Parser-inl.h ./src/frontend/ParseNode-inl.h ./src/ion/BaselineFrame-inl.h ./src/ion/PcScriptCache-inl.h ./src/ion/IonFrameIterator-inl.h ./src/ion/CompileInfo-inl.h ./src/ion/IonFrames-inl.h ./src/ion/shared/Lowering-shared-inl.h ./src/ion/shared/CodeGenerator-shared-inl.h ./src/ion/LIR-inl.h ./src/builtin/Iterator-inl.h ./src/vm/ArgumentsObject-inl.h ./src/vm/RegExpStatics-inl.h ./src/vm/GlobalObject-inl.h ./src/vm/RegExpObject-inl.h ./src/vm/Shape-inl.h ./src/vm/Stack-inl.h ./src/vm/StringObject-inl.h ./src/vm/BooleanObject-inl.h ./src/vm/String-inl.h ./src/vm/ScopeObject-inl.h ./src/vm/ObjectImpl-inl.h ./src/vm/NumberObject-inl.h ./src/gc/Barrier-inl.h ./src/gc/FindSCCs-inl.h ./src/gc/Nursery-inl.h |
[1]: https://wiki.mozilla.org/JS_engine_modularization
[2]: https://bugzilla.mozilla.org/show_bug.cgi?id=653057
在 SpiderMonkey 中,JSScript 是比较常见的一个数据结构,它封装了一个 JavaScript 脚本。而 UnrootedScript 是在 SpiderMonkey 代码中经常作为函数返回值出现的类型。奇怪的是,使用 Eclipse IDE 找不到该类型的定义;使用 grep 搜索也只能找到该类型的使用,找不到该类型的定义(这个类型的使用非常广泛,眼睛都看花了);直接使用 Google 搜索,也找不到这个类型。
最后,在 Mozilla 的 Bugzilla 上看到 bug 817818,才意识到:这个类型是用宏定义拼出来的。
以下这段代码来自于 Mozilla-central/js/src/vm/Root.h:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
#ifdef DEBUG /* irrelevant code ... */ /* * This macro simplifies declaration of the required * matching raw-pointer for optimized builds and * Unrooted<T> template for debug builds. */ # define ForwardDeclare(type) \ class type; \ typedef Unrooted<type*> Unrooted##type; \ typedef type * Raw##type # define ForwardDeclareJS(type) \ class JS##type; \ namespace js { \ typedef js::Unrooted<JS##type*> Unrooted##type; \ typedef JS##type * Raw##type; \ } \ class JS##type /* irrelevant code ... */ #else /* NDEBUG */ /* irrelevant code ... */ /* In opt builds |UnrootedFoo| is a real |Foo*|. */ # define ForwardDeclare(type) \ class type; \ typedef type * Unrooted##type; \ typedef type * Raw##type # define ForwardDeclareJS(type) \ class JS##type; \ namespace js { \ typedef JS##type * Unrooted##type; \ typedef JS##type * Raw##type; \ } \ class JS##type /* irrelevant code ... */ #endif |
在 Mozilla-central/js/src/JSScript.h 文件中,有一行对应的宏引用:
|
ForwardDeclareJS(Script); |
通过这种方式完成了 UnrootedScript 的定义。
类似的定义还有:
|
Mozilla-cental/js/src/$grep ForwardDeclare | grep -v define ./jsscript.h:21:ForwardDeclareJS(Script); ./gc/Root.h:959:ForwardDeclareJS(Script); ./gc/Root.h:960:ForwardDeclareJS(Function); ./jsfun.h:20:ForwardDeclareJS(Script); ./jsinfer.h:23:ForwardDeclareJS(Script); ./vm/ObjectImpl.h:27:ForwardDeclare(Shape); ./jsobj.h:38:ForwardDeclare(Shape); ./jsscope.h:225:ForwardDeclare(UnownedBaseShape); ./jsscope.h:226:ForwardDeclare(BaseShape); ./jsscope.h:227:ForwardDeclare(Shape); ./jspropertytree.h:14:ForwardDeclare(Shape); |
生成了以下类型:
|
js::UnrootedFunction js::RawFunction UnrootedShape RawShape UnrootedUnownedBaseShape RawUnownedBaseShape UnrootedBaseShape RawBaseShape |
评注:以前在 GCC 的代码中也见到了不少这样的技巧,用 C/C++ 中的宏拼出来很多的代码,使得源代码看起来简洁,代码行数更少。但是要看懂这样的代码也需要更多的耐心和技巧,对于初学者而言不是很友好。内部实现的文档稀缺,加之目前IDE中的智能提示系统(CCS)还搞不定这么复杂的宏展开,使得初学者的学习门槛更高了。
Recent Comments