1 /* Bcj2Enc.c -- BCJ2 Encoder (Converter for x86 code)
\r
2 2014-11-10 : Igor Pavlov : Public domain */
\r
6 /* #define SHOW_STAT */
\r
15 #include <windows.h>
\r
19 #include "CpuArch.h"
\r
21 #define CProb UInt16
\r
23 #define kTopValue ((UInt32)1 << 24)
\r
24 #define kNumModelBits 11
\r
25 #define kBitModelTotal (1 << kNumModelBits)
\r
26 #define kNumMoveBits 5
\r
28 void Bcj2Enc_Init(CBcj2Enc *p)
\r
32 p->state = BCJ2_ENC_STATE_OK;
\r
33 p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
\r
38 p->range = 0xFFFFFFFF;
\r
46 p->relatLimit = BCJ2_RELAT_LIMIT;
\r
52 for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)
\r
53 p->probs[i] = kBitModelTotal >> 1;
\r
56 static Bool MY_FAST_CALL RangeEnc_ShiftLow(CBcj2Enc *p)
\r
58 if ((UInt32)p->low < (UInt32)0xFF000000 || (UInt32)(p->low >> 32) != 0)
\r
60 Byte *buf = p->bufs[BCJ2_STREAM_RC];
\r
63 if (buf == p->lims[BCJ2_STREAM_RC])
\r
65 p->state = BCJ2_STREAM_RC;
\r
66 p->bufs[BCJ2_STREAM_RC] = buf;
\r
69 *buf++ = (Byte)(p->cache + (Byte)(p->low >> 32));
\r
72 while (--p->cacheSize);
\r
73 p->bufs[BCJ2_STREAM_RC] = buf;
\r
74 p->cache = (Byte)((UInt32)p->low >> 24);
\r
77 p->low = (UInt32)p->low << 8;
\r
81 static void Bcj2Enc_Encode_2(CBcj2Enc *p)
\r
83 if (BCJ2_IS_32BIT_STREAM(p->state))
\r
85 Byte *cur = p->bufs[p->state];
\r
86 if (cur == p->lims[p->state])
\r
88 SetBe32(cur, p->tempTarget);
\r
89 p->bufs[p->state] = cur + 4;
\r
92 p->state = BCJ2_ENC_STATE_ORIG;
\r
96 if (p->range < kTopValue)
\r
98 if (RangeEnc_ShiftLow(p))
\r
105 const Byte *src = p->src;
\r
106 const Byte *srcLim;
\r
108 SizeT num = p->srcLim - src;
\r
110 if (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE)
\r
119 dest = p->bufs[BCJ2_STREAM_MAIN];
\r
120 if (num > (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest))
\r
122 num = p->lims[BCJ2_STREAM_MAIN] - dest;
\r
125 p->state = BCJ2_STREAM_MAIN;
\r
130 srcLim = src + num;
\r
132 if (p->prevByte == 0x0F && (src[0] & 0xF0) == 0x80)
\r
140 if ((b & 0xFE) == 0xE8)
\r
143 if (++src != srcLim)
\r
148 if (++src == srcLim)
\r
150 if ((*src & 0xF0) != 0x80)
\r
156 num = src - p->src;
\r
160 p->prevByte = src[-1];
\r
161 p->bufs[BCJ2_STREAM_MAIN] = dest;
\r
163 p->ip += (UInt32)num;
\r
168 Byte context = (Byte)(num == 0 ? p->prevByte : src[-1]);
\r
171 p->bufs[BCJ2_STREAM_MAIN] = dest + 1;
\r
172 p->ip += (UInt32)num + 1;
\r
175 needConvert = False;
\r
177 if ((SizeT)(p->srcLim - src) >= 4)
\r
179 UInt32 relatVal = GetUi32(src);
\r
180 if ((p->fileSize == 0 || (UInt32)(p->ip + 4 + relatVal - p->fileIp) < p->fileSize)
\r
181 && ((relatVal + p->relatLimit) >> 1) < p->relatLimit)
\r
182 needConvert = True;
\r
189 CProb *prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)context : (b == 0xE9 ? 1 : 0));
\r
192 bound = (p->range >> kNumModelBits) * ttt;
\r
197 *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
\r
205 *prob = (CProb)(ttt - (ttt >> kNumMoveBits));
\r
208 UInt32 relatVal = GetUi32(src);
\r
211 absVal = p->ip + relatVal;
\r
212 p->prevByte = src[3];
\r
216 unsigned cj = (b == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;
\r
217 Byte *cur = p->bufs[cj];
\r
218 if (cur == p->lims[cj])
\r
221 p->tempTarget = absVal;
\r
224 SetBe32(cur, absVal);
\r
225 p->bufs[cj] = cur + 4;
\r
234 if (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM)
\r
237 for (; p->flushPos < 5; p->flushPos++)
\r
238 if (RangeEnc_ShiftLow(p))
\r
240 p->state = BCJ2_ENC_STATE_OK;
\r
244 void Bcj2Enc_Encode(CBcj2Enc *p)
\r
247 PRF(printf("---- ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));
\r
249 if (p->tempPos != 0)
\r
251 unsigned extra = 0;
\r
255 const Byte *src = p->src;
\r
256 const Byte *srcLim = p->srcLim;
\r
257 unsigned finishMode = p->finishMode;
\r
260 p->srcLim = p->temp + p->tempPos;
\r
262 p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
\r
264 PRF(printf(" ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));
\r
266 Bcj2Enc_Encode_2(p);
\r
269 unsigned num = (unsigned)(p->src - p->temp);
\r
270 unsigned tempPos = p->tempPos - num;
\r
272 p->tempPos = tempPos;
\r
273 for (i = 0; i < tempPos; i++)
\r
274 p->temp[i] = p->temp[i + num];
\r
277 p->srcLim = srcLim;
\r
278 p->finishMode = finishMode;
\r
280 if (p->state != BCJ2_ENC_STATE_ORIG || src == srcLim)
\r
283 if (extra >= tempPos)
\r
285 p->src = src - tempPos;
\r
290 p->temp[tempPos] = src[0];
\r
291 p->tempPos = tempPos + 1;
\r
298 PRF(printf("++++ ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));
\r
300 Bcj2Enc_Encode_2(p);
\r
302 if (p->state == BCJ2_ENC_STATE_ORIG)
\r
304 const Byte *src = p->src;
\r
305 unsigned rem = (unsigned)(p->srcLim - src);
\r
307 for (i = 0; i < rem; i++)
\r
308 p->temp[i] = src[i];
\r
310 p->src = src + rem;
\r