Refactory array maps to allow arrays of structs.
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"
33 #define PUSH_I32(top, value) \
35 top.sp->i32 = value; \
39 #define PUSH_F(top, value) \
48 int value = top.sp[-1].i32;
56 float value = top.sp[-1].f;
61 // Pawn's original semantics specify some kind of floor operation, so
62 // (8 / -3 == -3) and (-8 / 3 == -1). The SourcePawn 1 compiler (spcomp) uses
63 // the upstream algorithm when constant folding. However the SourcePawn 1 JIT
64 // does not. My guess is that Borja freaked out seeing the 13-instruction x86
65 // sequence necessary to get this functionality (I vaguely recall a thread
66 // where we discussed this with Mark Peter? But the ITB forums are gone...),
67 // and we just decided to break the damn thing. So SP1 was inconsistent, but
68 // we are not. And for completeness, we assert that the C compiler does the
69 // right thing, since C89 leaves it unspecified.
70 STATIC_ASSERT(8 / -3 == -2);
71 STATIC_ASSERT(-8 / 3 == -2);
74 PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
76 Reference *ref = Reference::NewStack(zone, location, tenure);
84 // Even though this function can fail, we immediately bail out, so it doesn't
85 // matter if we've leaving things unrooted.
87 CopyArray(Zone *zone, Array *source, Array *dest)
89 assert(source->type()->levels() == 1);
90 assert(dest->type()->levels() == 1);
91 assert(source->type()->contained()->primitive() ==
92 dest->type()->contained()->primitive());
93 assert(source->nelements() >= dest->nelements());
94 assert(dest->elementSize() == source->elementSize());
96 memcpy(source->vec(), dest->vec(), dest->nelements() * dest->elementSize());
101 GetField(Struct *obj, Descriptor *desc, LocalSlot *vp)
103 // :TODO: assert no GC.
104 if (desc->type()->isTraceable()) {
105 vp->obj = obj->get<Object *>(desc);
107 switch (desc->type()->pod()) {
108 case PrimitiveType_Float:
109 vp->f = obj->get<float>(desc);
113 assert(desc->type()->pod() == PrimitiveType_Int32);
114 vp->i32 = obj->get<int>(desc);
121 GetField(Struct *obj, unsigned index, LocalSlot *vp)
123 Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
124 GetField(obj, desc, vp);
128 SetField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v)
130 // :TODO: assert no GC.
131 if (desc->type()->isTraceable()) {
132 obj->set(zone, desc, v.obj);
134 switch (desc->type()->pod()) {
135 case PrimitiveType_Float:
136 obj->set<float>(desc, v.f);
140 assert(desc->type()->pod() == PrimitiveType_Int32);
141 obj->set<int>(desc, v.i32);
148 SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
150 Descriptor *desc = Descriptor::cast(obj->map()->type()->fields()->at(index));
151 SetField(zone, obj, desc, v);
154 // Even though this function can fail, we immediately bail out, so it doesn't
155 // matter if we've leaving things unrooted.
157 CopyStruct(Zone *zone, Struct *left, Struct *right)
159 assert(left->map()->type() == right->map()->type());
161 Type *type = left->map()->type();
162 for (unsigned i = 0; i < type->fields()->length(); i++) {
163 Descriptor *desc = Descriptor::cast(type->fields()->at(i));
166 GetField(right, desc, &rval);
168 // If the field is a struct, we need to deep-copy.
169 if (desc->type()->isStruct()) {
172 GetField(left, desc, &lval);
173 if (!CopyStruct(zone, Struct::cast(lval.obj), Struct::cast(rval.obj)))
175 } else if (desc->type()->isArray()) {
178 GetField(left, desc, &lval);
179 if (!CopyArray(zone, Array::cast(lval.obj), Array::cast(rval.obj)))
182 SetField(zone, left, desc, rval);
190 InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
195 if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
198 intptr_t *cells = guard.args();
200 // params[0] == argc, in ISPE
203 // Pass the formal arguments.
204 Local<Type> type(zone, native->type());
205 Local<Type> param(zone);
206 for (unsigned i = 0; i < type->parameters()->length(); i++) {
207 param = type->parameterAt(i);
209 // For floats, we rely on the aliasing of |i32| and |f|.
210 LocalSlot &arg = args[-int(i) - 1];
211 if (param->isInt32() || param->isFloat()) {
212 cells[i + 1] = arg.i32;
213 } else if (param->isReference()) {
214 cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
216 assert(param->isArray());
217 cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
221 // For variadic arguments, the compiler left either arrays or references.
222 for (unsigned i = type->parameters()->length(); i < argc; i++) {
223 LocalSlot &arg = args[-int(i) - 1];
225 if (arg.obj->is(MapKind_Reference)) {
226 cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
228 assert(arg.obj->is(MapKind_Array));
229 cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
233 typedef intptr_t (*INVOKE)(void *, intptr_t *);
234 INVOKE invoke = (INVOKE)native->function();
235 *result = invoke(identity, cells);
237 return !zone->hasPendingException();
241 ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
243 Top &top = *zone->stack().top();
247 LocalSlot *locals = entryFrame->locals();
250 Opcode op = Opcode(*top.pc);
257 PUSH_I32(top, READ_INT32(top.pc));
261 PUSH_F(top, READ_FLOAT(top.pc));
271 if (top.fp == entryFrame)
275 zone->stack().popInlineFrame();
276 locals = top.fp->locals();
281 top.pc += OpcodeInfo[*top.pc].length;
291 #define RELATIONAL_JUMP(op) \
293 int right = POP_I32(top); \
294 int left = POP_I32(top); \
295 if (left op right) { \
296 top.pc += READ_INT32(top.pc); \
325 #undef RELATIONAL_JUMP
329 int value = POP_I32(top);
331 top.pc += READ_INT32(top.pc);
339 int value = POP_I32(top);
341 top.pc += READ_INT32(top.pc);
347 #define RELATIONAL_JUMP_F(op) \
349 float right = POP_F(top); \
350 float left = POP_F(top); \
351 if (left op right) { \
352 top.pc += READ_INT32(top.pc); \
358 RELATIONAL_JUMP_F(<);
362 RELATIONAL_JUMP_F(<=);
366 RELATIONAL_JUMP_F(>);
370 RELATIONAL_JUMP_F(>=);
374 RELATIONAL_JUMP_F(==);
378 RELATIONAL_JUMP_F(!=);
383 float value = POP_F(top);
385 top.pc += READ_INT32(top.pc);
393 float value = POP_F(top);
395 top.pc += READ_INT32(top.pc);
402 top.pc += READ_INT32(top.pc);
407 int slot = READ_INT32(top.pc);
408 *top.sp++ = locals[slot];
414 int slot = READ_INT32(top.pc);
415 locals[slot] = top.sp[-1];
421 top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
428 top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
435 top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
442 if (top.sp[-1].i32 == 0) {
443 zone->reportError(Message_IntegerDivideByZero);
446 top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
453 if (top.sp[-1].i32 == 0) {
454 zone->reportError(Message_IntegerDivideByZero);
457 top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
464 top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
471 top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
478 top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
485 top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
492 top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
499 top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
506 top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
513 top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
520 top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
527 top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
534 top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
541 top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
548 top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
555 top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
562 top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
569 top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
576 top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
583 top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
590 top.sp[-2].i32 = unsigned(top.sp[-2].i32) << unsigned(top.sp[-1].i32);
597 top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
604 top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
611 top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
618 top.sp[-1].i32 = ~top.sp[-1].i32;
624 top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
630 top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
636 top.sp[-1].i32 = -top.sp[-1].i32;
642 top.sp[-1].f = -top.sp[-1].f;
648 Local<Function> newFun(zone, top.sp[-1].fun);
651 if (!zone->stack().pushInlineFrame(newFun))
654 locals = top.fp->locals();
660 unsigned slot = READ_UINT32(top.pc);
661 *top.sp++ = top.fp->arg(slot);
667 unsigned slot = READ_UINT32(top.pc);
668 top.fp->arg(slot) = *--top.sp;
674 Array *array = top.sp[-2].array;
675 int index = top.sp[-1].i32;
676 if (index < 0 || unsigned(index) >= array->nelements()) {
677 zone->reportError(Message_ArrayIndexOutOfBounds, index, array->nelements());
685 Array *array = top.sp[-2].array;
686 int index = top.sp[-1].i32;
687 top.sp[-2].i32 = array->readInt32(index);
694 Array *array = top.sp[-2].array;
695 int index = top.sp[-1].i32;
696 top.sp[-2].f = array->readFloat(index);
703 Array *array = top.sp[-2].array;
704 int index = top.sp[-1].i32;
705 top.sp[-2].i32 = array->readChar(index);
712 Array *array = top.sp[-3].array;
713 int index = top.sp[-2].i32;
714 array->writeInt32(index, top.sp[-1].i32);
715 top.sp[-3] = top.sp[-1];
722 Array *array = top.sp[-3].array;
723 int index = top.sp[-2].i32;
724 array->writeFloat(index, top.sp[-1].f);
725 top.sp[-3] = top.sp[-1];
732 Array *array = top.sp[-3].array;
733 int index = top.sp[-2].i32;
734 array->writeChar(index, top.sp[-1].i32);
735 top.sp[-3] = top.sp[-1];
742 Array *array = top.sp[-2].array;
743 int index = top.sp[-1].i32;
744 top.sp[-2].obj = array->readObject(index);
751 int ival = POP_I32(top);
752 float fval = (float)ival;
759 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
760 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
761 Array *array = Array::New(zone, map, map->type()->elements(), tenure);
771 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
772 Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
773 top.sp->obj = Struct::New(zone, map, tenure);
782 unsigned slot = READ_UINT32(top.pc);
783 locals[slot].address = zone->heap().lifoPosition();
789 unsigned slot = READ_UINT32(top.pc);
790 zone->heap().unwindLifo(locals[slot].address);
796 unsigned slot = READ_UINT32(top.pc);
797 if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
804 unsigned slot = READ_UINT32(top.pc);
805 if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
810 case OP_ARRAYREF_LIFO:
812 Local<Array> array(zone, top.sp[-2].array);
813 Local<Reference> ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack));
816 top.sp[-2].ref = ref;
821 case OP_SLOTREF_LIFO:
823 Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
826 top.sp[-1].ref = ref;
832 top.sp[-1].i32 = top.sp[-1].ref->getInt();
838 top.sp[-2].ref->setInt(top.sp[-1].i32);
839 top.sp[-2].i32 = top.sp[-1].i32;
846 top.sp[-1].f = top.sp[-1].ref->getFloat();
852 top.sp[-2].ref->setFloat(top.sp[-1].f);
853 top.sp[-2].f = top.sp[-1].f;
859 top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
866 // Note for this assignment opcode, we return the left-hand side, not the
867 // right, since in this case the result of the expression could be different.
868 if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array))
877 top.sp[-1] = top.sp[-2];
884 top.sp[-2] = top.sp[-4];
885 top.sp[-1] = top.sp[-3];
891 LocalSlot slot = top.sp[-2];
892 top.sp[-2] = top.sp[-1];
899 LocalSlot slot = top.sp[-3];
900 top.sp[-3] = top.sp[-2];
901 top.sp[-2] = top.sp[-1];
909 top.sp[-1] = top.sp[-3];
916 top.sp[-1] = top.sp[-4];
922 unsigned index = READ_UINT32(top.pc);
923 unsigned argc = READ_UINT32(top.pc + 4);
925 Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
926 if (!native->function()) {
927 zone->reportError(Message_NativeNotBound, native->name()->chars());
932 void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
933 if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
937 PUSH_I32(top, result);
944 top.sp[-1].module = top.fp->code()->module();
948 case OP_GETMODULE_FN:
950 top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc));
956 unsigned slot = READ_UINT32(top.pc);
958 top.sp[-1].i32 = top.fp->code()->module()->environment()->getInt32(slot);
964 unsigned slot = READ_UINT32(top.pc);
966 top.sp[-1].f = top.fp->code()->module()->environment()->getFloat(slot);
972 unsigned slot = READ_UINT32(top.pc);
974 top.sp[-1].obj = top.fp->code()->module()->environment()->getObject(slot);
980 unsigned slot = READ_UINT32(top.pc);
981 top.fp->code()->module()->environment()->setInt32(slot, top.sp[-1].i32);
987 unsigned slot = READ_UINT32(top.pc);
988 top.fp->code()->module()->environment()->setFloat(slot, top.sp[-1].f);
994 unsigned slot = READ_UINT32(top.pc);
995 top.fp->code()->module()->environment()->setObject(slot, top.sp[-1].obj);
1002 // Because the stack is a union, these are actually no-ops in the
1023 Struct *obj = Struct::cast(top.sp[-1].obj);
1024 GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
1030 Struct *obj = Struct::cast(top.sp[-2].obj);
1031 SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
1032 top.sp[-2] = top.sp[-1];
1039 if (!CopyStruct(zone, Struct::cast(top.sp[-2].obj), Struct::cast(top.sp[-1].obj)))
1041 top.sp[-2].obj = top.sp[-1].obj;
1052 top.pc += OpcodeInfo[op].length;
1059 // Unwind frames until we can continue.
1060 while (top.fp != entryFrame)
1061 zone->stack().popInlineFrame();