quipu mercurial repository
Revisión | d52ca309f785f7983ebe10a1c90ac18a23a151bc (tree) |
---|---|
Tiempo | 2017-12-15 08:13:52 |
Autor | Agustina Arzille <avarzille@rise...> |
Commiter | Agustina Arzille |
Implement exceptions
@@ -27,7 +27,6 @@ | ||
27 | 27 | OP_LOAD0, |
28 | 28 | OP_LOAD1, |
29 | 29 | OP_LOADI8, |
30 | - OP_TRY, | |
31 | 30 | OP_LOADA0, |
32 | 31 | OP_LOADA1, |
33 | 32 | OP_LOADC00, |
@@ -37,7 +36,7 @@ | ||
37 | 36 | OP_KWARGS, |
38 | 37 | OP_MKCONT, |
39 | 38 | OP_CAPTENV, |
40 | - OP_CAPTSETENV, | |
39 | + OP_TRYEND, | |
41 | 40 | // Opcodes with long forms. |
42 | 41 | OP_ARGC, |
43 | 42 | OP_ARGCL, |
@@ -80,7 +79,9 @@ | ||
80 | 79 | OP_MKFRAME, |
81 | 80 | OP_MKFRAMEL, |
82 | 81 | OP_UNWIND, |
83 | - OP_UNWINDL | |
82 | + OP_UNWINDL, | |
83 | + OP_TRYBEGIN, | |
84 | + OP_TRYBEGINL | |
84 | 85 | }; |
85 | 86 | |
86 | 87 | QP_DECLS_END |
@@ -47,7 +47,8 @@ | ||
47 | 47 | static bool |
48 | 48 | brform_p (object inst) |
49 | 49 | { |
50 | - return (inst >= OPX_(JMP) && inst <= OPX_(BRNEQL)); | |
50 | + return ((inst >= OPX_(JMP) && inst <= OPX_(BRNEQL)) || | |
51 | + inst == OPX_(TRYBEGIN) || inst == OPX_(TRYBEGINL)); | |
51 | 52 | } |
52 | 53 | |
53 | 54 | #if defined (QP_ARCH_I386) || defined (QP_ARCH_X8664) || \ |
@@ -348,6 +349,7 @@ | ||
348 | 349 | void compile_app (object env, bool tail, object expr); |
349 | 350 | void compile_recur (object env, bool tail, object expr); |
350 | 351 | bool compile_index_seq (object env, bool tail, object expr); |
352 | + void compile_try (object env, bool tail, object expr); | |
351 | 353 | int compile_in (object env, bool tail, object expr); |
352 | 354 | void emit_optargs_init (object env, object opta, object vars, int idx); |
353 | 355 |
@@ -1083,6 +1085,18 @@ | ||
1083 | 1085 | return (true); |
1084 | 1086 | } |
1085 | 1087 | |
1088 | +void bc_emitter::compile_try (object env, bool tail, object expr) | |
1089 | +{ | |
1090 | + int clbl = this->next_label (), end = this->next_label (); | |
1091 | + this->emit (OPX_(TRYBEGIN), intobj (clbl)); | |
1092 | + this->compile_in (env, false, xcadr (expr)); | |
1093 | + this->emit (OPX_(JMP), intobj (end)); | |
1094 | + this->mark_label (clbl); | |
1095 | + this->compile_in (env, false, xcar (xcddr (expr))); | |
1096 | + this->emit (OPX_(TRYEND)); | |
1097 | + this->mark_label (end); | |
1098 | +} | |
1099 | + | |
1086 | 1100 | static const object LOAD_OPS[] = |
1087 | 1101 | { |
1088 | 1102 | OPX_(LOADA), OPX_(LOADC), OPX_(LOADG), OPX_(LOADAP) |
@@ -1297,7 +1311,10 @@ | ||
1297 | 1311 | break; |
1298 | 1312 | } |
1299 | 1313 | |
1300 | - // XXX: SF_TRY here. | |
1314 | + case SF_TRY: | |
1315 | + this->compile_try (env, tail, expr); | |
1316 | + break; | |
1317 | + | |
1301 | 1318 | default: |
1302 | 1319 | this->compile_app (env, tail, expr); |
1303 | 1320 | break; |
@@ -1931,8 +1948,71 @@ | ||
1931 | 1948 | return (as_array(interp->retval)->data[ix]); |
1932 | 1949 | } |
1933 | 1950 | |
1951 | +// Dynamic frames. | |
1952 | + | |
1953 | +/* Inside a dynamic frame, we store some data that is used during | |
1954 | + * runtime execution. This includes exception information, | |
1955 | + * dynamic let bindings and dynamic locals from '%putd'. */ | |
1956 | + | |
1957 | +static const int dynframe_size = 2; | |
1958 | +static const int edata_size = 3; | |
1959 | + | |
1960 | +static void | |
1961 | +dynframe_make (interpreter *interp, object& dst) | |
1962 | +{ | |
1963 | + if (array_p (dst)) | |
1964 | + return; | |
1965 | + | |
1966 | + object prev = dst; | |
1967 | + array *fp = as_array (alloc_array (interp, dynframe_size, NIL)); | |
1968 | + fp->data[0] = prev; | |
1969 | + dst = fp->as_obj (); | |
1970 | +} | |
1971 | + | |
1972 | +static void | |
1973 | +edata_make (interpreter *interp, object& dst, uint32_t off) | |
1974 | +{ | |
1975 | + dynframe_make (interp, dst); | |
1976 | + object ed = alloc_array (interp, edata_size, NIL); | |
1977 | + | |
1978 | + as_array(ed)->data[0] = intobj (interp->sp); | |
1979 | + as_array(ed)->data[1] = intobj (off); | |
1980 | + as_array(ed)->data[2] = as_array(dst)->data[1]; | |
1981 | + | |
1982 | + as_array(dst)->data[1] = ed; | |
1983 | +} | |
1984 | + | |
1985 | +static void | |
1986 | +edata_pop (object& dst) | |
1987 | +{ | |
1988 | + object& tmp = as_array(dst)->data[1]; | |
1989 | + tmp = as_array(tmp)->data[edata_size - 1]; | |
1990 | +} | |
1991 | + | |
1992 | +static inline bool | |
1993 | +dynframe_captured_p (object ed) | |
1994 | +{ | |
1995 | + return (intobj (1) == (int_p (ed) ? ed : as_array(ed)->data[0])); | |
1996 | +} | |
1997 | + | |
1998 | +static inline void | |
1999 | +dynframe_set_captured (object& dst) | |
2000 | +{ | |
2001 | + if (int_p (dst)) | |
2002 | + dst = intobj (1); | |
2003 | + else | |
2004 | + as_array(dst)->data[0] = intobj (1); | |
2005 | +} | |
2006 | + | |
2007 | +// Additional data used in function calls. | |
2008 | +struct call_data | |
2009 | +{ | |
2010 | + uint32_t ip_offset; | |
2011 | + uint32_t topf; | |
2012 | +}; | |
2013 | + | |
1934 | 2014 | static object __attribute__((hot)) |
1935 | -apply_n (interpreter *interp, uint32_t nargs, object cont = UNBOUND) | |
2015 | +run_bytecode (interpreter *interp, uint32_t nargs, const call_data *cdp = 0) | |
1936 | 2016 | { |
1937 | 2017 | uint32_t lastf, top_frame = interp->cur_frame; |
1938 | 2018 | uint32_t n = 0, bp, ix; |
@@ -1952,26 +2032,23 @@ | ||
1952 | 2032 | uint32_t op; |
1953 | 2033 | #endif |
1954 | 2034 | |
1955 | - if (cont != UNBOUND) | |
2035 | + if (cdp != 0) | |
1956 | 2036 | { |
1957 | - continuation *cnp = as_continuation (cont); | |
1958 | - const array *argv = as_array (cnp->argv); | |
1959 | - | |
1960 | - interp->growstk (argv->len); | |
1961 | - copy_objs (&stack[sp], argv->data, argv->len); | |
1962 | - sp += argv->len; | |
1963 | - | |
1964 | - nargs = as_int (argv->data[argv->len - 3]); | |
1965 | - fn = argv->data[argv->len - nargs - 6]; | |
1966 | - ip = as_bvector(fct_bcode (fn))->data + cnp->ip_offset; | |
1967 | - bp = sp - nargs - 5; | |
1968 | - captured = array_p (stack[bp + nargs]); | |
1969 | - | |
1970 | - // Continuations always stem from non-artificial functions. | |
1971 | - ++interp->call_depth; | |
1972 | - // Include the recently evaluated continuation in the stack. | |
1973 | - interp->push (cont); | |
1974 | - interp->cur_frame = sp - 1; | |
2037 | + top_frame = cdp->topf; | |
2038 | + captured = dynframe_captured_p (stack[interp->cur_frame - 1]); | |
2039 | + nargs = as_int (stack[interp->cur_frame - 3]); | |
2040 | + bp = interp->cur_frame - 5 - nargs; | |
2041 | + fn = stack[bp - 1]; | |
2042 | + ip = as_bvector(fct_bcode (fn))->data + cdp->ip_offset; | |
2043 | + | |
2044 | + for (lastf = interp->cur_frame; lastf > 0 ; ) | |
2045 | + if (!(fn & EXTRA_BIT)) | |
2046 | + break; | |
2047 | + else | |
2048 | + { | |
2049 | + lastf = stack[lastf - 4]; | |
2050 | + fn = stack[lastf - 5 - as_int (stack[lastf - 3])]; | |
2051 | + } | |
1975 | 2052 | } |
1976 | 2053 | else |
1977 | 2054 | { |
@@ -1979,7 +2056,6 @@ | ||
1979 | 2056 | captured = false; |
1980 | 2057 | fn = stack[sp - nargs - 1]; |
1981 | 2058 | ip = as_bvector(fct_bcode (fn))->data; |
1982 | - ++interp->call_depth; | |
1983 | 2059 | |
1984 | 2060 | bp = sp - nargs; |
1985 | 2061 | interp->push (as_fct(fn)->env); |
@@ -2157,7 +2233,6 @@ | ||
2157 | 2233 | OP_(RET): |
2158 | 2234 | interp->pop (); |
2159 | 2235 | sp = interp->cur_frame; |
2160 | - --interp->call_depth; | |
2161 | 2236 | |
2162 | 2237 | if ((interp->cur_frame = as_int (stack[sp - 4])) == top_frame) |
2163 | 2238 | return (retval); |
@@ -2166,8 +2241,8 @@ | ||
2166 | 2241 | sp -= 5 + nargs; |
2167 | 2242 | nargs = as_int (stack[interp->cur_frame - 3]); |
2168 | 2243 | |
2169 | - bp = interp->cur_frame - 5 - nargs; | |
2170 | - captured = stack[interp->cur_frame - 1] != intobj (0); | |
2244 | + bp = interp->cur_frame - (5 + nargs); | |
2245 | + captured = dynframe_captured_p (stack[interp->cur_frame - 1]); | |
2171 | 2246 | stack[sp - 1] = retval; |
2172 | 2247 | |
2173 | 2248 | ip = as_bvector(fct_bcode (stack[bp - 1]))->data + |
@@ -2368,7 +2443,20 @@ | ||
2368 | 2443 | loadc_setc_helper(interp, ip, bp, nargs) = stack[sp - 1]; |
2369 | 2444 | NEXT_OP; |
2370 | 2445 | |
2371 | - // XXX: try-catch here. | |
2446 | + OP_(TRYBEGIN): | |
2447 | + OP_(TRYBEGINL): | |
2448 | + if (*(ip - 1) == OP_TRYBEGIN) | |
2449 | + sx = get16 (ip) - sizeof (int16_t), ip += sizeof (int16_t); | |
2450 | + else | |
2451 | + sx = fetch32 (ip) - sizeof (int32_t); | |
2452 | + | |
2453 | + sx = (ip - as_bvector(fct_bcode (stack[bp - 1]))->data) + sx; | |
2454 | + edata_make (interp, stack[interp->cur_frame - 1], sx); | |
2455 | + NEXT_OP; | |
2456 | + | |
2457 | + OP_(TRYEND): | |
2458 | + edata_pop (stack[interp->cur_frame - 1]); | |
2459 | + NEXT_OP; | |
2372 | 2460 | |
2373 | 2461 | OP_(OPTARGS): |
2374 | 2462 | ix = fetch32 (ip); |
@@ -2471,12 +2559,11 @@ | ||
2471 | 2559 | |
2472 | 2560 | stack[sp - n - 1] = fn = stack[bp - 1] | EXTRA_BIT; |
2473 | 2561 | ix = bp, bp = sp - n; |
2474 | - captured = false; | |
2475 | 2562 | interp->push (stack[ix]); |
2476 | 2563 | interp->push (intobj (interp->cur_frame)); |
2477 | 2564 | interp->push (intobj (n)); |
2478 | 2565 | interp->push (intobj (sx)); // Actually the SP. |
2479 | - interp->push (intobj (0)); // captured? | |
2566 | + interp->push (stack[interp->cur_frame - 1]); | |
2480 | 2567 | interp->cur_frame = sp; |
2481 | 2568 | nargs = n; |
2482 | 2569 | NEXT_OP; |
@@ -2496,7 +2583,7 @@ | ||
2496 | 2583 | lastf = interp->cur_frame; |
2497 | 2584 | nargs = as_int (stack[interp->cur_frame - 3]); |
2498 | 2585 | bp = sp - 5 - nargs; |
2499 | - captured = stack[interp->cur_frame - 1] != intobj (0); | |
2586 | + captured = dynframe_captured_p (stack[interp->cur_frame - 1]); | |
2500 | 2587 | interp->push (retval); |
2501 | 2588 | NEXT_OP; |
2502 | 2589 |
@@ -2505,9 +2592,9 @@ | ||
2505 | 2592 | { |
2506 | 2593 | alloc_array (interp, nargs + 1, UNBOUND); |
2507 | 2594 | copy_objs (as_array(interp->alval)->data, &stack[bp], nargs + 1); |
2595 | + stack[bp] = interp->alval; | |
2508 | 2596 | captured = true; |
2509 | - stack[interp->cur_frame - 1] = intobj (1); | |
2510 | - stack[bp] = interp->alval; | |
2597 | + dynframe_set_captured (stack[interp->cur_frame - 1]); | |
2511 | 2598 | } |
2512 | 2599 | |
2513 | 2600 | { |
@@ -2532,6 +2619,59 @@ | ||
2532 | 2619 | #endif |
2533 | 2620 | } |
2534 | 2621 | |
2622 | +// Test if we can handle an exception in a particular stack frame. | |
2623 | +static bool | |
2624 | +eh_inframe (interpreter *interp, uint32_t frame) | |
2625 | +{ | |
2626 | + object ed = interp->stack[frame - 1]; | |
2627 | + if (!array_p (ed) || !array_p (as_array(ed)->data[1])) | |
2628 | + return (false); | |
2629 | + | |
2630 | + array *edp = as_array (ed); | |
2631 | + interp->aux = edp->data[1]; | |
2632 | + edp->data[1] = as_array(interp->aux)->data[edata_size - 1]; | |
2633 | + return (true); | |
2634 | +} | |
2635 | + | |
2636 | +static bool | |
2637 | +exc_handled (interpreter *interp) | |
2638 | +{ | |
2639 | + for (uint32_t cf = interp->cur_frame; cf > 0; | |
2640 | + cf = as_int (interp->stack[cf - 4])) | |
2641 | + if (eh_inframe (interp, cf)) | |
2642 | + { | |
2643 | + interp->cur_frame = cf; | |
2644 | + return (true); | |
2645 | + } | |
2646 | + | |
2647 | + return (false); | |
2648 | +} | |
2649 | + | |
2650 | +static object | |
2651 | +apply_n (interpreter *interp, uint32_t nargs) | |
2652 | +{ | |
2653 | + call_data cd, *cdp = 0; | |
2654 | + cd.topf = interp->cur_frame; | |
2655 | + | |
2656 | + while (true) | |
2657 | + { | |
2658 | + try | |
2659 | + { | |
2660 | + return (run_bytecode (interp, nargs, cdp)); | |
2661 | + } | |
2662 | + catch (object obj) | |
2663 | + { | |
2664 | + if (!exc_handled (interp)) | |
2665 | + throw; | |
2666 | + | |
2667 | + const array *edp = as_array (interp->aux); | |
2668 | + interp->sp = as_int (edp->data[0]); | |
2669 | + cd.ip_offset = as_int (edp->data[1]); | |
2670 | + cdp = &cd; | |
2671 | + } | |
2672 | + } | |
2673 | +} | |
2674 | + | |
2535 | 2675 | object call_fct (interpreter *interp, object fct, uint32_t n, ...) |
2536 | 2676 | { |
2537 | 2677 | uint32_t saved_sp = interp->sp; |
@@ -2630,14 +2770,6 @@ | ||
2630 | 2770 | return (interp->retval); |
2631 | 2771 | } |
2632 | 2772 | |
2633 | -object call_continuation (interpreter *interp, object cont) | |
2634 | -{ | |
2635 | - uint32_t sp = interp->sp; | |
2636 | - apply_n (interp, 0, cont); | |
2637 | - interp->sp = sp; | |
2638 | - return (interp->retval); | |
2639 | -} | |
2640 | - | |
2641 | 2773 | static object |
2642 | 2774 | lookup_ctv (object env, object sym) |
2643 | 2775 | { |
@@ -2760,25 +2892,26 @@ | ||
2760 | 2892 | } |
2761 | 2893 | |
2762 | 2894 | // Disassembly. |
2763 | -static const char OPC_NAMES[] = | |
2895 | +static const char OPC_NAMES[] = | |
2764 | 2896 | "nop\0dup\0pop\0ret\0is\0not\0cons\0list\0car\0cdr\0cadr\0nputcar\0nputcdr\0" |
2765 | - "apply\0tapply\0loadt\0loadnil\0load0\0load1\0loadi8\0try\0loada0\0loada1\0" | |
2766 | - "loadc00\0loadc01\0optargs\0brbound\0kwargs\0mkcont\0captenv\0captsetenv\0" | |
2767 | - "argc\0argc.l\0vargc\0vargc.l\0jmp\0jmp.l\0brt\0brt.l\0brn\0brn.l\0brneq\0" | |
2897 | + "apply\0tapply\0loadt\0loadnil\0load0\0load1\0loadi8\0loada0\0loada1\0" | |
2898 | + "loadc00\0loadc01\0optargs\0brbound\0kwargs\0mkcont\0captenv\0tryend\0argc\0" | |
2899 | + "argc.l\0vargc\0vargc.l\0jmp\0jmp.l\0brt\0brt.l\0brn\0brn.l\0brneq\0" | |
2768 | 2900 | "brneq.l\0tcall\0tcall.l\0call\0call.l\0setc\0setc.l\0seta\0seta.l\0setap\0" |
2769 | 2901 | "setap.l\0setg\0setg.l\0loadc\0loadc.l\0loada\0loada.l\0loadap\0loadap.l\0" |
2770 | 2902 | "loadg\0loadg.l\0loadv\0loadv.l\0recur\0recur.l\0trecur\0trecur.l\0mkframe\0" |
2771 | - "mkframe.l\0unwind\0unwind.l\0"; | |
2772 | - | |
2773 | -static const uint16_t OPC_NAMESLEN[] = | |
2903 | + "mkframe.l\0unwind\0unwind.l\0trybegin\0trybegin.l\0"; | |
2904 | + | |
2905 | +static const uint16_t OPC_NAMESLEN[] = | |
2774 | 2906 | { |
2775 | - 0, 4, 8, 12, 16, 19, 23, 28, 33, 37, 41, 46, 54, 62, 68, 75, 81, 89, 95, | |
2776 | - 101, 108, 112, 119, 126, 134, 142, 150, 158, 165, 172, 180, 191, 196, 203, | |
2777 | - 209, 217, 221, 227, 231, 237, 241, 247, 253, 261, 267, 275, 280, 287, 292, | |
2778 | - 299, 304, 311, 317, 325, 330, 337, 343, 351, 357, 365, 372, 381, 387, 395, | |
2779 | - 401, 409, 415, 423, 430, 439, 447, 457 | |
2907 | + 0, 4, 8, 12, 16, 19, 23, 28, 33, 37, 41, 46, 54, 62, 68, 75, 81, 89, | |
2908 | + 95, 101, 108, 115, 122, 130, 138, 146, 154, 161, 168, 176, 183, 188, 195, | |
2909 | + 201, 209, 213, 219, 223, 229, 233, 239, 245, 253, 259, 267, 272, 279, 284, | |
2910 | + 291, 296, 303, 309, 317, 322, 329, 335, 343, 349, 357, 364, 373, 379, 387, | |
2911 | + 393, 401, 407, 415, 422, 431, 439, 449, 456, 465, 474 | |
2780 | 2912 | }; |
2781 | 2913 | |
2914 | + | |
2782 | 2915 | static void disasm_aux (interpreter *, object, stream *, int); |
2783 | 2916 | |
2784 | 2917 | static void |
@@ -2796,6 +2929,25 @@ | ||
2796 | 2929 | } |
2797 | 2930 | } |
2798 | 2931 | |
2932 | +static int | |
2933 | +endoftry_p (std::vector<int>& offs, const unsigned char* code, int ix) | |
2934 | +{ | |
2935 | + if (offs.empty () || (code[ix] != OP_JMP && code[ix] != OP_JMPL)) | |
2936 | + return (-1); | |
2937 | + | |
2938 | + int r; | |
2939 | + | |
2940 | + if (code[ix] == OP_JMP && ix + 3 == offs.back ()) | |
2941 | + r = 3; | |
2942 | + else if (code[ix] == OP_JMPL && ix + 5 == offs.back ()) | |
2943 | + r = 5; | |
2944 | + else | |
2945 | + return (-1); | |
2946 | + | |
2947 | + offs.pop_back (); | |
2948 | + return (r); | |
2949 | +} | |
2950 | + | |
2799 | 2951 | static void |
2800 | 2952 | disasm_aux (interpreter *interp, object fn, stream *strm, int lv) |
2801 | 2953 | { |
@@ -2815,13 +2967,24 @@ | ||
2815 | 2967 | const array *vals = as_array (fct_vals (fn)); |
2816 | 2968 | int sx, width = bc->nbytes < 0xff ? 2 : |
2817 | 2969 | bc->nbytes < 0xffff ? 4 : 8; |
2970 | + std::vector<int> troff; | |
2818 | 2971 | |
2819 | 2972 | for (int i = 0; i < bc->nbytes; ) |
2820 | 2973 | { |
2821 | - if (lv > 0) | |
2822 | - strm->nputb (interp, lv * 2, ' '); | |
2823 | - | |
2824 | 2974 | char buf[64]; |
2975 | + int tr = endoftry_p (troff, code, i); | |
2976 | + if (tr > 0) | |
2977 | + { | |
2978 | + strm->nputb (interp, (lv - 1) * 2, ' '); | |
2979 | + strm->write (interp, buf, sprintf (buf, "%0*x: catch\n", width, i)); | |
2980 | + i += tr; | |
2981 | + continue; | |
2982 | + } | |
2983 | + else if (code[i] == OP_TRYEND) | |
2984 | + --lv; | |
2985 | + | |
2986 | + strm->nputb (interp, lv * 2, ' '); | |
2987 | + | |
2825 | 2988 | strm->write (interp, buf, sprintf (buf, "%0*x: %s", |
2826 | 2989 | width, i, OPC_NAMES + OPC_NAMESLEN[code[i]])); |
2827 | 2990 |
@@ -2898,6 +3061,16 @@ | ||
2898 | 3061 | i += lform_p (code[i - 1]) ? sizeof (int32_t) : sizeof (int16_t); |
2899 | 3062 | break; |
2900 | 3063 | |
3064 | + case OP_TRYBEGIN: case OP_TRYBEGINL: | |
3065 | + if (lform_p (code[i - 1])) | |
3066 | + sx = get32 (&code[i]) + i, i += sizeof (int32_t); | |
3067 | + else | |
3068 | + sx = get16 (&code[i]) + i, i += sizeof (int16_t); | |
3069 | + | |
3070 | + troff.push_back (sx); | |
3071 | + ++lv; | |
3072 | + break; | |
3073 | + | |
2901 | 3074 | default: |
2902 | 3075 | break; |
2903 | 3076 | } |
@@ -239,7 +239,9 @@ | ||
239 | 239 | |
240 | 240 | int stream::nputb (interpreter *interp, unsigned int n, int byte) |
241 | 241 | { |
242 | - if (this->need_rflush () && !this->rflush (interp)) | |
242 | + if (n == 0) | |
243 | + return (0); | |
244 | + else if (this->need_rflush () && !this->rflush (interp)) | |
243 | 245 | return (-1); |
244 | 246 | |
245 | 247 | int off = n, cnt = min (this->wrbuf.left (), off); |