Added support for calling return-void functions.
Fixed a bug in array size calculation.
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"
30 #define PUSH_I32(top, value) \
32 top.sp->i32 = value; \
36 #define PUSH_F(top, value) \
45 int value = top.sp[-1].i32;
53 float value = top.sp[-1].f;
59 PushNewRef(Zone *zone, Top &top, void *location, Heap::Tenure tenure)
61 Reference *ref = Reference::NewStack(zone, location, tenure);
69 // Generate an array with completely static sizes.
71 GenerateArray(Zone *zone, Handle<ArrayMap> map)
73 assert(map->type()->elements() != -1);
75 Local<Array> array(zone, Array::New(zone, map, map->type()->elements(), Heap::Tenure_Stack));
79 if (map->type()->levels() == 1)
82 Local<ArrayMap> contained(zone, map->contained());
83 Local<Array> sub(zone);
84 for (unsigned i = 0; i < unsigned(map->type()->elements()); i++) {
85 sub = GenerateArray(zone, contained);
88 array->writeObject(zone, i, sub);
95 CopyArray(Zone *zone, Array *source, Array *dest)
97 assert(source->type()->levels() == 1);
98 assert(dest->type()->levels() == 1);
99 assert(source->type()->contained()->primitive() ==
100 dest->type()->contained()->primitive());
101 assert(source->nelements() >= dest->nelements());
102 assert(dest->elementSize() == source->elementSize());
104 memcpy(source->vec(), dest->vec(), dest->nelements() * dest->elementSize());
109 InvokeNative(Zone *zone, Handle<Native> native, void *identity, LocalSlot *args, unsigned argc,
114 if (!zone->stack().pushNativeFrame(native, guard, argc + 1))
117 intptr_t *cells = guard.args();
119 // params[0] == argc, in ISPE
122 // Pass the formal arguments.
123 Local<Type> type(zone, native->type());
124 Local<Type> param(zone);
125 for (unsigned i = 0; i < type->parameters()->length(); i++) {
126 param = type->parameterAt(i);
128 // For floats, we rely on the aliasing of |i32| and |f|.
129 LocalSlot &arg = args[-int(i) - 1];
130 if (param->isInt32() || param->isFloat()) {
131 cells[i + 1] = arg.i32;
132 } else if (param->isReference()) {
133 cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
135 assert(param->isArray());
136 cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
140 // For variadic arguments, the compiler left either arrays or references.
141 for (unsigned i = type->parameters()->length(); i < argc; i++) {
142 LocalSlot &arg = args[-int(i) - 1];
144 if (arg.obj->is(MapKind_Reference)) {
145 cells[i + 1] = reinterpret_cast<intptr_t>(arg.ref->location());
147 assert(arg.obj->is(MapKind_Array));
148 cells[i + 1] = reinterpret_cast<intptr_t>(arg.array->vec());
152 typedef intptr_t (*INVOKE)(void *, intptr_t *);
153 INVOKE invoke = (INVOKE)native->function();
154 *result = invoke(identity, cells);
156 return !zone->hasPendingException();
160 ke::Interpret(Zone *zone, Frame *entryFrame, LocalSlot *result)
162 Top &top = *zone->stack().top();
166 LocalSlot *locals = entryFrame->locals();
169 Opcode op = Opcode(*top.pc);
176 PUSH_I32(top, READ_INT32(top.pc));
180 PUSH_F(top, READ_FLOAT(top.pc));
190 if (top.fp == entryFrame)
194 zone->stack().popInlineFrame();
195 locals = top.fp->locals();
200 top.pc += OpcodeInfo[*top.pc].length;
204 #define RELATIONAL_JUMP(op) \
206 int right = POP_I32(top); \
207 int left = POP_I32(top); \
208 if (left op right) { \
209 top.pc += READ_INT32(top.pc); \
240 int value = POP_I32(top);
242 top.pc += READ_INT32(top.pc);
250 int value = POP_I32(top);
252 top.pc += READ_INT32(top.pc);
259 top.pc += READ_INT32(top.pc);
264 int slot = READ_INT32(top.pc);
265 *top.sp++ = locals[slot];
271 int slot = READ_INT32(top.pc);
272 locals[slot] = top.sp[-1];
278 int right = POP_I32(top);
279 int left = POP_I32(top);
280 int result = left + right;
281 PUSH_I32(top, result);
287 int right = POP_I32(top);
288 int left = POP_I32(top);
289 int result = left - right;
290 PUSH_I32(top, result);
296 int right = POP_I32(top);
297 int left = POP_I32(top);
298 int result = left * right;
299 PUSH_I32(top, result);
305 int right = POP_I32(top);
306 int left = POP_I32(top);
308 zone->reportError(Message_IntegerDivideByZero);
311 int result = left / right;
312 PUSH_I32(top, result);
318 float right = POP_F(top);
319 float left = POP_F(top);
320 float result = left + right;
327 float right = POP_F(top);
328 float left = POP_F(top);
329 float result = left - right;
336 float right = POP_F(top);
337 float left = POP_F(top);
338 float result = left * right;
345 float right = POP_F(top);
346 float left = POP_F(top);
347 float result = left / right;
354 int right = POP_I32(top);
355 int left = POP_I32(top);
356 int result = left << right;
357 PUSH_I32(top, result);
363 int right = POP_I32(top);
364 int left = POP_I32(top);
365 int result = left >> right;
366 PUSH_I32(top, result);
372 int right = POP_I32(top);
373 int left = POP_I32(top);
374 int result = unsigned(left) >> unsigned(right);
375 PUSH_I32(top, result);
381 int right = POP_I32(top);
382 int left = POP_I32(top);
383 int result = left & right;
384 PUSH_I32(top, result);
390 int right = POP_I32(top);
391 int left = POP_I32(top);
392 int result = left | right;
393 PUSH_I32(top, result);
399 int right = POP_I32(top);
400 int left = POP_I32(top);
401 int result = left ^ right;
402 PUSH_I32(top, result);
412 zone->heap().reclaim();
413 unsigned index = READ_UINT32(top.pc);
414 Local<Function> newFun(zone, top.fp->code()->module()->getFunction(index));
415 if (!zone->stack().pushInlineFrame(newFun))
418 locals = top.fp->locals();
424 unsigned slot = READ_UINT32(top.pc);
425 *top.sp++ = top.fp->arg(slot);
431 unsigned slot = READ_UINT32(top.pc);
432 top.fp->arg(slot) = *--top.sp;
438 Array *array = top.sp[-2].array;
439 int index = top.sp[-1].i32;
440 if (index < 0 || unsigned(index) >= array->nelements()) {
441 zone->reportError(Message_ArrayIndexOutOfBounds, index, array->nelements());
449 Array *array = top.sp[-2].array;
450 int index = top.sp[-1].i32;
451 top.sp[-2].i32 = array->readInt32(index);
458 Array *array = top.sp[-2].array;
459 int index = top.sp[-1].i32;
460 top.sp[-2].f = array->readFloat(index);
467 Array *array = top.sp[-2].array;
468 int index = top.sp[-1].i32;
469 top.sp[-2].i32 = array->readChar(index);
476 Array *array = top.sp[-3].array;
477 int index = top.sp[-2].i32;
478 array->writeInt32(index, top.sp[-1].i32);
479 top.sp[-3] = top.sp[-1];
486 Array *array = top.sp[-3].array;
487 int index = top.sp[-2].i32;
488 array->writeFloat(index, top.sp[-1].f);
489 top.sp[-3] = top.sp[-1];
496 Array *array = top.sp[-3].array;
497 int index = top.sp[-2].i32;
498 array->writeChar(index, top.sp[-1].i32);
499 top.sp[-3] = top.sp[-1];
506 Array *array = top.sp[-2].array;
507 int index = top.sp[-1].i32;
508 top.sp[-2].array = Array::cast(array->readObject(index));
515 int ival = POP_I32(top);
516 float fval = (float)ival;
521 case OP_NEWARRAY_LIFO:
523 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc))));
524 Array *array = GenerateArray(zone, map);
534 unsigned slot = READ_UINT32(top.pc);
535 locals[slot].address = zone->heap().lifoPosition();
541 unsigned slot = READ_UINT32(top.pc);
542 zone->heap().unwindLifo(locals[slot].address);
548 unsigned slot = READ_UINT32(top.pc);
549 if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
556 unsigned slot = READ_UINT32(top.pc);
557 if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
562 case OP_ARRAYREF_LIFO:
564 Local<Array> array(zone, top.sp[-2].array);
565 Local<Reference> ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack));
568 top.sp[-2].ref = ref;
573 case OP_SLOTREF_LIFO:
575 Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
578 top.sp[-1].ref = ref;
584 top.sp[-1].i32 = top.sp[-1].ref->getInt();
590 top.sp[-2].ref->setInt(top.sp[-1].i32);
591 top.sp[-2].i32 = top.sp[-1].i32;
598 top.sp[-1].f = top.sp[-1].ref->getFloat();
604 top.sp[-2].ref->setFloat(top.sp[-1].f);
605 top.sp[-2].f = top.sp[-1].f;
611 top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
618 // Note for this assignment opcode, we return the left-hand side, not the
619 // right, since in this case the result of the expression could be different.
620 if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array))
629 top.sp[-1] = top.sp[-2];
636 top.sp[-2] = top.sp[-4];
637 top.sp[-1] = top.sp[-3];
643 LocalSlot slot = top.sp[-2];
644 top.sp[-2] = top.sp[-1];
651 LocalSlot slot = top.sp[-3];
652 top.sp[-3] = top.sp[-2];
653 top.sp[-2] = top.sp[-1];
661 top.sp[-1] = top.sp[-3];
668 top.sp[-1] = top.sp[-4];
674 unsigned index = READ_UINT32(top.pc);
675 unsigned argc = READ_UINT32(top.pc + 4);
677 Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
678 if (!native->function()) {
679 zone->reportError(Message_NativeNotBound, native->name()->chars());
684 void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
685 if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
689 PUSH_I32(top, result);
699 top.pc += OpcodeInfo[op].length;
706 // Unwind frames until we can continue.
707 while (top.fp != entryFrame)
708 zone->stack().popInlineFrame();