WebGL-Native: "use strict"; 対応
prev: https://zenn.dev/okuoku/scraps/9b315e2f5a6639
next: https://zenn.dev/okuoku/scraps/83d06f50d62779
Strict mode に対応する
... 2021年やぞ!?
現状、Emscriptenが出力したランタイムのJavaScriptを eval して実行している。RollupのためにES6 Modulesに移行するわけだけど、Modulesなコードはstrict modeで実行されるため、先にそちらに対応する必要がある。
eval の挙動が変わる問題
例えば、以下のようなコードは strict の有無で挙動が変わる:
//"use strict"; // ← ★ これを付けるかどうかでこのプログラムの挙動が変わる
function run(){
var Boo = false;
eval("var Boo = Boo; console.log(Boo)");
}
run(); // strictの場合 "undefined" 、そうでない場合は false となる
Schemeで言うと letrec と let の挙動差だな。
Emscriptenはブラウザの <script> タグで実行されることを想定しているため、グローバル変数 Module が定義されている場合とされていない場合の両方を想定したコードとなっていて、そこでこの var テクニックを使用して オプショナルな Module 変数を受けいれるようになっている。
こういう時は function で囲って明示的に変数を渡してしまうのが早い。Schemeで言うと let を lambda に変換しているようなもんだな。
Dead code elimination 対策
同じような事が、 "eval でしか消費されない変数" にも発生する。
Rollupは eval のためだけに定義した変数は、使用されていないと見做して定義を省略してしまう。↑ のコミットはそれにも対処している。
プリミティブにプロパティを追加するとエラーになる
これ知らなかった。。strict modeでは整数やboolean値のようなプリミティブにはプロパティを追加しようとするとエラーになる。
第七に、ECMAScript 2015 の Strict モードでは、プリミティブ値にプロパティを設定することが禁止されます。
今までの実装では、WebGLのTexture等に生ポインタを使用していたため、Emscriptenのコードがこれに id を付与しようとした際に暗黙に失敗していた(はず)。
というわけでWebGLのオブジェクトは一旦JavaScript的なオブジェクトでwrapすることにした。
@@ -466,27 +467,28 @@ function GL(w, h, attr){
createFramebuffer: function(){
let ptr0 = CWGL.cwgl_createFramebuffer(ctx);
const ptr = wrapPointer(ptr0, framebufferfree);
- return ptr;
+ const r = {ptr: ptr};
+ return r;
},