# HG changeset patch # User Petter T. # Date 1695210281 -7200 # Wed Sep 20 13:44:41 2023 +0200 # Node ID f0f93e3b3b8e8b40148be6e07456191d3d122589 # Parent f7eaf872975ec1e7e5c7369ed7d31dd2f9d3f890 VM Support inlined functions in scripts New opcode INSTALL_FUNCTION to add a function to the frame in scripts. * libinterp/parse-tree/pt-bytecode-vm.cc: Implement opcode * libinterp/parse-tree/pt-bytecode-walk.cc: Visit func def * libinterp/parse-tree/pt-bytecode-walk.h * libinterp/parse-tree/pt-bytecode.h: New opcode * test/compile/bytecode_scripts.m: Update tests * test/compile/script1.m * test/compile/script11.m diff -r f7eaf872975e -r f0f93e3b3b8e libinterp/parse-tree/pt-bytecode-vm.cc --- a/libinterp/parse-tree/pt-bytecode-vm.cc Mon Sep 18 15:45:17 2023 +0200 +++ b/libinterp/parse-tree/pt-bytecode-vm.cc Wed Sep 20 13:44:41 2023 +0200 @@ -311,6 +311,8 @@ CASE_START (JMP_IFN_BOOL) PSHORT() CASE_END () CASE_START (FOR_COMPLEX_SETUP) PSHORT() CASE_END () + CASE_START (INSTALL_FUNCTION) PSLOT () PINT() CASE_END () + CASE_START (ASSIGN_COMPOUND) PSLOT () PCHAR () CASE_END () CASE_START (INDEX_ID_NARGOUT0) PSLOT () PCHAR () CASE_END () @@ -861,6 +863,7 @@ &&wordcmd_nx, &&anon_maybe_set_ignore_output, &&enter_nested_frame, + &&install_function, }; if (OCTAVE_UNLIKELY (m_profiler_enabled)) @@ -6218,6 +6221,30 @@ } DISPATCH_1BYTEOP (); + + install_function: + { + int slot = arg0; + int fn_cst_idx = POP_CODE_INT (); + + std::string fn_name = name_data [slot]; + + octave_value fn = data[fn_cst_idx]; + + symbol_table& symtab = m_tw->get_interpreter ().get_symbol_table (); + symtab.install_cmdline_function (fn_name, fn); + + // Make sure that any variable with the same name as the new + // function is cleared. + octave_value &ov = bsp[slot].ov; + + if (ov.is_ref ()) + ov.ref_rep ()->set_value (octave_value {}); + else + ov = octave_value {}; + } + DISPATCH (); + __builtin_unreachable (); } diff -r f7eaf872975e -r f0f93e3b3b8e libinterp/parse-tree/pt-bytecode-walk.cc --- a/libinterp/parse-tree/pt-bytecode-walk.cc Mon Sep 18 15:45:17 2023 +0200 +++ b/libinterp/parse-tree/pt-bytecode-walk.cc Wed Sep 20 13:44:41 2023 +0200 @@ -340,6 +340,11 @@ // We dont collect any id:s in the handle, since the original scope // don't. } + + void visit_function_def (tree_function_def &) + { + // Don't collect any id:s inside a function def (functions embedded in scripts) + } }; template @@ -4055,6 +4060,35 @@ void bytecode_walker:: +visit_function_def (tree_function_def &cmd) +{ + // Function definitions in scripts are supposed to be installed + // at runtime when reaching the relevant row. + // + // So we store the function in the constant data and load it + // with INSTALL_FUNCTION. + + CHECK (m_is_script); + + octave_value fcn = cmd.function (); + octave_function *f = fcn.function_value (); + + // tree_evaluator just does nothing on nullptr, but abort compilation instead here + CHECK_NONNULL (f); + + std::string name = f->name (); + int slot = add_id_to_table (name); + + int data_offset = DATA_SIZE (); + PUSH_DATA (fcn); + + PUSH_CODE (INSTR::INSTALL_FUNCTION); + PUSH_SLOT (slot); + PUSH_CODE_INT (data_offset); +} + +void +bytecode_walker:: visit_identifier (tree_identifier& id) { INC_DEPTH(); diff -r f7eaf872975e -r f0f93e3b3b8e libinterp/parse-tree/pt-bytecode-walk.h --- a/libinterp/parse-tree/pt-bytecode-walk.h Mon Sep 18 15:45:17 2023 +0200 +++ b/libinterp/parse-tree/pt-bytecode-walk.h Wed Sep 20 13:44:41 2023 +0200 @@ -289,7 +289,7 @@ void visit_octave_user_function (octave_user_function&); - void visit_function_def (tree_function_def&) ERROR_NOT_IMPLEMENTED + void visit_function_def (tree_function_def&); void visit_identifier (tree_identifier&); diff -r f7eaf872975e -r f0f93e3b3b8e libinterp/parse-tree/pt-bytecode.h --- a/libinterp/parse-tree/pt-bytecode.h Mon Sep 18 15:45:17 2023 +0200 +++ b/libinterp/parse-tree/pt-bytecode.h Wed Sep 20 13:44:41 2023 +0200 @@ -192,6 +192,7 @@ WORDCMD_NX, ANON_MAYBE_SET_IGNORE_OUTPUTS, ENTER_NESTED_FRAME, + INSTALL_FUNCTION, }; enum class unwind_entry_type diff -r f7eaf872975e -r f0f93e3b3b8e test/compile/bytecode_scripts.m --- a/test/compile/bytecode_scripts.m Mon Sep 18 15:45:17 2023 +0200 +++ b/test/compile/bytecode_scripts.m Wed Sep 20 13:44:41 2023 +0200 @@ -6,6 +6,7 @@ b1 = 2; __printf_assert__ ("%d ", exist ("a1")); script1 (); % defines 'a1', 'b1', 'c1', 'd1' + __printf_assert__ ("%d ", eval ("a1;")); __printf_assert__ ("%d ", b1); __printf_assert__ ("%d ", eval ("c1;")); @@ -18,4 +19,7 @@ end script3 (); + + % Inline function defined in script1 + assert (inlinefn2 (234) == 235) end \ No newline at end of file diff -r f7eaf872975e -r f0f93e3b3b8e test/compile/script1.m --- a/test/compile/script1.m Mon Sep 18 15:45:17 2023 +0200 +++ b/test/compile/script1.m Wed Sep 20 13:44:41 2023 +0200 @@ -3,9 +3,25 @@ eval ("c1 = 4;") eval ("d1 = 5;") +% Test function definitions inlined in scripts +function inlinefn1 (a) + assert (!exist ("a1")) % Ensure inlinefn1 has its own scope + b = inlinefn2 (a); + assert (b == a + 1); +end + +inlinefn2 = 3; % Assure a function can be defined when id exists with that name + +function b = inlinefn2 (a) + b = a + 1; +end + +assert (inlinefn2 (3) == 4); +inlinefn1 (123); + script11 (); assert (a11 == 1) assert (b11 == 3) eval ("assert (c11 == 4)") -eval ("assert (d11 == 5)") \ No newline at end of file +eval ("assert (d11 == 5)") diff -r f7eaf872975e -r f0f93e3b3b8e test/compile/script11.m --- a/test/compile/script11.m Mon Sep 18 15:45:17 2023 +0200 +++ b/test/compile/script11.m Wed Sep 20 13:44:41 2023 +0200 @@ -1,5 +1,8 @@ a11 = 1; b11 = 3; +% Inline function in parent script +assert (inlinefn2 (4) == 5); + eval ("c11 = 4;") eval ("d11 = 5;") \ No newline at end of file