2 * vim: set ts=2 sw=2 tw=99 et:
3 * =============================================================================
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
36 #include "../sp_vm_engine.h"
37 #include "../engine2.h"
38 #include "../BaseRuntime.h"
39 #include "../sp_vm_basecontext.h"
41 using namespace Knight;
43 #if defined USE_UNGEN_OPCODES
44 #include "ungen_opcodes.h"
50 KeCodeCache *g_pCodeCache = NULL;
51 ISourcePawnEngine *engine = &g_engine1;
54 LinkCode(AssemblerX86 &masm)
56 if (masm.outOfMemory())
59 void *code = Knight::KE_AllocCode(g_pCodeCache, masm.length());
63 masm.emitToExecutableMemory(code);
67 static inline ConditionCode
68 OpToCondition(OPCODE op)
95 struct array_creation_t
97 const cell_t *dim_list; /* Dimension sizes */
98 cell_t dim_count; /* Number of dimensions */
99 cell_t *data_offs; /* Current offset AFTER the indirection vectors (data) */
100 cell_t *base; /* array base */
104 GenerateInnerArrayIndirectionVectors(array_creation_t *ar, int dim, cell_t cur_offs)
106 cell_t write_offs = cur_offs;
107 cell_t *data_offs = ar->data_offs;
109 cur_offs += ar->dim_list[dim];
111 // Dimension n-x where x > 2 will have sub-vectors.
112 // Otherwise, we just need to reference the data section.
113 if (ar->dim_count > 2 && dim < ar->dim_count - 2) {
114 // For each index at this dimension, write offstes to our sub-vectors.
115 // After we write one sub-vector, we generate its sub-vectors recursively.
116 // At the end, we're given the next offset we can use.
117 for (int i = 0; i < ar->dim_list[dim]; i++) {
118 ar->base[write_offs] = (cur_offs - write_offs) * sizeof(cell_t);
120 cur_offs = GenerateInnerArrayIndirectionVectors(ar, dim + 1, cur_offs);
123 // In this section, there are no sub-vectors, we need to write offsets
124 // to the data. This is separate so the data stays in one big chunk.
125 // The data offset will increment by the size of the last dimension,
126 // because that is where the data is finally computed as.
127 for (int i = 0; i < ar->dim_list[dim]; i++) {
128 ar->base[write_offs] = (*data_offs - write_offs) * sizeof(cell_t);
130 *data_offs = *data_offs + ar->dim_list[dim + 1];
138 calc_indirection(const array_creation_t *ar, cell_t dim)
140 cell_t size = ar->dim_list[dim];
141 if (dim < ar->dim_count - 2)
142 size += ar->dim_list[dim] * calc_indirection(ar, dim + 1);
147 GenerateArrayIndirectionVectors(cell_t *arraybase, cell_t dims[], cell_t _dimcount, bool autozero)
152 /* Reverse the dimensions */
153 cell_t dim_list[sDIMEN_MAX];
155 for (int i = _dimcount - 1; i >= 0; i--)
156 dim_list[cur_dim++] = dims[i];
159 ar.dim_list = dim_list;
160 ar.dim_count = _dimcount;
161 ar.data_offs = &data_offs;
163 data_offs = calc_indirection(&ar, 0);
164 GenerateInnerArrayIndirectionVectors(&ar, 0, 0);
169 PopTrackerAndSetHeap(sp_plugin_t *plugin, InfoVars &vars)
171 tracker_t *trk = (tracker_t *)(vars.ctx->vm[JITVARS_TRACKER]);
172 assert(trk->pCur > trk->pBase);
175 if (trk->pCur < trk->pBase)
176 return SP_ERROR_TRACKER_BOUNDS;
178 ucell_t amt = *trk->pCur;
179 if (amt > (vars.hp - plugin->data_size))
180 return SP_ERROR_HEAPMIN;
183 return SP_ERROR_NONE;
187 PushTracker(sp_context_t *ctx, size_t amount)
189 tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]);
191 if ((size_t)(trk->pCur - trk->pBase) >= trk->size)
192 return SP_ERROR_TRACKER_BOUNDS;
194 if (trk->pCur + 1 - (trk->pBase + trk->size) == 0) {
195 size_t disp = trk->size - 1;
197 trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size * sizeof(cell_t));
200 return SP_ERROR_TRACKER_BOUNDS;
202 trk->pCur = trk->pBase + disp;
205 *trk->pCur++ = amount;
206 return SP_ERROR_NONE;
210 GenerateArray(sp_plugin_t *plugin, InfoVars &vars, uint32_t argc, cell_t *argv, int autozero)
212 // Calculate how many cells are needed.
214 return SP_ERROR_ARRAY_TOO_BIG;
216 uint32_t dim = 1; // second to last dimension
217 uint32_t cells = argv[0];
219 for (uint32_t dim = 1; dim < argc; dim++) {
220 cell_t dimsize = argv[dim];
222 return SP_ERROR_ARRAY_TOO_BIG;
223 if (!ke::IsUint32MultiplySafe(cells, dimsize))
224 return SP_ERROR_ARRAY_TOO_BIG;
225 cells *= uint32_t(dimsize);
226 if (!ke::IsUint32AddSafe(cells, dimsize))
227 return SP_ERROR_ARRAY_TOO_BIG;
228 cells += uint32_t(dimsize);
231 if (!ke::IsUint32MultiplySafe(cells, 4))
232 return SP_ERROR_ARRAY_TOO_BIG;
234 uint32_t bytes = cells * 4;
235 if (!ke::IsUint32AddSafe(vars.hp, bytes))
236 return SP_ERROR_ARRAY_TOO_BIG;
238 uint32_t new_hp = vars.hp + bytes;
239 cell_t *dat_hp = reinterpret_cast<cell_t *>(plugin->memory + new_hp);
241 // argv, coincidentally, is STK.
242 if (dat_hp >= argv - STACK_MARGIN)
243 return SP_ERROR_HEAPLOW;
245 if (int err = PushTracker(vars.ctx, bytes))
248 cell_t *base = reinterpret_cast<cell_t *>(plugin->memory + vars.hp);
249 cell_t offs = GenerateArrayIndirectionVectors(base, argv, argc, autozero);
250 assert(size_t(offs) == cells);
252 argv[argc - 1] = vars.hp;
254 return SP_ERROR_NONE;
259 GetFunctionName(const sp_plugin_t *plugin, uint32_t offs)
261 if (!plugin->debug.unpacked) {
263 sp_fdbg_symbol_t *sym;
264 sp_fdbg_arraydim_t *arr;
265 uint8_t *cursor = (uint8_t *)(plugin->debug.symbols);
267 max = plugin->debug.syms_num;
268 for (iter = 0; iter < max; iter++) {
269 sym = (sp_fdbg_symbol_t *)cursor;
271 if (sym->ident == SP_SYM_FUNCTION && sym->codestart <= offs && sym->codeend > offs)
272 return plugin->debug.stringbase + sym->name;
274 if (sym->dimcount > 0) {
275 cursor += sizeof(sp_fdbg_symbol_t);
276 arr = (sp_fdbg_arraydim_t *)cursor;
277 cursor += sizeof(sp_fdbg_arraydim_t) * sym->dimcount;
281 cursor += sizeof(sp_fdbg_symbol_t);
285 sp_u_fdbg_symbol_t *sym;
286 sp_u_fdbg_arraydim_t *arr;
287 uint8_t *cursor = (uint8_t *)(plugin->debug.symbols);
289 max = plugin->debug.syms_num;
290 for (iter = 0; iter < max; iter++) {
291 sym = (sp_u_fdbg_symbol_t *)cursor;
293 if (sym->ident == SP_SYM_FUNCTION && sym->codestart <= offs && sym->codeend > offs)
294 return plugin->debug.stringbase + sym->name;
296 if (sym->dimcount > 0) {
297 cursor += sizeof(sp_u_fdbg_symbol_t);
298 arr = (sp_u_fdbg_arraydim_t *)cursor;
299 cursor += sizeof(sp_u_fdbg_arraydim_t) * sym->dimcount;
303 cursor += sizeof(sp_u_fdbg_symbol_t);
312 CompileFromThunk(BaseRuntime *runtime, cell_t pcode_offs, void **addrp, char *pc)
314 JitFunction *fn = runtime->GetJittedFunctionByOffset(pcode_offs);
317 fn = g_Jit.CompileFunction(runtime, pcode_offs, &err);
323 g_engine1.GetDebugHook()->OnDebugSpew(
324 "Patching thunk to %s::%s\n",
325 runtime->plugin()->name,
326 GetFunctionName(runtime->plugin(), pcode_offs));
329 *addrp = fn->GetEntryAddress();
331 /* Right now, we always keep the code RWE */
332 *(intptr_t *)(pc - 4) = intptr_t(fn->GetEntryAddress()) - intptr_t(pc);
333 return SP_ERROR_NONE;
337 NativeCallback(sp_context_t *ctx, ucell_t native_idx, cell_t *params)
340 cell_t save_sp = ctx->sp;
341 cell_t save_hp = ctx->hp;
342 sp_plugin_t *pl = (sp_plugin_t *)(ctx->vm[JITVARS_PLUGIN]);
344 ctx->n_idx = native_idx;
346 if (ctx->hp < (cell_t)pl->data_size) {
347 ctx->n_err = SP_ERROR_HEAPMIN;
351 if (ctx->hp + STACK_MARGIN > ctx->sp) {
352 ctx->n_err = SP_ERROR_STACKLOW;
356 if ((uint32_t)ctx->sp >= pl->mem_size) {
357 ctx->n_err = SP_ERROR_STACKMIN;
361 native = &pl->natives[native_idx];
363 if (native->status == SP_NATIVE_UNBOUND) {
364 ctx->n_err = SP_ERROR_INVALID_NATIVE;
368 cell_t result = native->pfn(GET_CONTEXT(ctx), params);
370 if (ctx->n_err != SP_ERROR_NONE)
373 if (save_sp != ctx->sp) {
374 ctx->n_err = SP_ERROR_STACKLEAK;
377 if (save_hp != ctx->hp) {
378 ctx->n_err = SP_ERROR_HEAPLEAK;
385 Compiler::Compiler(BaseRuntime *rt, cell_t pcode_offs)
387 plugin_(rt->plugin()),
388 error_(SP_ERROR_NONE),
389 pcode_start_(pcode_offs),
390 code_start_(reinterpret_cast<cell_t *>(plugin_->pcode + pcode_start_)),
392 code_end_(reinterpret_cast<cell_t *>(plugin_->pcode + plugin_->pcode_size))
394 size_t nmaxops = plugin_->pcode_size / sizeof(cell_t) + 1;
395 jump_map_ = new Label[nmaxops];
398 Compiler::~Compiler()
404 Compiler::emit(int *errp)
406 if (cip_ >= code_end_ || *cip_ != OP_PROC) {
407 *errp = SP_ERROR_INVALID_INSTRUCTION;
412 g_engine1.GetDebugHook()->OnDebugSpew(
413 "Compiling function %s::%s\n",
415 GetFunctionName(plugin_, pcode_start_));
417 SpewOpcode(plugin_, code_start_, cip_);
420 cell_t *codeseg = reinterpret_cast<cell_t *>(plugin_->pcode);
423 if (!emitOp(OP_PROC)) {
424 *errp = (error_ == SP_ERROR_NONE) ? SP_ERROR_OUT_OF_MEMORY : error_;
428 while (cip_ < code_end_) {
429 // If we reach the end of this function, or the beginning of a new
430 // procedure, then stop.
431 if (*cip_ == OP_PROC || *cip_ == OP_ENDPROC)
435 SpewOpcode(plugin_, code_start_, cip_);
438 // We assume every instruction is a jump target, so before emitting
439 // an opcode, we bind its corresponding label.
440 __ bind(&jump_map_[cip_ - codeseg]);
442 OPCODE op = (OPCODE)readCell();
443 if (!emitOp(op) || error_ != SP_ERROR_NONE) {
444 *errp = (error_ == SP_ERROR_NONE) ? SP_ERROR_OUT_OF_MEMORY : error_;
452 void *code = LinkCode(masm);
454 *errp = SP_ERROR_OUT_OF_MEMORY;
458 return new JitFunction(code, pcode_start_);
462 Compiler::emitOp(OPCODE op)
479 cell_t offset = readCell();
480 __ movl(Operand(dat, offset), 0);
486 cell_t offset = readCell();
487 __ movl(Operand(frm, offset), 0);
494 Register reg = (op == OP_PUSH_PRI) ? pri : alt;
495 __ movl(Operand(stk, -4), reg);
507 if (op >= OP_PUSH2_C)
508 n = ((op - OP_PUSH2_C) / 4) + 2;
512 cell_t val = readCell();
513 __ movl(Operand(stk, -(4 * i)), val);
526 if (op >= OP_PUSH2_ADR)
527 n = ((op - OP_PUSH2_ADR) / 4) + 2;
531 // We temporarily relocate FRM to be a local address instead of an
535 cell_t offset = readCell();
536 __ lea(tmp, Operand(frm, offset));
537 __ movl(Operand(stk, -(4 * i)), tmp);
551 if (op >= OP_PUSH2_S)
552 n = ((op - OP_PUSH2_S) / 4) + 2;
556 cell_t offset = readCell();
557 __ movl(tmp, Operand(frm, offset));
558 __ movl(Operand(stk, -(4 * i)), tmp);
572 n = ((op - OP_PUSH2) / 4) + 2;
576 cell_t offset = readCell();
577 __ movl(tmp, Operand(dat, offset));
578 __ movl(Operand(stk, -(4 * i)), tmp);
607 // Push the old frame onto the stack.
608 __ movl(tmp, Operand(info, AMX_INFO_FRAME));
609 __ movl(Operand(stk, -4), tmp);
610 __ subl(stk, 8); // extra unused slot for non-existant CIP
612 // Get and store the new frame.
616 __ movl(Operand(info, AMX_INFO_FRAME), tmp);
618 // Align the stack to 16-bytes (each call adds 4 bytes).
624 cell_t val = readCell();
648 Register reg = (op == OP_SHL_C_PRI) ? pri : alt;
649 cell_t val = readCell();
657 Register reg = (op == OP_SHR_C_PRI) ? pri : alt;
658 cell_t val = readCell();
695 cell_t val = readCell();
702 cell_t val = readCell();
703 __ imull(pri, pri, val);
714 ConditionCode cc = OpToCondition(op);
724 Register reg = (op == OP_EQ_C_PRI) ? pri : alt;
725 cell_t val = readCell();
728 __ set(equal, r8_al);
735 Register reg = (OP_INC_PRI) ? pri : alt;
743 Register base = (op == OP_INC) ? dat : frm;
744 cell_t offset = readCell();
745 __ addl(Operand(base, offset), 1);
750 __ addl(Operand(dat, pri, NoScale), 1);
756 Register reg = (op == OP_DEC_PRI) ? pri : alt;
764 Register base = (op == OP_DEC) ? dat : frm;
765 cell_t offset = readCell();
766 __ subl(Operand(base, offset), 1);
771 __ subl(Operand(dat, pri, NoScale), 1);
777 Register reg = (op == OP_LOAD_PRI) ? pri : alt;
778 cell_t offset = readCell();
779 __ movl(reg, Operand(dat, offset));
785 cell_t offs1 = readCell();
786 cell_t offs2 = readCell();
787 __ movl(pri, Operand(dat, offs1));
788 __ movl(alt, Operand(dat, offs2));
795 Register reg = (op == OP_LOAD_S_PRI) ? pri : alt;
796 cell_t offset = readCell();
797 __ movl(reg, Operand(frm, offset));
803 cell_t offs1 = readCell();
804 cell_t offs2 = readCell();
805 __ movl(pri, Operand(frm, offs1));
806 __ movl(alt, Operand(frm, offs2));
813 Register reg = (op == OP_LREF_S_PRI) ? pri : alt;
814 cell_t offset = readCell();
815 __ movl(reg, Operand(frm, offset));
816 __ movl(reg, Operand(dat, reg, NoScale));
823 Register reg = (op == OP_CONST_PRI) ? pri : alt;
824 cell_t val = readCell();
832 Register reg = (op == OP_ADDR_PRI) ? pri : alt;
833 cell_t offset = readCell();
834 __ movl(reg, Operand(info, AMX_INFO_FRAME));
835 __ addl(reg, offset);
842 Register reg = (op == OP_STOR_PRI) ? pri : alt;
843 cell_t offset = readCell();
844 __ movl(Operand(dat, offset), reg);
851 Register reg = (op == OP_STOR_S_PRI) ? pri : alt;
852 cell_t offset = readCell();
853 __ movl(Operand(frm, offset), reg);
858 __ lea(pri, Operand(alt, pri, ScaleFour));
864 Register reg = (op == OP_SREF_S_PRI) ? pri : alt;
865 cell_t offset = readCell();
866 __ movl(tmp, Operand(frm, offset));
867 __ movl(Operand(dat, tmp, NoScale), reg);
874 Register reg = (op == OP_POP_PRI) ? pri : alt;
875 __ movl(reg, Operand(stk, 0));
883 Register reg = (op == OP_SWAP_PRI) ? pri : alt;
884 __ movl(tmp, Operand(stk, 0));
885 __ movl(Operand(stk, 0), reg);
891 __ lea(pri, Operand(alt, pri, ScaleFour));
892 __ movl(pri, Operand(dat, pri, NoScale));
897 cell_t val = readCell();
898 if (val >= 0 && val <= 3) {
899 __ lea(pri, Operand(alt, pri, Scale(val)));
904 emitCheckAddress(pri);
905 __ movl(pri, Operand(dat, pri, NoScale));
912 Register base = (op == OP_CONST) ? dat : frm;
913 cell_t offset = readCell();
914 cell_t val = readCell();
915 __ movl(Operand(base, offset), val);
920 emitCheckAddress(pri);
921 __ movl(pri, Operand(dat, pri, NoScale));
925 emitCheckAddress(alt);
926 __ movl(Operand(dat, alt, NoScale), pri);
932 Register dividend = (op == OP_SDIV) ? pri : alt;
933 Register divisor = (op == OP_SDIV) ? alt : pri;
935 // Guard against divide-by-zero.
936 __ testl(divisor, divisor);
937 __ j(zero, &error_divide_by_zero_);
939 // A more subtle case; -INT_MIN / -1 yields an overflow exception.
941 __ cmpl(divisor, -1);
942 __ j(not_equal, &ok);
943 __ cmpl(dividend, 0x80000000);
944 __ j(equal, &error_integer_overflow_);
947 // Now we can actually perform the divide.
948 __ movl(tmp, divisor);
950 __ movl(edx, dividend);
952 __ movl(eax, dividend);
960 cell_t val = readCell();
961 emitCheckAddress(pri);
962 __ movl(pri, Operand(dat, pri, NoScale));
966 __ andl(pri, 0xffff);
972 cell_t val = readCell();
973 emitCheckAddress(alt);
975 __ movb(Operand(dat, alt, NoScale), pri);
977 __ movw(Operand(dat, alt, NoScale), pri);
979 __ movl(Operand(dat, alt, NoScale), pri);
985 // Restore the old frame pointer.
986 __ movl(frm, Operand(stk, 4)); // get the old frm
987 __ addl(stk, 8); // pop stack
988 __ movl(Operand(info, AMX_INFO_FRAME), frm); // store back old frm
989 __ addl(frm, dat); // relocate
991 // Remove parameters.
992 __ movl(tmp, Operand(stk, 0));
993 __ lea(stk, Operand(stk, tmp, ScaleFour, 4));
1001 cell_t val = readCell();
1002 unsigned dwords = val / 4;
1003 unsigned bytes = val % 4;
1008 __ lea(esi, Operand(dat, pri, NoScale));
1009 __ lea(edi, Operand(dat, alt, NoScale));
1011 __ movl(ecx, dwords);
1015 __ movl(ecx, bytes);
1025 // eax/pri is used implicitly.
1026 unsigned dwords = readCell() / 4;
1028 __ lea(edi, Operand(dat, alt, NoScale));
1029 __ movl(ecx, dwords);
1036 case OP_STRADJUST_PRI:
1042 __ movl(pri, Operand(stk, 0));
1043 __ andl(pri, 0x7fffffff);
1048 if (MacroAssemblerX86::Features().sse2) {
1049 __ cvtsi2ss(xmm0, Operand(edi, 0));
1052 __ fild32(Operand(edi, 0));
1054 __ fstp32(Operand(esp, 0));
1064 if (MacroAssemblerX86::Features().sse2) {
1065 __ movss(xmm0, Operand(stk, 0));
1066 if (op == OP_FLOATADD)
1067 __ addss(xmm0, Operand(stk, 4));
1068 else if (op == OP_FLOATSUB)
1069 __ subss(xmm0, Operand(stk, 4));
1070 else if (op == OP_FLOATMUL)
1071 __ mulss(xmm0, Operand(stk, 4));
1072 else if (op == OP_FLOATDIV)
1073 __ divss(xmm0, Operand(stk, 4));
1077 __ fld32(Operand(stk, 0));
1079 if (op == OP_FLOATADD)
1080 __ fadd32(Operand(stk, 4));
1081 else if (op == OP_FLOATSUB)
1082 __ fsub32(Operand(stk, 4));
1083 else if (op == OP_FLOATMUL)
1084 __ fmul32(Operand(stk, 4));
1085 else if (op == OP_FLOATDIV)
1086 __ fdiv32(Operand(stk, 4));
1088 __ fstp32(Operand(esp, 0));
1094 case OP_RND_TO_NEAREST:
1096 if (MacroAssemblerX86::Features().sse) {
1097 // Assume no one is touching MXCSR.
1098 __ cvtss2si(pri, Operand(stk, 0));
1100 static float kRoundToNearest = 0.5f;
1101 // From http://wurstcaptures.untergrund.net/assembler_tricks.html#fastfloorf
1102 __ fld32(Operand(stk, 0));
1103 __ fadd32(st0, st0);
1104 __ fadd32(Operand(ExternalAddress(&kRoundToNearest)));
1106 __ fistp32(Operand(esp, 0));
1114 case OP_RND_TO_CEIL:
1116 static float kRoundToCeil = -0.5f;
1117 // From http://wurstcaptures.untergrund.net/assembler_tricks.html#fastfloorf
1118 __ fld32(Operand(stk, 0));
1119 __ fadd32(st0, st0);
1120 __ fsubr32(Operand(ExternalAddress(&kRoundToCeil)));
1122 __ fistp32(Operand(esp, 0));
1130 case OP_RND_TO_ZERO:
1131 if (MacroAssemblerX86::Features().sse) {
1132 __ cvttss2si(pri, Operand(stk, 0));
1134 __ fld32(Operand(stk, 0));
1136 __ fstcw(Operand(esp, 4));
1137 __ movl(Operand(esp, 0), 0xfff);
1138 __ fldcw(Operand(esp, 0));
1139 __ fistp32(Operand(esp, 0));
1141 __ fldcw(Operand(esp, 0));
1147 case OP_RND_TO_FLOOR:
1148 __ fld32(Operand(stk, 0));
1150 __ fstcw(Operand(esp, 4));
1151 __ movl(Operand(esp, 0), 0x7ff);
1152 __ fldcw(Operand(esp, 0));
1153 __ fistp32(Operand(esp, 0));
1155 __ fldcw(Operand(esp, 0));
1163 if (MacroAssemblerX86::Features().sse) {
1164 __ movss(xmm0, Operand(stk, 4));
1165 __ ucomiss(xmm0, Operand(stk, 0));
1167 __ fld32(Operand(stk, 0));
1168 __ fld32(Operand(stk, 4));
1188 cell_t amount = readCell();
1189 __ addl(stk, amount);
1192 // Check if the stack went beyond the stack top - usually a compiler error.
1193 __ cmpl(stk, intptr_t(plugin_->memory + plugin_->mem_size));
1194 __ j(not_below, &error_stack_min_);
1196 // Check if the stack is going to collide with the heap.
1197 __ movl(tmp, Operand(info, AMX_INFO_HEAP));
1198 __ lea(tmp, Operand(dat, ecx, NoScale, STACK_MARGIN));
1200 __ j(below, &error_stack_low_);
1207 cell_t amount = readCell();
1208 __ movl(alt, Operand(info, AMX_INFO_HEAP));
1209 __ addl(Operand(info, AMX_INFO_HEAP), amount);
1212 __ cmpl(Operand(info, AMX_INFO_HEAP), plugin_->data_size);
1213 __ j(below, &error_heap_min_);
1215 __ movl(tmp, Operand(info, AMX_INFO_HEAP));
1216 __ lea(tmp, Operand(dat, ecx, NoScale, STACK_MARGIN));
1218 __ j(above, &error_heap_low_);
1225 Label *target = labelAt(readCell());
1235 ConditionCode cc = (op == OP_JZER) ? zero : not_zero;
1236 Label *target = labelAt(readCell());
1251 Label *target = labelAt(readCell());
1254 ConditionCode cc = OpToCondition(op);
1260 case OP_TRACKER_PUSH_C:
1262 cell_t amount = readCell();
1267 __ movl(eax, Operand(info, AMX_INFO_CONTEXT));
1268 __ push(amount * 4);
1270 __ call(ExternalAddress((void *)PushTracker));
1273 __ j(not_zero, &extern_error_);
1280 case OP_TRACKER_POP_SETHEAP:
1286 // Get the context pointer and call the sanity checker.
1288 __ push(intptr_t(plugin_));
1289 __ call(ExternalAddress((void *)PopTrackerAndSetHeap));
1292 __ j(not_zero, &extern_error_);
1301 cell_t cip = uintptr_t(cip_ - 1) - uintptr_t(plugin_->pcode);
1302 __ movl(Operand(info, AMX_INFO_CIP), cip);
1308 __ movl(tmp, Operand(info, AMX_INFO_RETVAL));
1309 __ movl(Operand(ecx, 0), pri);
1310 __ movl(pri, readCell());
1311 __ jmp(&extern_error_);
1316 cell_t value = readCell();
1317 __ cmpl(eax, value);
1318 __ j(above, &error_bounds_);
1324 emitGenArray(op == OP_GENARRAY_Z);
1334 if (!emitNativeCall(op))
1345 size_t ncases = readCell();
1347 // Two cells per case, and one extra cell for the default address.
1348 cip_ += (ncases * 2) + 1;
1356 error_ = SP_ERROR_INVALID_INSTRUCTION;
1364 Compiler::labelAt(size_t offset)
1366 if (offset % 4 != 0 ||
1367 offset > plugin_->pcode_size ||
1368 offset <= pcode_start_)
1370 // If the jump target is misaligned, or out of pcode bounds, or is an
1371 // address out of the function bounds, we abort. Unfortunately we can't
1372 // test beyond the end of the function since we don't have a precursor
1374 error_ = SP_ERROR_INSTRUCTION_PARAM;
1378 return &jump_map_[offset / sizeof(cell_t)];
1382 Compiler::emitCheckAddress(Register reg)
1384 // Check if we're in memory bounds.
1385 __ cmpl(reg, plugin_->mem_size);
1386 __ j(not_below, &error_memaccess_);
1388 // Check if we're in the invalid region between hp and sp.
1390 __ cmpl(reg, Operand(info, AMX_INFO_HEAP));
1392 __ lea(tmp, Operand(dat, reg, NoScale));
1394 __ j(below, &error_memaccess_);
1399 Compiler::emitGenArray(bool autozero)
1401 cell_t val = readCell();
1404 // flat array; we can generate this without indirection tables.
1405 // Note that we can overwrite ALT because technically STACK should be destroying ALT
1406 __ movl(alt, Operand(info, AMX_INFO_HEAP));
1407 __ movl(tmp, Operand(stk, 0));
1408 __ movl(Operand(stk, 0), alt); // store base of the array into the stack.
1409 __ lea(alt, Operand(alt, tmp, ScaleFour));
1410 __ movl(Operand(info, AMX_INFO_HEAP), alt);
1413 __ j(not_below, &error_heap_low_);
1417 __ push(Operand(info, AMX_INFO_CONTEXT));
1418 __ call(ExternalAddress((void *)PushTracker));
1423 __ j(not_zero, &extern_error_);
1426 // Note - tmp is ecx and still intact.
1430 __ movl(edi, Operand(stk, 0));
1440 // int GenerateArray(sp_plugin_t, vars[], uint32_t, cell_t *, int, unsigned *);
1441 __ push(autozero ? 1 : 0);
1445 __ push(intptr_t(plugin_));
1446 __ call(ExternalAddress((void *)GenerateArray));
1447 __ addl(esp, 5 * sizeof(void *));
1449 // restore pri to tmp
1453 __ j(not_zero, &extern_error_);
1455 // Move tmp back to pri, remove pushed args.
1457 __ addl(stk, (val - 1) * 4);
1462 Compiler::emitCall()
1464 cell_t offset = readCell();
1466 // If this offset looks crappy, i.e. not aligned or out of bounds, we just
1468 if (offset % 4 != 0 || uint32_t(offset) >= plugin_->pcode_size) {
1469 error_ = SP_ERROR_INSTRUCTION_PARAM;
1475 __ movl(eax, Operand(info, AMX_INFO_CONTEXT));
1476 __ movl(ecx, Operand(eax, offsetof(sp_context_t, rp)));
1478 // Check if the return stack is used up.
1479 __ cmpl(ecx, SP_MAX_RETURN_STACK);
1480 __ j(not_below, &error_stack_low_);
1482 // Add to the return stack.
1483 uintptr_t cip = uintptr_t(cip_ - 2) - uintptr_t(plugin_->pcode);
1484 __ movl(Operand(eax, ecx, ScaleFour, offsetof(sp_context_t, rstk_cips)), cip);
1486 // Increment the return stack pointer.
1487 __ addl(Operand(eax, offsetof(sp_context_t, rp)), 1);
1489 // Store the CIP of the function we're about to call.
1490 __ movl(Operand(info, AMX_INFO_CIP), offset);
1492 JitFunction *fun = rt_->GetJittedFunctionByOffset(offset);
1494 // Need to emit a delayed thunk.
1495 CallThunk *thunk = new CallThunk(offset);
1496 __ call(&thunk->call);
1497 if (!thunks_.append(thunk))
1500 // Function is already emitted, we can do a direct call.
1501 __ call(ExternalAddress(fun->GetEntryAddress()));
1504 // Restore the last cip.
1505 __ movl(Operand(info, AMX_INFO_CIP), cip);
1507 // Mark us as leaving the last frame.
1508 __ movl(tmp, Operand(info, AMX_INFO_CONTEXT));
1509 __ subl(Operand(tmp, offsetof(sp_context_t, rp)), 1);
1514 Compiler::emitCallThunks()
1516 for (size_t i = 0; i < thunks_.length(); i++) {
1517 CallThunk *thunk = thunks_[i];
1520 __ bind(&thunk->call);
1521 // Huge hack - get the return address, since that is the call that we
1523 __ movl(eax, Operand(esp, 0));
1525 // Align the stack. Unfortunately this is a pretty careful dance based
1526 // on the number of words we push (4 args, 1 saved esp), and someday
1527 // we should look into automating this.
1529 __ andl(esp, 0xfffffff0);
1536 __ movl(Operand(esp, 0), esp);
1537 __ push(thunk->pcode_offset);
1538 __ push(intptr_t(rt_));
1539 __ call(ExternalAddress((void *)CompileFromThunk));
1540 __ movl(edx, Operand(esp, 8));
1541 __ movl(esp, Operand(esp, 16));
1543 __ j(not_zero, &error);
1548 __ movl(Operand(info, AMX_INFO_CIP), thunk->pcode_offset);
1549 __ jmp(g_Jit.GetUniversalReturn());
1554 Compiler::readCell()
1556 if (cip_ >= code_end_) {
1557 error_= SP_ERROR_INVALID_INSTRUCTION;
1564 Compiler::emitNativeCall(OPCODE op)
1566 uint32_t native_index = readCell();
1568 if (native_index >= plugin_->num_natives) {
1569 error_ = SP_ERROR_INSTRUCTION_PARAM;
1573 uint32_t num_params;
1574 if (op == OP_SYSREQ_N) {
1575 num_params = readCell();
1577 // See if we can get a replacement opcode. If we can, then recursively
1578 // call emitOp() to generate it. Note: it's important that we do this
1579 // before generating any code for the SYSREQ.N.
1580 unsigned replacement = rt_->GetNativeReplacement(native_index);
1581 if (replacement != OP_NOP)
1582 return emitOp((OPCODE)replacement);
1584 // Store the number of parameters.
1585 __ movl(Operand(stk, -4), num_params);
1592 // Push the parameters for the C++ function.
1594 __ push(native_index);
1596 // Relocate all our absolute junk to be dat-relative, and store it all back
1597 // into the context.
1598 __ movl(eax, Operand(info, AMX_INFO_CONTEXT));
1599 __ movl(ecx, Operand(info, AMX_INFO_HEAP));
1600 __ movl(Operand(eax, offsetof(sp_context_t, hp)), ecx);
1602 __ movl(Operand(eax, offsetof(sp_context_t, sp)), stk);
1603 __ movl(ecx, Operand(info, AMX_INFO_FRAME));
1604 __ movl(Operand(eax, offsetof(sp_context_t, frm)), ecx);
1606 // Push context and make the call.
1608 __ call(ExternalAddress((void *)NativeCallback));
1610 // Check for errors.
1611 __ movl(ecx, Operand(info, AMX_INFO_CONTEXT));
1612 __ movl(ecx, Operand(ecx, offsetof(sp_context_t, n_err)));
1614 __ j(not_zero, &extern_error_);
1616 // Restore local state.
1621 if (op == OP_SYSREQ_N) {
1622 // Pop the stack. Do not check the margins.
1623 __ addl(stk, (num_params + 1) * sizeof(cell_t));
1629 Compiler::emitSwitch()
1631 cell_t offset = readCell();
1632 if (!labelAt(offset))
1635 cell_t *tbl = (cell_t *)((char *)plugin_->pcode + offset + sizeof(cell_t));
1642 size_t ncases = *tbl++;
1644 Label *defaultCase = labelAt(*tbl);
1648 // Degenerate - 0 cases.
1650 __ jmp(defaultCase);
1654 Entry *cases = (Entry *)(tbl + 1);
1656 // Degenerate - 1 case.
1658 Label *maybe = labelAt(cases[0].offset);
1661 __ cmpl(pri, cases[0].val);
1663 __ jmp(defaultCase);
1667 // We have two or more cases, so let's generate a full switch. Decide
1668 // whether we'll make an if chain, or a jump table, based on whether
1669 // the numbers are strictly sequential.
1670 bool sequential = true;
1672 cell_t first = cases[0].val;
1673 cell_t last = first;
1674 for (size_t i = 1; i < ncases; i++) {
1675 if (cases[i].val != ++last) {
1682 // First check whether the bounds are correct: if (a < LOW || a > HIGH);
1683 // this check is valid whether or not we emit a sequential-optimized switch.
1684 cell_t low = cases[0].val;
1686 // negate it so we'll get a lower bound of 0.
1688 __ lea(tmp, Operand(pri, low));
1693 cell_t high = abs(cases[0].val - cases[ncases - 1].val);
1695 __ j(above, defaultCase);
1698 // Optimized table version. The tomfoolery below is because we only have
1699 // one free register... it seems unlikely pri or alt will be used given
1700 // that we're at the end of a control-flow point, but we'll play it safe.
1703 __ movl(eax, &table);
1704 __ movl(ecx, Operand(eax, ecx, ScaleFour));
1709 for (size_t i = 0; i < ncases; i++) {
1710 Label *label = labelAt(cases[i].offset);
1713 __ emit_absolute_address(label);
1716 // Slower version. Go through each case and generate a check.
1717 for (size_t i = 0; i < ncases; i++) {
1718 Label *label = labelAt(cases[i].offset);
1721 __ cmpl(pri, cases[i].val);
1724 __ jmp(defaultCase);
1730 Compiler::emitErrorPath(Label *dest, int code)
1735 __ jmp(g_Jit.GetUniversalReturn());
1740 Compiler::emitErrorPaths()
1742 emitErrorPath(&error_divide_by_zero_, SP_ERROR_DIVIDE_BY_ZERO);
1743 emitErrorPath(&error_stack_low_, SP_ERROR_STACKLOW);
1744 emitErrorPath(&error_stack_min_, SP_ERROR_STACKMIN);
1745 emitErrorPath(&error_bounds_, SP_ERROR_ARRAY_BOUNDS);
1746 emitErrorPath(&error_memaccess_, SP_ERROR_MEMACCESS);
1747 emitErrorPath(&error_heap_low_, SP_ERROR_HEAPLOW);
1748 emitErrorPath(&error_heap_min_, SP_ERROR_HEAPMIN);
1749 emitErrorPath(&error_integer_overflow_, SP_ERROR_INTEGER_OVERFLOW);
1751 if (extern_error_.used()) {
1752 __ bind(&extern_error_);
1753 __ movl(eax, Operand(info, AMX_INFO_CONTEXT));
1754 __ movl(eax, Operand(eax, offsetof(sp_context_t, n_err)));
1755 __ jmp(g_Jit.GetUniversalReturn());
1760 GenerateEntry(void **retp)
1764 // Variables we're passed in:
1765 // InfoVars *vars, void *entry, uint8_t *memory
1774 __ movl(esi, Operand(ebp, 8 + 4 * 0));
1775 __ movl(ecx, Operand(ebp, 8 + 4 * 1));
1776 __ movl(eax, Operand(ebp, 8 + 4 * 2));
1777 __ movl(edx, Operand(esi, AMX_INFO_CONTEXT));
1779 // Set up run-time registers.
1780 __ movl(edi, Operand(edx, offsetof(sp_context_t, sp)));
1784 __ movl(Operand(esi, AMX_INFO_NSTACK), esp);
1787 __ andl(esp, 0xfffffff0);
1789 // Call into plugin (align the stack first).
1792 __ movl(ecx, Operand(info, AMX_INFO_RETVAL));
1793 __ movl(Operand(ecx, 0), pri);
1794 __ movl(eax, SP_ERROR_NONE);
1796 // If stuff goes wrong, it'll jump directly to here.
1799 __ movl(esp, Operand(info, AMX_INFO_NSTACK));
1800 __ movl(ecx, Operand(info, AMX_INFO_CONTEXT));
1802 __ movl(Operand(ecx, offsetof(sp_context_t, sp)), stk);
1810 void *code = LinkCode(masm);
1814 *retp = reinterpret_cast<uint8_t *>(code) + error.offset();
1818 ICompilation *JITX86::ApplyOptions(ICompilation *_IN, ICompilation *_OUT)
1823 CompData *_in = (CompData * )_IN;
1824 CompData *_out = (CompData * )_OUT;
1826 _in->inline_level = _out->inline_level;
1827 _in->profile = _out->profile;
1838 bool JITX86::InitializeJIT()
1840 g_pCodeCache = KE_CreateCodeCache();
1842 m_pJitEntry = GenerateEntry(&m_pJitReturn);
1846 MacroAssemblerX86 masm;
1847 MacroAssemblerX86::GenerateFeatureDetection(masm);
1848 void *code = LinkCode(masm);
1851 MacroAssemblerX86::RunFeatureDetection(code);
1852 KE_FreeCode(g_pCodeCache, code);
1858 JITX86::ShutdownJIT()
1860 KE_DestroyCodeCache(g_pCodeCache);
1864 JITX86::CompileFunction(BaseRuntime *prt, cell_t pcode_offs, int *err)
1866 Compiler cc(prt, pcode_offs);
1867 JitFunction *fun = cc.emit(err);
1870 prt->AddJittedFunction(fun);
1875 JITX86::SetupContextVars(BaseRuntime *runtime, BaseContext *pCtx, sp_context_t *ctx)
1877 tracker_t *trk = new tracker_t;
1879 ctx->vm[JITVARS_TRACKER] = trk;
1880 ctx->vm[JITVARS_BASECTX] = pCtx; /* GetDefaultContext() is not constructed yet */
1881 ctx->vm[JITVARS_PROFILER] = g_engine2.GetProfiler();
1882 ctx->vm[JITVARS_PLUGIN] = const_cast<sp_plugin_t *>(runtime->plugin());
1884 trk->pBase = (ucell_t *)malloc(1024);
1885 trk->pCur = trk->pBase;
1886 trk->size = 1024 / sizeof(cell_t);
1890 JITX86::CreateFakeNative(SPVM_FAKENATIVE_FUNC callback, void *pData)
1897 __ movl(edi, Operand(esp, 16)); // store ctx
1898 __ movl(esi, Operand(esp, 20)); // store params
1900 __ andl(esp, 0xfffffff0);
1903 __ push(intptr_t(pData));
1906 __ call(ExternalAddress((void *)callback));
1913 return (SPVM_NATIVE_FUNC)LinkCode(masm);
1916 void JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func)
1918 KE_FreeCode(g_pCodeCache, (void *)func);
1921 ICompilation *JITX86::StartCompilation()
1923 return new CompData;
1926 ICompilation *JITX86::StartCompilation(BaseRuntime *runtime)
1928 return new CompData;
1931 void CompData::Abort()
1936 void JITX86::FreeContextVars(sp_context_t *ctx)
1938 free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase);
1939 delete (tracker_t *)ctx->vm[JITVARS_TRACKER];
1942 bool CompData::SetOption(const char *key, const char *val)
1944 if (strcmp(key, SP_JITCONF_DEBUG) == 0)
1946 if (strcmp(key, SP_JITCONF_PROFILE) == 0) {
1947 profile = atoi(val);
1949 /** Callbacks must be profiled to profile functions! */
1950 if ((profile & SP_PROF_FUNCTIONS) == SP_PROF_FUNCTIONS)
1951 profile |= SP_PROF_CALLBACKS;
1959 typedef int (*JIT_EXECUTE)(InfoVars *vars, void *addr, uint8_t *memory);
1960 int JITX86::InvokeFunction(BaseRuntime *runtime, JitFunction *fn, cell_t *result)
1967 ctx = runtime->GetBaseContext()->GetCtx();
1973 vars.cip = fn->GetPCodeAddress();
1974 /* vars.esp will be set in the entry code */
1976 pfn = (JIT_EXECUTE)m_pJitEntry;
1977 err = pfn(&vars, fn->GetEntryAddress(), runtime->plugin()->memory);
1980 ctx->err_cip = vars.cip;
1985 void *JITX86::AllocCode(size_t size)
1987 return Knight::KE_AllocCode(g_pCodeCache, size);
1990 void JITX86::FreeCode(void *code)
1992 KE_FreeCode(g_pCodeCache, code);