Added support for ISourcePawnEngine natives.
1 /* vim: set ts=4 sw=4 tw=99 et:
3 * Copyright (C) 2012 David Anderson
5 * This file is part of JITCraft.
7 * JITCraft is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License as published by the Free
9 * Software Foundation, either version 3 of the License, or (at your option)
12 * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY
13 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along with
17 * JITCraft. If not, see http://www.gnu.org/licenses/.
19 #include "Interpreter.h"
24 #include "Reference.h"
29 #define PUSH_I32(top, value) \
31 top.sp->i32 = value; \
35 #define PUSH_F(top, value) \
44 int value = top.sp[-1].i32;
52 float value = top.sp[-1].f;
58 PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
60 Reference *ref = Reference::NewStack(zone, location, tenure);
69 CheckDimensionSize(int size, unsigned width)
75 // One word, because we hide stuff below and need to add that in.
76 if (unsigned(size) >= (INT_MAX / width) - sizeof(unsigned)) {
83 // Generate an array with completely static sizes.
85 GenerateArray(Zone *zone, Handle<ArrayMap> map)
87 assert(map->type()->elements() != -1);
89 Local<Array> array(zone, Array::New(zone, map, map->type()->elements(), Heap::Tenure_Stack));
93 if (map->type()->levels() == 1)
96 Local<ArrayMap> contained(zone, map->contained());
97 Local<Array> sub(zone);
98 for (unsigned i = 0; i < unsigned(map->type()->elements()); i++) {
99 sub = GenerateArray(zone, contained);
102 array->writeObject(zone, i, sub);
109 CopyArray(Zone *zone, Array *source, Array *dest)
111 assert(source->type()->levels() == 1);
112 assert(dest->type()->levels() == 1);
113 assert(source->type()->contained()->primitive() ==
114 dest->type()->contained()->primitive());
115 assert(source->nelements() >= dest->nelements());
116 assert(dest->elementSize() == source->elementSize());
118 memcpy(source->vec(), dest->vec(), dest->nelements() * dest->elementSize());
123 InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
128 if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
131 intptr_t *cells = guard.args();
133 // params[0] == argc, in ISPE
136 // Pass the formal arguments.
137 Local<Type> type(zone, native->type());
138 Local<Type> param(zone);
139 for (unsigned i = 0; i < type->parameters()->length(); i++) {
140 param = type->parameterAt(i);
142 // For floats, we rely on the aliasing of |i32| and |f|.
143 LocalSlot &arg = args[-int(i) - 1];
144 if (param->isInt32() || param->isFloat()) {
145 cells[i + 1] = arg.i32;
146 } else if (param->isReference()) {
147 cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
149 assert(param->isArray());
150 cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
154 // For variadic arguments, the compiler left either arrays or references.
155 for (unsigned i = type->parameters()->length(); i < argc; i++) {
156 LocalSlot &arg = args[-int(i) - 1];
158 if (arg.obj->is(MapKind_Reference)) {
159 cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
161 assert(arg.obj->is(MapKind_Array));
162 cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
166 typedef intptr_t (*INVOKE)(void *, intptr_t *);
167 INVOKE invoke = (INVOKE)native->function();
168 *result = invoke(identity, cells);
170 // :TODO: detect errors.
175 ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
177 Top &top = *zone->stack().top();
178 LocalSlot *locals = entryFrame->locals();
181 Opcode op = Opcode(*top.pc);
188 PUSH_I32(top, READ_INT32(top.pc));
192 PUSH_F(top, READ_FLOAT(top.pc));
201 zone->stack().popInlineFrame();
202 locals = top.fp->locals();
204 top.pc += OpcodeInfo[*top.pc].length;
208 #define RELATIONAL_JUMP(op) \
210 int right = POP_I32(top); \
211 int left = POP_I32(top); \
212 if (left op right) { \
213 top.pc += READ_INT32(top.pc); \
244 int value = POP_I32(top);
246 top.pc += READ_INT32(top.pc);
254 int value = POP_I32(top);
256 top.pc += READ_INT32(top.pc);
263 top.pc += READ_INT32(top.pc);
268 int slot = READ_INT32(top.pc);
269 *top.sp++ = locals[slot];
275 int slot = READ_INT32(top.pc);
276 locals[slot] = top.sp[-1];
282 int right = POP_I32(top);
283 int left = POP_I32(top);
284 int result = left + right;
285 PUSH_I32(top, result);
291 int right = POP_I32(top);
292 int left = POP_I32(top);
293 int result = left - right;
294 PUSH_I32(top, result);
300 int right = POP_I32(top);
301 int left = POP_I32(top);
302 int result = left * right;
303 PUSH_I32(top, result);
309 int right = POP_I32(top);
310 int left = POP_I32(top);
313 int result = left / right;
314 PUSH_I32(top, result);
320 float right = POP_F(top);
321 float left = POP_F(top);
322 float result = left + right;
329 float right = POP_F(top);
330 float left = POP_F(top);
331 float result = left - right;
338 float right = POP_F(top);
339 float left = POP_F(top);
340 float result = left * right;
347 float right = POP_F(top);
348 float left = POP_F(top);
351 float result = left / right;
358 int right = POP_I32(top);
359 int left = POP_I32(top);
360 int result = left << right;
361 PUSH_I32(top, result);
367 int right = POP_I32(top);
368 int left = POP_I32(top);
369 int result = left >> right;
370 PUSH_I32(top, result);
376 int right = POP_I32(top);
377 int left = POP_I32(top);
378 int result = unsigned(left) >> unsigned(right);
379 PUSH_I32(top, result);
385 int right = POP_I32(top);
386 int left = POP_I32(top);
387 int result = left & right;
388 PUSH_I32(top, result);
394 int right = POP_I32(top);
395 int left = POP_I32(top);
396 int result = left | right;
397 PUSH_I32(top, result);
403 int right = POP_I32(top);
404 int left = POP_I32(top);
405 int result = left ^ right;
406 PUSH_I32(top, result);
420 zone->heap().reclaim();
421 unsigned index = READ_UINT32(top.pc);
422 Local<Function> newFun(zone, top.fp->code()->module()->getFunction(index));
423 if (!zone->stack().pushInlineFrame(newFun)) {
428 locals = top.fp->locals();
434 unsigned slot = READ_UINT32(top.pc);
435 *top.sp++ = top.fp->arg(slot);
441 unsigned slot = READ_UINT32(top.pc);
442 top.fp->arg(slot) = *--top.sp;
448 Array *array = top.sp[-2].array;
449 int index = top.sp[-1].i32;
450 if (index < 0 || unsigned(index) >= array->nelements())
457 Array *array = top.sp[-2].array;
458 int index = top.sp[-1].i32;
459 top.sp[-2].i32 = array->readInt32(index);
466 Array *array = top.sp[-2].array;
467 int index = top.sp[-1].i32;
468 top.sp[-2].f = array->readFloat(index);
475 Array *array = top.sp[-2].array;
476 int index = top.sp[-1].i32;
477 top.sp[-2].i32 = array->readChar(index);
484 Array *array = top.sp[-3].array;
485 int index = top.sp[-2].i32;
486 array->writeInt32(index, top.sp[-1].i32);
487 top.sp[-3] = top.sp[-1];
494 Array *array = top.sp[-3].array;
495 int index = top.sp[-2].i32;
496 array->writeFloat(index, top.sp[-1].f);
497 top.sp[-3] = top.sp[-1];
504 Array *array = top.sp[-3].array;
505 int index = top.sp[-2].i32;
506 array->writeChar(index, top.sp[-1].i32);
507 top.sp[-3] = top.sp[-1];
514 Array *array = top.sp[-2].array;
515 int index = top.sp[-1].i32;
516 top.sp[-2].array = Array::cast(array->readObject(index));
523 int ival = POP_I32(top);
524 float fval = (float)ival;
529 case OP_NEWARRAY_LIFO:
531 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc))));
532 Array *array = GenerateArray(zone, map);
544 unsigned slot = READ_UINT32(top.pc);
545 locals[slot].address = zone->heap().lifoPosition();
551 unsigned slot = READ_UINT32(top.pc);
552 zone->heap().unwindLifo(locals[slot].address);
558 unsigned slot = READ_UINT32(top.pc);
559 if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack)) {
568 unsigned slot = READ_UINT32(top.pc);
569 if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack)) {
576 case OP_ARRAYREF_LIFO:
578 Local<Array> array(zone, top.sp[-2].array);
579 Local<Reference> ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack));
584 top.sp[-2].ref = ref;
589 case OP_SLOTREF_LIFO:
591 Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
596 top.sp[-1].ref = ref;
602 top.sp[-1].i32 = top.sp[-1].ref->getInt();
608 top.sp[-2].ref->setInt(top.sp[-1].i32);
609 top.sp[-2].i32 = top.sp[-1].i32;
616 top.sp[-1].f = top.sp[-1].ref->getFloat();
622 top.sp[-2].ref->setFloat(top.sp[-1].f);
623 top.sp[-2].f = top.sp[-1].f;
629 top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
636 // Note for this assignment opcode, we return the left-hand side, not the
637 // right, since in this case the result of the expression could be different.
638 if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array)) {
649 top.sp[-1] = top.sp[-2];
656 top.sp[-2] = top.sp[-4];
657 top.sp[-1] = top.sp[-3];
663 LocalSlot slot = top.sp[-2];
664 top.sp[-2] = top.sp[-1];
671 LocalSlot slot = top.sp[-3];
672 top.sp[-3] = top.sp[-2];
673 top.sp[-2] = top.sp[-1];
681 top.sp[-1] = top.sp[-3];
688 top.sp[-1] = top.sp[-4];
694 unsigned index = READ_UINT32(top.pc);
695 unsigned argc = READ_UINT32(top.pc + 4);
697 Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
698 if (!native->function()) {
705 void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
706 if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result)) {
712 PUSH_I32(top, result);
722 top.pc += OpcodeInfo[op].length;