Small refactoring to make callees pushed explicitly.
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();
414 Local<Function> newFun(zone, top.sp[-1].fun);
417 if (!zone->stack().pushInlineFrame(newFun))
420 locals = top.fp->locals();
426 unsigned slot = READ_UINT32(top.pc);
427 *top.sp++ = top.fp->arg(slot);
433 unsigned slot = READ_UINT32(top.pc);
434 top.fp->arg(slot) = *--top.sp;
440 Array *array = top.sp[-2].array;
441 int index = top.sp[-1].i32;
442 if (index < 0 || unsigned(index) >= array->nelements()) {
443 zone->reportError(Message_ArrayIndexOutOfBounds, index, array->nelements());
451 Array *array = top.sp[-2].array;
452 int index = top.sp[-1].i32;
453 top.sp[-2].i32 = array->readInt32(index);
460 Array *array = top.sp[-2].array;
461 int index = top.sp[-1].i32;
462 top.sp[-2].f = array->readFloat(index);
469 Array *array = top.sp[-2].array;
470 int index = top.sp[-1].i32;
471 top.sp[-2].i32 = array->readChar(index);
478 Array *array = top.sp[-3].array;
479 int index = top.sp[-2].i32;
480 array->writeInt32(index, top.sp[-1].i32);
481 top.sp[-3] = top.sp[-1];
488 Array *array = top.sp[-3].array;
489 int index = top.sp[-2].i32;
490 array->writeFloat(index, top.sp[-1].f);
491 top.sp[-3] = top.sp[-1];
498 Array *array = top.sp[-3].array;
499 int index = top.sp[-2].i32;
500 array->writeChar(index, top.sp[-1].i32);
501 top.sp[-3] = top.sp[-1];
508 Array *array = top.sp[-2].array;
509 int index = top.sp[-1].i32;
510 top.sp[-2].array = Array::cast(array->readObject(index));
517 int ival = POP_I32(top);
518 float fval = (float)ival;
523 case OP_NEWARRAY_LIFO:
525 Local<ArrayMap> map(zone, ArrayMap::cast(top.fp->code()->map(READ_UINT32(top.pc))));
526 Array *array = GenerateArray(zone, map);
536 unsigned slot = READ_UINT32(top.pc);
537 locals[slot].address = zone->heap().lifoPosition();
543 unsigned slot = READ_UINT32(top.pc);
544 zone->heap().unwindLifo(locals[slot].address);
550 unsigned slot = READ_UINT32(top.pc);
551 if (!PushNewRef(zone, top, &locals[slot], Heap::Tenure_Stack))
558 unsigned slot = READ_UINT32(top.pc);
559 if (!PushNewRef(zone, top, &top.fp->arg(slot), Heap::Tenure_Stack))
564 case OP_ARRAYREF_LIFO:
566 Local<Array> array(zone, top.sp[-2].array);
567 Local<Reference> ref(zone, Reference::NewArray(zone, array, top.sp[-1].i32, Heap::Tenure_Stack));
570 top.sp[-2].ref = ref;
575 case OP_SLOTREF_LIFO:
577 Reference *ref = Reference::NewStack(zone, top.sp[-1], Heap::Tenure_Stack);
580 top.sp[-1].ref = ref;
586 top.sp[-1].i32 = top.sp[-1].ref->getInt();
592 top.sp[-2].ref->setInt(top.sp[-1].i32);
593 top.sp[-2].i32 = top.sp[-1].i32;
600 top.sp[-1].f = top.sp[-1].ref->getFloat();
606 top.sp[-2].ref->setFloat(top.sp[-1].f);
607 top.sp[-2].f = top.sp[-1].f;
613 top.sp->obj = top.fp->code()->object(READ_UINT32(top.pc));
620 // Note for this assignment opcode, we return the left-hand side, not the
621 // right, since in this case the result of the expression could be different.
622 if (!CopyArray(zone, top.sp[-2].array, top.sp[-1].array))
631 top.sp[-1] = top.sp[-2];
638 top.sp[-2] = top.sp[-4];
639 top.sp[-1] = top.sp[-3];
645 LocalSlot slot = top.sp[-2];
646 top.sp[-2] = top.sp[-1];
653 LocalSlot slot = top.sp[-3];
654 top.sp[-3] = top.sp[-2];
655 top.sp[-2] = top.sp[-1];
663 top.sp[-1] = top.sp[-3];
670 top.sp[-1] = top.sp[-4];
676 unsigned index = READ_UINT32(top.pc);
677 unsigned argc = READ_UINT32(top.pc + 4);
679 Local<Native> native(zone, Native::cast(top.fp->code()->module()->natives()->at(index)));
680 if (!native->function()) {
681 zone->reportError(Message_NativeNotBound, native->name()->chars());
686 void *nativeIdentity = top.fp->code()->module()->nativeIdentity();
687 if (!InvokeNative(zone, native, nativeIdentity, top.sp, argc, &result))
691 PUSH_I32(top, result);
698 top.sp[-1].module = top.fp->code()->module();
702 case OP_GETMODULE_FN:
704 top.sp[-1].fun = top.sp[-1].module->getFunction(READ_UINT32(top.pc));
714 top.pc += OpcodeInfo[op].length;
721 // Unwind frames until we can continue.
722 while (top.fp != entryFrame)
723 zone->stack().popInlineFrame();