Fix clang bustage.
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"
34 #define PUSH_I32(top, value) \
36 top.sp->i32 = value; \
40 #define PUSH_F(top, value) \
49 int value = top.sp[-1].i32;
57 float value = top.sp[-1].f;
62 // Pawn's original semantics specify some kind of floor operation, so
63 // (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
64 // the upstream algorithm when constant folding. However the SourcePawn 1 JIT
65 // does not. My guess is that Borja freaked out seeing the 13-instruction x86
66 // sequence necessary to get this functionality (I vaguely recall a thread
67 // where we discussed this with Mark Peter? But the ITB forums are gone...),
68 // and we just decided to break the damn thing. So SP1 was inconsistent, but
69 // we are not. And for completeness, we assert that the C compiler does the
70 // right thing, since C89 leaves it unspecified.
71 STATIC_ASSERT(8 / -3 == -2);
72 STATIC_ASSERT(-8 / 3 == -2);
75 PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
77 Reference *ref = Reference::NewStack(zone, location, tenure);
86 GetElement(Array *array, int index, LocalSlot *vp)
88 if (array->type()->contained()->isTraceable()) {
89 vp->obj = array->readObject(index);
93 switch (array->type()->contained()->pod()) {
94 case PrimitiveType_Float:
95 vp->f = array->readFloat(index);
98 case PrimitiveType_Char:
99 vp->i32 = array->readChar(index);
103 assert(array->type()->contained()->pod() == PrimitiveType_Int32);
104 vp->i32 = array->readInt32(index);
110 SetElement(Zone *zone, Array *array, int index, const LocalSlot &v)
112 if (array->type()->contained()->isTraceable()) {
113 array->writeObject(zone, index, v.obj);
117 switch (array->type()->contained()->pod()) {
118 case PrimitiveType_Float:
119 array->writeFloat(index, v.f);
122 case PrimitiveType_Char:
123 array->writeChar(index, v.i32);
127 assert(array->type()->contained()->pod() == PrimitiveType_Int32);
128 array->writeInt32(index, v.i32);
134 FetchField(Struct *obj, Descriptor *desc, LocalSlot *vp)
136 // :TODO: assert no GC.
137 if (desc->type()->isTraceable()) {
138 vp->obj = obj->get<Object *>(desc);
142 switch (desc->type()->pod()) {
143 case PrimitiveType_Float:
144 vp->f = obj->get<float>(desc);
148 assert(desc->type()->pod() == PrimitiveType_Int32);
149 vp->i32 = obj->get<int>(desc);
155 GetField(Struct *obj, unsigned index, LocalSlot *vp)
157 StructType *type = StructType::cast(obj->map()->type());
158 Descriptor *desc = Descriptor::cast(type->fields()->at(index));
159 FetchField(obj, desc, vp);
163 GetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot *vp)
165 Local<StructType> type(zone, StructType::cast(obj->map()->type()));
166 Local<Descriptor> desc(zone, type->lookupField(name, NULL));
167 FetchField(obj, desc, vp);
171 StoreField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v)
173 // :TODO: assert no GC.
174 if (desc->type()->isTraceable()) {
175 obj->set(zone, desc, v.obj);
179 switch (desc->type()->pod()) {
180 case PrimitiveType_Float:
181 obj->set<float>(desc, v.f);
185 assert(desc->type()->pod() == PrimitiveType_Int32);
186 obj->set<int>(desc, v.i32);
192 SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
194 StructType *type = StructType::cast(obj->map()->type());
195 Descriptor *desc = Descriptor::cast(type->fields()->at(index));
196 StoreField(zone, obj, desc, v);
200 SetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot &v)
202 Local<StructType> type(zone, StructType::cast(obj->map()->type()));
203 Local<Descriptor> desc(zone, type->lookupField(name, NULL));
204 StoreField(zone, obj, desc, v);
208 InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
213 void *address = zone->nativeTable()->address(native->index());
215 Local<String> name(zone, zone->nativeTable()->name(native->index()));
216 zone->reportError(Message_NativeNotBound, name->chars());
220 if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
223 intptr_t *cells = guard.args();
225 // params[0] == argc, in ISPE
228 // Pass the formal arguments.
229 Local<FunctionType> type(zone, native->type());
230 Local<Type> param(zone);
231 for (unsigned i = 0; i < type->parameters()->length(); i++) {
232 param = type->parameterAt(i);
234 // For floats, we rely on the aliasing of |i32| and |f|.
235 LocalSlot &arg = args[-int(i) - 1];
236 if (param->isInt32() || param->isFloat()) {
237 cells[i + 1] = arg.i32;
238 } else if (param->isReference()) {
239 cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
241 assert(param->isArray());
242 cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
246 // For variadic arguments, the compiler left either arrays or references.
247 for (unsigned i = type->parameters()->length(); i < argc; i++) {
248 LocalSlot &arg = args[-int(i) - 1];
250 if (arg.obj->is(MapKind_Reference)) {
251 cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
253 assert(arg.obj->is(MapKind_Array));
254 cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
258 typedef intptr_t (*INVOKE)(void *, intptr_t *);
259 INVOKE invoke = (INVOKE)address;
260 *result = invoke(identity, cells);
262 return !zone->hasPendingException();
266 ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
268 Top &top = *zone->stack().top();
272 LocalSlot *locals = entryFrame->locals();
275 Opcode op = Opcode(*top.pc);
277 if (OpcodeInfo[op].nuses > 0)
278 assert(top.sp - OpcodeInfo[op].nuses >= top.fp->stackBase());
286 PUSH_I32(top, READ_INT32(top.pc));
290 PUSH_F(top, READ_FLOAT(top.pc));
300 if (top.fp == entryFrame)
304 zone->stack().popInlineFrame();
305 locals = top.fp->locals();
310 top.pc += OpcodeInfo[*top.pc].length;
322 int value = POP_I32(top);
324 top.pc += READ_INT32(top.pc);
332 int value = POP_I32(top);
334 top.pc += READ_INT32(top.pc);
342 top.pc += READ_INT32(top.pc);
349 top.fp->leaveLoop(zone);
350 top.pc += READ_INT32(top.pc);
356 unsigned slot = READ_UINT32(top.pc);
357 assert(slot < top.fp->code()->nlocals());
358 *top.sp++ = locals[slot];
364 unsigned slot = READ_UINT32(top.pc);
365 assert(slot < top.fp->code()->nlocals());
366 locals[slot] = top.sp[-1];
372 top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
379 top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
386 top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
393 if (top.sp[-1].i32 == 0) {
394 zone->reportError(Message_IntegerDivideByZero);
397 top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
404 if (top.sp[-1].i32 == 0) {
405 zone->reportError(Message_IntegerDivideByZero);
408 top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
415 top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
422 top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
429 top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
436 top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
443 top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
450 top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
457 top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
464 top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
471 top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
478 top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
485 top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
492 top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
499 top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
506 top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
513 top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
520 top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
527 top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
534 top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
541 top.sp[-2].i32 = unsigned(top.sp[-2].i32) >> unsigned(top.sp[-1].i32);
548 top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
555 top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
562 top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
569 top.sp[-1].i32 = ~top.sp[-1].i32;
575 top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
581 top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
587 top.sp[-1].i32 = -top.sp[-1].i32;
593 top.sp[-1].f = -top.sp[-1].f;
599 Local<Function> newFun(zone, Function::cast(top.sp[-1].obj));
602 if (!zone->stack().pushInlineFrame(newFun))
605 locals = top.fp->locals();
611 unsigned slot = READ_UINT32(top.pc);
612 *top.sp++ = top.fp->arg(slot);
618 unsigned slot = READ_UINT32(top.pc);
619 top.fp->arg(slot) = top.sp[-1];
625 Array *array = Array::cast(top.sp[-2].obj);
626 int index = top.sp[-1].i32;
628 if (index < 0 || unsigned(index) >= array->length()) {
629 zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
633 GetElement(array, index, &top.sp[-2]);
640 Array *array = Array::cast(top.sp[-3].obj);
641 int index = top.sp[-2].i32;
643 if (index < 0 || unsigned(index) >= array->length()) {
644 zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
648 SetElement(zone, array, index, top.sp[-1]);
649 top.sp[-3] = top.sp[-1];
656 int ival = POP_I32(top);
657 float fval = (float)ival;
664 top.sp[-1].i32 = !!top.sp[-1].i32;
670 Local<Array> src(zone, Array::cast(top.sp[-1].obj));
671 top.sp[-1].obj = Array::DeepCopy(zone, src, Heap::Tenure_Default);
679 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
680 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
681 Array *array = Array::NewFixed(zone, map, tenure);
691 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
692 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
693 Array *array = Array::NewEmpty(zone, map, tenure);
703 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
704 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
705 assert(map->type()->levels() < MAX_ARRAY_DEPTH);
707 int dims[MAX_ARRAY_DEPTH];
708 for (unsigned i = map->type()->levels() - 1; i < map->type()->levels(); i--)
709 dims[i] = POP_I32(top);
711 Array *array = Array::NewSized(zone, map, dims, tenure);
721 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
722 Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
723 top.sp->obj = Struct::New(zone, map, tenure);
732 unsigned slot = READ_UINT32(top.pc);
733 locals[slot].address = zone->heap().lifoPosition();
739 unsigned slot = READ_UINT32(top.pc);
740 zone->heap().unwindLifo(locals[slot].address);
746 unsigned slot = READ_UINT32(top.pc);
747 if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
754 unsigned slot = READ_UINT32(top.pc);
755 if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
760 case OP_SLOTREF_LIFO:
762 Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
765 top.sp[-1].ref = ref;
771 top.sp[-1].i32 = top.sp[-1].ref->getInt();
777 top.sp[-2].ref->setInt(top.sp[-1].i32);
778 top.sp[-2].i32 = top.sp[-1].i32;
785 top.sp[-1].f = top.sp[-1].ref->getFloat();
791 top.sp[-2].ref->setFloat(top.sp[-1].f);
792 top.sp[-2].f = top.sp[-1].f;
798 top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
805 // Note for this assignment opcode, we return the left-hand side, not the
806 // right, since in this case the result of the expression could be different.
807 Local<Array> left(zone, Array::cast(top.sp[-2].array));
808 Local<Array> right(zone, Array::cast(top.sp[-1].array));
809 if (!Array::ShallowCopy(zone, left, right))
818 top.sp[-1] = top.sp[-2];
825 top.sp[-2] = top.sp[-4];
826 top.sp[-1] = top.sp[-3];
832 LocalSlot slot = top.sp[-2];
833 top.sp[-2] = top.sp[-1];
840 LocalSlot slot = top.sp[-3];
841 top.sp[-3] = top.sp[-2];
842 top.sp[-2] = top.sp[-1];
850 top.sp[-1] = top.sp[-3];
857 top.sp[-1] = top.sp[-4];
863 unsigned argc = READ_UINT32(top.pc);
865 Local<Native> native(zone, Native::cast(top.sp[-1].obj));
869 void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
870 if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
874 PUSH_I32(top, result);
881 // Because the stack is a union, these are actually no-ops in the
902 Struct *obj = Struct::cast(top.sp[-1].obj);
903 GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
909 Struct *obj = Struct::cast(top.sp[-2].obj);
910 SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
911 top.sp[-2] = top.sp[-1];
918 Local<Struct> left(zone, Struct::cast(top.sp[-2].obj));
919 Local<Struct> right(zone, Struct::cast(top.sp[-1].obj));
920 if (!Struct::Copy(zone, left, right))
922 top.sp[-2].obj = top.sp[-1].obj;
929 int value = top.sp[-1].i32;
930 int low = READ_TABLESWITCH_LOW(top.pc);
931 int high = READ_TABLESWITCH_HIGH(top.pc);
935 unsigned index = unsigned(value - low);
936 unsigned tablesize = TableSwitchEntries(low, high);
937 if (index < tablesize) {
938 top.pc += OP_TABLESWITCH_LENGTH + OP_JUMP_LENGTH;
939 top.pc += index * OP_JUMP_LENGTH;
947 Array *array = Array::cast(top.sp[-1].obj);
948 top.sp[-1].i32 = array->length();
954 Local<Function> fun(zone, Function::cast(top.sp[-1].obj));
955 zone->registerPublic(fun);
962 Local<Code> code(zone, top.fp->code());
963 Local<Struct> obj(zone, code->module()->globals());
964 Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
965 SetGlobal(zone, obj, name, top.sp[-1]);
971 Local<Code> code(zone, top.fp->code());
972 Local<Struct> obj(zone, code->module()->globals());
973 Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
974 GetGlobal(zone, obj, name, top.sp);
981 top.fp->enterLoop(zone);
987 top.fp->leaveLoop(zone);
997 top.pc += OpcodeInfo[op].length;
998 assert(top.sp >= top.fp->stackBase());
1005 // Unwind frames until we can continue.
1006 while (top.fp != entryFrame)
1007 zone->stack().popInlineFrame();