/* Copyright 2001,2009-2014,2017-2019 Free Software Foundation, Inc. This file is part of Guile. Guile is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Guile is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with Guile. If not, see . */ #if HAVE_CONFIG_H # include #endif #include #include "alist.h" #include "boolean.h" #include "eval.h" #include "extensions.h" #include "gsubr.h" #include "instructions.h" #include "modules.h" #include "numbers.h" #include "pairs.h" #include "ports.h" #include "procprop.h" /* scm_sym_name */ #include "variable.h" #include "version.h" #include "vm.h" #include "programs.h" static SCM write_program = SCM_BOOL_F; SCM_DEFINE (scm_program_code, "program-code", 1, 0, 0, (SCM program), "") #define FUNC_NAME s_scm_program_code { SCM_VALIDATE_PROGRAM (1, program); return scm_from_uintptr_t ((uintptr_t) SCM_PROGRAM_CODE (program)); } #undef FUNC_NAME SCM scm_i_program_name (SCM program) { static SCM program_name = SCM_BOOL_F; if (SCM_PRIMITIVE_P (program)) return scm_i_primitive_name (SCM_PROGRAM_CODE (program)); if (scm_is_false (program_name) && scm_module_system_booted_p) program_name = scm_c_private_variable ("system vm program", "program-name"); return scm_call_1 (scm_variable_ref (program_name), program); } SCM scm_i_program_documentation (SCM program) { static SCM program_documentation = SCM_BOOL_F; if (SCM_PRIMITIVE_P (program)) return SCM_BOOL_F; if (scm_is_false (program_documentation) && scm_module_system_booted_p) program_documentation = scm_c_private_variable ("system vm program", "program-documentation"); return scm_call_1 (scm_variable_ref (program_documentation), program); } SCM scm_i_program_properties (SCM program) { static SCM program_properties = SCM_BOOL_F; if (SCM_PRIMITIVE_P (program)) { SCM name = scm_i_program_name (program); if (scm_is_false (name)) return SCM_EOL; return scm_acons (scm_sym_name, name, SCM_EOL); } if (scm_is_false (program_properties) && scm_module_system_booted_p) program_properties = scm_c_private_variable ("system vm program", "program-properties"); return scm_call_1 (scm_variable_ref (program_properties), program); } void scm_i_program_print (SCM program, SCM port, scm_print_state *pstate) { static int print_error = 0; if (scm_is_false (write_program) && scm_module_system_booted_p) write_program = scm_c_private_variable ("system vm program", "write-program"); if (SCM_PROGRAM_IS_CONTINUATION (program)) { /* twingliness */ scm_puts ("#', port); } else if (SCM_PROGRAM_IS_PARTIAL_CONTINUATION (program)) { /* twingliness */ scm_puts ("#', port); } else if (scm_is_false (write_program) || print_error) { scm_puts ("#', port); } else { print_error = 1; scm_call_2 (SCM_VARIABLE_REF (write_program), program, port); print_error = 0; } } /* * Scheme interface */ SCM_DEFINE (scm_program_p, "program?", 1, 0, 0, (SCM obj), "") #define FUNC_NAME s_scm_program_p { return scm_from_bool (SCM_PROGRAM_P (obj)); } #undef FUNC_NAME SCM_DEFINE (scm_primitive_code_p, "primitive-code?", 1, 0, 0, (SCM code), "") #define FUNC_NAME s_scm_primitive_code_p { const uint32_t * ptr = (const uint32_t *) scm_to_uintptr_t (code); return scm_from_bool (scm_i_primitive_code_p (ptr)); } #undef FUNC_NAME SCM_DEFINE (scm_primitive_call_ip, "primitive-call-ip", 1, 0, 0, (SCM prim), "") #define FUNC_NAME s_scm_primitive_call_ip { uintptr_t ip; SCM_MAKE_VALIDATE (1, prim, PRIMITIVE_P); ip = scm_i_primitive_call_ip (prim); return ip ? scm_from_uintptr_t (ip) : SCM_BOOL_F; } #undef FUNC_NAME SCM_DEFINE (scm_primitive_code_name, "primitive-code-name", 1, 0, 0, (SCM code), "") #define FUNC_NAME s_scm_primitive_code_name { const uint32_t * ptr = (const uint32_t *) scm_to_uintptr_t (code); if (scm_i_primitive_code_p (ptr)) return scm_i_primitive_name (ptr); return SCM_BOOL_F; } #undef FUNC_NAME SCM scm_find_source_for_addr (SCM ip) { static SCM source_for_addr = SCM_BOOL_F; if (scm_is_false (source_for_addr)) { if (!scm_module_system_booted_p) return SCM_BOOL_F; source_for_addr = scm_c_private_variable ("system vm program", "source-for-addr"); } return scm_call_1 (scm_variable_ref (source_for_addr), ip); } SCM scm_program_address_range (SCM program) { static SCM program_address_range = SCM_BOOL_F; if (scm_is_false (program_address_range) && scm_module_system_booted_p) program_address_range = scm_c_private_variable ("system vm program", "program-address-range"); return scm_call_1 (scm_variable_ref (program_address_range), program); } SCM_DEFINE (scm_program_num_free_variables, "program-num-free-variables", 1, 0, 0, (SCM program), "") #define FUNC_NAME s_scm_program_num_free_variables { SCM_VALIDATE_PROGRAM (1, program); return scm_from_ulong (SCM_PROGRAM_NUM_FREE_VARIABLES (program)); } #undef FUNC_NAME SCM_DEFINE (scm_program_free_variable_ref, "program-free-variable-ref", 2, 0, 0, (SCM program, SCM i), "") #define FUNC_NAME s_scm_program_free_variable_ref { unsigned long idx; SCM_VALIDATE_PROGRAM (1, program); SCM_VALIDATE_ULONG_COPY (2, i, idx); if (idx >= SCM_PROGRAM_NUM_FREE_VARIABLES (program)) SCM_OUT_OF_RANGE (2, i); return SCM_PROGRAM_FREE_VARIABLE_REF (program, idx); } #undef FUNC_NAME SCM_DEFINE (scm_program_free_variable_set_x, "program-free-variable-set!", 3, 0, 0, (SCM program, SCM i, SCM x), "") #define FUNC_NAME s_scm_program_free_variable_set_x { unsigned long idx; SCM_VALIDATE_PROGRAM (1, program); SCM_VALIDATE_ULONG_COPY (2, i, idx); if (idx >= SCM_PROGRAM_NUM_FREE_VARIABLES (program)) SCM_OUT_OF_RANGE (2, i); SCM_PROGRAM_FREE_VARIABLE_SET (program, idx, x); return SCM_UNSPECIFIED; } #undef FUNC_NAME /* It's hacky, but it manages to cover all of the non-keyword cases. */ static int try_parse_arity (SCM program, int *req, int *opt, int *rest) { uint32_t *code = SCM_PROGRAM_CODE (program); uint32_t slots, min; if ((code[0] & 0xff) == scm_op_instrument_entry) code += 2; switch (code[0] & 0xff) { case scm_op_assert_nargs_ee: slots = code[0] >> 8; *req = slots - 1; *opt = 0; *rest = 0; return 1; case scm_op_assert_nargs_ee_locals: slots = (code[0] >> 8) & 0xfff; *req = slots - 1; *opt = 0; *rest = 0; return 1; case scm_op_assert_nargs_le: slots = code[0] >> 8; *req = 0; *opt = slots - 1; *rest = 0; return 1; case scm_op_bind_optionals: slots = code[0] >> 8; *req = 0; *opt = slots - 1; *rest = ((code[1] & 0xff) == scm_op_bind_rest); return 1; case scm_op_bind_rest: slots = code[0] >> 8; *req = 0; *opt = slots - 1; *rest = 1; return 1; case scm_op_assert_nargs_ge: min = code[0] >> 8; switch (code[1] & 0xff) { case scm_op_assert_nargs_le: slots = code[1] >> 8; *req = min - 1; *opt = slots - 1 - *req; *rest = 0; return 1; case scm_op_bind_optionals: slots = code[1] >> 8; *req = min - 1; *opt = slots - 1 - *req; *rest = ((code[2] & 0xff) == scm_op_bind_rest); return 1; case scm_op_bind_rest: slots = code[1] >> 8; *req = min - 1; *opt = slots - min; *rest = 1; return 1; case scm_op_shuffle_down: case scm_op_abort: *req = min - 1; *opt = 0; *rest = 1; return 1; default: return 0; } case scm_op_continuation_call: case scm_op_compose_continuation: case scm_op_shuffle_down: *req = 0; *opt = 0; *rest = 1; return 1; default: return 0; } } int scm_i_program_arity (SCM program, int *req, int *opt, int *rest) { static SCM program_minimum_arity = SCM_BOOL_F; SCM l; if (try_parse_arity (program, req, opt, rest)) return 1; if (scm_is_false (program_minimum_arity) && scm_module_system_booted_p) program_minimum_arity = scm_c_private_variable ("system vm program", "program-minimum-arity"); l = scm_call_1 (scm_variable_ref (program_minimum_arity), program); if (scm_is_false (l)) return 0; *req = scm_to_int (scm_car (l)); *opt = scm_to_int (scm_cadr (l)); *rest = scm_is_true (scm_caddr (l)); return 1; } void scm_bootstrap_programs (void) { scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION, "scm_init_programs", (scm_t_extension_init_func)scm_init_programs, NULL); } void scm_init_programs (void) { #ifndef SCM_MAGIC_SNARFER #include "programs.x" #endif }