mosh

x86-64 アドレッシングまとめ

このまとめは、間違い勘違いを含んでいる可能性があります。ご注意を。 基本 mov [base-reg + index-reg * scale + displacement], src-reg ; intel 形式 movq src-reg, displacement(base-reg, index-reg, scale) ; gas 形式 (movq (& base-reg + (* index-…

ドライバとか

Mosh JIT 実験の副産物として Mosh で動くアセンブラが出来てきた。 もう u8-list->c-procedure 手続きと組み合わせれば、ドライバも Scheme で書けそうだな。 Mosh を Mona に移植するのは来年の4月くらいまでには終わらせたい。

やっと BRANCH が動いた - Jit

Fixnum の範囲でしか動かない。Bignum になると SIGTRAP 。 (define (BRANCH_NOT_LT label) (let ([label1 (gensym)] [label2 (gensym)]) `((movq rax ,(vm-register 'sp)) ; rax = sp (leaq rdx (& rax -8)) ; rdx = sp - 8 (movq rdx ,(vm-register 'sp)) …

JIT 実験を緩やかに奨めている

アセンブラを作り、理解を深めつつゆっくり進めている。条件付き move など色々あることを知った。 gcc の出力するアセンブリを見ると、64bit でも "l" や "b" の命令が出てきて興味深い。 andl $3, %eax subb $1, %al 意図としては、命令長が短くて済むから…

C++ の Object::isNumber 呼べた - JIT

Object クラスのメンバ関数呼べた。 うまく動くはずなのになんで動かないんだろう?とずっと悩んでいた件も解決。 isNumber の call 後に第一引数 VM*(rdi) を restore し忘れていた。正確には rdi を参照している場合は restore が必要な事は理解していたの…

C++ メンバ関数のポインタをアドレスとして取得

C++ のメンバ関数は関数ポインタをとる事は出来てもアドレスは無理。とはいえ JIT で必要なので以下の方法でとる事に。 実体は this が第一引数のマングリングされた関数だから呼べるのは当たり前だけど合法かが微妙。 const Object t = Object::makeFixnum(…

分岐が動くようになった - JIT実験中

(let* ([label (gensym)] [asm (assemble `((movq rax ,(vm-make-fixnum 2)) (movq rbx ,(vm-make-fixnum 2)) (cmpq rax rbx) (je ,label) (movq rax ,(vm-make-fixnum 3)) (label ,label) (retq)))] [proc (u8-list->c-procedure asm)]) (test-true (proced…

マクロアセンブラっぽくなってきた

VM Instruction の REFER_LOCAL_PUSH_CONSTANT を定義。 macro-xxx はヘルパー的なマクロ。このマクロのおかげで細かいミスが減らせるはず。 VM Instruction の定義は quasiquote でやってるけど、これが正しいのかは、もう少し進んでみないと分からない。 …

JIT の関数呼び出しどうしよう

obj.isNumber などインスタンス関数のポインタを JIT コンパイラ側に渡さないと。 C だったら楽なんだけど。 追記 よく考えれば特に変わらないか。

JIT のデバッグには 0xEB 0xFE か 0xCC が便利

JIT コンパイラが生成したコードで落ちるときは、無限ループ(=0xEB 0xFE)を挿入し二分法で場所を特定。 落ちる直前のコードにデバッガ起動(0xCC)を挿入し、デバッガで事前条件が成り立っているか調べる。 という感じで進めると良いかも。0xCC だけでも…

アセンブラゆっくりと実装中

sar とか movsxd など知らなかったな。 SAR r/m64, imm8 : REX.W + C1 /7 ib MOVSXD r64, r/m32 : REX.W** + 63 /r

Intel64 の ModR/M の仕組みをやっと理解した

Intel 64 and IA-32 Architectures Software Developer's Manual を読んでも ModR/M や SIB が理解できない。 x86系CPUのネイティブコードを解析する(2/3):CodeZine を読んでやっと理解できた。日本語でまとまっているのは大変ありがたい。 例えば以下の…

Mod R/M

(test-equal '(#x48 #x89 #xe3) (assemble '(movq rbx rsp))) (test-equal '(#x48 #x89 #xeb) (assemble '(movq rbx rbp))) (test-equal '(#x48 #x89 #xc4) (assemble '(movq rsp rax)))

アセンブラ書く準備

シンタックスは Sassy 互換にした方が良いのか迷う。 若干アドレッシングが気持ち悪い。 (add ecx (& edx)) (mov edx (& (* 8 ecx))) (add eax (& #x64)) (mov eax (& foo (* ebx 4) edx 1000)) (add eax (& -1 2 -3 4 ebx -5 6 -7 8)) あと Intel のマニュ…

JIT 予備実験1

CONSTANT 命令 CONSTANT 命令 を -S で見てみる。 ac_ レジスタにオペランドを放り込む。 CASE(CONSTANT) { asm volatile(" \t # -- CONSTANT start"); ac_ = fetchOperand(); asm volatile(" \t # -- CONSTANT end"); NEXT1; } .loc 9 50 0 movq 80(%rsp), …

JIT コンパイルまとめ

Mosh のパフォーマンスを向上させたいので JIT コンパイル周りを調べてみました。誤りや不足がありましたらご指摘いただけると助かります。 何か? Just in time コンパイルの略。実行時に必要になった時点で動的にコードを生成する仕組み。 VM 型のインタプ…

Transcoder のデフォルト EolStyle のバグを修正

id:mtakuya さんから Windows の Mosh で GET リクエストがうまくいかないとバグ指摘を頂いていた件の修正。 string->utf8 際に Transcoder を使っているのだが、これのデフォルト EolStyle が CRLF になっていた。 utf8に変換するさいに、LF が CRLF に変換…

FFI callback のサンプル

libc の qsort を呼び出してみる。こんな感じの API はどうでしょうか?>id:mjt さん Ubuntu AMD64 で確認しています。 ;; Mosh callback example *draft*. (import (mosh) (mosh ffi) (rnrs)) (define array (u8-list->bytevector '(6 5 3 4 1 7 2))) (let…

FFI callback 実装

ようやく動き出した。結局 Ypsilon のコードをほぼ移植した形になりそう。 signatures が NULL terminated な文字列ってのは工夫してあるなあ。

FFI callback 実装中

gcc には __LOCAL_SIZE とか naked がないので全てインラインアセンブラで書くのは無理だ。 as さん使うか。

GCC Machine Constraints

GCC のインラインアセンブリ拡張の AMD64 用は、まだないっぽい。引数に使われる R9 などに簡単にアクセスできたら楽なのに。 Machine Constraints - Using the GNU Compiler Collection (GCC)

FFI callback 実装中

int returnCallback(int (*func) (void)) { return func(); } (let () (define libffitest (open-shared-library "./libffitest.so.1.0")) (define returnCallback (c-function libffitest int returnCallback void*)) (let ([callback (make-c-callback 'in…

FFI callback 準備 - 実行可能属性メモリ

/* int return3() { return 3; } */ #ifdef ARCH_IA32 ASSERT_TRUE(mem.push(0x55)); // push %ebp ASSERT_TRUE(mem.push(0x89)); // mov %esp,%ebp ASSERT_TRUE(mem.push(0xe5)); ASSERT_TRUE(mem.push(0x83)); // sub $0x8,%esp ASSERT_TRUE(mem.push(0xec…

Scheme 処理系の FFI callback の仕様を見る

FFI callback とは何か? Scheme の手続きを C のコールバック関数として渡す事の出来る仕組み。 着目する点 マーシャシリングを「誰が、いつ、どのように」やっているか API Ypsilon callback 関数を引数に持つ、C 関数を Scheme から利用する際に callback…

let/named-let を backend にそのまま渡す

psyntax-system-macros に core-macro として let を追加 psyntax-system-macros から (let (macro . let)) を削除 build.ss に buile-let, build-named-let 追加 expander.ss core-macro-transformer に let 追加 expander.ss に let-transformer 追加 ポイ…

psyntax の展開をいじりたい let/named-let

let/named-let がそれぞれ、lambda, letrec に展開されてしまうのだが、展開せずにバックエンドに渡す方法を模索中。

psyntax の展開パターンを変更

いくつかベンチマークをとっていて気づいたこと。 R5RS モード(-5オプションで起動)では十分速いが、R6RS モードでは遅いものがある。 psyntax ではコードを変換してバックエンドに渡すのだが、そこで効率的でないコードになっているのかもしれない。 psyn…

「継続の生成におけるスタックコピーの遅延」のメモ

論文CiNii - Lazy Stack Copying fDr First-class Continuationsのメモ。 動作原理 (call/cc ) の 呼び出し中には呼び出し側の関数フレームは破壊されない事を利用する この段階ではスタックポインタを記憶するだけでコピーする必要がない(不完全継続オブジ…

call/cc 高速化第一弾

call/cc 高速化の第一弾として、dynamic-wind 実装のための構造を C++ 側に持ってきた。 call/cc と dynamic-wind は密接に関連している。dynamic-wind の winders(before, after thunk) を call/cc が参照する。 この関係を Scheme のコードで構築していた…

Windows の Emacs でエラー出力がとれない件の修正など

Lisp Scheme Part27 で指摘してもらった点を追加・修正。 WriteConsole の件は、ototoi さん、finalfusionさん、成瀬さんに貴重なアドバイスを頂きました。ありがとうございました。 Windows 2000 で freeaddrinfo がない件対応。 Windows 上の Emacs でエラ…