タグ

ブックマーク / nmi.jp (17)

  • JavaScript 実行エンジン V8 の JIT 出力コードを読んでみよう

    ChromeJavaScript はとても高速なことでも有名ですが、その実行エンジンは V8 と呼ばれます。V8 自体は独立したモジュールであり、Node.js 等にも使われております。 V8 が JavaScript を高速に実行する技術の一つが JIT (Just In Time) コンパイルです(一般的に JIT と呼ばれます)。これは、そのまま実行すると遅い JavaScript を実行中にリアルタイムに直接マシンコードに変換し(これが Just In Time と呼ばれる所以です)、途中からそのコードに入れ替えて実行することで高速化を達成しています。特に何度も実行される関数で効力を発揮します。 JIT という名前は聞いたことがあろうとも、実際に JIT がどのようなコードを実行しているのかを確認する機会は滅多にないでしょう。この記事では、実際に V8 の JIT の出力を確

  • JavaScript で CPU が Intel かどうかを判定する(ついでに JIT を検知する)

    先日、次のような Tweet を見かけました TIL I discovered that TensorFlow.js uses an interesting trick to sniff your CPU architecture in WebAssembly. pic.twitter.com/LVyywIM48I — Robert Knight (@robknight_) January 4, 2023 面白かったので、なぜこうなるのかの解説と、ついでにこのテクニックを使った JIT 検知方法などについて紹介します。 JavaScript における低レイヤーの扱い JavaScript においては、挙動が比較的しっかりと仕様に定められているために、環境による振る舞いの違いはあまり発生しません。しかし、低レイヤーに降りるほど振る舞いは実装依存になり、環境差が発生する余地が出てきます。 一番

  • setTimeout を完璧に理解する

    setTimeout は、指定された時間以降に指定されたコードを実行する JavaScriptAPI です。ブラウザでも Node.js でも広く使われているのですが、実装はまちまちで、色々と特殊な条件も多く、挙動を完璧に理解している人は少ないと思います。この記事では、そんな setTimeout を可能な限り深堀りしてみようと思います。 先に書いておきますが、ものすごくニッチで細かい話ばかり並びます。突然私が、ただ純粋に setTimeout について調べたくなったので、その結果をまとめただけのものです。普通に開発している人には必要のない情報が多くなるでしょう。この記事は基礎から setTimeout を学ぼう、という方には全然向かないと思います。 また、JavaScript のイベントループについてある程度理解していることを前提とします。その詳しい理解には、@PADAone さん

  • Chrome の console.log でハマらないために

    JavaScript を書いたことがある人ならば一度は使うであろう console.log ですが、この関数は思ったよりも厄介な性質を持っています。その性質を知らずに console.log を使うと、デバッグ時に大ハマリしてしまうことがあります。この記事では console.log の落とし穴についてお話します。 今回は Chrome に特化して解説しますが、Firefox や Safari でも同じ落とし穴があります。 console.log とは まずはさらっと基をおさらいしましょう。 大前提なのですが、console.logJavaScript の言語仕様(ECMAScript)で定義されていません。ブラウザ向けには whatwg の仕様がありますが、あくまでもそれはブラウザ向けの仕様であり、Node.js を含むほぼ全ての JavaScript 環境で使えるのは cons

  • JavaScript の undefined と null を完全に理解する

    JavaScript で頻出する undefined と null について語ります。 言語仕様上の違い JavaScript (ECMAScript) において、仕様上 undefined と null は当然ながら明確に区別されています。いくつか言語仕様上の扱いについて挙げてみます。 比較 厳密な比較演算子 === において undefined と null は区別されます。ゆるい比較演算子 == においては両者は区別されません(仕様 7.2.14)。 console.log(undefined === null); // false console.log(undefined == null); // true 他の falsy な値(false とみなされる値)との比較は、ゆるい比較演算子であっても区別されます(仕様 同上)。 console.log(undefined == fa

  • JavaScript のクロージャーと for 文の let 初期化の例外

    先日、次のような JavaScript クイズを Twitter で出しました。 // JavaScript quiz: 出力は? const a = []; { for(let i = 0; i < 10; i++) { a[i] = () => console.log(i); } } a[3](); { let i; for(i = 0; i < 10; i++) { a[i] = () => console.log(i); } } a[3](); { for(let i = 0; i < 10;) { a[i] = () => console.log(i); i++; } } a[3](); — Takuo Kihira (@tkihira) August 15, 2022 答えは 3, 10, 4 なのですが、for 文の let 初期化専用の例外処理がない場合は 10, 10,

  • document.all の例外仕様を知っていますか

    昨日、ツイッターで次のような JavaScript クイズを出しました。 久しぶりの JavaScript クイズ! function hello(x) { if(typeof x === 'undefined') { alert(x.f()); } } この hello 関数で "Hello, World!" のアラートを表示させることが出来るか? — Takuo Kihira (@tkihira) July 31, 2022 このブログ記事では、この問題について解説します。 解答 答えは「出来る」です。出題者の意図としては document.all を想定しておりました。 document.all は、ブラウザに存在する、非常に特殊なオブジェクトです。 document.all 自体は object 型である。console.log(document.all) とすると内容が確認出来る

  • WebAssembly を動的生成した場合のパフォーマンスについて

    以下では、それぞれのプログラム実装について詳細を説明していきます。 1. JavaScript simple implementation(js-simple) ソースコード / 実行結果 このプログラムは、JavaScript で BF の文字を 1 文字ずつパースし実行していく、一番シンプルな実装です。対応する括弧のジャンプも、そのたびに愚直に計算して求めています。 一切最適化を施していないため、実行結果はその他のプログラムに比べて一番遅くなっており、各プラットフォームで最も速い結果に比べて 30 倍〜50 倍ほど遅くなっています。 2. JavaScript dynamic-code-creation implementation: single function (js-dcc) ソースコード / 実行結果 このプログラムは、BF の各記号に対応する JavaScript を直接文

  • 正規表現の脆弱性 (ReDoS) を JavaScript で学ぶ

    先日、このようなツイートを書いたところ、かなりの反響がありました。 JavaScript の正規表現の脆弱性の例でいうと、例えば /\s+$/ は脆弱性があると言える console.time(); /\s+$/.test(" ".repeat(65536) + "a"); console.timeEnd(); 結構時間がかかるのがわかる。でも /\s+$/ を見て「これは危険だな」と理解出来る人はそんなにいない。JavaScript に限らないけれど。 — Takuo Kihira (@tkihira) February 17, 2022 これは一般に ReDoS (Regular expression Denial of Service) と呼ばれる脆弱性です。正確に理解するのが難しい脆弱性なので、少し解説してみたいと思います。 結論 長い記事になるので、最初に「とりあえずこれだけ知っ

  • JavaScript で parseInt / parseFloat を使わない方が良い理由

    となるのが原因です。parseInt というのは、文字列を解析して整数値(int)を返すグローバル関数であり、引数をまず文字列に変換する仕様となっております。その段階で 0.0000005 が "5e-7" という文字列に変換されてしまい、その文字列の先頭の 5 だけが数字として解析されてしまったため、結果として parseInt(0.0000005) === 5 となりました。 なぜ String(0.000005) === "0.000005" に、String(0.0000005) === "5e-7" になるのかについては、この記事の最後で余談として説明します。 整数化には Math.trunc を使おう このように、parseInt は文字列を引数にすることを前提にしているため、速度の面でも可読性の面でも「小数値を整数値に変換したい」という場合に使うのは望ましくありません。最も望

  • JavaScript で学ぶビット演算の基礎

    唐突にビット演算の話です。今回は当に基礎的な事しか書きませんので、ある程度のレベルの方には常識レベルの話になることをご承知ください。 近年のプログラミング環境で、ビットを意識する機会はほとんど無くなりました。プログラミングの抽象化が進んだおかげで良いことだと思います。今や知らないのが普通なのかもしれません。しかし、もしちょっと低レイヤーな処理を書く機会があった時に、今までの私達にとっては常識レベルであった知識であっても、重要度が下がり学ぶ機会も無くなってしまったが故に、知らない人はそこで躓いてしまう可能性が高いことに気が付きました。この記事は、普段のプログラミングにはあまり必要のないビット演算を、とりあえずこれだけ知っておけばその先は自力でなんとかなるかな、というレベルまで解説したいと思います。 解説は JavaScript を使って行いますが、基は他の言語でも同じです。 JavaSc

  • JavaScript クイズ解説: NaN === NaN の結果はどうなる?

    先日、このようなツイートを書きました。 久しぶりの JavaScript クイズ。 JavaScript において NaN === NaN の結果は次のうちどれになるでしょうか? — Takuo Kihira (@tkihira) September 7, 2021 答えは 4 の「状況によって上記以外もありうる」です。でも、2 や 3 を選んだ方も、もはや正解だといって差し支えないと思います。 解説が長くなったので、ブログ記事にまとめました。 そもそも NaN とは NaN は “Not a Number” を意味する数値です。数値なのに「Not a Number」というのは違和感があるかもしれませんが、数値表現することが出来ない状態を保持するために便宜的に用意された数値、というようなものです。 NaN は、浮動小数点演算において数値では表現出来ない計算をしようとすると登場します。例えば

  • 10 年前に JavaScript で Flash Player を開発し買収された話

    この記事は、JavaScript で Flash Player の実現を頑張った(もしくは現在進行系で頑張っている)人たちの集う Flash Advent Calendar 2020 に参加しております。 私は過去に自分が設立した会社で ExGame という HTML5 実装の Flash Player(正確には Flash Runtime Engine)を開発し、その会社ごと DeNA に買収(M&A)されました。あまり出来ない体験であるのは間違いないので、Flash が終了を迎える今、改めて振り返ってみようと思います。 Flash Player の開発 今から 10 年前の 2010 年、ちょうど iPhone が普及し始めてきてガラケーのシェアが 8 割から 6 割くらいに落ちようとしていた時期に、私は Flash Player を JavaScript で実装していました。以前この

  • JavaScript における VM の高速化手法

    この記事は、JavaScript で Flash Player の実現を頑張った(もしくは現在進行系で頑張っている)人たちの集う Flash Advent Calendar 2020 に参加しております。 皆さん、JavaScript で VM を実装する経験をお持ちでしょうか?私は過去に Java VM と ActionScript VM を JavaScript で実装したことがあります。Flash Player において VM は最も重い場所になることが多く、ここの高速化は Engine 全体の性能に大きく寄与します。この記事では、私が Pex.js にて導入し、素晴らしい成果をあげた VM の高速化手法をご紹介しましょう。 とはいえ今更 ActionScript の VM の話をされても困ると思うので、この記事では簡単な Java VM のサブセットをターゲットにして説明をします。

  • 巨大 WebAssembly ファイルのコンパイル時間

    funcs というのは、wasm 内に何個関数が入っているか、です。1 func の場合は Function body が約 25Mb、100,000 funcs の場合は約 2.5kb、500,000 funcs の場合は約 0.5kb です。 Chrome では 20秒〜1分 ほどかかっています。なおこのコンパイル処理は現在の Chrome の実装だとページをロードする度に必ず発生するので、巨大 WebAssembly が存在するページを Chrome で開いた場合、キャッシュの有無等と関係なく相当待つ必要があります。 Firefox だと、Function Body のサイズによって処理時間が大きく変わります。1 つしか関数がないときはクラッシュしましたが、Function Body が小さくなるにつれて速度が向上しています。例えば Emscripten 等で出力される巨大な Web

  • WebAssembly の基礎

    WebAssembly をご存知でしょうか?2年前に突然発表された新しい仕様です。まだ登場して間もないため、実際に格的に利用しているサービスは数えるほどしかありませんが、Twitter 等を見ているとじわりじわりと評判になっており、技術としての勢いを感じます。 一方で、WebAssembly について言及された資料がまだまだ少なかったり、技術のレイヤーが一般的なフロントエンドエンジニア技術セットとは大きくかけ離れているなどの理由により、WebAssembly について誤解されていることも多々あることを感じました。 そこで今回、あまり技術的に詳細な所まで深入りせず、「専門外の方でもこの程度知っておけば良い」よりちょっと詳しいくらいの内容を目標にして WebAssembly を解説してみたいと思います。 WebAssembly とは WebAssemblywasmとも呼ばれます)とは、ざ

  • トレタの増井さんに聞く、B2Bサービスのカスタマイズ

    今日の夜、トレタの増井さん(@masuidrive)さんと会って晩御飯をべました。下らない話や日企業の海外進出の話などをする中で、B2Bサービスがカスタマイズを受け入れるというのがどういうことなのか、という話が大変面白かったので、許可を得た上でブログ記事にさせてもらいました。 B2Bとは、Business to Businessの略語であり、企業が主に企業に向かってサービスやプロダクトを提供するタイプのビジネスモデルを指す言葉です。対義語がB2C(Business to Consumer)で、企業が主に個人に向かってサービスやプロダクトを提供するタイプのビジネスモデルを指します。B2Bビジネスの場合は契約1口あたりの金額が大きくなる傾向があり、逆にB2Cビジネスは1口あたりの金額はさほど大きくないのが普通です。 自分も昔の会社でB2Bを経験したことがあるのですが、B2Bをやる上で1つ大

  • 1