« FlashLite: SHA1計算 | メイン | Perl: オブジェクトのunbless »

FlashLite: 定数を変数に入れる基準

Flashでは変数名や定数など、頻繁に使用する文字列はLookup Tableに入れてコードサイズを節約してくれますが、FlashLite1.xにはその機能がありません。ですので、頻繁に使う定数などは短い名前の変数に入れてしまう、ということを自分でやることでコードサイズの節約ができる場合があります。FL1では、数値のデータも文字列としてコンパイルされるため、65536とかを大量に使う人には役に立つかもしれません。

で、このエントリーでは、何回使ったらお得なのかというのを計算してみようと思います。

65536を参照するときは、SWFでは65536をスタックにプッシュするという処理にコンパイルされます。

push [65536]

16進ダンプすると、以下の10バイトになります。
96 07 00 00 36 35 35 33 36 00

65536の5文字 + 5バイトというわけです。

一方変数Aの値の参照は、以下の7バイトになります。

push [A]
getvar

96 03 00 00 41 00 1C

また、A=65536の代入処理は、以下の17バイトになります。

push [A]
push [65536]
setvar

96 03 00 00 41 00 96 07 00 00 36 35 35 33 36 00 1D

これは、定数長5文字+12バイトです。

したがって、たとえば65536を10回使うとすると、定数のまま使うと10 x 10バイトで100バイト、変数Aに65536を代入してから使うと17バイト+10 x 7バイトで87バイトで、変数Aに代入するほうが13バイト少ないということになります。

もし、A=65536の代入を行うときに、Aと65536をまとめてpushしてよいことにすると、さらに3バイト節約になります。

一般に長さnの定数をk回使用するとき、1文字の変数に代入してから使うほうがバイトコードのサイズが小さくなる条件は、
12+n - (n + 5 - 7) x k < 0
である、ということになります。
これを整数kについて解くと、
minimum(k) = CEILING((13+n)/(n-2))
となります。ただし、CEILING(x)はxを下回らない最小の整数です。
(まとめプッシュありの場合はminimum(k) = CEILING((10+n)/(n-2)))

実際の値を入れて表にしてみました。65536ならn=5なので、6回以上使うならお得ということになります。

nk(まとめpushなし)k(まとめpushあり)
31613
497
565
654
744
843
943
10 33
11 33
12 33
13 33
14 32
15 32
16 32
17 22

また、剰余(%)演算に定数が含まれる場合、たとえば

X = Y % 65536;
は、
X = Y - int(Y / 65536) * 65536;

に変換されてコンパイルされるので、定数が使用される回数は1回ではなく2回とカウントします。

剰余演算をたくさん使っているときなどで、予想以上にコードサイズが大きくなってしまった場合など、定数を変数に代入することによってコードサイズの削減効果が期待できそうです。
とはいっても、せいぜい数10バイト程度かもしれませんが。

トラックバック

このエントリーのトラックバックURL:
http://labs.cybozu.co.jp/cgi-bin/mt-admin/mt-tbp.cgi/1157

コメントを投稿