diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2016-11-22 16:16:58 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2016-11-22 18:15:21 +0100 |
commit | 0bf380ff110897d2b5db2e22ef6efe1e9ba9888d (patch) | |
tree | 038f9aaac800097a630564a7465f0255cbb19df0 /src/parser.cpp | |
parent | dd6410b2b35a76de75622660cae9c1444b7a1880 (diff) | |
download | sciteco-0bf380ff110897d2b5db2e22ef6efe1e9ba9888d.tar.gz |
fixed local Q-Register management on certain broken platforms
* on MSVCRT/MinGW, space allocated with alloca()/g_newa() was apparently
freed once the first exception was caught.
This prevented the proper destruction of local Q-Reg tables and
broke the Windows port.
* Since all alternatives to alloca() like VLAs are not practical,
the default Q-Register initialization has been moved out of the
QRegisterTable constructor into QRegisterTable::insert_defaults().
* The remaining QRegisterTable initialization and destruction is
very cheap, so we simply reserve an empty QRegisterTable for
local registers on every Execute::macro() call.
The default registers are only initialized when required, though.
* All of this has to change anyway once we replace the
C++ call-stack approach to macro calls with our own macro
call frame memory management.
Diffstat (limited to 'src/parser.cpp')
-rw-r--r-- | src/parser.cpp | 47 |
1 files changed, 26 insertions, 21 deletions
diff --git a/src/parser.cpp b/src/parser.cpp index 05694a2..de7184a 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -159,7 +159,23 @@ Execute::macro(const gchar *macro, bool locals) GotoTable *parent_goto_table = Goto::table; GotoTable macro_goto_table(false); - QRegisterTable *parent_locals = NULL; + QRegisterTable *parent_locals = QRegisters::locals; + /* + * NOTE: A local QReg table is not required + * for local macro calls (:M). + * However allocating it on the stack on-demand is + * tricky (VLAs are not in standard C++ and alloca() + * is buggy on MSCVRT), so we always reserve a + * local Q-Reg table. + * This is OK since the table object itself is very + * small and it's empty by default. + * Best would be to let Execute::macro() be a wrapper + * around something like Execute::local_macro() which + * cares about local Q-Reg allocation, but the special + * handling of currently-edited local Q-Regs below + * prevents this. + */ + QRegisterTable macro_locals(false); State *parent_state = States::current; gint parent_pc = macro_pc; @@ -177,17 +193,14 @@ Execute::macro(const gchar *macro, bool locals) loop_stack_fp = loop_stack.items(); Goto::table = ¯o_goto_table; + + /* + * Locals are only initialized when needed to + * improve the speed of local macro calls. + */ if (locals) { - /* - * Locals are only allocated when needed to save - * space on the call stack and to improve the speed - * of local macro calls. - * However since the QRegisterTable object is rather - * small we can allocate it using alloca() on the stack. - */ - parent_locals = QRegisters::locals; - QRegisters::locals = g_newa(QRegisterTable, 1); - new (QRegisters::locals) QRegisterTable(false); + macro_locals.insert_defaults(); + QRegisters::locals = ¯o_locals; } try { @@ -269,11 +282,7 @@ Execute::macro(const gchar *macro, bool locals) g_free(Goto::skip_label); Goto::skip_label = NULL; - if (locals) { - /* memory is reclaimed on return */ - QRegisters::locals->~QRegisterTable(); - QRegisters::locals = parent_locals; - } + QRegisters::locals = parent_locals; Goto::table = parent_goto_table; loop_stack_fp = parent_loop_fp; @@ -283,11 +292,7 @@ Execute::macro(const gchar *macro, bool locals) throw; /* forward */ } - if (locals) { - /* memory is reclaimed on return */ - QRegisters::locals->~QRegisterTable(); - QRegisters::locals = parent_locals; - } + QRegisters::locals = parent_locals; Goto::table = parent_goto_table; loop_stack_fp = parent_loop_fp; |