dvander@47: /* vim: set ts=4 sw=4 tw=99 et: dvander@47: * dvander@0: * Copyright (C) 2012 David Anderson dvander@0: * dvander@0: * This file is part of JITCraft. dvander@0: * dvander@0: * JITCraft is free software: you can redistribute it and/or modify it under dvander@0: * the terms of the GNU General Public License as published by the Free dvander@0: * Software Foundation, either version 3 of the License, or (at your option) dvander@0: * any later version. dvander@0: * dvander@0: * Foobar is distributed in the hope that it will be useful, but WITHOUT ANY dvander@0: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@0: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@0: * dvander@0: * You should have received a copy of the GNU General Public License along with dvander@0: * JITCraft. If not, see http://www.gnu.org/licenses/. dvander@0: */ dvander@0: // Opcode macros: dvander@0: // NAME NUMBER TEXT LENGTH USES DEFS dvander@0: // dvander@0: // Type suffixes: dvander@0: // I = 32-bit integer dvander@19: // F = 32-bit IEEE-754 float dvander@19: // O = object reference dvander@0: dvander@0: // No operation. dvander@0: OPDEF(OP_NOP, 0, "nop", 1, 0, 0) dvander@0: dvander@0: // Pushes a signed integer immediate onto the stack. dvander@0: OPDEF(OP_INT, 1, "int", 5, 0, 1) dvander@0: dvander@0: // Returns from the current routine, propagating the value at the top of the dvander@0: // stack to the caller. dvander@0: OPDEF(OP_RETURN, 2, "return", 1, 1, 0) dvander@0: dvander@0: // Stack transitions for these comparison ops: dvander@0: // rhs = pop() dvander@0: // lhs = pop() dvander@0: // if (lhs COMPARE rhs) dvander@0: // goto target (immediate, relative to the beginning of the jump instruction) dvander@0: OPDEF(OP_JL, 3, "jl", 5, 2, 0) dvander@0: OPDEF(OP_JLE, 4, "jle", 5, 2, 0) dvander@0: OPDEF(OP_JG, 5, "jg", 5, 2, 0) dvander@0: OPDEF(OP_JGE, 6, "jge", 5, 2, 0) dvander@0: OPDEF(OP_JEQ, 7, "jeq", 5, 2, 0) dvander@0: OPDEF(OP_JNE, 8, "jne", 5, 2, 0) dvander@0: dvander@0: // value = pop() dvander@0: // if (value == [true, false]) dvander@0: // goto target dvander@0: OPDEF(OP_JT, 9, "jt", 5, 1, 0) dvander@0: OPDEF(OP_JF, 10, "jf", 5, 1, 0) dvander@0: dvander@74: OPDEF(OP_JL_F, 11, "jl.f", 5, 2, 0) dvander@74: OPDEF(OP_JLE_F, 12, "jle.f", 5, 2, 0) dvander@74: OPDEF(OP_JG_F, 13, "jg.f", 5, 2, 0) dvander@74: OPDEF(OP_JGE_F, 14, "jge.f", 5, 2, 0) dvander@74: OPDEF(OP_JEQ_F, 15, "jeq.f", 5, 2, 0) dvander@74: OPDEF(OP_JNE_F, 16, "jne.f", 5, 2, 0) dvander@74: OPDEF(OP_JT_F, 17, "jt.f", 5, 1, 0) dvander@74: OPDEF(OP_JF_F, 18, "jf.f", 5, 1, 0) dvander@74: dvander@0: // Unconditional jump. dvander@74: OPDEF(OP_JUMP, 19, "jump", 5, 0, 0) dvander@0: dvander@0: // Gets or sets the value of a local variable onto the stack. The local dvander@0: // variable is given by an immediate index. dvander@74: OPDEF(OP_GETLOCAL, 20, "getlocal", 5, 0, 1) dvander@74: OPDEF(OP_SETLOCAL, 21, "setlocal", 5, 1, 1) dvander@0: dvander@0: // Stack transitions for these binary operators: dvander@0: // rhs = pop() dvander@0: // lhs = pop() dvander@0: // push(lhs OP rhs) dvander@74: OPDEF(OP_ADD, 22, "add", 1, 2, 1) dvander@74: OPDEF(OP_SUB, 23, "sub", 1, 2, 1) dvander@74: OPDEF(OP_MUL, 24, "mul", 1, 2, 1) dvander@74: OPDEF(OP_DIV, 25, "div", 1, 2, 1) dvander@82: OPDEF(OP_MOD, 26, "mod", 1, 2, 1) dvander@0: dvander@82: OPDEF(OP_LT, 27, "lt", 1, 2, 1) dvander@82: OPDEF(OP_LE, 28, "le", 1, 2, 1) dvander@82: OPDEF(OP_GE, 29, "ge", 1, 2, 1) dvander@82: OPDEF(OP_GT, 30, "gt", 1, 2, 1) dvander@82: OPDEF(OP_EQ, 31, "eq", 1, 2, 1) dvander@82: OPDEF(OP_NE, 32, "ne", 1, 2, 1) dvander@74: dvander@82: OPDEF(OP_NOT, 33, "not", 1, 1, 1) dvander@82: OPDEF(OP_NEG, 34, "neg", 1, 1, 1) dvander@79: dvander@82: OPDEF(OP_POP, 35, "pop", 1, 1, 0) dvander@0: dvander@72: // Unconditional terminator placed at the end of code. If a function returns dvander@72: // void, this acts as a RETURNVOID. Otherwise, it must be unreachable. dvander@82: OPDEF(OP_STOP, 36, "stop", 1, 0, 0) dvander@0: dvander@73: // Call a function with N arguments. The target function must be the last item dvander@73: // on the stack. dvander@82: OPDEF(OP_CALL, 37, "call", 1, -1, 1) dvander@0: dvander@0: // Similar to GET/LOCAL, except for arguments. dvander@82: OPDEF(OP_GETARG, 38, "getarg", 5, 0, 1) dvander@82: OPDEF(OP_SETARG, 39, "setarg", 5, 1, 1) dvander@0: dvander@0: // Reads or writes an integer element to an unsafe array. dvander@0: // index = pop() dvander@0: // ref = pop() dvander@0: // ref[index] dvander@0: // dvander@82: OPDEF(OP_GETARRAY_I, 40, "getarray.i", 1, 2, 1) dvander@82: OPDEF(OP_SETARRAY_I, 41, "setarray.i", 1, 3, 1) dvander@82: OPDEF(OP_GETARRAY_F, 42, "getarray.f", 1, 2, 1) dvander@82: OPDEF(OP_SETARRAY_F, 43, "setarray.f", 1, 3, 1) dvander@82: OPDEF(OP_GETARRAY_C, 44, "getarray.c", 1, 2, 1) dvander@82: OPDEF(OP_SETARRAY_C, 45, "setarray.c", 1, 3, 1) dvander@82: OPDEF(OP_GETARRAY_O, 46, "getarray.o", 1, 2, 1) dvander@0: dvander@12: // Allocate an array, info LIFO space if possible. The ArrayMap to use is dvander@12: // specified as an index into the script's Map table. dvander@0: // dvander@0: // Format: dvander@12: // [u8 op] [u32 index] dvander@82: OPDEF(OP_NEWARRAY_LIFO, 47, "newarray.lifo", 5, 0, 1) dvander@0: dvander@0: // Performs a bounds check on an unsafe array. dvander@0: // dvander@0: // index = pop() dvander@0: // array = pop() dvander@0: // push(array) dvander@0: // push(index) dvander@82: OPDEF(OP_BOUNDS, 48, "bounds", 1, 2, 2) dvander@4: dvander@4: // Pushes a 32-bit IEEE-754 floating point immediate onto the stack. dvander@82: OPDEF(OP_FLOAT, 49, "float", 5, 0, 1) dvander@4: dvander@4: // Converts an integer to a 32-bit IEEE-754 floating point immediate. dvander@82: OPDEF(OP_CVT_I2F, 50, "cvt.i2f", 1, 1, 1) dvander@4: dvander@4: // Stack transitions for these binary operators: dvander@4: // rhs = pop() dvander@4: // lhs = pop() dvander@4: // push(lhs OP rhs) dvander@82: OPDEF(OP_ADD_F, 51, "add.f", 1, 2, 1) dvander@82: OPDEF(OP_SUB_F, 52, "sub.f", 1, 2, 1) dvander@82: OPDEF(OP_MUL_F, 53, "mul.f", 1, 2, 1) dvander@82: OPDEF(OP_DIV_F, 54, "div.f", 1, 2, 1) dvander@82: OPDEF(OP_UNUSED1, 55, "unused0", 1, 0, 0) dvander@74: dvander@82: OPDEF(OP_LT_F, 56, "lt.f", 1, 2, 1) dvander@82: OPDEF(OP_LE_F, 57, "le.f", 1, 2, 1) dvander@82: OPDEF(OP_GE_F, 58, "ge.f", 1, 2, 1) dvander@82: OPDEF(OP_GT_F, 59, "gt.f", 1, 2, 1) dvander@82: OPDEF(OP_EQ_F, 60, "eq.f", 1, 2, 1) dvander@82: OPDEF(OP_NE_F, 61, "ne.f", 1, 2, 1) dvander@79: dvander@82: OPDEF(OP_NOT_F, 62, "not.f", 1, 1, 1) dvander@82: OPDEF(OP_NEG_F, 63, "neg.f", 1, 1, 1) dvander@4: dvander@8: // Bitwise operators. dvander@82: OPDEF(OP_SHL, 64, "shl", 1, 2, 1) dvander@82: OPDEF(OP_SHR, 65, "shr", 1, 2, 1) dvander@82: OPDEF(OP_USHR, 66, "ushr", 1, 2, 1) dvander@82: OPDEF(OP_BITAND, 67, "bitand", 1, 2, 1) dvander@82: OPDEF(OP_BITOR, 68, "bitor", 1, 2, 1) dvander@82: OPDEF(OP_BITXOR, 69, "bitxor", 1, 2, 1) dvander@82: OPDEF(OP_BITNOT, 70, "bitnot", 1, 1, 1) dvander@12: dvander@12: // Saves or restores the position of the LIFO heap to/from a local slot. dvander@82: OPDEF(OP_SAVELIFO, 71, "savelifo", 5, 0, 0) dvander@82: OPDEF(OP_UNWINDLIFO, 72, "unwindlifo", 5, 0, 0) dvander@14: dvander@14: // Composes a variable reference to a stack slot or argument. dvander@82: OPDEF(OP_VARREF_LIFO, 73, "varref.lifo", 5, 0, 1) dvander@82: OPDEF(OP_ARGREF_LIFO, 74, "argref.lifo", 5, 0, 1) dvander@82: OPDEF(OP_SLOTREF_LIFO, 75, "slotref.lifo", 1, 1, 1) dvander@82: OPDEF(OP_ARRAYREF_LIFO, 76, "arrayref.lifo",1, 2, 1) dvander@82: OPDEF(OP_GETREF_I, 77, "getref.i", 1, 1, 1) dvander@82: OPDEF(OP_SETREF_I, 78, "setref.i", 1, 2, 1) dvander@82: OPDEF(OP_GETREF_F, 79, "getref.f", 1, 1, 1) dvander@82: OPDEF(OP_SETREF_F, 80, "setref.f", 1, 2, 1) dvander@21: dvander@21: // Pushes an object reference onto the stack. dvander@82: OPDEF(OP_OBJECT, 81, "object", 5, 0, 1) dvander@21: dvander@21: // Performs an array-to-array assignment. dvander@21: // Left = pop() dvander@21: // Right = pop() dvander@21: // copy(Left, Right) dvander@21: // push(Left) dvander@82: OPDEF(OP_ARRAYCOPY, 82, "arraycopy", 1, 2, 1) dvander@22: dvander@22: // Duplicates the top item on the stack. dvander@82: OPDEF(OP_DUP, 83, "dup", 1, 1, 2) dvander@22: dvander@22: // Duplicates the top two items on the stack. dvander@82: OPDEF(OP_DUP2, 84, "dup2", 1, 2, 4) dvander@23: dvander@23: // Swaps the two items at the top of the stack. dvander@82: OPDEF(OP_SWAP, 85, "swap", 1, 2, 2) dvander@23: dvander@23: // Roll operation is the same as Forth. It steals a value on the stack, dvander@23: // shifting all stack values down, and then places the stolen value back at dvander@23: // the top of the stack. dvander@23: // dvander@23: // p = sp[-3] dvander@23: // sp[-3] = sp[-2] dvander@23: // sp[-2] = sp[-1] dvander@23: // sp[-1] = p dvander@82: OPDEF(OP_ROLL3, 86, "roll3", 1, 3, 3) dvander@23: dvander@23: // Pick operation is the same as Forth. It pushes a copy of a slot at a dvander@23: // specific depth. dvander@23: // dvander@23: // push(sp[-n]) dvander@82: OPDEF(OP_PICK2, 87, "pick2", 1, 2, 3) dvander@82: OPDEF(OP_PICK3, 88, "pick3", 1, 3, 4) dvander@68: dvander@68: // Calls a native function. During the course of calling a native, arguments dvander@68: // on the stack are re-pushed to match the cell-based native calling dvander@68: // convention expected by ISourcePawnEngine. dvander@68: // dvander@68: // Unlike the normal CALL instruction, natives take truly variadic arguments dvander@68: // and so we must specify the number of arguments. The format is: dvander@68: // dvander@68: // [u8 Opcode] [u32 Index] [u32 ArgCount] dvander@68: // dvander@82: OPDEF(OP_CALLNATIVE, 89, "callnative", 9, -1, 1) dvander@72: dvander@72: // Returns from a function that does return a value. dvander@82: OPDEF(OP_RETURNVOID, 90, "returnvoid", 1, 0, 0) dvander@73: dvander@73: // Loads the module of the running function. dvander@82: OPDEF(OP_MODULE, 91, "module", 1, 0, 1) dvander@73: dvander@73: // Loads a function from a module object. The operand is the slot number dvander@73: // in the module. dvander@82: OPDEF(OP_GETMODULE_FN, 92, "getmodule.fn", 5, 1, 1)