Get string literals working again.
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 DuplicateArray(Zone *zone, Handle<Array> src)
88 Local<ArrayMap> map(zone, ArrayMap::cast(src->map()));
89 Local<Array> dest(zone);
91 if (map->type()->isFixedLength()) {
92 dest = Array::NewFixed(zone, map);
94 Type *type = map->type();
95 int sizes[MAX_ARRAY_DEPTH];
96 for (unsigned i = 0; i < map->type()->levels(); i++) {
97 ArrayType *atype = ArrayType::cast(type);
98 sizes[i] = atype->isFixedLength()
99 ? atype->fixedLength()
101 type = atype->contained();
105 Local<Array> dst(zone);
109 GetElement(Array *array, int index, LocalSlot *vp)
111 if (array->type()->contained()->isTraceable()) {
112 vp->obj = array->readObject(index);
116 switch (array->type()->contained()->pod()) {
117 case PrimitiveType_Float:
118 vp->f = array->readFloat(index);
121 case PrimitiveType_Char:
122 vp->i32 = array->readChar(index);
126 assert(array->type()->contained()->pod() == PrimitiveType_Int32);
127 vp->i32 = array->readInt32(index);
133 SetElement(Zone *zone, Array *array, int index, const LocalSlot &v)
135 if (array->type()->contained()->isTraceable()) {
136 array->writeObject(zone, index, v.obj);
140 switch (array->type()->contained()->pod()) {
141 case PrimitiveType_Float:
142 array->writeFloat(index, v.f);
145 case PrimitiveType_Char:
146 array->writeChar(index, v.i32);
150 assert(array->type()->contained()->pod() == PrimitiveType_Int32);
151 array->writeInt32(index, v.i32);
157 FetchField(Struct *obj, Descriptor *desc, LocalSlot *vp)
159 // :TODO: assert no GC.
160 if (desc->type()->isTraceable()) {
161 vp->obj = obj->get<Object *>(desc);
165 switch (desc->type()->pod()) {
166 case PrimitiveType_Float:
167 vp->f = obj->get<float>(desc);
171 assert(desc->type()->pod() == PrimitiveType_Int32);
172 vp->i32 = obj->get<int>(desc);
178 GetField(Struct *obj, unsigned index, LocalSlot *vp)
180 StructType *type = StructType::cast(obj->map()->type());
181 Descriptor *desc = Descriptor::cast(type->fields()->at(index));
182 FetchField(obj, desc, vp);
186 GetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot *vp)
188 Local<StructType> type(zone, StructType::cast(obj->map()->type()));
189 Local<Descriptor> desc(zone, type->lookupField(name, NULL));
190 FetchField(obj, desc, vp);
194 StoreField(Zone *zone, Struct *obj, Descriptor *desc, const LocalSlot &v)
196 // :TODO: assert no GC.
197 if (desc->type()->isTraceable()) {
198 obj->set(zone, desc, v.obj);
202 switch (desc->type()->pod()) {
203 case PrimitiveType_Float:
204 obj->set<float>(desc, v.f);
208 assert(desc->type()->pod() == PrimitiveType_Int32);
209 obj->set<int>(desc, v.i32);
215 SetField(Zone *zone, Struct *obj, unsigned index, const LocalSlot &v)
217 StructType *type = StructType::cast(obj->map()->type());
218 Descriptor *desc = Descriptor::cast(type->fields()->at(index));
219 StoreField(zone, obj, desc, v);
223 SetGlobal(Zone *zone, Handle<Struct> obj, Handle<String> name, LocalSlot &v)
225 Local<StructType> type(zone, StructType::cast(obj->map()->type()));
226 Local<Descriptor> desc(zone, type->lookupField(name, NULL));
227 StoreField(zone, obj, desc, v);
231 InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
236 void *address = zone->nativeTable()->address(native->index());
238 Local<String> name(zone, zone->nativeTable()->name(native->index()));
239 zone->reportError(Message_NativeNotBound, name->chars());
243 if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
246 intptr_t *cells = guard.args();
248 // params[0] == argc, in ISPE
251 // Pass the formal arguments.
252 Local<FunctionType> type(zone, native->type());
253 Local<Type> param(zone);
254 for (unsigned i = 0; i < type->parameters()->length(); i++) {
255 param = type->parameterAt(i);
257 // For floats, we rely on the aliasing of |i32| and |f|.
258 LocalSlot &arg = args[-int(i) - 1];
259 if (param->isInt32() || param->isFloat()) {
260 cells[i + 1] = arg.i32;
261 } else if (param->isReference()) {
262 cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
264 assert(param->isArray());
265 cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
269 // For variadic arguments, the compiler left either arrays or references.
270 for (unsigned i = type->parameters()->length(); i < argc; i++) {
271 LocalSlot &arg = args[-int(i) - 1];
273 if (arg.obj->is(MapKind_Reference)) {
274 cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
276 assert(arg.obj->is(MapKind_Array));
277 cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->bytes());
281 typedef intptr_t (*INVOKE)(void *, intptr_t *);
282 INVOKE invoke = (INVOKE)address;
283 *result = invoke(identity, cells);
285 return !zone->hasPendingException();
289 ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
291 Top &top = *zone->stack().top();
295 LocalSlot *locals = entryFrame->locals();
298 Opcode op = Opcode(*top.pc);
300 if (OpcodeInfo[op].nuses > 0)
301 assert(top.sp - OpcodeInfo[op].nuses >= top.fp->stackBase());
309 PUSH_I32(top, READ_INT32(top.pc));
313 PUSH_F(top, READ_FLOAT(top.pc));
323 if (top.fp == entryFrame)
327 zone->stack().popInlineFrame();
328 locals = top.fp->locals();
333 top.pc += OpcodeInfo[*top.pc].length;
345 int value = POP_I32(top);
347 top.pc += READ_INT32(top.pc);
355 int value = POP_I32(top);
357 top.pc += READ_INT32(top.pc);
365 top.pc += READ_INT32(top.pc);
372 top.fp->leaveLoop(zone);
373 top.pc += READ_INT32(top.pc);
379 unsigned slot = READ_UINT32(top.pc);
380 assert(slot < top.fp->code()->nlocals());
381 *top.sp++ = locals[slot];
387 unsigned slot = READ_UINT32(top.pc);
388 assert(slot < top.fp->code()->nlocals());
389 locals[slot] = top.sp[-1];
395 top.sp[-2].i32 = top.sp[-2].i32 + top.sp[-1].i32;
402 top.sp[-2].i32 = top.sp[-2].i32 - top.sp[-1].i32;
409 top.sp[-2].i32 = top.sp[-2].i32 * top.sp[-1].i32;
416 if (top.sp[-1].i32 == 0) {
417 zone->reportError(Message_IntegerDivideByZero);
420 top.sp[-2].i32 = top.sp[-2].i32 / top.sp[-1].i32;
427 if (top.sp[-1].i32 == 0) {
428 zone->reportError(Message_IntegerDivideByZero);
431 top.sp[-2].i32 = top.sp[-2].i32 % top.sp[-1].i32;
438 top.sp[-2].i32 = top.sp[-2].i32 < top.sp[-1].i32;
445 top.sp[-2].i32 = top.sp[-2].i32 <= top.sp[-1].i32;
452 top.sp[-2].i32 = top.sp[-2].i32 > top.sp[-1].i32;
459 top.sp[-2].i32 = top.sp[-2].i32 >= top.sp[-1].i32;
466 top.sp[-2].i32 = (top.sp[-2].i32 == top.sp[-1].i32);
473 top.sp[-2].i32 = (top.sp[-2].i32 != top.sp[-1].i32);
480 top.sp[-2].f = top.sp[-2].f + top.sp[-1].f;
487 top.sp[-2].f = top.sp[-2].f - top.sp[-1].f;
494 top.sp[-2].f = top.sp[-2].f * top.sp[-1].f;
501 top.sp[-2].f = top.sp[-2].f / top.sp[-1].f;
508 top.sp[-2].f = top.sp[-2].f < top.sp[-1].f;
515 top.sp[-2].f = top.sp[-2].f <= top.sp[-1].f;
522 top.sp[-2].f = top.sp[-2].f > top.sp[-1].f;
529 top.sp[-2].f = top.sp[-2].f >= top.sp[-1].f;
536 top.sp[-2].i32 = (top.sp[-2].f == top.sp[-1].f);
543 top.sp[-2].i32 = (top.sp[-2].f != top.sp[-1].f);
550 top.sp[-2].i32 = top.sp[-2].i32 << top.sp[-1].i32;
557 top.sp[-2].i32 = top.sp[-2].i32 >> top.sp[-1].i32;
564 top.sp[-2].i32 = unsigned(top.sp[-2].i32) >> unsigned(top.sp[-1].i32);
571 top.sp[-2].i32 = top.sp[-2].i32 & top.sp[-1].i32;
578 top.sp[-2].i32 = top.sp[-2].i32 | top.sp[-1].i32;
585 top.sp[-2].i32 = top.sp[-2].i32 ^ top.sp[-1].i32;
592 top.sp[-1].i32 = ~top.sp[-1].i32;
598 top.sp[-1].i32 = top.sp[-1].i32 ? 0 : 1;
604 top.sp[-1].i32 = top.sp[-1].f ? 0 : 1;
610 top.sp[-1].i32 = -top.sp[-1].i32;
616 top.sp[-1].f = -top.sp[-1].f;
622 Local<Function> newFun(zone, Function::cast(top.sp[-1].obj));
625 if (!zone->stack().pushInlineFrame(newFun))
628 locals = top.fp->locals();
634 unsigned slot = READ_UINT32(top.pc);
635 *top.sp++ = top.fp->arg(slot);
641 unsigned slot = READ_UINT32(top.pc);
642 top.fp->arg(slot) = top.sp[-1];
648 Array *array = Array::cast(top.sp[-2].obj);
649 int index = top.sp[-1].i32;
651 if (index < 0 || unsigned(index) >= array->length()) {
652 zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
656 GetElement(array, index, &top.sp[-2]);
663 Array *array = Array::cast(top.sp[-3].obj);
664 int index = top.sp[-2].i32;
666 if (index < 0 || unsigned(index) >= array->length()) {
667 zone->reportError(Message_ArrayIndexOutOfBounds, index, array->length());
671 SetElement(zone, array, index, top.sp[-1]);
672 top.sp[-3] = top.sp[-1];
679 int ival = POP_I32(top);
680 float fval = (float)ival;
687 top.sp[-1].i32 = !!top.sp[-1].i32;
693 Local<Array> src(zone, Array::cast(top.sp[-1].obj));
694 top.sp[-1].obj = Array::DeepCopy(zone, src, Heap::Tenure_Default);
702 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
703 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
704 Array *array = Array::NewFixed(zone, map, tenure);
714 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
715 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
716 Array *array = Array::NewEmpty(zone, map, tenure);
726 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
727 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
728 assert(map->type()->levels() < MAX_ARRAY_DEPTH);
730 int dims[MAX_ARRAY_DEPTH];
731 for (unsigned i = map->type()->levels() - 1; i < map->type()->levels(); i--)
732 dims[i] = POP_I32(top);
734 Array *array = Array::NewSized(zone, map, dims, tenure);
744 Heap::Tenure tenure = (Heap::Tenure)top.pc[1];
745 Local<StructMap> map(zone, StructMap::cast(top.fp->code()->map(READ_UINT32(top.pc + 1))));
746 top.sp->obj = Struct::New(zone, map, tenure);
755 unsigned slot = READ_UINT32(top.pc);
756 locals[slot].address = zone->heap().lifoPosition();
762 unsigned slot = READ_UINT32(top.pc);
763 zone->heap().unwindLifo(locals[slot].address);
769 unsigned slot = READ_UINT32(top.pc);
770 if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
777 unsigned slot = READ_UINT32(top.pc);
778 if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
783 case OP_SLOTREF_LIFO:
785 Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
788 top.sp[-1].ref = ref;
794 top.sp[-1].i32 = top.sp[-1].ref->getInt();
800 top.sp[-2].ref->setInt(top.sp[-1].i32);
801 top.sp[-2].i32 = top.sp[-1].i32;
808 top.sp[-1].f = top.sp[-1].ref->getFloat();
814 top.sp[-2].ref->setFloat(top.sp[-1].f);
815 top.sp[-2].f = top.sp[-1].f;
821 top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
828 // Note for this assignment opcode, we return the left-hand side, not the
829 // right, since in this case the result of the expression could be different.
830 Local<Array> left(zone, Array::cast(top.sp[-2].array));
831 Local<Array> right(zone, Array::cast(top.sp[-1].array));
832 if (!Array::ShallowCopy(zone, left, right))
841 top.sp[-1] = top.sp[-2];
848 top.sp[-2] = top.sp[-4];
849 top.sp[-1] = top.sp[-3];
855 LocalSlot slot = top.sp[-2];
856 top.sp[-2] = top.sp[-1];
863 LocalSlot slot = top.sp[-3];
864 top.sp[-3] = top.sp[-2];
865 top.sp[-2] = top.sp[-1];
873 top.sp[-1] = top.sp[-3];
880 top.sp[-1] = top.sp[-4];
886 unsigned argc = READ_UINT32(top.pc);
888 Local<Native> native(zone, Native::cast(top.sp[-1].obj));
892 void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
893 if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
897 PUSH_I32(top, result);
904 // Because the stack is a union, these are actually no-ops in the
925 Struct *obj = Struct::cast(top.sp[-1].obj);
926 GetField(obj, READ_UINT32(top.pc), &top.sp[-1]);
932 Struct *obj = Struct::cast(top.sp[-2].obj);
933 SetField(zone, obj, READ_UINT32(top.pc), top.sp[-1]);
934 top.sp[-2] = top.sp[-1];
941 Local<Struct> left(zone, Struct::cast(top.sp[-2].obj));
942 Local<Struct> right(zone, Struct::cast(top.sp[-1].obj));
943 if (!Struct::Copy(zone, left, right))
945 top.sp[-2].obj = top.sp[-1].obj;
952 int value = top.sp[-1].i32;
953 int low = READ_TABLESWITCH_LOW(top.pc);
954 int high = READ_TABLESWITCH_HIGH(top.pc);
958 unsigned index = unsigned(value - low);
959 unsigned tablesize = TableSwitchEntries(low, high);
960 if (index < tablesize) {
961 top.pc += OP_TABLESWITCH_LENGTH + OP_JUMP_LENGTH;
962 top.pc += index * OP_JUMP_LENGTH;
970 Array *array = Array::cast(top.sp[-1].obj);
971 top.sp[-1].i32 = array->length();
977 Local<Function> fun(zone, Function::cast(top.sp[-1].obj));
978 zone->registerPublic(fun);
985 Local<Code> code(zone, top.fp->code());
986 Local<Struct> obj(zone, code->module()->globals());
987 Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
988 SetGlobal(zone, obj, name, top.sp[-1]);
994 Local<Code> code(zone, top.fp->code());
995 Local<Struct> obj(zone, code->module()->globals());
996 Local<String> name(zone, String::cast(code->strings()->at(READ_UINT32(top.pc))));
997 GetGlobal(zone, obj, name, top.sp);
1004 top.fp->enterLoop(zone);
1010 top.fp->leaveLoop(zone);
1020 top.pc += OpcodeInfo[op].length;
1021 assert(top.sp >= top.fp->stackBase());
1028 // Unwind frames until we can continue.
1029 while (top.fp != entryFrame)
1030 zone->stack().popInlineFrame();