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), %rbx .LVL809: movq 48(%rbx), %rax .LBE14145: movq (%rax), %rdx .LBB14146: leaq 8(%rax), %rcx movq %rcx, 48(%rbx) .loc 3 312 0 movq %rdx, 8(%rbx) .LBE14146: .LBE14144: .loc 3 313 0 #APP # 313 "VM-Run.cpp" 1 # -- CONSTANT end
少し複雑すぎたので
ac_ = Object::makeFixnum(3);
と書き直してみる。
# 311 "VM-Run.cpp" 1 # -- CONSTANT start # 0 "" 2 .loc 3 312 0 #NO_APP movq 80(%rsp), %rbx ;; %rbx = this .LVL809: movq $13, 8(%rbx) ;; this->ac_ = 13 .loc 3 313 0 #APP # 313 "VM-Run.cpp" 1 # -- CONSTANT end # 0 "" 2
80(%rsp) は this っぽい。
というわけで、先ほどのコードにコメントをいれると。
.loc 9 50 0 movq 80(%rsp), %rbx ;; %rbx = this .LVL809: movq 48(%rbx), %rax ;; %rax = this->pc_ .LBE14145: movq (%rax), %rdx ;; %rdx = *(this->pc_) .LBB14146: leaq 8(%rax), %rcx ;; %rcx = this->pc_ + 8 movq %rcx, 48(%rbx) ;; this->pc_ = %rcx .loc 3 312 0 movq %rdx, 8(%rbx) ;; this->ac_ = %rdx .LBE14146: .LBE14144: .loc 3 313 0 #APP # 313 "VM-Run.cpp" 1 # -- CONSTANT end
うむ。理屈は通った。
ところで .loc って何。デバッグ用の情報か。
this が 80(%rsp) に割り当てられている背景が知りたい。
CProcedure
JIT 実験では、コンパイル済みコードを Object hoge(VM* theVM, int argc, const Object* argv) というシグネチャで実行する。
theVM は1つ目の引数なので %rdi だろう。
実験したら
movq $13, 8(%rdi)
OK。
CONSTANT 3 を発行するだけの CProcedure を返す CProcedure を定義(ややこしい)。
Object scheme::returnJitEx(VM* theVM, int argc, const Object* argv) { ExecutableMemory* mem = new ExecutableMemory(256); if (!mem->allocate()) { fprintf(stderr, "returnJit Error"); exit(-1); } mem->push(0x48); // movq $0xd,0x8(%rdi) mem->push(0xc7); mem->push(0x47); mem->push(0x08); mem->push(0x0d); mem->push(0x00); mem->push(0x00); mem->push(0x00); mem->push(0x48);// movq 0x8(%rdi),%rax mem->push(0x8b); mem->push(0x47); mem->push(0x08); mem->push(0xc3);// retq uint8_t* address = mem->address(); return Object::makeCProcedure(((Object (*)(VM* vm, int, const Object*))address)); }
(display ((return-jit))) ;; 3
うごいた。
分岐を見てみる
# -- Branch on not null start # 0 "" 2 #NO_APP .LBB15377: .LBB15378: .loc 10 218 0 movq 64(%rsp), %rsi ;; %rsi = this .LVL786: movl $_ZN6scheme6Object5FalseE, %eax ;; %eax = False movl $_ZN6scheme6Object4TrueE, %edx ;; %edx = True cmpq $6, 8(%rsi) ;; ac_.isNil() ? cmove %rdx, %rax ;; isNil() に従い %rax = False or True .LBE15378: movq (%rax), %rax .LBE15377: .loc 27 1128 0 cmpq $86, %rax ;; %rax is False ? .LBB15379: .loc 27 1127 0 movq %rax, 8(%rsi) ac = %rax .LBE15379: .loc 27 1128 0 je .L1563 ;; jump 先はあとで見る movq 64(%rsp), %rcx ;; %rcx = stackEnd_ .LVL787: addq $8, 48(%rcx) ;; this->pc_ ++; .L1023: .loc 27 1129 0 #APP # 1129 "VM-Run.cpp" 1 # -- end ...... .L1563: .LBE17379: .LBB17380: .LBB17383: .LBB17384: .loc 6 50 0 movq 48(%rsi), %rax ;; %rax = this->pc_ .LBE17384: movq (%rax), %rdx ;; %rax = *(this->pc_) .LBB17385: addq $8, %rax ;; %rax += 8 movq %rax, 48(%rsi) this->pc_ = %rax .loc 27 1128 0 movq %rdx, 400(%rsp) ;; ここから MOSH_ASSERT による isFixnum .LBE17385: .LBE17383: andl $3, %edx subb $1, %dl jne .L1671 leaq 400(%rsp), %rdi ;; 引数に %rdx .LVL1539: call _ZNK6scheme6Object8toFixnumEv ;;