#if (jitCompA0001_USE_R3F_IMM32 != 0)
int r3f;
#endif
- char prefix;
+ char prefix; //CND命令の値を記録(初期値=0)
};
#define jitCompPutByte1(p, c0) *p++ = c0
void errHndl(struct Regs *r);
+/*
+ * dst : 現在の書き込みアドレス。
+ * dst1 : 書き込みアドレスの最大値
+ * src : 現在の読み込みアドレス(ヘッダ部は飛ばしてある
+ * src1 : 読み込みアドレスの最大値
+ * src0 : 読み込みバイナリのアドレス
+ */
int jitCompiler(unsigned char *dst, unsigned char *dst1, const unsigned char *src, const unsigned char *src1, const unsigned char *src0, struct LabelTable *label, int maxLabels, int level, int debugInfo1, int flags)
/* IA-32用 */
/* 本来ならこのレイヤでは文法チェックしない */
w.dst = w.dst0 = dst;
w.err = 0;
w.maxLabels = maxLabels;
+
if ((flags & JITC_NOSTARTUP) == 0) {
jitCompPutByte1(w.dst, 0x60); /* PUSHAD(); */
jitCompA000_loadRegCacheAll(&w); /* start-up */
jitCompA0001_movEbpDispReg32(&w, 2304 + 4, 0 /* EAX */); /* MOV(debugInfo1, EAX); */
}
while (src < src1) {
- w.prefix = 0;
- if (w.dst + 256 > dst1) { w.err = JITC_ERR_DST1; goto err_w; }
+ w.prefix = 0; //0x04 CND 命令で変更される
+ if (w.dst + 256 > dst1) { w.err = JITC_ERR_DST1; goto err_w; } // 書き込み領域が残り256バイト未満ならエラー
timecount++;
if (timecount >= 64) {
timecount -= 64;
/* 未完成(timeoutチェックコードを入れる) */
}
- prefix_continue:
+ prefix_continue: // CND命令実行後ここに戻る
switch (*src) {
case 0x00: /* NOP */
- if (w.prefix != 0) { w.err = JITC_ERR_PREFIX; goto err_w; }
+ if (w.prefix != 0) { w.err = JITC_ERR_PREFIX; goto err_w; } // 「条件付きでNOPを実行」するなんて、矛盾している!
break;
case 0x01: /* LB */
- if (enter0 == NULL && (src[6] == 0x3c || (src[6] == 0xfe && src[7] == 0x01 && src[9] == 0x3c))) {
- jitCompPutByte1(w.dst, 0xe9);
+
+ /*
+ * LB : ラベル設置命令。(6byte)
+ * ・prefex = 1にする
+ * ・timecount++し、timecountのチェックをする。
+ * ・ラベル位置を登録する。
+ * ・割り込みがある場合、このタイミングで割り込みを発生させる。
+ *
+ * 1 2 3 456
+ * LB 01 opt imm32
+ *
+ */
+
+ if (enter0 == NULL && (src[6] == 0x3c /* 多数のレジスタをスタックに退避 */ || (src[6] == 0xfe/* REMARK */ && src[7] == 0x01 && src[9] == 0x3c))) { //beginFunc()中のLB
+ // LB命令の後に0x3C命令・・・beginFunc()
+ jitCompPutByte1(w.dst, 0xe9); // (x86) JMP rel32 : 次の命令との相対オフセットだけ相対ニアジャンプする
enter0 = w.dst;
- jitCompPutImm32(&w, 0);
+ jitCompPutImm32(&w, 0); // 飛び相対座標が0 ・・・パイプラインのフラッシュ??
}
- if (src[6] == 0x34) {
+ if (src[6] == 0x34) { // LBの次の命令がDATA ・・・DAT_SA0(label, typ32, length) ・・・メモリ確保命令
tmp_ucp = w.dst;
- jitCompPutByte1(w.dst, 0xe9);
- i = jitCompGetImm32(&src[7]);
+ jitCompPutByte1(w.dst, 0xe9); // (x86) JMP rel32 : 次の命令との相対オフセットだけ相対ニアジャンプする
+ i = jitCompGetImm32(&src[7]); // type32 を取得
j = 32;
if (i != 1) {
i = jitCompA000_convTyp(i);
/* 未完成(timeoutチェックコードを入れる) */
break;
- case 0x02: /* LIMM */
- if (src[1] == 0x3f && w.prefix != 0) w.err = JITC_ERR_PREFIX;
+ case 0x02: /* LIMM */
+
+ /*
+ * LIMM : 定数即値代入命令(6byte)
+ *
+ * 1 2 3456
+ * 02 reg0R imm32
+ *
+ * ・reg3F は条件比較慣用句指定用&演算命令即値慣用句指定用。よってCND命令の直後では使用できない。
+ */
+
+ if (src[1] == 0x3f && w.prefix != 0) w.err = JITC_ERR_PREFIX; // CND命令の直後でR3Fを書き換えるなんて変だよね
+
#if (jitCompA0001_USE_R3F_IMM32 != 0)
- if (src[1] == 0x3f) {
+ if (src[1] == 0x3f) { // R3Fへの代入は例外敵に、 w.r3f を使用
w.r3f = jitCompGetImm32(src + 2);
break;
}
#endif
- i = jitCompGetImm32(src + 2);
+ i = jitCompGetImm32(src + 2); // 与えられた即値(第二引数)を取得
+
+ /* R00-R02 なら EBX, ECX, EDX 、それ以外なら EAX のレジスタIDを reg0 に代入 */
reg0 = jitCompA000_selectRegCache(src[1], 0 /* EAX */);
+
#if (jitCompA0001_OPTIMIZE_MOV != 0)
if (i == 0) {
jitCompPutByte2(w.dst, 0x31, 0xc0 | reg0 << 3 | reg0); /* XOR(reg0, reg0); */
break;
}
#endif
- jitCompPutByte1(w.dst, 0xb8 | reg0); /* MOV(reg0, ?); */
+
+ /* reg0 のレジスタに対応したMOV命令を発行 */
+ jitCompPutByte1(w.dst, 0xb8 | reg0); /* MOV(reg0, ?); == 10111000b+wr imm32 */
jitCompPutImm32(&w, i);
- if (reg0 == 0)
+
+ if (reg0 == 0) // R03以降の、レジスタの内容をメモリ上に格納してエミュレートする場合
+
jitCompA0001_movRxxEax(&w, src[1]);
break;
case 0x03: /* PLIMM */ /* 未完成(plsまで対応) */
- i = jitCompGetLabelNum(&w, src + 2);
- if ((flags & JITC_PHASE1) != 0 && w.err == 0) {
- if (label[i].opt == 0) { w.err = JITC_ERR_LABELNODEF; goto err_w; }
- if (src[1] != 0x3f && label[i].opt != 2) { w.err = JITC_ERR_LABELTYP; goto err_w; }
- if (src[1] == 0x3f && label[i].typ != 0) { w.err = JITC_ERR_LABELTYP; goto err_w; }
+
+ /*
+ * PLIMM : ラベル番号代入命令(6byte)
+ *
+ * 1 2 3456
+ * 03 PXX imm32
+ *
+ * ・P28 はAPI用
+ * ・P3F はプログラムカウンタ
+ */
+
+ i = jitCompGetLabelNum(&w, src + 2); // Pxxに代入するラベルの番号(第二引数)
+ if ((flags & JITC_PHASE1) != 0 && w.err == 0) { // Phase 1であるならば
+ if (label[i].opt == 0) { w.err = JITC_ERR_LABELNODEF; goto err_w; } // 指定されたラベル番号は存在しない
+ if (src[1] != 0x3f && label[i].opt != 2) { w.err = JITC_ERR_LABELTYP; goto err_w; } //
+ if (src[1] == 0x3f && label[i].typ != 0) { w.err = JITC_ERR_LABELTYP; goto err_w; } // プログラムカウンタに TYP_CODEでない値は代入できない
}
- if (src[1] == 0x3f) {
- if (w.prefix == 0) {
+ if (src[1] == 0x3f) { // プログラムカウンタへの代入なら
+ if (w.prefix == 0) { // CND命令による条件付きでなければ、即座に移動
jitCompPutByte1(w.dst, 0xe9); /* JMP(?); */
}
- else {
+ else { // 直前はCND命令。
+
+ /*
+ * CND命令
+ * 1 2
+ * 04 reg0R
+ *
+ * いま、dstの末端はJZ命令になっている。 0x0F 0x84 cd
+ */
+
+ // JZのとび先アドレスの書き換え?
w.dst[-1] = w.dst[-2] ^ 0xf1; /* 74->85, 75->84 */
w.dst[-2] = 0x0f;
+
w.prefix = 0;
}
j = 0;
- if ((flags & JITC_PHASE1) != 0 || ((flags & JITC_PHASE1) == 0) && label[i].opt != 0)
- j = label[i].p - (w.dst + 4);
- jitCompPutImm32(&w, j);
+ if ((flags & JITC_PHASE1) != 0 || ((flags & JITC_PHASE1) == 0) && label[i].opt != 0) // label番号iが確保されていれば (このif文は意味をなさない)
+ j = label[i].p - (w.dst + 4); // j はとび先の相対番地
+ jitCompPutImm32(&w, j); // JMP もしくは JZ 命令のアドレス部を記述
#if (jitCompA0001_OPTIMIZE_JMP != 0)
if (-128 - 3 <= j && j < 0) {
if (w.dst[-5] == 0xe9) {
}
#endif
}
- else {
+ else { // プログラムカウンタ以外への代入
+
+ // 代入先が P01, P02なら ESI, EDI,それ以外ならEAXを指定
reg0 = jitCompA000_selectPRegCache(src[1], 0 /* EAX */);
jitCompPutByte1(w.dst, 0xb8 | reg0); /* MOV(reg0, ?); */
- jitCompPutImm32(&w, (int)label[i].p);
+ jitCompPutImm32(&w, (int)label[i].p); // ラベルのパスを各レジスタに代入
+
+ // レジスタへの代入をメモリでエミュレーションする場合は、スタックに積む。
if (reg0 == 0)
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32, 0); /* MOV([EBP+?], EAX); */
+
if (level < JITC_LV_FASTEST) {
jitCompA0001_movEbpDispReg32(&w, 256 + src[1] * 32 + 8, reg0); /* MOV([EBP+?], reg0); */ /* p0 */
jitCompPutByte1(w.dst, 0xb8); /* MOV(EAX, ?); */
}
/*
+ * jitcの出力コードをひとまとめにする関数を作成しその中身をjitCompile()で生成
+ *
* qq : 出力バイナリの書き込み位置のアドレスへの参照(書き込み位置を呼び出しに反映させるため参照渡しにする)
* q1 : 出力バイナリの書き込み位置のアドレスの最大値
* p0 : (*.ose)バイナリの読み込み位置のアドレス(ヘッダ部除去済)
for (i = 0; i < JITC_MAXLABELS; i++)
label[i].opt = 0;
+ // 以下のjitCompile()呼び出しでは第二引数をq1-2にした方がよいのではないか?
i = jitCompiler(q, q1, p0 + 2, p1, p0, label, JITC_MAXLABELS, level, di1_serial, 0);
if (i != 0) return 2;
i = jitCompiler(q, q1, p0 + 2, p1, p0, label, JITC_MAXLABELS, level, di1_serial, JITC_PHASE1 + 0);