Fix warnings when building with clang.
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/.
20 #include "Interpreter.h"
25 #include "Reference.h"
27 #include "Environments.h"
28 #include "Structures.h"
29 #include "NativeTable.h"
35 #define PUSH_I32(top, value) \
37 top.sp->i32 = value; \
41 #define PUSH_F(top, value) \
50 int value = top.sp[-1].i32;
58 float value = top.sp[-1].f;
63 // Pawn's original semantics specify some kind of floor operation, so
64 // (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
65 // the upstream algorithm when constant folding. However the SourcePawn 1 JIT
66 // does not. My guess is that Borja freaked out seeing the 13-instruction x86
67 // sequence necessary to get this functionality (I vaguely recall a thread
68 // where we discussed this with Mark Peter? But the ITB forums are gone...),
69 // and we just decided to break the damn thing. So SP1 was inconsistent, but
70 // we are not. And for completeness, we assert that the C compiler does the
71 // right thing, since C89 leaves it unspecified.
72 STATIC_ASSERT(8 / -3 == -2);
73 STATIC_ASSERT(-8 / 3 == -2);
76 PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
78 Reference *ref = Reference::NewStack(zone, location, tenure);
87 GetElement(Array *array, int index, LocalSlot *vp)
89 if (array->type()->contained()->isTraceable()) {
90 vp->obj = array->readObject(index);
94 switch (array->type()->contained()->pod()) {
95 case PrimitiveType_Float:
96 vp->f = array->readFloat(index);
99 case PrimitiveType_Char:
100 vp->i32 = array->readChar(index);
104 assert(array->type()->contained()->pod() == PrimitiveType_Int32);
105 vp->i32 = array->readInt32(index);
111 SetElement(Zone *zone, Array *array, int index, const LocalSlot &v)
113 if (array->type()->contained()->isTraceable()) {
114 array->writeObject(zone, index, v.obj);
118 switch (array->type()->contained()->pod()) {
119 case PrimitiveType_Float:
120 array->writeFloat(index, v.f);
123 case PrimitiveType_Char:
124 array->writeChar(index, v.i32);
128 assert(array->type()->contained()->pod() == PrimitiveType_Int32);
129 array->writeInt32(index, v.i32);
135 FetchField(Struct *obj, Descriptor *desc, LocalSlot *vp)
137 // :TODO: assert no GC.
138 if (desc->type()->isTraceable()) {
139 vp->obj = obj->get<Object *>(desc);
143 switch (desc->type()->pod()) {
144 case PrimitiveType_Float:
145 vp->f = obj->get<float>(desc);
149 assert(desc->type()->pod() == PrimitiveType_Int32);
150 vp->i32 = obj->get<int>(desc);
156 GetField(Struct *obj, unsigned index, LocalSlot *vp)
158 StructType *type = StructType::cast(obj->map()->type());
159 Descriptor *desc = Descriptor::cast(type->fields()->at(index));
160 FetchField(obj, desc, vp);
164 GetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot *vp)
166 Local<StructType> type(zone, StructType::cast(obj->map()->type()));
167 Local<Descriptor> desc(zone, type->lookupField(name, NULL));
168 FetchField(obj, desc, vp);
172 StoreField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v)
174 // :TODO: assert no GC.
175 if (desc->type()->isTraceable()) {
176 obj->set(zone, desc, v.obj);
180 switch (desc->type()->pod()) {
181 case PrimitiveType_Float:
182 obj->set<float>(desc, v.f);
186 assert(desc->type()->pod() == PrimitiveType_Int32);
187 obj->set<int>(desc, v.i32);
193 SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
195 StructType *type = StructType::cast(obj->map()->type());
196 Descriptor *desc = Descriptor::cast(type->fields()->at(index));
197 StoreField(zone, obj, desc, v);
201 SetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot &v)
203 Local<StructType> type(zone, StructType::cast(obj->map()->type()));
204 Local<Descriptor> desc(zone, type->lookupField(name, NULL));
205 StoreField(zone, obj, desc, v);
209 InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
214 void *address = zone->nativeTable()->address(native->index());
216 Local<String> name(zone, zone->nativeTable()->name(native->index()));
217 zone->reportError(Message_NativeNotBound, name->chars());
221 if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
224 intptr_t *cells = guard.args();
226 // params[0] == argc, in ISPE
229 // Pass the formal arguments.
230 Local<FunctionType> type(zone, native->type());
231 Local<Type> param(zone);
232 for (unsigned i = 0; i < type->parameters()->length(); i++) {
233 param = type->parameterAt(i);
235 // For floats, we rely on the aliasing of |i32| and |f|.
236 LocalSlot &arg = args[-int(i) - 1];
237 if (param->isInt32() || param->isFloat()) {
238 cells[i + 1] = arg.i32;
239 } else if (param->isReference()) {
240 cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
242 assert(param->isArray());
243 cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
247 // For variadic arguments, the compiler left either arrays or references.
248 for (unsigned i = type->parameters()->length(); i < argc; i++) {
249 LocalSlot &arg = args[-int(i) - 1];
251 if (arg.obj->is(MapKind_Reference)) {
252 cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
254 assert(arg.obj->is(MapKind_Array));
255 cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
259 typedef intptr_t (*INVOKE)(void *, intptr_t *);
260 INVOKE invoke = (INVOKE)address;
261 *result = invoke(identity, cells);
263 return !zone->hasPendingException();
267 ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
269 Top &top = *zone->stack().top();
273 LocalSlot *locals = entryFrame->locals();
276 Opcode op = Opcode(*top.pc);
278 if (OpcodeInfo[op].nuses > 0)
279 assert(top.sp - OpcodeInfo[op].nuses >= top.fp->stackBase());
287 PUSH_I32(top, READ_INT32(top.pc));
291 PUSH_F(top, READ_FLOAT(top.pc));
301 if (top.fp == entryFrame)
305 zone->stack().popInlineFrame();
306 locals = top.fp->locals();
311 top.pc += OpcodeInfo[*top.pc].length;
323 int value = POP_I32(top);
325 top.pc += READ_INT32(top.pc);
333 int value = POP_I32(top);
335 top.pc += READ_INT32(top.pc);
343 top.pc += READ_INT32(top.pc);
350 top.fp->leaveLoop(zone);
351 top.pc += READ_INT32(top.pc);
357 unsigned slot = READ_UINT32(top.pc);
358 assert(slot < top.fp->code()->nlocals());
359 *top.sp++ = locals[slot];
365 unsigned slot = READ_UINT32(top.pc);
366 assert(slot < top.fp->code()->nlocals());
367 locals[slot] = top.sp[-1];
373 top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
380 top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
387 top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
394 if (top.sp[-1].i32 == 0) {
395 zone->reportError(Message_IntegerDivideByZero);
398 top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
405 if (top.sp[-1].i32 == 0) {
406 zone->reportError(Message_IntegerDivideByZero);
409 top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
416 top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
423 top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
430 top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
437 top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
444 top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
451 top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
458 top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
465 top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
472 top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
479 top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
486 top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
493 top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
500 top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
507 top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
514 top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
521 top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
528 top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
535 top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
542 top.sp[-2].i32 = unsigned(top.sp[-2].i32) >> unsigned(top.sp[-1].i32);
549 top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
556 top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
563 top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
570 top.sp[-1].i32 = ~top.sp[-1].i32;
576 top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
582 top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
588 top.sp[-1].i32 = -top.sp[-1].i32;
594 top.sp[-1].f = -top.sp[-1].f;
600 Local<Function> newFun(zone, Function::cast(top.sp[-1].obj));
603 if (!zone->stack().pushInlineFrame(newFun))
606 locals = top.fp->locals();
612 unsigned slot = READ_UINT32(top.pc);
613 *top.sp++ = top.fp->arg(slot);
619 unsigned slot = READ_UINT32(top.pc);
620 top.fp->arg(slot) = top.sp[-1];
626 Array *array = Array::cast(top.sp[-2].obj);
627 int index = top.sp[-1].i32;
629 if (index < 0 || unsigned(index) >= array->length()) {
630 zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
634 GetElement(array, index, &top.sp[-2]);
641 Array *array = Array::cast(top.sp[-3].obj);
642 int index = top.sp[-2].i32;
644 if (index < 0 || unsigned(index) >= array->length()) {
645 zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
649 SetElement(zone, array, index, top.sp[-1]);
650 top.sp[-3] = top.sp[-1];
657 int ival = POP_I32(top);
658 float fval = (float)ival;
665 top.sp[-1].i32 = !!top.sp[-1].i32;
671 Local<Array> src(zone, Array::cast(top.sp[-1].obj));
672 top.sp[-1].obj = Array::DeepCopy(zone, src, Heap::Tenure_Default);
680 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
681 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
682 Array *array = Array::NewFixed(zone, map, tenure);
692 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
693 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
694 Array *array = Array::NewEmpty(zone, map, tenure);
704 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
705 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
706 assert(map->type()->levels() < MAX_ARRAY_DEPTH);
708 int dims[MAX_ARRAY_DEPTH];
709 for (unsigned i = map->type()->levels() - 1; i < map->type()->levels(); i--)
710 dims[i] = POP_I32(top);
712 Array *array = Array::NewSized(zone, map, dims, tenure);
722 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
723 Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
724 top.sp->obj = Struct::New(zone, map, tenure);
733 unsigned slot = READ_UINT32(top.pc);
734 locals[slot].address = zone->heap().lifoPosition();
740 unsigned slot = READ_UINT32(top.pc);
741 zone->heap().unwindLifo(locals[slot].address);
747 unsigned slot = READ_UINT32(top.pc);
748 if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
755 unsigned slot = READ_UINT32(top.pc);
756 if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
761 case OP_SLOTREF_LIFO:
763 Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
766 top.sp[-1].ref = ref;
772 top.sp[-1].i32 = top.sp[-1].ref->getInt();
778 top.sp[-2].ref->setInt(top.sp[-1].i32);
779 top.sp[-2].i32 = top.sp[-1].i32;
786 top.sp[-1].f = top.sp[-1].ref->getFloat();
792 top.sp[-2].ref->setFloat(top.sp[-1].f);
793 top.sp[-2].f = top.sp[-1].f;
799 top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
806 // Note for this assignment opcode, we return the left-hand side, not the
807 // right, since in this case the result of the expression could be different.
808 Local<Array> left(zone, Array::cast(top.sp[-2].array));
809 Local<Array> right(zone, Array::cast(top.sp[-1].array));
810 if (!Array::ShallowCopy(zone, left, right))
819 top.sp[-1] = top.sp[-2];
826 top.sp[-2] = top.sp[-4];
827 top.sp[-1] = top.sp[-3];
833 LocalSlot slot = top.sp[-2];
834 top.sp[-2] = top.sp[-1];
841 LocalSlot slot = top.sp[-3];
842 top.sp[-3] = top.sp[-2];
843 top.sp[-2] = top.sp[-1];
851 top.sp[-1] = top.sp[-3];
858 top.sp[-1] = top.sp[-4];
864 unsigned argc = READ_UINT32(top.pc);
866 Local<Native> native(zone, Native::cast(top.sp[-1].obj));
870 void *nativeIdentity = top.fp->code()->module()->parent()->getNativeIdentity();
871 if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
875 PUSH_I32(top, result);
881 // Because the stack is a union, this is a no-op.
902 if (top.sp[-1].obj->is(MapKind_Module))
903 obj = Module::cast(top.sp[-1].obj)->globals();
905 obj = Struct::cast(top.sp[-1].obj);
906 GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
912 Struct *obj = Struct::cast(top.sp[-2].obj);
913 SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
914 top.sp[-2] = top.sp[-1];
921 Local<Struct> left(zone, Struct::cast(top.sp[-2].obj));
922 Local<Struct> right(zone, Struct::cast(top.sp[-1].obj));
923 if (!Struct::Copy(zone, left, right))
925 top.sp[-2].obj = top.sp[-1].obj;
932 int value = top.sp[-1].i32;
933 int low = READ_TABLESWITCH_LOW(top.pc);
934 int high = READ_TABLESWITCH_HIGH(top.pc);
938 unsigned index = unsigned(value - low);
939 unsigned tablesize = TableSwitchEntries(low, high);
940 if (index < tablesize) {
941 top.pc += OP_TABLESWITCH_LENGTH + OP_JUMP_LENGTH;
942 top.pc += index * OP_JUMP_LENGTH;
950 Array *array = Array::cast(top.sp[-1].obj);
951 top.sp[-1].i32 = array->length();
957 Local<Function> fun(zone, Function::cast(top.sp[-1].obj));
958 zone->registerPublic(fun);
965 Local<Code> code(zone, top.fp->code());
966 Local<Struct> obj(zone, code->module()->globals());
967 Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
968 SetGlobal(zone, obj, name, top.sp[-1]);
974 Local<Code> code(zone, top.fp->code());
975 Local<Struct> obj(zone, code->module()->globals());
976 Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
977 GetGlobal(zone, obj, name, top.sp);
984 top.fp->enterLoop(zone);
990 top.fp->leaveLoop(zone);
996 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->object(READ_UINT32(top.pc))));
997 Local<Array> array(zone, Array::cast(top.sp[-2].obj));
998 int index = top.sp[-1].i32;
1000 // We allow taking 0-length dependent arrays.
1001 if (index < 0 || unsigned(index) > array->length()) {
1002 zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
1006 top.sp[-2].obj = DependentArray::New(zone, array, map, index);
1007 if (!top.sp[-2].obj)
1016 unsigned index = READ_UINT32(top.pc);
1019 top.sp[-1].obj = top.fp->code()->module()->getImportAt(index);
1029 top.pc += OpcodeInfo[op].length;
1030 assert(top.sp >= top.fp->stackBase());
1037 // Unwind frames until we can continue.
1038 while (top.fp != entryFrame)
1039 zone->stack().popInlineFrame();