Damien | 429d719 | 2013-10-04 19:53:11 +0100 | [diff] [blame^] | 1 | #include <stdint.h> |
| 2 | #include <stdlib.h> |
| 3 | #include <stdio.h> |
| 4 | #include <string.h> |
| 5 | #include <assert.h> |
| 6 | |
| 7 | #include "misc.h" |
| 8 | #include "machine.h" |
| 9 | #include "runtime.h" |
| 10 | #include "bc.h" |
| 11 | |
| 12 | #define DECODE_UINT do { unum = *ip++; if (unum > 127) { unum = ((unum & 0x3f) << 8) | (*ip++); } } while (0) |
| 13 | #define DECODE_QSTR do { qstr = *ip++; if (qstr > 127) { qstr = ((qstr & 0x3f) << 8) | (*ip++); } } while (0) |
| 14 | #define PUSH(val) *--sp = (val) |
| 15 | #define POP() (*sp++) |
| 16 | |
| 17 | py_obj_t py_execute_byte_code(byte *code, uint len, py_obj_t *args, uint n_args) { |
| 18 | byte *ip = code; |
| 19 | py_obj_t stack[10]; |
| 20 | py_obj_t *sp = &stack[10]; // stack grows down, sp points to top of stack |
| 21 | machine_uint_t unum; |
| 22 | machine_int_t snum; |
| 23 | qstr qstr; |
| 24 | py_obj_t obj1, obj2; |
| 25 | py_obj_t fast0 = NULL, fast1 = NULL, fast2 = NULL, fastn[4] = {NULL, NULL, NULL, NULL}; |
| 26 | |
| 27 | // init args |
| 28 | for (int i = 0; i < n_args; i++) { |
| 29 | if (i == 0) { |
| 30 | fast0 = args[0]; |
| 31 | } else if (i == 1) { |
| 32 | fast1 = args[1]; |
| 33 | } else if (i == 2) { |
| 34 | fast2 = args[2]; |
| 35 | } else { |
| 36 | assert(i - 3 < 4); |
| 37 | fastn[i - 3] = args[i]; |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | // execute byte code |
| 42 | for (;;) { |
| 43 | int op = *ip++; |
| 44 | switch (op) { |
| 45 | case PYBC_LOAD_CONST_FALSE: |
| 46 | PUSH(py_const_false); |
| 47 | break; |
| 48 | |
| 49 | case PYBC_LOAD_CONST_NONE: |
| 50 | PUSH(py_const_none); |
| 51 | break; |
| 52 | |
| 53 | case PYBC_LOAD_CONST_TRUE: |
| 54 | PUSH(py_const_true); |
| 55 | break; |
| 56 | |
| 57 | case PYBC_LOAD_CONST_SMALL_INT: |
| 58 | snum = ip[0] | (ip[1] << 8); |
| 59 | if (snum & 0x8000) { |
| 60 | snum |= ~0xffff; |
| 61 | } |
| 62 | ip += 2; |
| 63 | PUSH((py_obj_t)(snum << 1 | 1)); |
| 64 | break; |
| 65 | |
| 66 | case PYBC_LOAD_CONST_ID: |
| 67 | DECODE_QSTR; |
| 68 | PUSH(rt_load_const_str(qstr)); // TODO |
| 69 | break; |
| 70 | |
| 71 | case PYBC_LOAD_CONST_STRING: |
| 72 | DECODE_QSTR; |
| 73 | PUSH(rt_load_const_str(qstr)); |
| 74 | break; |
| 75 | |
| 76 | case PYBC_LOAD_FAST_0: |
| 77 | PUSH(fast0); |
| 78 | break; |
| 79 | |
| 80 | case PYBC_LOAD_FAST_1: |
| 81 | PUSH(fast1); |
| 82 | break; |
| 83 | |
| 84 | case PYBC_LOAD_FAST_2: |
| 85 | PUSH(fast2); |
| 86 | break; |
| 87 | |
| 88 | case PYBC_LOAD_FAST_N: |
| 89 | DECODE_UINT; |
| 90 | PUSH(fastn[unum - 3]); |
| 91 | break; |
| 92 | |
| 93 | case PYBC_LOAD_NAME: |
| 94 | DECODE_QSTR; |
| 95 | PUSH(rt_load_name(qstr)); |
| 96 | break; |
| 97 | |
| 98 | case PYBC_LOAD_GLOBAL: |
| 99 | DECODE_QSTR; |
| 100 | PUSH(rt_load_global(qstr)); |
| 101 | break; |
| 102 | |
| 103 | case PYBC_LOAD_ATTR: |
| 104 | DECODE_QSTR; |
| 105 | *sp = rt_load_attr(*sp, qstr); |
| 106 | break; |
| 107 | |
| 108 | case PYBC_LOAD_METHOD: |
| 109 | DECODE_QSTR; |
| 110 | sp -= 1; |
| 111 | rt_load_method(sp[1], qstr, sp); |
| 112 | break; |
| 113 | |
| 114 | case PYBC_LOAD_BUILD_CLASS: |
| 115 | PUSH(rt_load_build_class()); |
| 116 | break; |
| 117 | |
| 118 | case PYBC_STORE_FAST_0: |
| 119 | fast0 = POP(); |
| 120 | break; |
| 121 | |
| 122 | case PYBC_STORE_FAST_1: |
| 123 | fast1 = POP(); |
| 124 | break; |
| 125 | |
| 126 | case PYBC_STORE_FAST_2: |
| 127 | fast2 = POP(); |
| 128 | break; |
| 129 | |
| 130 | case PYBC_STORE_FAST_N: |
| 131 | DECODE_UINT; |
| 132 | fastn[unum - 3] = POP(); |
| 133 | break; |
| 134 | |
| 135 | case PYBC_STORE_NAME: |
| 136 | DECODE_QSTR; |
| 137 | rt_store_name(qstr, POP()); |
| 138 | break; |
| 139 | |
| 140 | case PYBC_STORE_SUBSCR: |
| 141 | rt_store_subscr(sp[1], sp[0], sp[2]); |
| 142 | sp += 3; |
| 143 | break; |
| 144 | |
| 145 | case PYBC_DUP_TOP: |
| 146 | obj1 = *sp; |
| 147 | PUSH(obj1); |
| 148 | break; |
| 149 | |
| 150 | case PYBC_DUP_TOP_TWO: |
| 151 | sp -= 2; |
| 152 | sp[0] = sp[2]; |
| 153 | sp[1] = sp[3]; |
| 154 | break; |
| 155 | |
| 156 | case PYBC_POP_TOP: |
| 157 | ++sp; |
| 158 | break; |
| 159 | |
| 160 | case PYBC_ROT_THREE: |
| 161 | obj1 = sp[0]; |
| 162 | sp[0] = sp[1]; |
| 163 | sp[1] = sp[2]; |
| 164 | sp[2] = obj1; |
| 165 | break; |
| 166 | |
| 167 | case PYBC_JUMP: |
| 168 | DECODE_UINT; |
| 169 | ip = code + unum; |
| 170 | break; |
| 171 | |
| 172 | case PYBC_POP_JUMP_IF_FALSE: |
| 173 | DECODE_UINT; |
| 174 | if (!rt_is_true(POP())) { |
| 175 | ip = code + unum; |
| 176 | } |
| 177 | break; |
| 178 | |
| 179 | case PYBC_SETUP_LOOP: |
| 180 | DECODE_UINT; |
| 181 | break; |
| 182 | |
| 183 | case PYBC_POP_BLOCK: |
| 184 | break; |
| 185 | |
| 186 | case PYBC_BINARY_OP: |
| 187 | unum = *ip++; |
| 188 | obj2 = POP(); |
| 189 | obj1 = *sp; |
| 190 | *sp = rt_binary_op(unum, obj1, obj2); |
| 191 | break; |
| 192 | |
| 193 | case PYBC_COMPARE_OP: |
| 194 | unum = *ip++; |
| 195 | obj2 = POP(); |
| 196 | obj1 = *sp; |
| 197 | *sp = rt_compare_op(unum, obj1, obj2); |
| 198 | break; |
| 199 | |
| 200 | case PYBC_BUILD_LIST: |
| 201 | DECODE_UINT; |
| 202 | obj1 = rt_build_list(unum, sp); |
| 203 | sp += unum - 1; |
| 204 | *sp = obj1; |
| 205 | break; |
| 206 | |
| 207 | case PYBC_BUILD_MAP: |
| 208 | DECODE_UINT; |
| 209 | PUSH(rt_build_map(unum)); |
| 210 | break; |
| 211 | |
| 212 | case PYBC_STORE_MAP: |
| 213 | sp += 2; |
| 214 | rt_store_map(sp[0], sp[-2], sp[-1]); |
| 215 | break; |
| 216 | |
| 217 | case PYBC_BUILD_SET: |
| 218 | DECODE_UINT; |
| 219 | obj1 = rt_build_set(unum, sp); |
| 220 | sp += unum - 1; |
| 221 | *sp = obj1; |
| 222 | break; |
| 223 | |
| 224 | case PYBC_MAKE_FUNCTION: |
| 225 | DECODE_UINT; |
| 226 | PUSH(rt_make_function_from_id(unum)); |
| 227 | break; |
| 228 | |
| 229 | case PYBC_CALL_FUNCTION: |
| 230 | DECODE_UINT; |
| 231 | assert((unum & 0xff00) == 0); // n_keyword |
| 232 | // switch on n_positional |
| 233 | if ((unum & 0xff) == 0) { |
| 234 | *sp = rt_call_function_0(*sp); |
| 235 | } else if ((unum & 0xff) == 1) { |
| 236 | obj1 = *sp++; // the single argument |
| 237 | *sp = rt_call_function_1(*sp, obj1); |
| 238 | } else if ((unum & 0xff) == 2) { |
| 239 | obj2 = *sp++; // the second argument |
| 240 | obj1 = *sp++; // the first argument |
| 241 | *sp = rt_call_function_2(*sp, obj1, obj2); |
| 242 | } else { |
| 243 | assert(0); |
| 244 | } |
| 245 | break; |
| 246 | |
| 247 | case PYBC_CALL_METHOD: |
| 248 | DECODE_UINT; |
| 249 | assert((unum & 0xff00) == 0); // n_keyword |
| 250 | // switch on n_positional |
| 251 | if ((unum & 0xff) == 0) { |
| 252 | obj1 = *sp++; // the self object (or NULL) |
| 253 | *sp = rt_call_method_1(*sp, obj1); |
| 254 | } else if ((unum & 0xff) == 1) { |
| 255 | obj2 = *sp++; // the first argument |
| 256 | obj1 = *sp++; // the self object (or NULL) |
| 257 | *sp = rt_call_function_2(*sp, obj1, obj2); |
| 258 | } else { |
| 259 | assert(0); |
| 260 | } |
| 261 | break; |
| 262 | |
| 263 | case PYBC_RETURN_VALUE: |
| 264 | return *sp; |
| 265 | |
| 266 | default: |
| 267 | printf("code %p, offset %u, byte code 0x%02x not implemented\n", code, (uint)(ip - code), op); |
| 268 | assert(0); |
| 269 | return py_const_none; |
| 270 | } |
| 271 | } |
| 272 | } |