Added support for bitwise operators.
2 * Copyright (C) 2012 David Anderson
4 * This file is part of JITCraft.
6 * JITCraft is free software: you can redistribute it and/or modify it under
7 * the terms of the GNU General Public License as published by the Free
8 * Software Foundation, either version 3 of the License, or (at your option)
11 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * JITCraft. If not, see http://www.gnu.org/licenses/.
18 #include "Interpreter.h"
25 #define PUSH_I32(top, value) \
27 top.sp->i32 = value; \
31 #define PUSH_F(top, value) \
40 int value = top.sp[-1].i32;
48 float value = top.sp[-1].f;
54 CheckDimensionSize(int size, unsigned width)
60 // One word, because we hide stuff below and need to add that in.
61 if (unsigned(size) >= (INT_MAX / width) - sizeof(unsigned)) {
76 // Unlike the old SourcePawn VM, we do not allocate the final levels in one
77 // contiguous block. This might result in different cache behavior, but who
78 // knows. This algorithm is simpler and faster.
80 // In pawn, an array reference a[b][c]
84 // That is, when hopping to the next array, the slot is relative to the
85 // current address, not absolute.
88 GenerateIndirectionVectors(const ArrayBuilder &builder, unsigned cursor, unsigned level)
90 unsigned current = cursor;
92 // Reserve space for this level.
93 cursor += builder.dims[level] *
94 ((level == builder.ndims - 1) ? builder.width : sizeof(unsigned));
96 // If we're at the last level, we're done.
97 if (level == builder.ndims - 1)
100 for (unsigned i = 0; i < unsigned(builder.dims[level]); i++) {
101 // Hide the number of elements in the next vector, right behind it.
102 *reinterpret_cast<unsigned *>(builder.base + cursor) = builder.dims[level + 1];
103 cursor += sizeof(unsigned);
105 // The next hop will be generated at |cursor|, which will be read from |current|.
106 *reinterpret_cast<unsigned *>(builder.base + current) = cursor - current;
108 cursor = GenerateIndirectionVectors(builder, cursor, level + 1);
109 current += sizeof(unsigned);
116 jc::AllocateUnsafeArray(unsigned width, unsigned ndims, int *dims)
119 if (!CheckDimensionSize(dims[ndims - 1], width))
122 // All innermost vectors must be this size.
123 size_t nbytes = dims[ndims - 1] * width + sizeof(unsigned);
126 // Fast path, no complicated indirection vectors.
127 unsigned *ptr = (unsigned *)ZONE()->unsafeStack().allocate(nbytes);
130 memset(ptr, 0, nbytes);
134 UnsafeArray *array = reinterpret_cast<UnsafeArray *>(ptr + 1);
138 // Add space from the innermost indrect array to the outermost. Each time,
139 // we must also add space for the indirection slots.
140 for (unsigned i = ndims - 2; i < ndims; i--) {
141 if (!CheckDimensionSize(dims[ndims - 1], sizeof(unsigned) * 2))
144 if (!IsUint32MultiplySafe(nbytes, dims[i])) {
151 // Add space for the indirection vectors at this level.
152 if (!IsUint32AddSafe(nbytes, dims[i] * sizeof(unsigned) + sizeof(unsigned))) {
157 // Reserve space for each indirection vector.
158 nbytes += dims[i] * sizeof(unsigned);
160 // Reserve space for our own indirection vector.
161 nbytes += sizeof(unsigned);
164 void *base = ZONE()->unsafeStack().allocate(nbytes);
167 memset(base, 0, nbytes);
170 array.base = (char *)base;
177 // Hide the length behind the array.
178 *reinterpret_cast<unsigned *>(array.base + cursor) = dims[0];
179 cursor += sizeof(unsigned);
181 cursor = GenerateIndirectionVectors(array, cursor, 0);
182 assert(cursor == nbytes);
184 return reinterpret_cast<UnsafeArray *>(reinterpret_cast<unsigned *>(base) + 1);
188 jc::Interpret(Frame *frame, LocalSlot *result)
190 Top &top = *ZONE()->stack().top();
191 LocalSlot *locals = frame->locals();
194 Opcode op = Opcode(*top.pc);
201 PUSH_I32(top, READ_INT32(top.pc));
205 PUSH_F(top, READ_FLOAT(top.pc));
214 frame = ZONE()->stack().popFrame(frame);
215 locals = frame->locals();
217 top.pc += OpcodeInfo[*top.pc].length;
221 #define RELATIONAL_JUMP(op) \
223 int right = POP_I32(top); \
224 int left = POP_I32(top); \
225 if (left op right) { \
226 top.pc += READ_INT32(top.pc); \
257 int value = POP_I32(top);
259 top.pc += READ_INT32(top.pc);
267 int value = POP_I32(top);
269 top.pc += READ_INT32(top.pc);
276 top.pc += READ_INT32(top.pc);
281 int slot = READ_INT32(top.pc);
282 *top.sp++ = locals[slot];
288 int slot = READ_INT32(top.pc);
289 locals[slot] = top.sp[-1];
295 int right = POP_I32(top);
296 int left = POP_I32(top);
297 int result = left + right;
298 PUSH_I32(top, result);
304 int right = POP_I32(top);
305 int left = POP_I32(top);
306 int result = left - right;
307 PUSH_I32(top, result);
313 int right = POP_I32(top);
314 int left = POP_I32(top);
315 int result = left * right;
316 PUSH_I32(top, result);
322 int right = POP_I32(top);
323 int left = POP_I32(top);
326 int result = left / right;
327 PUSH_I32(top, result);
333 float right = POP_F(top);
334 float left = POP_F(top);
335 float result = left + right;
342 float right = POP_F(top);
343 float left = POP_F(top);
344 float result = left - right;
351 float right = POP_F(top);
352 float left = POP_F(top);
353 float result = left * right;
360 float right = POP_F(top);
361 float left = POP_F(top);
364 float result = left / right;
371 int right = POP_I32(top);
372 int left = POP_I32(top);
373 int result = left << right;
374 PUSH_I32(top, result);
380 int right = POP_I32(top);
381 int left = POP_I32(top);
382 int result = left >> right;
383 PUSH_I32(top, result);
389 int right = POP_I32(top);
390 int left = POP_I32(top);
391 int result = unsigned(left) >> unsigned(right);
392 PUSH_I32(top, result);
398 int right = POP_I32(top);
399 int left = POP_I32(top);
400 int result = left & right;
401 PUSH_I32(top, result);
407 int right = POP_I32(top);
408 int left = POP_I32(top);
409 int result = left | right;
410 PUSH_I32(top, result);
416 int right = POP_I32(top);
417 int left = POP_I32(top);
418 int result = left ^ right;
419 PUSH_I32(top, result);
433 unsigned argc = READ_UINT32(top.pc);
434 unsigned index = READ_UINT32(top.pc + 4);
435 Code *newCode = frame->code()->module()->getFunction(index);
436 frame = ZONE()->stack().pushFrame(frame, newCode);
438 assert(newCode->nargs() == argc);
440 locals = frame->locals();
446 unsigned slot = READ_UINT32(top.pc);
447 *top.sp++ = frame->arg(slot);
453 unsigned slot = READ_UINT32(top.pc);
454 frame->arg(slot) = *--top.sp;
460 unsigned width = top.pc[1];
461 unsigned ndims = top.pc[2];
462 UnsafeArray *ptr = AllocateUnsafeArray(width, ndims, reinterpret_cast<int *>(top.pc + 3));
466 top.sp->unsafeArray = ptr;
468 top.pc += 3 + ndims * sizeof(int);
474 UnsafeArray *array = top.sp[-2].unsafeArray;
475 int index = top.sp[-1].i32;
476 if (index < 0 || unsigned(index) >= array->length())
483 UnsafeArray *array = top.sp[-2].unsafeArray;
484 int index = top.sp[-1].i32;
485 top.sp[-2].i32 = array->readInt32(index);
492 UnsafeArray *array = top.sp[-2].unsafeArray;
493 int index = top.sp[-1].i32;
494 top.sp[-2].f = array->readFloat(index);
501 UnsafeArray *array = top.sp[-3].unsafeArray;
502 int index = top.sp[-2].i32;
503 array->writeInt32(index, top.sp[-1].i32);
504 top.sp[-3] = top.sp[-1];
511 UnsafeArray *array = top.sp[-3].unsafeArray;
512 int index = top.sp[-2].i32;
513 array->writeFloat(index, top.sp[-1].f);
514 top.sp[-3] = top.sp[-1];
521 UnsafeArray *array = top.sp[-2].unsafeArray;
522 int index = top.sp[-1].i32;
523 top.sp[-2].unsafeArray = array->indirect(index);
530 int ival = POP_I32(top);
531 float fval = (float)ival;
542 top.pc += OpcodeInfo[op].length;