guile/libguile/vm-i-system.c

1732 lines
39 KiB
C
Raw Normal View History

/* Copyright (C) 2001,2008,2009,2010,2011 Free Software Foundation, Inc.
2000-08-22 15:54:19 +00:00
*
static opcodes; refactor program/objcode division; use new assembly pipeline * gdbinit: Untested attempts to get the stack fondling macros to deal with the new program representation. * libguile/frames.c (scm_vm_frame_arguments, scm_vm_frame_source) (scm_vm_frame_local_ref, scm_vm_frame_local_set_x): SCM_PROGRAM_DATA is a struct scm_objcode*. * libguile/instructions.h: * libguile/instructions.c: Hide the instruction table and the struct scm_instruction structure; all access to instructions now goes through procedures. This is because instructions are no longer in a packed array indexed by opcode. Also, declare a mask that all instructions should fit in. * libguile/objcodes.h: * libguile/objcodes.c: Rewrite so that object code directly maps its arity and length from its bytecode. This makes it unnecessary to keep this information in programs, allowing programs to be simple conses between the code (objcodes) and data (the object table and the closure variables). * libguile/programs.c (scm_make_program): Rework so that make-program takes objcode, an object table, and externals as arguments. It's much clearer this way, and we avoid malloc(). * libguile/stacks.c (is_vm_bootstrap_frame): Update for program/objcode changes. * libguile/vm-engine.c (vm_run): Initialize the jump table on the first run, with the opcodes declared in the instruction sources, and with bad instructions raising an error instead of wandering off into the Unknown. * libguile/vm-engine.h (FETCH_LENGTH): Always represent lengths as 3 bytes. The old code was too error-prone. (NEXT_JUMP): Mask the instruction with SCM_VM_INSTRUCTION_MASK. (NEW_FRAME): Update for program/objcode changes. * libguile/vm-expand.h (VM_DEFINE_FUNCTION, VM_DEFINE_INSTRUCTION) (VM_DEFINE_LOADER): Update so that we explicitly specify opcodes, so that we have a stable bytecode API. * libguile/vm-i-loader.c: Update license to LGPLv2+. Explicitly declare opcodes. (load-integer): Use an int instead of a long as the accumulator; still need to revisit this code at some point, I think. (load-program): Simplify, thankfully!! Just creates the objcode slice and rolls with it. * libguile/vm-i-scheme.c: Number the opcodes explicitly. * libguile/vm-i-system.c: Update license to LGPLv2+. Explicitly declare opcodes. (make-closure): Update for new program API. * libguile/vm.c (vm_make_boot_program): Update for new program/objcode API. Still a bit ugly. (scm_load_compiled_with_vm): Update for new program/objcode API. * module/language/assembly.scm (byte-length): Fix byte-length calculation for loaders, and load-program. (code-pack, code-unpack): Start to move things from (system vm conv) here. (object->code, code->object): More things from conv.scm. * module/language/glil.scm (<glil-program>): Add a new field, closure-level. (make-glil-program, compute-closure-level): Calculate the "closure level" when making a glil program. This is the maximum depth of external binding refs in this closure. (unparse-glil): Fix label serialization. * module/language/glil/compile-assembly.scm (make-meta): Prepend #f for the meta's object table, though maybe in the future we can avoid creating assembly in the first place. (assoc-ref-or-acons, object-index-and-alist): GRRR! Caught again by the different sets of arguments to assoc and assoc-ref! (glil->assembly): Attempt to make the <glil-program> case more readable, and fix the bugs. Sorry I don't know how to comment this change any more than this. (glil->assembly): For <glil-module> serialize the whole key, not just the name. (dump-object): subprogram-code is already a list. Serialize integers as strings, not u8vectors. Fix the order of lists and vectors. * module/language/glil/spec.scm (glil): Switch orders, so we prefer glil -> assembly -> objcode. Actually glil->objcode doesn't work any more, needs to be removed I think. * module/language/objcode/spec.scm (objcode->value): s/objcode->program/make-program/. * module/language/scheme/inline.scm: Add acons inline. * module/system/vm/conv.scm (make-byte-decoder): Skip the first 8 bytes, they are header. Handle subprograms properly. Still needs help though. (decode-length): Lengths are always 3 bytes now. * module/system/vm/disasm.scm: Superficial changes to keep things working. I'd like to fix this better in the future. * module/system/vm/frame.scm (bootstrap-frame?): Fixes for program-bytecode. * module/system/vm/program.scm: Export make-program. It's program-objcode now, no more program-bytecode. * module/system/vm/vm.scm (vm-load): Use make-program. * test-suite/tests/asm-to-bytecode.test: New test, very minimal. * module/system/vm/objcode.scm: Export word-size, byte-order, and write-objcode.
2009-01-29 21:09:04 +01:00
* This library 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.
2000-08-22 15:54:19 +00:00
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
static opcodes; refactor program/objcode division; use new assembly pipeline * gdbinit: Untested attempts to get the stack fondling macros to deal with the new program representation. * libguile/frames.c (scm_vm_frame_arguments, scm_vm_frame_source) (scm_vm_frame_local_ref, scm_vm_frame_local_set_x): SCM_PROGRAM_DATA is a struct scm_objcode*. * libguile/instructions.h: * libguile/instructions.c: Hide the instruction table and the struct scm_instruction structure; all access to instructions now goes through procedures. This is because instructions are no longer in a packed array indexed by opcode. Also, declare a mask that all instructions should fit in. * libguile/objcodes.h: * libguile/objcodes.c: Rewrite so that object code directly maps its arity and length from its bytecode. This makes it unnecessary to keep this information in programs, allowing programs to be simple conses between the code (objcodes) and data (the object table and the closure variables). * libguile/programs.c (scm_make_program): Rework so that make-program takes objcode, an object table, and externals as arguments. It's much clearer this way, and we avoid malloc(). * libguile/stacks.c (is_vm_bootstrap_frame): Update for program/objcode changes. * libguile/vm-engine.c (vm_run): Initialize the jump table on the first run, with the opcodes declared in the instruction sources, and with bad instructions raising an error instead of wandering off into the Unknown. * libguile/vm-engine.h (FETCH_LENGTH): Always represent lengths as 3 bytes. The old code was too error-prone. (NEXT_JUMP): Mask the instruction with SCM_VM_INSTRUCTION_MASK. (NEW_FRAME): Update for program/objcode changes. * libguile/vm-expand.h (VM_DEFINE_FUNCTION, VM_DEFINE_INSTRUCTION) (VM_DEFINE_LOADER): Update so that we explicitly specify opcodes, so that we have a stable bytecode API. * libguile/vm-i-loader.c: Update license to LGPLv2+. Explicitly declare opcodes. (load-integer): Use an int instead of a long as the accumulator; still need to revisit this code at some point, I think. (load-program): Simplify, thankfully!! Just creates the objcode slice and rolls with it. * libguile/vm-i-scheme.c: Number the opcodes explicitly. * libguile/vm-i-system.c: Update license to LGPLv2+. Explicitly declare opcodes. (make-closure): Update for new program API. * libguile/vm.c (vm_make_boot_program): Update for new program/objcode API. Still a bit ugly. (scm_load_compiled_with_vm): Update for new program/objcode API. * module/language/assembly.scm (byte-length): Fix byte-length calculation for loaders, and load-program. (code-pack, code-unpack): Start to move things from (system vm conv) here. (object->code, code->object): More things from conv.scm. * module/language/glil.scm (<glil-program>): Add a new field, closure-level. (make-glil-program, compute-closure-level): Calculate the "closure level" when making a glil program. This is the maximum depth of external binding refs in this closure. (unparse-glil): Fix label serialization. * module/language/glil/compile-assembly.scm (make-meta): Prepend #f for the meta's object table, though maybe in the future we can avoid creating assembly in the first place. (assoc-ref-or-acons, object-index-and-alist): GRRR! Caught again by the different sets of arguments to assoc and assoc-ref! (glil->assembly): Attempt to make the <glil-program> case more readable, and fix the bugs. Sorry I don't know how to comment this change any more than this. (glil->assembly): For <glil-module> serialize the whole key, not just the name. (dump-object): subprogram-code is already a list. Serialize integers as strings, not u8vectors. Fix the order of lists and vectors. * module/language/glil/spec.scm (glil): Switch orders, so we prefer glil -> assembly -> objcode. Actually glil->objcode doesn't work any more, needs to be removed I think. * module/language/objcode/spec.scm (objcode->value): s/objcode->program/make-program/. * module/language/scheme/inline.scm: Add acons inline. * module/system/vm/conv.scm (make-byte-decoder): Skip the first 8 bytes, they are header. Handle subprograms properly. Still needs help though. (decode-length): Lengths are always 3 bytes now. * module/system/vm/disasm.scm: Superficial changes to keep things working. I'd like to fix this better in the future. * module/system/vm/frame.scm (bootstrap-frame?): Fixes for program-bytecode. * module/system/vm/program.scm: Export make-program. It's program-objcode now, no more program-bytecode. * module/system/vm/vm.scm (vm-load): Use make-program. * test-suite/tests/asm-to-bytecode.test: New test, very minimal. * module/system/vm/objcode.scm: Export word-size, byte-order, and write-objcode.
2009-01-29 21:09:04 +01:00
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
2000-08-22 15:54:19 +00:00
*
static opcodes; refactor program/objcode division; use new assembly pipeline * gdbinit: Untested attempts to get the stack fondling macros to deal with the new program representation. * libguile/frames.c (scm_vm_frame_arguments, scm_vm_frame_source) (scm_vm_frame_local_ref, scm_vm_frame_local_set_x): SCM_PROGRAM_DATA is a struct scm_objcode*. * libguile/instructions.h: * libguile/instructions.c: Hide the instruction table and the struct scm_instruction structure; all access to instructions now goes through procedures. This is because instructions are no longer in a packed array indexed by opcode. Also, declare a mask that all instructions should fit in. * libguile/objcodes.h: * libguile/objcodes.c: Rewrite so that object code directly maps its arity and length from its bytecode. This makes it unnecessary to keep this information in programs, allowing programs to be simple conses between the code (objcodes) and data (the object table and the closure variables). * libguile/programs.c (scm_make_program): Rework so that make-program takes objcode, an object table, and externals as arguments. It's much clearer this way, and we avoid malloc(). * libguile/stacks.c (is_vm_bootstrap_frame): Update for program/objcode changes. * libguile/vm-engine.c (vm_run): Initialize the jump table on the first run, with the opcodes declared in the instruction sources, and with bad instructions raising an error instead of wandering off into the Unknown. * libguile/vm-engine.h (FETCH_LENGTH): Always represent lengths as 3 bytes. The old code was too error-prone. (NEXT_JUMP): Mask the instruction with SCM_VM_INSTRUCTION_MASK. (NEW_FRAME): Update for program/objcode changes. * libguile/vm-expand.h (VM_DEFINE_FUNCTION, VM_DEFINE_INSTRUCTION) (VM_DEFINE_LOADER): Update so that we explicitly specify opcodes, so that we have a stable bytecode API. * libguile/vm-i-loader.c: Update license to LGPLv2+. Explicitly declare opcodes. (load-integer): Use an int instead of a long as the accumulator; still need to revisit this code at some point, I think. (load-program): Simplify, thankfully!! Just creates the objcode slice and rolls with it. * libguile/vm-i-scheme.c: Number the opcodes explicitly. * libguile/vm-i-system.c: Update license to LGPLv2+. Explicitly declare opcodes. (make-closure): Update for new program API. * libguile/vm.c (vm_make_boot_program): Update for new program/objcode API. Still a bit ugly. (scm_load_compiled_with_vm): Update for new program/objcode API. * module/language/assembly.scm (byte-length): Fix byte-length calculation for loaders, and load-program. (code-pack, code-unpack): Start to move things from (system vm conv) here. (object->code, code->object): More things from conv.scm. * module/language/glil.scm (<glil-program>): Add a new field, closure-level. (make-glil-program, compute-closure-level): Calculate the "closure level" when making a glil program. This is the maximum depth of external binding refs in this closure. (unparse-glil): Fix label serialization. * module/language/glil/compile-assembly.scm (make-meta): Prepend #f for the meta's object table, though maybe in the future we can avoid creating assembly in the first place. (assoc-ref-or-acons, object-index-and-alist): GRRR! Caught again by the different sets of arguments to assoc and assoc-ref! (glil->assembly): Attempt to make the <glil-program> case more readable, and fix the bugs. Sorry I don't know how to comment this change any more than this. (glil->assembly): For <glil-module> serialize the whole key, not just the name. (dump-object): subprogram-code is already a list. Serialize integers as strings, not u8vectors. Fix the order of lists and vectors. * module/language/glil/spec.scm (glil): Switch orders, so we prefer glil -> assembly -> objcode. Actually glil->objcode doesn't work any more, needs to be removed I think. * module/language/objcode/spec.scm (objcode->value): s/objcode->program/make-program/. * module/language/scheme/inline.scm: Add acons inline. * module/system/vm/conv.scm (make-byte-decoder): Skip the first 8 bytes, they are header. Handle subprograms properly. Still needs help though. (decode-length): Lengths are always 3 bytes now. * module/system/vm/disasm.scm: Superficial changes to keep things working. I'd like to fix this better in the future. * module/system/vm/frame.scm (bootstrap-frame?): Fixes for program-bytecode. * module/system/vm/program.scm: Export make-program. It's program-objcode now, no more program-bytecode. * module/system/vm/vm.scm (vm-load): Use make-program. * test-suite/tests/asm-to-bytecode.test: New test, very minimal. * module/system/vm/objcode.scm: Export word-size, byte-order, and write-objcode.
2009-01-29 21:09:04 +01:00
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA
static opcodes; refactor program/objcode division; use new assembly pipeline * gdbinit: Untested attempts to get the stack fondling macros to deal with the new program representation. * libguile/frames.c (scm_vm_frame_arguments, scm_vm_frame_source) (scm_vm_frame_local_ref, scm_vm_frame_local_set_x): SCM_PROGRAM_DATA is a struct scm_objcode*. * libguile/instructions.h: * libguile/instructions.c: Hide the instruction table and the struct scm_instruction structure; all access to instructions now goes through procedures. This is because instructions are no longer in a packed array indexed by opcode. Also, declare a mask that all instructions should fit in. * libguile/objcodes.h: * libguile/objcodes.c: Rewrite so that object code directly maps its arity and length from its bytecode. This makes it unnecessary to keep this information in programs, allowing programs to be simple conses between the code (objcodes) and data (the object table and the closure variables). * libguile/programs.c (scm_make_program): Rework so that make-program takes objcode, an object table, and externals as arguments. It's much clearer this way, and we avoid malloc(). * libguile/stacks.c (is_vm_bootstrap_frame): Update for program/objcode changes. * libguile/vm-engine.c (vm_run): Initialize the jump table on the first run, with the opcodes declared in the instruction sources, and with bad instructions raising an error instead of wandering off into the Unknown. * libguile/vm-engine.h (FETCH_LENGTH): Always represent lengths as 3 bytes. The old code was too error-prone. (NEXT_JUMP): Mask the instruction with SCM_VM_INSTRUCTION_MASK. (NEW_FRAME): Update for program/objcode changes. * libguile/vm-expand.h (VM_DEFINE_FUNCTION, VM_DEFINE_INSTRUCTION) (VM_DEFINE_LOADER): Update so that we explicitly specify opcodes, so that we have a stable bytecode API. * libguile/vm-i-loader.c: Update license to LGPLv2+. Explicitly declare opcodes. (load-integer): Use an int instead of a long as the accumulator; still need to revisit this code at some point, I think. (load-program): Simplify, thankfully!! Just creates the objcode slice and rolls with it. * libguile/vm-i-scheme.c: Number the opcodes explicitly. * libguile/vm-i-system.c: Update license to LGPLv2+. Explicitly declare opcodes. (make-closure): Update for new program API. * libguile/vm.c (vm_make_boot_program): Update for new program/objcode API. Still a bit ugly. (scm_load_compiled_with_vm): Update for new program/objcode API. * module/language/assembly.scm (byte-length): Fix byte-length calculation for loaders, and load-program. (code-pack, code-unpack): Start to move things from (system vm conv) here. (object->code, code->object): More things from conv.scm. * module/language/glil.scm (<glil-program>): Add a new field, closure-level. (make-glil-program, compute-closure-level): Calculate the "closure level" when making a glil program. This is the maximum depth of external binding refs in this closure. (unparse-glil): Fix label serialization. * module/language/glil/compile-assembly.scm (make-meta): Prepend #f for the meta's object table, though maybe in the future we can avoid creating assembly in the first place. (assoc-ref-or-acons, object-index-and-alist): GRRR! Caught again by the different sets of arguments to assoc and assoc-ref! (glil->assembly): Attempt to make the <glil-program> case more readable, and fix the bugs. Sorry I don't know how to comment this change any more than this. (glil->assembly): For <glil-module> serialize the whole key, not just the name. (dump-object): subprogram-code is already a list. Serialize integers as strings, not u8vectors. Fix the order of lists and vectors. * module/language/glil/spec.scm (glil): Switch orders, so we prefer glil -> assembly -> objcode. Actually glil->objcode doesn't work any more, needs to be removed I think. * module/language/objcode/spec.scm (objcode->value): s/objcode->program/make-program/. * module/language/scheme/inline.scm: Add acons inline. * module/system/vm/conv.scm (make-byte-decoder): Skip the first 8 bytes, they are header. Handle subprograms properly. Still needs help though. (decode-length): Lengths are always 3 bytes now. * module/system/vm/disasm.scm: Superficial changes to keep things working. I'd like to fix this better in the future. * module/system/vm/frame.scm (bootstrap-frame?): Fixes for program-bytecode. * module/system/vm/program.scm: Export make-program. It's program-objcode now, no more program-bytecode. * module/system/vm/vm.scm (vm-load): Use make-program. * test-suite/tests/asm-to-bytecode.test: New test, very minimal. * module/system/vm/objcode.scm: Export word-size, byte-order, and write-objcode.
2009-01-29 21:09:04 +01:00
*/
2000-08-22 15:54:19 +00:00
/* This file is included in vm_engine.c */
/*
* Basic operations
*/
static opcodes; refactor program/objcode division; use new assembly pipeline * gdbinit: Untested attempts to get the stack fondling macros to deal with the new program representation. * libguile/frames.c (scm_vm_frame_arguments, scm_vm_frame_source) (scm_vm_frame_local_ref, scm_vm_frame_local_set_x): SCM_PROGRAM_DATA is a struct scm_objcode*. * libguile/instructions.h: * libguile/instructions.c: Hide the instruction table and the struct scm_instruction structure; all access to instructions now goes through procedures. This is because instructions are no longer in a packed array indexed by opcode. Also, declare a mask that all instructions should fit in. * libguile/objcodes.h: * libguile/objcodes.c: Rewrite so that object code directly maps its arity and length from its bytecode. This makes it unnecessary to keep this information in programs, allowing programs to be simple conses between the code (objcodes) and data (the object table and the closure variables). * libguile/programs.c (scm_make_program): Rework so that make-program takes objcode, an object table, and externals as arguments. It's much clearer this way, and we avoid malloc(). * libguile/stacks.c (is_vm_bootstrap_frame): Update for program/objcode changes. * libguile/vm-engine.c (vm_run): Initialize the jump table on the first run, with the opcodes declared in the instruction sources, and with bad instructions raising an error instead of wandering off into the Unknown. * libguile/vm-engine.h (FETCH_LENGTH): Always represent lengths as 3 bytes. The old code was too error-prone. (NEXT_JUMP): Mask the instruction with SCM_VM_INSTRUCTION_MASK. (NEW_FRAME): Update for program/objcode changes. * libguile/vm-expand.h (VM_DEFINE_FUNCTION, VM_DEFINE_INSTRUCTION) (VM_DEFINE_LOADER): Update so that we explicitly specify opcodes, so that we have a stable bytecode API. * libguile/vm-i-loader.c: Update license to LGPLv2+. Explicitly declare opcodes. (load-integer): Use an int instead of a long as the accumulator; still need to revisit this code at some point, I think. (load-program): Simplify, thankfully!! Just creates the objcode slice and rolls with it. * libguile/vm-i-scheme.c: Number the opcodes explicitly. * libguile/vm-i-system.c: Update license to LGPLv2+. Explicitly declare opcodes. (make-closure): Update for new program API. * libguile/vm.c (vm_make_boot_program): Update for new program/objcode API. Still a bit ugly. (scm_load_compiled_with_vm): Update for new program/objcode API. * module/language/assembly.scm (byte-length): Fix byte-length calculation for loaders, and load-program. (code-pack, code-unpack): Start to move things from (system vm conv) here. (object->code, code->object): More things from conv.scm. * module/language/glil.scm (<glil-program>): Add a new field, closure-level. (make-glil-program, compute-closure-level): Calculate the "closure level" when making a glil program. This is the maximum depth of external binding refs in this closure. (unparse-glil): Fix label serialization. * module/language/glil/compile-assembly.scm (make-meta): Prepend #f for the meta's object table, though maybe in the future we can avoid creating assembly in the first place. (assoc-ref-or-acons, object-index-and-alist): GRRR! Caught again by the different sets of arguments to assoc and assoc-ref! (glil->assembly): Attempt to make the <glil-program> case more readable, and fix the bugs. Sorry I don't know how to comment this change any more than this. (glil->assembly): For <glil-module> serialize the whole key, not just the name. (dump-object): subprogram-code is already a list. Serialize integers as strings, not u8vectors. Fix the order of lists and vectors. * module/language/glil/spec.scm (glil): Switch orders, so we prefer glil -> assembly -> objcode. Actually glil->objcode doesn't work any more, needs to be removed I think. * module/language/objcode/spec.scm (objcode->value): s/objcode->program/make-program/. * module/language/scheme/inline.scm: Add acons inline. * module/system/vm/conv.scm (make-byte-decoder): Skip the first 8 bytes, they are header. Handle subprograms properly. Still needs help though. (decode-length): Lengths are always 3 bytes now. * module/system/vm/disasm.scm: Superficial changes to keep things working. I'd like to fix this better in the future. * module/system/vm/frame.scm (bootstrap-frame?): Fixes for program-bytecode. * module/system/vm/program.scm: Export make-program. It's program-objcode now, no more program-bytecode. * module/system/vm/vm.scm (vm-load): Use make-program. * test-suite/tests/asm-to-bytecode.test: New test, very minimal. * module/system/vm/objcode.scm: Export word-size, byte-order, and write-objcode.
2009-01-29 21:09:04 +01:00
VM_DEFINE_INSTRUCTION (0, nop, "nop", 0, 0, 0)
2000-08-22 15:54:19 +00:00
{
NEXT;
}
static opcodes; refactor program/objcode division; use new assembly pipeline * gdbinit: Untested attempts to get the stack fondling macros to deal with the new program representation. * libguile/frames.c (scm_vm_frame_arguments, scm_vm_frame_source) (scm_vm_frame_local_ref, scm_vm_frame_local_set_x): SCM_PROGRAM_DATA is a struct scm_objcode*. * libguile/instructions.h: * libguile/instructions.c: Hide the instruction table and the struct scm_instruction structure; all access to instructions now goes through procedures. This is because instructions are no longer in a packed array indexed by opcode. Also, declare a mask that all instructions should fit in. * libguile/objcodes.h: * libguile/objcodes.c: Rewrite so that object code directly maps its arity and length from its bytecode. This makes it unnecessary to keep this information in programs, allowing programs to be simple conses between the code (objcodes) and data (the object table and the closure variables). * libguile/programs.c (scm_make_program): Rework so that make-program takes objcode, an object table, and externals as arguments. It's much clearer this way, and we avoid malloc(). * libguile/stacks.c (is_vm_bootstrap_frame): Update for program/objcode changes. * libguile/vm-engine.c (vm_run): Initialize the jump table on the first run, with the opcodes declared in the instruction sources, and with bad instructions raising an error instead of wandering off into the Unknown. * libguile/vm-engine.h (FETCH_LENGTH): Always represent lengths as 3 bytes. The old code was too error-prone. (NEXT_JUMP): Mask the instruction with SCM_VM_INSTRUCTION_MASK. (NEW_FRAME): Update for program/objcode changes. * libguile/vm-expand.h (VM_DEFINE_FUNCTION, VM_DEFINE_INSTRUCTION) (VM_DEFINE_LOADER): Update so that we explicitly specify opcodes, so that we have a stable bytecode API. * libguile/vm-i-loader.c: Update license to LGPLv2+. Explicitly declare opcodes. (load-integer): Use an int instead of a long as the accumulator; still need to revisit this code at some point, I think. (load-program): Simplify, thankfully!! Just creates the objcode slice and rolls with it. * libguile/vm-i-scheme.c: Number the opcodes explicitly. * libguile/vm-i-system.c: Update license to LGPLv2+. Explicitly declare opcodes. (make-closure): Update for new program API. * libguile/vm.c (vm_make_boot_program): Update for new program/objcode API. Still a bit ugly. (scm_load_compiled_with_vm): Update for new program/objcode API. * module/language/assembly.scm (byte-length): Fix byte-length calculation for loaders, and load-program. (code-pack, code-unpack): Start to move things from (system vm conv) here. (object->code, code->object): More things from conv.scm. * module/language/glil.scm (<glil-program>): Add a new field, closure-level. (make-glil-program, compute-closure-level): Calculate the "closure level" when making a glil program. This is the maximum depth of external binding refs in this closure. (unparse-glil): Fix label serialization. * module/language/glil/compile-assembly.scm (make-meta): Prepend #f for the meta's object table, though maybe in the future we can avoid creating assembly in the first place. (assoc-ref-or-acons, object-index-and-alist): GRRR! Caught again by the different sets of arguments to assoc and assoc-ref! (glil->assembly): Attempt to make the <glil-program> case more readable, and fix the bugs. Sorry I don't know how to comment this change any more than this. (glil->assembly): For <glil-module> serialize the whole key, not just the name. (dump-object): subprogram-code is already a list. Serialize integers as strings, not u8vectors. Fix the order of lists and vectors. * module/language/glil/spec.scm (glil): Switch orders, so we prefer glil -> assembly -> objcode. Actually glil->objcode doesn't work any more, needs to be removed I think. * module/language/objcode/spec.scm (objcode->value): s/objcode->program/make-program/. * module/language/scheme/inline.scm: Add acons inline. * module/system/vm/conv.scm (make-byte-decoder): Skip the first 8 bytes, they are header. Handle subprograms properly. Still needs help though. (decode-length): Lengths are always 3 bytes now. * module/system/vm/disasm.scm: Superficial changes to keep things working. I'd like to fix this better in the future. * module/system/vm/frame.scm (bootstrap-frame?): Fixes for program-bytecode. * module/system/vm/program.scm: Export make-program. It's program-objcode now, no more program-bytecode. * module/system/vm/vm.scm (vm-load): Use make-program. * test-suite/tests/asm-to-bytecode.test: New test, very minimal. * module/system/vm/objcode.scm: Export word-size, byte-order, and write-objcode.
2009-01-29 21:09:04 +01:00
VM_DEFINE_INSTRUCTION (1, halt, "halt", 0, 0, 0)
2000-08-22 15:54:19 +00:00
{
nvalues = SCM_I_INUM (*sp--);
precise stack marking, fix some missed references, still imperfect * libguile/vm-engine.h (CHECK_STACK_LEAK, NULLSTACK): Add a new mode, VM_ENABLE_STACK_NULLING, that tries to ensure that all stack data past the top of the stack is NULL. This helps to verify the VM's consistency. If VM_ENABLE_STACK_NULLING is not defined, there is no overhead. (DROP, DROPN): Hook into NULLSTACK. (POP_LIST): Hoo, fix a good bug: if CONS triggered a GC, the elements of the list that had not yet been consed would not be marked, because the sp was already below them. (NEXT): Hook into CHECK_STACK_LEAK. (INIT_ARGS): Add a note that consing the rest arg can cause GC. (NEW_FRAME): Cons up the external data after initializing the frame, so that if GC is triggered, the precise marker sees a well-formed frame. * libguile/vm-i-loader.c (load-program): In the four-integers case, use the POP macro so that we can hook into NULLSTACK (if necessary). * libguile/vm-i-scheme.c (ARGS2, ARGS3): Hook into NULLSTACK. * libguile/vm-i-system.c (halt): Null the nvalues. Rework some asserts into using ASSERT, and null the stack when we free the frame. (variable-set): Use DROPN instead of sp -= 2. (BR): Hook into NULLSTACK. (goto/args): Hook into NULLSTACK. In the non-self case, delay updating the frame until after INIT_ARGS so that GC sees a well-formed frame. Delay consing the externals until after the frame is set up, as in NEW_FRAME. (call/cc): Add some asserts. (return): Rework some asserts into ASSERT, and hook into NULLSTACK. (return/values): Hook into NULLSTACK, and use ASSERT. (return/values*) Use ASSERT. * libguile/vm.c (VM_ENABLE_ASSERTIONS, VM_ENABLE_STACK_NULLING): These are the variables that control assertions and nulling. Perhaps we can do these per-engine when we start compiling the debug engine separate from a speedy engine. (vm_mark_stack): Add a precise stack marker. Yay! (vm_cont_mark): Mark the continuation stack precisely. (capture_vm_cont): Record the difference from the vp's stack_base too, so that we can translate the dynamic links when marking the continuation stack. Memset the stack to NULL if we are doing nulling. (reinstate_vm_cont): If we are nulling, null out the relevant part of the stack. (vm_reset_stack): When resetting sp due to a nonlocal exit, null out the stack too. (vm_mark): If we are nulling, assert that there are no extra values on the stack. Mark the stack precisely.
2008-10-03 16:00:30 +02:00
NULLSTACK (1);
if (nvalues == 1)
POP (finish_args);
else
{
POP_LIST (nvalues);
POP (finish_args);
SYNC_REGISTER ();
finish_args = scm_values (finish_args);
}
{
runtime and debugging support for callee-parsed procedure args * libguile/objcodes.h: Bump for metadata format change. * libguile/frames.h: Rework so we don't frob the program's nargs, nlocs, etc at runtime. Instead we don't really know what's a local var, an argument, or an intermediate value. It's a little unfortunate, but this will allow for case-lambda, and eventually for good polymorphic generic dispatch; and the nlocs etc can be heuristically reconstructed. Such a reconstruction would be better done at the Scheme level, though. (SCM_FRAME_STACK_ADDRESS): New macro, the pointer to the base of the stack elements (not counting the program). (SCM_FRAME_UPPER_ADDRESS): Repurpose to be the address of the last element in the bookkeeping part of the stack -- i.e. to point to the return address. * libguile/vm-engine.h: * libguile/vm-i-system.c: Adapt to removal of stack_base. Though we still detect stack-smashing underflow, we don't do so as precisely as we did before, because now we only detect overwriting of the frame metadata. * libguile/vm-engine.c (vm_engine): Remove the stack_base variable. It is unnecessary, and difficult to keep track of in the face of case-lambda. Also fix miscommented "ra" and "mvra" pushes. Push the vp->ip as the first ra... * libguile/vm-i-system.c (halt): ...because here we can restore the vp->ip instead of setting ip to 0. Allows us to introspect ips all down the stack, including in recursive VM invocations. * libguile/frames.h: * libguile/frames.c (scm_vm_frame_stack): Removed, because it's getting more difficult to tell what's an argument and what's a temporary stack element. (scm_vm_frame_num_locals): New accessor. (scm_vm_frame_instruction_pointer): New accessor. (scm_vm_frame_arguments): Defer to an implementation in Scheme. (scm_vm_frame_num_locals scm_vm_frame_local_ref) (scm_vm_frame_local_set_x): Since we can get not-yet-active frames on the stack now, with our current calling convention, we have to add a heuristic here to jump over those frames -- because frames have pointers in them, not Scheme values. * libguile/programs.h: * libguile/programs.c (scm_program_arity): Remove, in favor of.. (scm_program_arities): ...this, which a list of arities, in a new format, occupying a slot in the metadata. * module/language/assembly/decompile-bytecode.scm (decode-load-program): Fix mv-call decompilation. * module/system/vm/frame.scm (vm-frame-bindings, vm-frame-binding-ref) (vm-frame-binding-set!): New functions, to access bindings by name in a frame. (vm-frame-arguments): Function now implemented in Scheme. Commented fairly extensively. * module/system/vm/program.scm (program-bindings-by-index) (program-bindings-for-ip): New accessors, parsing the program bindings metadata into something more useful. (program-arities, program-arguments): In a case-lambda world, we have to assume that programs can have multiple arities. But it's tough to detect this algorithmically; instead we're going to require that the program metadata include information about the arities, and the parts of the program that that metadata applies to. (program-lambda-list): New accessor. (write-program): Show multiple arities. * module/language/glil/compile-assembly.scm (glil->assembly): Add "arities" to the state of the compiler, and add arities entries as appropriate.
2009-09-27 19:25:58 -04:00
#ifdef VM_ENABLE_STACK_NULLING
SCM *old_sp = sp;
#endif
/* Restore registers */
sp = SCM_FRAME_LOWER_ADDRESS (fp) - 1;
runtime and debugging support for callee-parsed procedure args * libguile/objcodes.h: Bump for metadata format change. * libguile/frames.h: Rework so we don't frob the program's nargs, nlocs, etc at runtime. Instead we don't really know what's a local var, an argument, or an intermediate value. It's a little unfortunate, but this will allow for case-lambda, and eventually for good polymorphic generic dispatch; and the nlocs etc can be heuristically reconstructed. Such a reconstruction would be better done at the Scheme level, though. (SCM_FRAME_STACK_ADDRESS): New macro, the pointer to the base of the stack elements (not counting the program). (SCM_FRAME_UPPER_ADDRESS): Repurpose to be the address of the last element in the bookkeeping part of the stack -- i.e. to point to the return address. * libguile/vm-engine.h: * libguile/vm-i-system.c: Adapt to removal of stack_base. Though we still detect stack-smashing underflow, we don't do so as precisely as we did before, because now we only detect overwriting of the frame metadata. * libguile/vm-engine.c (vm_engine): Remove the stack_base variable. It is unnecessary, and difficult to keep track of in the face of case-lambda. Also fix miscommented "ra" and "mvra" pushes. Push the vp->ip as the first ra... * libguile/vm-i-system.c (halt): ...because here we can restore the vp->ip instead of setting ip to 0. Allows us to introspect ips all down the stack, including in recursive VM invocations. * libguile/frames.h: * libguile/frames.c (scm_vm_frame_stack): Removed, because it's getting more difficult to tell what's an argument and what's a temporary stack element. (scm_vm_frame_num_locals): New accessor. (scm_vm_frame_instruction_pointer): New accessor. (scm_vm_frame_arguments): Defer to an implementation in Scheme. (scm_vm_frame_num_locals scm_vm_frame_local_ref) (scm_vm_frame_local_set_x): Since we can get not-yet-active frames on the stack now, with our current calling convention, we have to add a heuristic here to jump over those frames -- because frames have pointers in them, not Scheme values. * libguile/programs.h: * libguile/programs.c (scm_program_arity): Remove, in favor of.. (scm_program_arities): ...this, which a list of arities, in a new format, occupying a slot in the metadata. * module/language/assembly/decompile-bytecode.scm (decode-load-program): Fix mv-call decompilation. * module/system/vm/frame.scm (vm-frame-bindings, vm-frame-binding-ref) (vm-frame-binding-set!): New functions, to access bindings by name in a frame. (vm-frame-arguments): Function now implemented in Scheme. Commented fairly extensively. * module/system/vm/program.scm (program-bindings-by-index) (program-bindings-for-ip): New accessors, parsing the program bindings metadata into something more useful. (program-arities, program-arguments): In a case-lambda world, we have to assume that programs can have multiple arities. But it's tough to detect this algorithmically; instead we're going to require that the program metadata include information about the arities, and the parts of the program that that metadata applies to. (program-lambda-list): New accessor. (write-program): Show multiple arities. * module/language/glil/compile-assembly.scm (glil->assembly): Add "arities" to the state of the compiler, and add arities entries as appropriate.
2009-09-27 19:25:58 -04:00
/* Setting the ip here doesn't actually affect control flow, as the calling
code will restore its own registers, but it does help when walking the
stack */
ip = SCM_FRAME_RETURN_ADDRESS (fp);
fp = SCM_FRAME_DYNAMIC_LINK (fp);
runtime and debugging support for callee-parsed procedure args * libguile/objcodes.h: Bump for metadata format change. * libguile/frames.h: Rework so we don't frob the program's nargs, nlocs, etc at runtime. Instead we don't really know what's a local var, an argument, or an intermediate value. It's a little unfortunate, but this will allow for case-lambda, and eventually for good polymorphic generic dispatch; and the nlocs etc can be heuristically reconstructed. Such a reconstruction would be better done at the Scheme level, though. (SCM_FRAME_STACK_ADDRESS): New macro, the pointer to the base of the stack elements (not counting the program). (SCM_FRAME_UPPER_ADDRESS): Repurpose to be the address of the last element in the bookkeeping part of the stack -- i.e. to point to the return address. * libguile/vm-engine.h: * libguile/vm-i-system.c: Adapt to removal of stack_base. Though we still detect stack-smashing underflow, we don't do so as precisely as we did before, because now we only detect overwriting of the frame metadata. * libguile/vm-engine.c (vm_engine): Remove the stack_base variable. It is unnecessary, and difficult to keep track of in the face of case-lambda. Also fix miscommented "ra" and "mvra" pushes. Push the vp->ip as the first ra... * libguile/vm-i-system.c (halt): ...because here we can restore the vp->ip instead of setting ip to 0. Allows us to introspect ips all down the stack, including in recursive VM invocations. * libguile/frames.h: * libguile/frames.c (scm_vm_frame_stack): Removed, because it's getting more difficult to tell what's an argument and what's a temporary stack element. (scm_vm_frame_num_locals): New accessor. (scm_vm_frame_instruction_pointer): New accessor. (scm_vm_frame_arguments): Defer to an implementation in Scheme. (scm_vm_frame_num_locals scm_vm_frame_local_ref) (scm_vm_frame_local_set_x): Since we can get not-yet-active frames on the stack now, with our current calling convention, we have to add a heuristic here to jump over those frames -- because frames have pointers in them, not Scheme values. * libguile/programs.h: * libguile/programs.c (scm_program_arity): Remove, in favor of.. (scm_program_arities): ...this, which a list of arities, in a new format, occupying a slot in the metadata. * module/language/assembly/decompile-bytecode.scm (decode-load-program): Fix mv-call decompilation. * module/system/vm/frame.scm (vm-frame-bindings, vm-frame-binding-ref) (vm-frame-binding-set!): New functions, to access bindings by name in a frame. (vm-frame-arguments): Function now implemented in Scheme. Commented fairly extensively. * module/system/vm/program.scm (program-bindings-by-index) (program-bindings-for-ip): New accessors, parsing the program bindings metadata into something more useful. (program-arities, program-arguments): In a case-lambda world, we have to assume that programs can have multiple arities. But it's tough to detect this algorithmically; instead we're going to require that the program metadata include information about the arities, and the parts of the program that that metadata applies to. (program-lambda-list): New accessor. (write-program): Show multiple arities. * module/language/glil/compile-assembly.scm (glil->assembly): Add "arities" to the state of the compiler, and add arities entries as appropriate.
2009-09-27 19:25:58 -04:00
NULLSTACK (old_sp - sp);
}
goto vm_done;
2000-08-22 15:54:19 +00:00
}
VM_DEFINE_INSTRUCTION (2, drop, "drop", 0, 1, 0)
2000-08-22 15:54:19 +00:00
{
2001-04-01 05:03:41 +00:00
DROP ();
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (3, dup, "dup", 0, 0, 1)
{
2001-04-09 04:08:46 +00:00
SCM x = *sp;
PUSH (x);
NEXT;
}
2001-04-01 05:03:41 +00:00
/*
* Object creation
*/
2000-08-22 15:54:19 +00:00
VM_DEFINE_INSTRUCTION (4, void, "void", 0, 0, 1)
2000-08-22 15:54:19 +00:00
{
2001-04-01 05:03:41 +00:00
PUSH (SCM_UNSPECIFIED);
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (5, make_true, "make-true", 0, 0, 1)
2000-08-22 15:54:19 +00:00
{
2001-04-01 05:03:41 +00:00
PUSH (SCM_BOOL_T);
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (6, make_false, "make-false", 0, 0, 1)
2000-08-22 15:54:19 +00:00
{
2001-04-01 05:03:41 +00:00
PUSH (SCM_BOOL_F);
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (7, make_nil, "make-nil", 0, 0, 1)
{
PUSH (SCM_ELISP_NIL);
NEXT;
}
VM_DEFINE_INSTRUCTION (8, make_eol, "make-eol", 0, 0, 1)
2000-08-22 15:54:19 +00:00
{
2001-04-01 05:03:41 +00:00
PUSH (SCM_EOL);
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (9, make_int8, "make-int8", 1, 0, 1)
2000-08-22 15:54:19 +00:00
{
PUSH (SCM_I_MAKINUM ((signed char) FETCH ()));
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (10, make_int8_0, "make-int8:0", 0, 0, 1)
2000-08-22 15:54:19 +00:00
{
PUSH (SCM_INUM0);
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (11, make_int8_1, "make-int8:1", 0, 0, 1)
2000-08-22 15:54:19 +00:00
{
PUSH (SCM_I_MAKINUM (1));
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (12, make_int16, "make-int16", 2, 0, 1)
2000-08-22 15:54:19 +00:00
{
2001-04-05 01:38:38 +00:00
int h = FETCH ();
int l = FETCH ();
PUSH (SCM_I_MAKINUM ((signed short) (h << 8) + l));
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (13, make_int64, "make-int64", 8, 0, 1)
{
scm_t_uint64 v = 0;
v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
PUSH (scm_from_int64 ((scm_t_int64) v));
NEXT;
}
VM_DEFINE_INSTRUCTION (14, make_uint64, "make-uint64", 8, 0, 1)
{
scm_t_uint64 v = 0;
v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
PUSH (scm_from_uint64 (v));
NEXT;
}
VM_DEFINE_INSTRUCTION (15, make_char8, "make-char8", 1, 0, 1)
2000-08-22 15:54:19 +00:00
{
scm_t_uint8 v = 0;
v = FETCH ();
PUSH (SCM_MAKE_CHAR (v));
/* Don't simplify this to PUSH (SCM_MAKE_CHAR (FETCH ())). The
contents of SCM_MAKE_CHAR may be evaluated more than once,
resulting in a double fetch. */
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (16, make_char32, "make-char32", 4, 0, 1)
{
scm_t_wchar v = 0;
v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
v <<= 8; v += FETCH ();
PUSH (SCM_MAKE_CHAR (v));
NEXT;
}
VM_DEFINE_INSTRUCTION (17, list, "list", 2, -1, 1)
2001-04-15 15:02:41 +00:00
{
unsigned h = FETCH ();
unsigned l = FETCH ();
unsigned len = ((h << 8) + l);
POP_LIST (len);
2001-04-15 15:02:41 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (18, vector, "vector", 2, -1, 1)
2001-04-15 15:02:41 +00:00
{
unsigned h = FETCH ();
unsigned l = FETCH ();
unsigned len = ((h << 8) + l);
SCM vect;
SYNC_REGISTER ();
sp++; sp -= len;
CHECK_UNDERFLOW ();
vect = scm_make_vector (scm_from_uint (len), SCM_BOOL_F);
memcpy (SCM_I_VECTOR_WELTS(vect), sp, sizeof(SCM) * len);
NULLSTACK (len);
*sp = vect;
2001-04-15 15:02:41 +00:00
NEXT;
}
2000-08-22 15:54:19 +00:00
/*
2001-04-01 05:03:41 +00:00
* Variable access
2000-08-22 15:54:19 +00:00
*/
2001-04-01 05:03:41 +00:00
#define OBJECT_REF(i) objects[i]
#define OBJECT_SET(i,o) objects[i] = o
2000-08-22 15:54:19 +00:00
2001-04-23 04:28:13 +00:00
#define LOCAL_REF(i) SCM_FRAME_VARIABLE (fp, i)
#define LOCAL_SET(i,o) SCM_FRAME_VARIABLE (fp, i) = o
2000-08-22 15:54:19 +00:00
/* For the variable operations, we _must_ obviously avoid function calls to
`scm_variable_ref ()', `scm_variable_bound_p ()' and friends which do
nothing more than the corresponding macros. */
#define VARIABLE_REF(v) SCM_VARIABLE_REF (v)
#define VARIABLE_SET(v,o) SCM_VARIABLE_SET (v, o)
#define VARIABLE_BOUNDP(v) (!scm_is_eq (VARIABLE_REF (v), SCM_UNDEFINED))
2000-08-22 15:54:19 +00:00
#define FREE_VARIABLE_REF(i) SCM_PROGRAM_FREE_VARIABLE_REF (program, i)
2001-04-01 05:03:41 +00:00
/* ref */
2000-08-22 15:54:19 +00:00
VM_DEFINE_INSTRUCTION (19, object_ref, "object-ref", 1, 0, 1)
2000-08-22 15:54:19 +00:00
{
register unsigned objnum = FETCH ();
CHECK_OBJECT (objnum);
PUSH (OBJECT_REF (objnum));
2001-04-01 05:03:41 +00:00
NEXT;
2000-08-22 15:54:19 +00:00
}
/* FIXME: necessary? elt 255 of the vector could be a vector... */
VM_DEFINE_INSTRUCTION (20, long_object_ref, "long-object-ref", 2, 0, 1)
{
unsigned int objnum = FETCH ();
objnum <<= 8;
objnum += FETCH ();
CHECK_OBJECT (objnum);
PUSH (OBJECT_REF (objnum));
NEXT;
}
VM_DEFINE_INSTRUCTION (21, local_ref, "local-ref", 1, 0, 1)
2000-08-22 15:54:19 +00:00
{
2001-04-01 05:03:41 +00:00
PUSH (LOCAL_REF (FETCH ()));
and, or, cond etc use syntax-rules, compile scheme through tree-il * libguile/vm-i-system.c: * libguile/vm-engine.h (ASSERT_BOUND): New assertion, that a value is bound. Used by local-ref and external-ref in paranoid mode. * module/ice-9/boot-9.scm (and, or, cond, case, do): Since we are switching to use psyntax as the first pass of the compiler, and perhaps soon of the interpreter too, we need to make sure it expands out all forms to primitive expressions. So define expanders for these derived syntax forms, as in the R5RS report. * module/ice-9/psyntax-pp.scm: Regenerate, with core forms fully expanded. * module/ice-9/psyntax.scm (build-void): New constructor, for making undefined values. (build-primref): Add in a hack so that primitive refs in the boot module expand out to toplevel refs, not module refs. (chi-void): Use build-void. (if): Define an expander for if that calls build-conditional. * module/language/scheme/compile-tree-il.scm (compile-tree-il): Use let* so as not to depend on binding order for the result of (current-module). * module/language/scheme/spec.scm (scheme): Switch over to tree-il as the primary intermediate language. Not yet fully tested, but at least it can compile psyntax-pp.scm. * module/language/tree-il/analyze.scm (analyze-lexicals): Arguments don't count towards a function's nlocs. * module/language/tree-il/compile-glil.scm (*comp-module*, compile-glil): Define a "compilation module" fluid. (flatten-lambda): Fix a call to make-glil-argument. Fix bug in heapifying arguments. (flatten): Fix number of arguments passed to apply instruction. Add a special case for `(values ...)'. If inlining primitive-refs fails, try expanding into toplevel-refs if the comp-module's variable is the same as the root variable. * module/language/tree-il/optimize.scm (resolve-primitives!): Add missing src variable for <module-ref>. * test-suite/tests/tree-il.test ("lambda"): Fix nlocs counts. Add a closure test case.
2009-05-20 11:15:22 +02:00
ASSERT_BOUND (*sp);
2001-04-01 05:03:41 +00:00
NEXT;
2000-08-22 15:54:19 +00:00
}
VM_DEFINE_INSTRUCTION (22, long_local_ref, "long-local-ref", 2, 0, 1)
2000-08-22 15:54:19 +00:00
{
unsigned int i = FETCH ();
i <<= 8;
i += FETCH ();
make sure all programs are 8-byte aligned * libguile/objcodes.c (OBJCODE_COOKIE): Bump objcode cookie, as we added to struct scm_objcode. * libguile/objcodes.h (struct scm_objcode): Add a uint32 after metalen and before base, so that if the structure has 8-byte alignment, base will have 8-byte alignment too. (Before, base was 12 bytes from the start of the structure, now it's 16 bytes.) * libguile/vm-engine.h (ASSERT_ALIGNED_PROCEDURE): Add a check that can be turned on with VM_ENABLE_PARANOID_ASSERTIONS. (CACHE_PROGRAM): Call ASSERT_ALIGNED_PROCEDURE. * libguile/vm-i-system.c (long-local-ref): Add a missing semicolon. * libguile/vm.c (really_make_boot_program): Rework to operate directly on a malloc'd buffer, so that the program will be 8-byte aligned. * module/language/assembly.scm (*program-header-len*): Add another 4 for the padding. (object->assembly): Fix case in which we would return (make-int8 0) instead of (make-int8:0). This would throw off compile-assembly.scm's use of addr+. * module/language/assembly/compile-bytecode.scm (write-bytecode): Write out the padding int. * module/language/assembly/decompile-bytecode.scm (decode-load-program): And pop off the padding int too. * module/language/glil/compile-assembly.scm (glil->assembly): Don't pack the assembly, assume that assembly.scm has done it for us. If a program has a meta, pad out the program so that meta will be aligned. * test-suite/tests/asm-to-bytecode.test: Adapt to expect programs to have the extra 4-byte padding int.
2009-07-26 12:56:11 +02:00
PUSH (LOCAL_REF (i));
and, or, cond etc use syntax-rules, compile scheme through tree-il * libguile/vm-i-system.c: * libguile/vm-engine.h (ASSERT_BOUND): New assertion, that a value is bound. Used by local-ref and external-ref in paranoid mode. * module/ice-9/boot-9.scm (and, or, cond, case, do): Since we are switching to use psyntax as the first pass of the compiler, and perhaps soon of the interpreter too, we need to make sure it expands out all forms to primitive expressions. So define expanders for these derived syntax forms, as in the R5RS report. * module/ice-9/psyntax-pp.scm: Regenerate, with core forms fully expanded. * module/ice-9/psyntax.scm (build-void): New constructor, for making undefined values. (build-primref): Add in a hack so that primitive refs in the boot module expand out to toplevel refs, not module refs. (chi-void): Use build-void. (if): Define an expander for if that calls build-conditional. * module/language/scheme/compile-tree-il.scm (compile-tree-il): Use let* so as not to depend on binding order for the result of (current-module). * module/language/scheme/spec.scm (scheme): Switch over to tree-il as the primary intermediate language. Not yet fully tested, but at least it can compile psyntax-pp.scm. * module/language/tree-il/analyze.scm (analyze-lexicals): Arguments don't count towards a function's nlocs. * module/language/tree-il/compile-glil.scm (*comp-module*, compile-glil): Define a "compilation module" fluid. (flatten-lambda): Fix a call to make-glil-argument. Fix bug in heapifying arguments. (flatten): Fix number of arguments passed to apply instruction. Add a special case for `(values ...)'. If inlining primitive-refs fails, try expanding into toplevel-refs if the comp-module's variable is the same as the root variable. * module/language/tree-il/optimize.scm (resolve-primitives!): Add missing src variable for <module-ref>. * test-suite/tests/tree-il.test ("lambda"): Fix nlocs counts. Add a closure test case.
2009-05-20 11:15:22 +02:00
ASSERT_BOUND (*sp);
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (23, local_bound, "local-bound?", 1, 0, 1)
{
PUSH (scm_from_bool (!scm_is_eq (LOCAL_REF (FETCH ()), SCM_UNDEFINED)));
NEXT;
}
VM_DEFINE_INSTRUCTION (24, long_local_bound, "long-local-bound?", 2, 0, 1)
{
unsigned int i = FETCH ();
i <<= 8;
i += FETCH ();
PUSH (scm_from_bool (!scm_is_eq (LOCAL_REF (i), SCM_UNDEFINED)));
NEXT;
}
VM_DEFINE_INSTRUCTION (25, variable_ref, "variable-ref", 0, 1, 1)
2000-08-22 15:54:19 +00:00
{
2001-04-01 05:03:41 +00:00
SCM x = *sp;
/* We don't use ASSERT_VARIABLE or ASSERT_BOUND_VARIABLE here because,
unlike in top-variable-ref, it really isn't an internal assertion
that can be optimized out -- the variable could be coming directly
from the user. */
if (SCM_UNLIKELY (!SCM_VARIABLEP (x)))
{
func_name = "variable-ref";
finish_args = x;
goto vm_error_not_a_variable;
}
else if (SCM_UNLIKELY (!VARIABLE_BOUNDP (x)))
2001-04-01 05:03:41 +00:00
{
SCM var_name;
/* Attempt to provide the variable name in the error message. */
var_name = scm_module_reverse_lookup (scm_current_module (), x);
finish_args = scm_is_true (var_name) ? var_name : x;
2001-04-01 05:03:41 +00:00
goto vm_error_unbound;
}
else
{
SCM o = VARIABLE_REF (x);
*sp = o;
}
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (26, variable_bound, "variable-bound?", 0, 1, 1)
{
SCM x = *sp;
if (SCM_UNLIKELY (!SCM_VARIABLEP (x)))
{
func_name = "variable-bound?";
finish_args = x;
goto vm_error_not_a_variable;
}
else
*sp = scm_from_bool (VARIABLE_BOUNDP (x));
NEXT;
}
VM_DEFINE_INSTRUCTION (27, toplevel_ref, "toplevel-ref", 1, 0, 1)
{
unsigned objnum = FETCH ();
SCM what, resolved;
CHECK_OBJECT (objnum);
what = OBJECT_REF (objnum);
if (!SCM_VARIABLEP (what))
{
SYNC_REGISTER ();
resolved = resolve_variable (what, scm_program_module (program));
if (!VARIABLE_BOUNDP (resolved))
{
finish_args = what;
goto vm_error_unbound;
}
what = resolved;
OBJECT_SET (objnum, what);
}
PUSH (VARIABLE_REF (what));
NEXT;
}
VM_DEFINE_INSTRUCTION (28, long_toplevel_ref, "long-toplevel-ref", 2, 0, 1)
{
SCM what, resolved;
unsigned int objnum = FETCH ();
objnum <<= 8;
objnum += FETCH ();
CHECK_OBJECT (objnum);
what = OBJECT_REF (objnum);
if (!SCM_VARIABLEP (what))
{
SYNC_REGISTER ();
resolved = resolve_variable (what, scm_program_module (program));
if (!VARIABLE_BOUNDP (resolved))
{
finish_args = what;
goto vm_error_unbound;
}
what = resolved;
OBJECT_SET (objnum, what);
}
PUSH (VARIABLE_REF (what));
NEXT;
}
2001-04-01 05:03:41 +00:00
/* set */
VM_DEFINE_INSTRUCTION (29, local_set, "local-set", 1, 1, 0)
2000-08-22 15:54:19 +00:00
{
SCM x;
POP (x);
LOCAL_SET (FETCH (), x);
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (30, long_local_set, "long-local-set", 2, 1, 0)
2000-08-22 15:54:19 +00:00
{
SCM x;
unsigned int i = FETCH ();
i <<= 8;
i += FETCH ();
POP (x);
LOCAL_SET (i, x);
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (31, variable_set, "variable-set", 0, 2, 0)
2000-08-22 15:54:19 +00:00
{
if (SCM_UNLIKELY (!SCM_VARIABLEP (sp[0])))
{
func_name = "variable-set!";
finish_args = sp[0];
goto vm_error_not_a_variable;
}
VARIABLE_SET (sp[0], sp[-1]);
precise stack marking, fix some missed references, still imperfect * libguile/vm-engine.h (CHECK_STACK_LEAK, NULLSTACK): Add a new mode, VM_ENABLE_STACK_NULLING, that tries to ensure that all stack data past the top of the stack is NULL. This helps to verify the VM's consistency. If VM_ENABLE_STACK_NULLING is not defined, there is no overhead. (DROP, DROPN): Hook into NULLSTACK. (POP_LIST): Hoo, fix a good bug: if CONS triggered a GC, the elements of the list that had not yet been consed would not be marked, because the sp was already below them. (NEXT): Hook into CHECK_STACK_LEAK. (INIT_ARGS): Add a note that consing the rest arg can cause GC. (NEW_FRAME): Cons up the external data after initializing the frame, so that if GC is triggered, the precise marker sees a well-formed frame. * libguile/vm-i-loader.c (load-program): In the four-integers case, use the POP macro so that we can hook into NULLSTACK (if necessary). * libguile/vm-i-scheme.c (ARGS2, ARGS3): Hook into NULLSTACK. * libguile/vm-i-system.c (halt): Null the nvalues. Rework some asserts into using ASSERT, and null the stack when we free the frame. (variable-set): Use DROPN instead of sp -= 2. (BR): Hook into NULLSTACK. (goto/args): Hook into NULLSTACK. In the non-self case, delay updating the frame until after INIT_ARGS so that GC sees a well-formed frame. Delay consing the externals until after the frame is set up, as in NEW_FRAME. (call/cc): Add some asserts. (return): Rework some asserts into ASSERT, and hook into NULLSTACK. (return/values): Hook into NULLSTACK, and use ASSERT. (return/values*) Use ASSERT. * libguile/vm.c (VM_ENABLE_ASSERTIONS, VM_ENABLE_STACK_NULLING): These are the variables that control assertions and nulling. Perhaps we can do these per-engine when we start compiling the debug engine separate from a speedy engine. (vm_mark_stack): Add a precise stack marker. Yay! (vm_cont_mark): Mark the continuation stack precisely. (capture_vm_cont): Record the difference from the vp's stack_base too, so that we can translate the dynamic links when marking the continuation stack. Memset the stack to NULL if we are doing nulling. (reinstate_vm_cont): If we are nulling, null out the relevant part of the stack. (vm_reset_stack): When resetting sp due to a nonlocal exit, null out the stack too. (vm_mark): If we are nulling, assert that there are no extra values on the stack. Mark the stack precisely.
2008-10-03 16:00:30 +02:00
DROPN (2);
2000-08-22 15:54:19 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (32, toplevel_set, "toplevel-set", 1, 1, 0)
{
unsigned objnum = FETCH ();
SCM what;
CHECK_OBJECT (objnum);
what = OBJECT_REF (objnum);
if (!SCM_VARIABLEP (what))
{
SYNC_BEFORE_GC ();
what = resolve_variable (what, scm_program_module (program));
OBJECT_SET (objnum, what);
}
VARIABLE_SET (what, *sp);
DROP ();
NEXT;
}
VM_DEFINE_INSTRUCTION (33, long_toplevel_set, "long-toplevel-set", 2, 1, 0)
{
SCM what;
unsigned int objnum = FETCH ();
objnum <<= 8;
objnum += FETCH ();
CHECK_OBJECT (objnum);
what = OBJECT_REF (objnum);
if (!SCM_VARIABLEP (what))
{
SYNC_BEFORE_GC ();
what = resolve_variable (what, scm_program_module (program));
OBJECT_SET (objnum, what);
}
VARIABLE_SET (what, *sp);
DROP ();
NEXT;
}
2000-08-22 15:54:19 +00:00
/*
* branch and jump
*/
/* offset must be at least 24 bits wide, and signed */
compile call-with-values, woot! * libguile/vm-engine.c (vm_run): Add another byte onto the bootstrap program, as the offset passed to mv-call now takes two bytes. * module/system/vm/frame.scm (bootstrap-frame?): Update for the new bootstrap length. Really we should just check for 'halt though. * libguile/vm-i-system.c (FETCH_OFFSET): New helper, used in BR(). (goto/nargs, call/nargs): Versions of goto/args and call, respectively, that take the number of arguments from a value on the top of the stack. (mv-call): Call FETCH_OFFSET to get the offset. * module/language/scheme/translate.scm (custom-transformer-table): Compile call-with-values to <ghil-mv-call>. There is some trickery because of the r4rs.scm call-with-values trampolines. * module/system/il/ghil.scm: Add <ghil-mv-call> and accessors. * module/system/il/compile.scm (codegen): Compile <ghil-mv-call>. * module/system/il/glil.scm: Add <glil-mv-call>, which needs some special assembly because of the label. Fix some typos. * module/system/vm/assemble.scm (byte-length): New helper, factored out and made more general. (codegen): Assemble mv-call, including the label. (check-length): New helper, makes sure that the addressing is consistent within the produced object code. (stack->bytes): Rewrite to be more generic -- now `br' instructions aren't the only ones jumping around in the instruction stream. * module/system/vm/conv.scm (make-byte-decoder): Return two values in the #f case. * module/system/vm/disasm.scm (disassemble-bytecode): Rewrite, because the previous implementation depended on a guile interpreter quirk: namely, that multiple values could be represented within one value, and destructured later.
2008-09-16 00:26:22 +02:00
#define FETCH_OFFSET(offset) \
2001-04-01 05:03:41 +00:00
{ \
offset = FETCH () << 16; \
offset += FETCH () << 8; \
offset += FETCH (); \
offset -= (offset & (1<<23)) << 1; \
compile call-with-values, woot! * libguile/vm-engine.c (vm_run): Add another byte onto the bootstrap program, as the offset passed to mv-call now takes two bytes. * module/system/vm/frame.scm (bootstrap-frame?): Update for the new bootstrap length. Really we should just check for 'halt though. * libguile/vm-i-system.c (FETCH_OFFSET): New helper, used in BR(). (goto/nargs, call/nargs): Versions of goto/args and call, respectively, that take the number of arguments from a value on the top of the stack. (mv-call): Call FETCH_OFFSET to get the offset. * module/language/scheme/translate.scm (custom-transformer-table): Compile call-with-values to <ghil-mv-call>. There is some trickery because of the r4rs.scm call-with-values trampolines. * module/system/il/ghil.scm: Add <ghil-mv-call> and accessors. * module/system/il/compile.scm (codegen): Compile <ghil-mv-call>. * module/system/il/glil.scm: Add <glil-mv-call>, which needs some special assembly because of the label. Fix some typos. * module/system/vm/assemble.scm (byte-length): New helper, factored out and made more general. (codegen): Assemble mv-call, including the label. (check-length): New helper, makes sure that the addressing is consistent within the produced object code. (stack->bytes): Rewrite to be more generic -- now `br' instructions aren't the only ones jumping around in the instruction stream. * module/system/vm/conv.scm (make-byte-decoder): Return two values in the #f case. * module/system/vm/disasm.scm (disassemble-bytecode): Rewrite, because the previous implementation depended on a guile interpreter quirk: namely, that multiple values could be represented within one value, and destructured later.
2008-09-16 00:26:22 +02:00
}
#define BR(p) \
compile call-with-values, woot! * libguile/vm-engine.c (vm_run): Add another byte onto the bootstrap program, as the offset passed to mv-call now takes two bytes. * module/system/vm/frame.scm (bootstrap-frame?): Update for the new bootstrap length. Really we should just check for 'halt though. * libguile/vm-i-system.c (FETCH_OFFSET): New helper, used in BR(). (goto/nargs, call/nargs): Versions of goto/args and call, respectively, that take the number of arguments from a value on the top of the stack. (mv-call): Call FETCH_OFFSET to get the offset. * module/language/scheme/translate.scm (custom-transformer-table): Compile call-with-values to <ghil-mv-call>. There is some trickery because of the r4rs.scm call-with-values trampolines. * module/system/il/ghil.scm: Add <ghil-mv-call> and accessors. * module/system/il/compile.scm (codegen): Compile <ghil-mv-call>. * module/system/il/glil.scm: Add <glil-mv-call>, which needs some special assembly because of the label. Fix some typos. * module/system/vm/assemble.scm (byte-length): New helper, factored out and made more general. (codegen): Assemble mv-call, including the label. (check-length): New helper, makes sure that the addressing is consistent within the produced object code. (stack->bytes): Rewrite to be more generic -- now `br' instructions aren't the only ones jumping around in the instruction stream. * module/system/vm/conv.scm (make-byte-decoder): Return two values in the #f case. * module/system/vm/disasm.scm (disassemble-bytecode): Rewrite, because the previous implementation depended on a guile interpreter quirk: namely, that multiple values could be represented within one value, and destructured later.
2008-09-16 00:26:22 +02:00
{ \
scm_t_int32 offset; \
compile call-with-values, woot! * libguile/vm-engine.c (vm_run): Add another byte onto the bootstrap program, as the offset passed to mv-call now takes two bytes. * module/system/vm/frame.scm (bootstrap-frame?): Update for the new bootstrap length. Really we should just check for 'halt though. * libguile/vm-i-system.c (FETCH_OFFSET): New helper, used in BR(). (goto/nargs, call/nargs): Versions of goto/args and call, respectively, that take the number of arguments from a value on the top of the stack. (mv-call): Call FETCH_OFFSET to get the offset. * module/language/scheme/translate.scm (custom-transformer-table): Compile call-with-values to <ghil-mv-call>. There is some trickery because of the r4rs.scm call-with-values trampolines. * module/system/il/ghil.scm: Add <ghil-mv-call> and accessors. * module/system/il/compile.scm (codegen): Compile <ghil-mv-call>. * module/system/il/glil.scm: Add <glil-mv-call>, which needs some special assembly because of the label. Fix some typos. * module/system/vm/assemble.scm (byte-length): New helper, factored out and made more general. (codegen): Assemble mv-call, including the label. (check-length): New helper, makes sure that the addressing is consistent within the produced object code. (stack->bytes): Rewrite to be more generic -- now `br' instructions aren't the only ones jumping around in the instruction stream. * module/system/vm/conv.scm (make-byte-decoder): Return two values in the #f case. * module/system/vm/disasm.scm (disassemble-bytecode): Rewrite, because the previous implementation depended on a guile interpreter quirk: namely, that multiple values could be represented within one value, and destructured later.
2008-09-16 00:26:22 +02:00
FETCH_OFFSET (offset); \
2001-04-01 05:03:41 +00:00
if (p) \
ip += offset; \
if (offset < 0) \
VM_HANDLE_INTERRUPTS; \
2001-04-01 05:03:41 +00:00
NEXT; \
}
VM_DEFINE_INSTRUCTION (34, br, "br", 3, 0, 0)
2001-04-11 20:57:44 +00:00
{
scm_t_int32 offset;
FETCH_OFFSET (offset);
ip += offset;
if (offset < 0)
VM_HANDLE_INTERRUPTS;
2001-04-11 20:57:44 +00:00
NEXT;
}
VM_DEFINE_INSTRUCTION (35, br_if, "br-if", 3, 0, 0)
2000-08-22 15:54:19 +00:00
{
SCM x;
POP (x);
BR (scm_is_true (x));
2000-08-22 15:54:19 +00:00
}
VM_DEFINE_INSTRUCTION (36, br_if_not, "br-if-not", 3, 0, 0)
2000-08-22 15:54:19 +00:00
{
SCM x;
POP (x);
BR (scm_is_false (x));
2000-08-22 15:54:19 +00:00
}
VM_DEFINE_INSTRUCTION (37, br_if_eq, "br-if-eq", 3, 0, 0)
2000-08-22 15:54:19 +00:00
{
SCM x, y;
POP2 (y, x);
BR (scm_is_eq (x, y));
2000-08-22 15:54:19 +00:00
}
VM_DEFINE_INSTRUCTION (38, br_if_not_eq, "br-if-not-eq", 3, 0, 0)
2000-08-22 15:54:19 +00:00
{
SCM x, y;
POP2 (y, x);
BR (!scm_is_eq (x, y));
2001-04-01 05:03:41 +00:00
}
VM_DEFINE_INSTRUCTION (39, br_if_null, "br-if-null", 3, 0, 0)
2001-04-01 05:03:41 +00:00
{
SCM x;
POP (x);
BR (scm_is_null (x));
2001-04-01 05:03:41 +00:00
}
VM_DEFINE_INSTRUCTION (40, br_if_not_null, "br-if-not-null", 3, 0, 0)
2001-04-01 05:03:41 +00:00
{
SCM x;
POP (x);
BR (!scm_is_null (x));
2000-08-22 15:54:19 +00:00
}
/*
* Subprogram call
*/
VM_DEFINE_INSTRUCTION (41, br_if_nargs_ne, "br-if-nargs-ne", 5, 0, 0)
{
scm_t_ptrdiff n;
scm_t_int32 offset;
n = FETCH () << 8;
n += FETCH ();
FETCH_OFFSET (offset);
if (sp - (fp - 1) != n)
ip += offset;
NEXT;
}
VM_DEFINE_INSTRUCTION (42, br_if_nargs_lt, "br-if-nargs-lt", 5, 0, 0)
{
scm_t_ptrdiff n;
scm_t_int32 offset;
n = FETCH () << 8;
n += FETCH ();
FETCH_OFFSET (offset);
if (sp - (fp - 1) < n)
ip += offset;
NEXT;
}
VM_DEFINE_INSTRUCTION (43, br_if_nargs_gt, "br-if-nargs-gt", 5, 0, 0)
{
scm_t_ptrdiff n;
scm_t_int32 offset;
n = FETCH () << 8;
n += FETCH ();
FETCH_OFFSET (offset);
if (sp - (fp - 1) > n)
ip += offset;
NEXT;
}
VM_DEFINE_INSTRUCTION (44, assert_nargs_ee, "assert-nargs-ee", 2, 0, 0)
{
scm_t_ptrdiff n;
n = FETCH () << 8;
n += FETCH ();
if (sp - (fp - 1) != n)
goto vm_error_wrong_num_args;
NEXT;
}
VM_DEFINE_INSTRUCTION (45, assert_nargs_ge, "assert-nargs-ge", 2, 0, 0)
{
scm_t_ptrdiff n;
n = FETCH () << 8;
n += FETCH ();
if (sp - (fp - 1) < n)
goto vm_error_wrong_num_args;
NEXT;
}
VM_DEFINE_INSTRUCTION (46, bind_optionals, "bind-optionals", 2, -1, -1)
{
scm_t_ptrdiff n;
n = FETCH () << 8;
n += FETCH ();
while (sp - (fp - 1) < n)
PUSH (SCM_UNDEFINED);
NEXT;
}
VM_DEFINE_INSTRUCTION (47, bind_optionals_shuffle, "bind-optionals/shuffle", 6, -1, -1)
{
SCM *walk;
scm_t_ptrdiff nreq, nreq_and_opt, ntotal;
nreq = FETCH () << 8;
nreq += FETCH ();
nreq_and_opt = FETCH () << 8;
nreq_and_opt += FETCH ();
ntotal = FETCH () << 8;
ntotal += FETCH ();
/* look in optionals for first keyword or last positional */
/* starting after the last required positional arg */
walk = fp + nreq;
while (/* while we have args */
walk <= sp
/* and we still have positionals to fill */
&& walk - fp < nreq_and_opt
/* and we haven't reached a keyword yet */
&& !scm_is_keyword (*walk))
/* bind this optional arg (by leaving it in place) */
walk++;
/* now shuffle up, from walk to ntotal */
{
scm_t_ptrdiff nshuf = sp - walk + 1, i;
sp = (fp - 1) + ntotal + nshuf;
CHECK_OVERFLOW ();
for (i = 0; i < nshuf; i++)
sp[-i] = walk[nshuf-i-1];
}
/* and fill optionals & keyword args with SCM_UNDEFINED */
while (walk <= (fp - 1) + ntotal)
*walk++ = SCM_UNDEFINED;
NEXT;
}
/* Flags that determine whether other keywords are allowed, and whether a
rest argument is expected. These values must match those used by the
glil->assembly compiler. */
#define F_ALLOW_OTHER_KEYS 1
#define F_REST 2
VM_DEFINE_INSTRUCTION (48, bind_kwargs, "bind-kwargs", 5, 0, 0)
{
scm_t_uint16 idx;
scm_t_ptrdiff nkw;
int kw_and_rest_flags;
SCM kw;
idx = FETCH () << 8;
idx += FETCH ();
/* XXX: We don't actually use NKW. */
nkw = FETCH () << 8;
nkw += FETCH ();
kw_and_rest_flags = FETCH ();
if (!(kw_and_rest_flags & F_REST)
&& ((sp - (fp - 1) - nkw) % 2))
goto vm_error_kwargs_length_not_even;
CHECK_OBJECT (idx);
kw = OBJECT_REF (idx);
/* Switch NKW to be a negative index below SP. */
for (nkw = -(sp - (fp - 1) - nkw) + 1; nkw < 0; nkw++)
{
SCM walk;
if (scm_is_keyword (sp[nkw]))
{
for (walk = kw; scm_is_pair (walk); walk = SCM_CDR (walk))
{
if (scm_is_eq (SCM_CAAR (walk), sp[nkw]))
{
SCM si = SCM_CDAR (walk);
LOCAL_SET (SCM_I_INUMP (si) ? SCM_I_INUM (si) : scm_to_long (si),
sp[nkw + 1]);
break;
}
}
if (!(kw_and_rest_flags & F_ALLOW_OTHER_KEYS) && !scm_is_pair (walk))
goto vm_error_kwargs_unrecognized_keyword;
nkw++;
}
else if (!(kw_and_rest_flags & F_REST))
goto vm_error_kwargs_invalid_keyword;
}
NEXT;
}
#undef F_ALLOW_OTHER_KEYS
#undef F_REST
VM_DEFINE_INSTRUCTION (49, push_rest, "push-rest", 2, -1, -1)
{
scm_t_ptrdiff n;
SCM rest = SCM_EOL;
n = FETCH () << 8;
n += FETCH ();
while (sp - (fp - 1) > n)
/* No need to check for underflow. */
CONS (rest, *sp--, rest);
PUSH (rest);
NEXT;
}
VM_DEFINE_INSTRUCTION (50, bind_rest, "bind-rest", 4, -1, -1)
{
scm_t_ptrdiff n;
scm_t_uint32 i;
SCM rest = SCM_EOL;
n = FETCH () << 8;
n += FETCH ();
i = FETCH () << 8;
i += FETCH ();
while (sp - (fp - 1) > n)
/* No need to check for underflow. */
CONS (rest, *sp--, rest);
LOCAL_SET (i, rest);
NEXT;
}
VM_DEFINE_INSTRUCTION (51, reserve_locals, "reserve-locals", 2, -1, -1)
{
SCM *old_sp;
scm_t_int32 n;
n = FETCH () << 8;
n += FETCH ();
old_sp = sp;
sp = (fp - 1) + n;
if (old_sp < sp)
{
CHECK_OVERFLOW ();
while (old_sp < sp)
*++old_sp = SCM_UNDEFINED;
}
else
NULLSTACK (old_sp - sp);
NEXT;
}
VM_DEFINE_INSTRUCTION (52, new_frame, "new-frame", 0, 0, 3)
{
runtime and debugging support for callee-parsed procedure args * libguile/objcodes.h: Bump for metadata format change. * libguile/frames.h: Rework so we don't frob the program's nargs, nlocs, etc at runtime. Instead we don't really know what's a local var, an argument, or an intermediate value. It's a little unfortunate, but this will allow for case-lambda, and eventually for good polymorphic generic dispatch; and the nlocs etc can be heuristically reconstructed. Such a reconstruction would be better done at the Scheme level, though. (SCM_FRAME_STACK_ADDRESS): New macro, the pointer to the base of the stack elements (not counting the program). (SCM_FRAME_UPPER_ADDRESS): Repurpose to be the address of the last element in the bookkeeping part of the stack -- i.e. to point to the return address. * libguile/vm-engine.h: * libguile/vm-i-system.c: Adapt to removal of stack_base. Though we still detect stack-smashing underflow, we don't do so as precisely as we did before, because now we only detect overwriting of the frame metadata. * libguile/vm-engine.c (vm_engine): Remove the stack_base variable. It is unnecessary, and difficult to keep track of in the face of case-lambda. Also fix miscommented "ra" and "mvra" pushes. Push the vp->ip as the first ra... * libguile/vm-i-system.c (halt): ...because here we can restore the vp->ip instead of setting ip to 0. Allows us to introspect ips all down the stack, including in recursive VM invocations. * libguile/frames.h: * libguile/frames.c (scm_vm_frame_stack): Removed, because it's getting more difficult to tell what's an argument and what's a temporary stack element. (scm_vm_frame_num_locals): New accessor. (scm_vm_frame_instruction_pointer): New accessor. (scm_vm_frame_arguments): Defer to an implementation in Scheme. (scm_vm_frame_num_locals scm_vm_frame_local_ref) (scm_vm_frame_local_set_x): Since we can get not-yet-active frames on the stack now, with our current calling convention, we have to add a heuristic here to jump over those frames -- because frames have pointers in them, not Scheme values. * libguile/programs.h: * libguile/programs.c (scm_program_arity): Remove, in favor of.. (scm_program_arities): ...this, which a list of arities, in a new format, occupying a slot in the metadata. * module/language/assembly/decompile-bytecode.scm (decode-load-program): Fix mv-call decompilation. * module/system/vm/frame.scm (vm-frame-bindings, vm-frame-binding-ref) (vm-frame-binding-set!): New functions, to access bindings by name in a frame. (vm-frame-arguments): Function now implemented in Scheme. Commented fairly extensively. * module/system/vm/program.scm (program-bindings-by-index) (program-bindings-for-ip): New accessors, parsing the program bindings metadata into something more useful. (program-arities, program-arguments): In a case-lambda world, we have to assume that programs can have multiple arities. But it's tough to detect this algorithmically; instead we're going to require that the program metadata include information about the arities, and the parts of the program that that metadata applies to. (program-lambda-list): New accessor. (write-program): Show multiple arities. * module/language/glil/compile-assembly.scm (glil->assembly): Add "arities" to the state of the compiler, and add arities entries as appropriate.
2009-09-27 19:25:58 -04:00
/* NB: if you change this, see frames.c:vm-frame-num-locals */
/* and frames.h, vm-engine.c, etc of course */
/* We don't initialize the dynamic link here because we don't actually
know that this frame will point to the current fp: it could be
placed elsewhere on the stack if captured in a partial
continuation, and invoked from some other context. */
PUSH (0); /* dynamic link */
PUSH (0); /* mvra */
PUSH (0); /* ra */
NEXT;
}
VM_DEFINE_INSTRUCTION (53, call, "call", 1, -1, 1)
2000-08-22 15:54:19 +00:00
{
2001-04-01 05:03:41 +00:00
nargs = FETCH ();
2000-08-22 15:54:19 +00:00
vm_call:
program = sp[-nargs];
2001-04-07 23:32:03 +00:00
VM_HANDLE_INTERRUPTS;
if (SCM_UNLIKELY (!SCM_PROGRAM_P (program)))
2000-08-22 15:54:19 +00:00
{
if (SCM_STRUCTP (program) && SCM_STRUCT_APPLICABLE_P (program))
{
sp[-nargs] = SCM_STRUCT_PROCEDURE (program);
goto vm_call;
}
else if (SCM_NIMP (program) && SCM_TYP7 (program) == scm_tc7_smob
&& SCM_SMOB_APPLICABLE_P (program))
{
SYNC_REGISTER ();
sp[-nargs] = scm_i_smob_apply_trampoline (program);
goto vm_call;
}
else
goto vm_error_wrong_type_apply;
2000-08-22 15:54:19 +00:00
}
CACHE_PROGRAM ();
{
SCM *old_fp = fp;
fp = sp - nargs + 1;
ASSERT (SCM_FRAME_DYNAMIC_LINK (fp) == 0);
ASSERT (SCM_FRAME_RETURN_ADDRESS (fp) == 0);
ASSERT (SCM_FRAME_MV_RETURN_ADDRESS (fp) == 0);
SCM_FRAME_SET_DYNAMIC_LINK (fp, old_fp);
SCM_FRAME_SET_RETURN_ADDRESS (fp, ip);
SCM_FRAME_SET_MV_RETURN_ADDRESS (fp, 0);
}
ip = SCM_C_OBJCODE_BASE (bp);
PUSH_CONTINUATION_HOOK ();
APPLY_HOOK ();
NEXT;
2000-08-22 15:54:19 +00:00
}
VM_DEFINE_INSTRUCTION (54, tail_call, "tail-call", 1, -1, 1)
2000-08-22 15:54:19 +00:00
{
2001-04-01 05:03:41 +00:00
nargs = FETCH ();
vm_tail_call:
program = sp[-nargs];
2001-04-01 05:03:41 +00:00
VM_HANDLE_INTERRUPTS;
2000-08-22 15:54:19 +00:00
if (SCM_UNLIKELY (!SCM_PROGRAM_P (program)))
{
if (SCM_STRUCTP (program) && SCM_STRUCT_APPLICABLE_P (program))
{
sp[-nargs] = SCM_STRUCT_PROCEDURE (program);
goto vm_tail_call;
}
else if (SCM_NIMP (program) && SCM_TYP7 (program) == scm_tc7_smob
&& SCM_SMOB_APPLICABLE_P (program))
{
SYNC_REGISTER ();
sp[-nargs] = scm_i_smob_apply_trampoline (program);
goto vm_tail_call;
}
else
goto vm_error_wrong_type_apply;
}
else
2001-04-01 05:03:41 +00:00
{
int i;
precise stack marking, fix some missed references, still imperfect * libguile/vm-engine.h (CHECK_STACK_LEAK, NULLSTACK): Add a new mode, VM_ENABLE_STACK_NULLING, that tries to ensure that all stack data past the top of the stack is NULL. This helps to verify the VM's consistency. If VM_ENABLE_STACK_NULLING is not defined, there is no overhead. (DROP, DROPN): Hook into NULLSTACK. (POP_LIST): Hoo, fix a good bug: if CONS triggered a GC, the elements of the list that had not yet been consed would not be marked, because the sp was already below them. (NEXT): Hook into CHECK_STACK_LEAK. (INIT_ARGS): Add a note that consing the rest arg can cause GC. (NEW_FRAME): Cons up the external data after initializing the frame, so that if GC is triggered, the precise marker sees a well-formed frame. * libguile/vm-i-loader.c (load-program): In the four-integers case, use the POP macro so that we can hook into NULLSTACK (if necessary). * libguile/vm-i-scheme.c (ARGS2, ARGS3): Hook into NULLSTACK. * libguile/vm-i-system.c (halt): Null the nvalues. Rework some asserts into using ASSERT, and null the stack when we free the frame. (variable-set): Use DROPN instead of sp -= 2. (BR): Hook into NULLSTACK. (goto/args): Hook into NULLSTACK. In the non-self case, delay updating the frame until after INIT_ARGS so that GC sees a well-formed frame. Delay consing the externals until after the frame is set up, as in NEW_FRAME. (call/cc): Add some asserts. (return): Rework some asserts into ASSERT, and hook into NULLSTACK. (return/values): Hook into NULLSTACK, and use ASSERT. (return/values*) Use ASSERT. * libguile/vm.c (VM_ENABLE_ASSERTIONS, VM_ENABLE_STACK_NULLING): These are the variables that control assertions and nulling. Perhaps we can do these per-engine when we start compiling the debug engine separate from a speedy engine. (vm_mark_stack): Add a precise stack marker. Yay! (vm_cont_mark): Mark the continuation stack precisely. (capture_vm_cont): Record the difference from the vp's stack_base too, so that we can translate the dynamic links when marking the continuation stack. Memset the stack to NULL if we are doing nulling. (reinstate_vm_cont): If we are nulling, null out the relevant part of the stack. (vm_reset_stack): When resetting sp due to a nonlocal exit, null out the stack too. (vm_mark): If we are nulling, assert that there are no extra values on the stack. Mark the stack precisely.
2008-10-03 16:00:30 +02:00
#ifdef VM_ENABLE_STACK_NULLING
SCM *old_sp = sp;
CHECK_STACK_LEAK ();
precise stack marking, fix some missed references, still imperfect * libguile/vm-engine.h (CHECK_STACK_LEAK, NULLSTACK): Add a new mode, VM_ENABLE_STACK_NULLING, that tries to ensure that all stack data past the top of the stack is NULL. This helps to verify the VM's consistency. If VM_ENABLE_STACK_NULLING is not defined, there is no overhead. (DROP, DROPN): Hook into NULLSTACK. (POP_LIST): Hoo, fix a good bug: if CONS triggered a GC, the elements of the list that had not yet been consed would not be marked, because the sp was already below them. (NEXT): Hook into CHECK_STACK_LEAK. (INIT_ARGS): Add a note that consing the rest arg can cause GC. (NEW_FRAME): Cons up the external data after initializing the frame, so that if GC is triggered, the precise marker sees a well-formed frame. * libguile/vm-i-loader.c (load-program): In the four-integers case, use the POP macro so that we can hook into NULLSTACK (if necessary). * libguile/vm-i-scheme.c (ARGS2, ARGS3): Hook into NULLSTACK. * libguile/vm-i-system.c (halt): Null the nvalues. Rework some asserts into using ASSERT, and null the stack when we free the frame. (variable-set): Use DROPN instead of sp -= 2. (BR): Hook into NULLSTACK. (goto/args): Hook into NULLSTACK. In the non-self case, delay updating the frame until after INIT_ARGS so that GC sees a well-formed frame. Delay consing the externals until after the frame is set up, as in NEW_FRAME. (call/cc): Add some asserts. (return): Rework some asserts into ASSERT, and hook into NULLSTACK. (return/values): Hook into NULLSTACK, and use ASSERT. (return/values*) Use ASSERT. * libguile/vm.c (VM_ENABLE_ASSERTIONS, VM_ENABLE_STACK_NULLING): These are the variables that control assertions and nulling. Perhaps we can do these per-engine when we start compiling the debug engine separate from a speedy engine. (vm_mark_stack): Add a precise stack marker. Yay! (vm_cont_mark): Mark the continuation stack precisely. (capture_vm_cont): Record the difference from the vp's stack_base too, so that we can translate the dynamic links when marking the continuation stack. Memset the stack to NULL if we are doing nulling. (reinstate_vm_cont): If we are nulling, null out the relevant part of the stack. (vm_reset_stack): When resetting sp due to a nonlocal exit, null out the stack too. (vm_mark): If we are nulling, assert that there are no extra values on the stack. Mark the stack precisely.
2008-10-03 16:00:30 +02:00
#endif
/* switch programs */
CACHE_PROGRAM ();
/* shuffle down the program and the arguments */
for (i = -1, sp = sp - nargs + 1; i < nargs; i++)
SCM_FRAME_STACK_ADDRESS (fp)[i] = sp[i];
precise stack marking, fix some missed references, still imperfect * libguile/vm-engine.h (CHECK_STACK_LEAK, NULLSTACK): Add a new mode, VM_ENABLE_STACK_NULLING, that tries to ensure that all stack data past the top of the stack is NULL. This helps to verify the VM's consistency. If VM_ENABLE_STACK_NULLING is not defined, there is no overhead. (DROP, DROPN): Hook into NULLSTACK. (POP_LIST): Hoo, fix a good bug: if CONS triggered a GC, the elements of the list that had not yet been consed would not be marked, because the sp was already below them. (NEXT): Hook into CHECK_STACK_LEAK. (INIT_ARGS): Add a note that consing the rest arg can cause GC. (NEW_FRAME): Cons up the external data after initializing the frame, so that if GC is triggered, the precise marker sees a well-formed frame. * libguile/vm-i-loader.c (load-program): In the four-integers case, use the POP macro so that we can hook into NULLSTACK (if necessary). * libguile/vm-i-scheme.c (ARGS2, ARGS3): Hook into NULLSTACK. * libguile/vm-i-system.c (halt): Null the nvalues. Rework some asserts into using ASSERT, and null the stack when we free the frame. (variable-set): Use DROPN instead of sp -= 2. (BR): Hook into NULLSTACK. (goto/args): Hook into NULLSTACK. In the non-self case, delay updating the frame until after INIT_ARGS so that GC sees a well-formed frame. Delay consing the externals until after the frame is set up, as in NEW_FRAME. (call/cc): Add some asserts. (return): Rework some asserts into ASSERT, and hook into NULLSTACK. (return/values): Hook into NULLSTACK, and use ASSERT. (return/values*) Use ASSERT. * libguile/vm.c (VM_ENABLE_ASSERTIONS, VM_ENABLE_STACK_NULLING): These are the variables that control assertions and nulling. Perhaps we can do these per-engine when we start compiling the debug engine separate from a speedy engine. (vm_mark_stack): Add a precise stack marker. Yay! (vm_cont_mark): Mark the continuation stack precisely. (capture_vm_cont): Record the difference from the vp's stack_base too, so that we can translate the dynamic links when marking the continuation stack. Memset the stack to NULL if we are doing nulling. (reinstate_vm_cont): If we are nulling, null out the relevant part of the stack. (vm_reset_stack): When resetting sp due to a nonlocal exit, null out the stack too. (vm_mark): If we are nulling, assert that there are no extra values on the stack. Mark the stack precisely.
2008-10-03 16:00:30 +02:00
sp = fp + i - 1;
precise stack marking, fix some missed references, still imperfect * libguile/vm-engine.h (CHECK_STACK_LEAK, NULLSTACK): Add a new mode, VM_ENABLE_STACK_NULLING, that tries to ensure that all stack data past the top of the stack is NULL. This helps to verify the VM's consistency. If VM_ENABLE_STACK_NULLING is not defined, there is no overhead. (DROP, DROPN): Hook into NULLSTACK. (POP_LIST): Hoo, fix a good bug: if CONS triggered a GC, the elements of the list that had not yet been consed would not be marked, because the sp was already below them. (NEXT): Hook into CHECK_STACK_LEAK. (INIT_ARGS): Add a note that consing the rest arg can cause GC. (NEW_FRAME): Cons up the external data after initializing the frame, so that if GC is triggered, the precise marker sees a well-formed frame. * libguile/vm-i-loader.c (load-program): In the four-integers case, use the POP macro so that we can hook into NULLSTACK (if necessary). * libguile/vm-i-scheme.c (ARGS2, ARGS3): Hook into NULLSTACK. * libguile/vm-i-system.c (halt): Null the nvalues. Rework some asserts into using ASSERT, and null the stack when we free the frame. (variable-set): Use DROPN instead of sp -= 2. (BR): Hook into NULLSTACK. (goto/args): Hook into NULLSTACK. In the non-self case, delay updating the frame until after INIT_ARGS so that GC sees a well-formed frame. Delay consing the externals until after the frame is set up, as in NEW_FRAME. (call/cc): Add some asserts. (return): Rework some asserts into ASSERT, and hook into NULLSTACK. (return/values): Hook into NULLSTACK, and use ASSERT. (return/values*) Use ASSERT. * libguile/vm.c (VM_ENABLE_ASSERTIONS, VM_ENABLE_STACK_NULLING): These are the variables that control assertions and nulling. Perhaps we can do these per-engine when we start compiling the debug engine separate from a speedy engine. (vm_mark_stack): Add a precise stack marker. Yay! (vm_cont_mark): Mark the continuation stack precisely. (capture_vm_cont): Record the difference from the vp's stack_base too, so that we can translate the dynamic links when marking the continuation stack. Memset the stack to NULL if we are doing nulling. (reinstate_vm_cont): If we are nulling, null out the relevant part of the stack. (vm_reset_stack): When resetting sp due to a nonlocal exit, null out the stack too. (vm_mark): If we are nulling, assert that there are no extra values on the stack. Mark the stack precisely.
2008-10-03 16:00:30 +02:00
NULLSTACK (old_sp - sp);
ip = SCM_C_OBJCODE_BASE (bp);
precise stack marking, fix some missed references, still imperfect * libguile/vm-engine.h (CHECK_STACK_LEAK, NULLSTACK): Add a new mode, VM_ENABLE_STACK_NULLING, that tries to ensure that all stack data past the top of the stack is NULL. This helps to verify the VM's consistency. If VM_ENABLE_STACK_NULLING is not defined, there is no overhead. (DROP, DROPN): Hook into NULLSTACK. (POP_LIST): Hoo, fix a good bug: if CONS triggered a GC, the elements of the list that had not yet been consed would not be marked, because the sp was already below them. (NEXT): Hook into CHECK_STACK_LEAK. (INIT_ARGS): Add a note that consing the rest arg can cause GC. (NEW_FRAME): Cons up the external data after initializing the frame, so that if GC is triggered, the precise marker sees a well-formed frame. * libguile/vm-i-loader.c (load-program): In the four-integers case, use the POP macro so that we can hook into NULLSTACK (if necessary). * libguile/vm-i-scheme.c (ARGS2, ARGS3): Hook into NULLSTACK. * libguile/vm-i-system.c (halt): Null the nvalues. Rework some asserts into using ASSERT, and null the stack when we free the frame. (variable-set): Use DROPN instead of sp -= 2. (BR): Hook into NULLSTACK. (goto/args): Hook into NULLSTACK. In the non-self case, delay updating the frame until after INIT_ARGS so that GC sees a well-formed frame. Delay consing the externals until after the frame is set up, as in NEW_FRAME. (call/cc): Add some asserts. (return): Rework some asserts into ASSERT, and hook into NULLSTACK. (return/values): Hook into NULLSTACK, and use ASSERT. (return/values*) Use ASSERT. * libguile/vm.c (VM_ENABLE_ASSERTIONS, VM_ENABLE_STACK_NULLING): These are the variables that control assertions and nulling. Perhaps we can do these per-engine when we start compiling the debug engine separate from a speedy engine. (vm_mark_stack): Add a precise stack marker. Yay! (vm_cont_mark): Mark the continuation stack precisely. (capture_vm_cont): Record the difference from the vp's stack_base too, so that we can translate the dynamic links when marking the continuation stack. Memset the stack to NULL if we are doing nulling. (reinstate_vm_cont): If we are nulling, null out the relevant part of the stack. (vm_reset_stack): When resetting sp due to a nonlocal exit, null out the stack too. (vm_mark): If we are nulling, assert that there are no extra values on the stack. Mark the stack precisely.
2008-10-03 16:00:30 +02:00
APPLY_HOOK ();
NEXT;
2001-04-01 05:03:41 +00:00
}
}
VM_DEFINE_INSTRUCTION (55, subr_call, "subr-call", 1, -1, -1)
{
SCM pointer, ret;
SCM (*subr)();
nargs = FETCH ();
POP (pointer);
subr = SCM_POINTER_VALUE (pointer);
VM_HANDLE_INTERRUPTS;
SYNC_REGISTER ();
switch (nargs)
{
case 0:
ret = subr ();
break;
case 1:
ret = subr (sp[0]);
break;
case 2:
ret = subr (sp[-1], sp[0]);
break;
case 3:
ret = subr (sp[-2], sp[-1], sp[0]);
break;
case 4:
ret = subr (sp[-3], sp[-2], sp[-1], sp[0]);
break;
case 5:
ret = subr (sp[-4], sp[-3], sp[-2], sp[-1], sp[0]);
break;
case 6:
ret = subr (sp[-5], sp[-4], sp[-3], sp[-2], sp[-1], sp[0]);
break;
case 7:
ret = subr (sp[-6], sp[-5], sp[-4], sp[-3], sp[-2], sp[-1], sp[0]);
break;
case 8:
ret = subr (sp[-7], sp[-6], sp[-5], sp[-4], sp[-3], sp[-2], sp[-1], sp[0]);
break;
case 9:
ret = subr (sp[-8], sp[-7], sp[-6], sp[-5], sp[-4], sp[-3], sp[-2], sp[-1], sp[0]);
break;
case 10:
ret = subr (sp[-9], sp[-8], sp[-7], sp[-6], sp[-5], sp[-4], sp[-3], sp[-2], sp[-1], sp[0]);
break;
default:
abort ();
}
NULLSTACK_FOR_NONLOCAL_EXIT ();
if (SCM_UNLIKELY (SCM_VALUESP (ret)))
{
/* multiple values returned to continuation */
ret = scm_struct_ref (ret, SCM_INUM0);
nvalues = scm_ilength (ret);
PUSH_LIST (ret, scm_is_null);
goto vm_return_values;
}
else
{
PUSH (ret);
goto vm_return;
}
}
VM_DEFINE_INSTRUCTION (56, smob_call, "smob-call", 1, -1, -1)
{
SCM smob, ret;
SCM (*subr)();
nargs = FETCH ();
POP (smob);
subr = SCM_SMOB_DESCRIPTOR (smob).apply;
VM_HANDLE_INTERRUPTS;
SYNC_REGISTER ();
switch (nargs)
{
case 0:
ret = subr (smob);
break;
case 1:
ret = subr (smob, sp[0]);
break;
case 2:
ret = subr (smob, sp[-1], sp[0]);
break;
case 3:
ret = subr (smob, sp[-2], sp[-1], sp[0]);
break;
default:
abort ();
}
NULLSTACK_FOR_NONLOCAL_EXIT ();
if (SCM_UNLIKELY (SCM_VALUESP (ret)))
{
/* multiple values returned to continuation */
ret = scm_struct_ref (ret, SCM_INUM0);
nvalues = scm_ilength (ret);
PUSH_LIST (ret, scm_is_null);
goto vm_return_values;
}
else
{
PUSH (ret);
goto vm_return;
}
}
VM_DEFINE_INSTRUCTION (57, foreign_call, "foreign-call", 1, -1, -1)
{
SCM foreign, ret;
nargs = FETCH ();
POP (foreign);
VM_HANDLE_INTERRUPTS;
SYNC_REGISTER ();
ret = scm_i_foreign_call (foreign, sp - nargs + 1);
NULLSTACK_FOR_NONLOCAL_EXIT ();
if (SCM_UNLIKELY (SCM_VALUESP (ret)))
{
/* multiple values returned to continuation */
ret = scm_struct_ref (ret, SCM_INUM0);
nvalues = scm_ilength (ret);
PUSH_LIST (ret, scm_is_null);
goto vm_return_values;
}
else
{
PUSH (ret);
goto vm_return;
}
}
VM_DEFINE_INSTRUCTION (58, continuation_call, "continuation-call", 0, -1, 0)
{
SCM contregs;
POP (contregs);
continuations return multiple values on the stack * libguile/vm.h (struct scm_vm_cont): Instead of saving the "IP", save "RA" and "MVRA". That is, save singly-valued and multiply-valued return addresses, so that we can return multiple values on the stack. (scm_i_vm_reinstate_continuation): Remove. * libguile/vm.c (vm_capture_continuation): Rename from capture_vm_cont, and change the prototype so we can capture the RA and MVRA, and so that tail calls to call/cc can capture a continuation without the call/cc application frame. (vm_return_to_continuation): Rename from reinstate_vm_cont, and take arguments to return to the continuation. Handles returning to single or multiple-value RA. (scm_i_vm_capture_continuation): Change to invoke vm_capture_continuation. Kept around for the benefit of make-stack. * libguile/vm-i-system.c (continuation-call): Handle reinstatement of the VM stack, with arguments. (call/cc, tail-call/cc): Adapt to new vm_capture_continuation prototype. tail-call/cc captures tail continuations. * libguile/stacks.c (scm_make_stack): Update for scm_vm_cont structure change. * libguile/continuations.h (struct scm_contregs): Remove throw_value member, which was used to return a value to a continuation. (scm_i_check_continuation): New internal function, checks that a continuation may be reinstated. (scm_i_reinstate_continuation): Replaces scm_i_continuation_call; just reinstates the C stack. (scm_i_contregs_vm, scm_i_contregs_vm_cont): New internal accessors. * libguile/continuations.c (scm_i_make_continuation): Return SCM_UNDEFINED if we are returning again. (grow_stack, copy_stack_and_call, scm_dynthrow): Remove extra arg, as vm opcodes handle value returns. (copy_stack): No need to instate VM continuation. (scm_i_reinstate_continuation): Adapt.
2010-02-08 22:59:25 +01:00
SYNC_ALL ();
continuations return multiple values on the stack * libguile/vm.h (struct scm_vm_cont): Instead of saving the "IP", save "RA" and "MVRA". That is, save singly-valued and multiply-valued return addresses, so that we can return multiple values on the stack. (scm_i_vm_reinstate_continuation): Remove. * libguile/vm.c (vm_capture_continuation): Rename from capture_vm_cont, and change the prototype so we can capture the RA and MVRA, and so that tail calls to call/cc can capture a continuation without the call/cc application frame. (vm_return_to_continuation): Rename from reinstate_vm_cont, and take arguments to return to the continuation. Handles returning to single or multiple-value RA. (scm_i_vm_capture_continuation): Change to invoke vm_capture_continuation. Kept around for the benefit of make-stack. * libguile/vm-i-system.c (continuation-call): Handle reinstatement of the VM stack, with arguments. (call/cc, tail-call/cc): Adapt to new vm_capture_continuation prototype. tail-call/cc captures tail continuations. * libguile/stacks.c (scm_make_stack): Update for scm_vm_cont structure change. * libguile/continuations.h (struct scm_contregs): Remove throw_value member, which was used to return a value to a continuation. (scm_i_check_continuation): New internal function, checks that a continuation may be reinstated. (scm_i_reinstate_continuation): Replaces scm_i_continuation_call; just reinstates the C stack. (scm_i_contregs_vm, scm_i_contregs_vm_cont): New internal accessors. * libguile/continuations.c (scm_i_make_continuation): Return SCM_UNDEFINED if we are returning again. (grow_stack, copy_stack_and_call, scm_dynthrow): Remove extra arg, as vm opcodes handle value returns. (copy_stack): No need to instate VM continuation. (scm_i_reinstate_continuation): Adapt.
2010-02-08 22:59:25 +01:00
scm_i_check_continuation (contregs);
vm_return_to_continuation (scm_i_contregs_vm (contregs),
scm_i_contregs_vm_cont (contregs),
sp - (fp - 1), fp);
scm_i_reinstate_continuation (contregs);
/* no NEXT */
abort ();
}
VM_DEFINE_INSTRUCTION (59, partial_cont_call, "partial-cont-call", 0, -1, 0)
{
SCM vmcont, intwinds, prevwinds;
POP2 (intwinds, vmcont);
SYNC_REGISTER ();
if (SCM_UNLIKELY (!SCM_VM_CONT_REWINDABLE_P (vmcont)))
{ finish_args = vmcont;
goto vm_error_continuation_not_rewindable;
}
prevwinds = scm_i_dynwinds ();
vm_reinstate_partial_continuation (vm, vmcont, intwinds, sp + 1 - fp, fp,
vm_cookie);
/* Rewind prompt jmpbuffers, if any. */
{
SCM winds = scm_i_dynwinds ();
for (; !scm_is_eq (winds, prevwinds); winds = scm_cdr (winds))
if (SCM_PROMPT_P (scm_car (winds)) && SCM_PROMPT_SETJMP (scm_car (winds)))
break;
}
CACHE_REGISTER ();
program = SCM_FRAME_PROGRAM (fp);
CACHE_PROGRAM ();
NEXT;
}
VM_DEFINE_INSTRUCTION (60, tail_call_nargs, "tail-call/nargs", 0, 0, 1)
compile call-with-values, woot! * libguile/vm-engine.c (vm_run): Add another byte onto the bootstrap program, as the offset passed to mv-call now takes two bytes. * module/system/vm/frame.scm (bootstrap-frame?): Update for the new bootstrap length. Really we should just check for 'halt though. * libguile/vm-i-system.c (FETCH_OFFSET): New helper, used in BR(). (goto/nargs, call/nargs): Versions of goto/args and call, respectively, that take the number of arguments from a value on the top of the stack. (mv-call): Call FETCH_OFFSET to get the offset. * module/language/scheme/translate.scm (custom-transformer-table): Compile call-with-values to <ghil-mv-call>. There is some trickery because of the r4rs.scm call-with-values trampolines. * module/system/il/ghil.scm: Add <ghil-mv-call> and accessors. * module/system/il/compile.scm (codegen): Compile <ghil-mv-call>. * module/system/il/glil.scm: Add <glil-mv-call>, which needs some special assembly because of the label. Fix some typos. * module/system/vm/assemble.scm (byte-length): New helper, factored out and made more general. (codegen): Assemble mv-call, including the label. (check-length): New helper, makes sure that the addressing is consistent within the produced object code. (stack->bytes): Rewrite to be more generic -- now `br' instructions aren't the only ones jumping around in the instruction stream. * module/system/vm/conv.scm (make-byte-decoder): Return two values in the #f case. * module/system/vm/disasm.scm (disassemble-bytecode): Rewrite, because the previous implementation depended on a guile interpreter quirk: namely, that multiple values could be represented within one value, and destructured later.
2008-09-16 00:26:22 +02:00
{
SCM x;
POP (x);
nargs = scm_to_int (x);
lambda-lifting for (lambda () ...) as consumer of call-with-values * libguile/vm-engine.c (vm_run): Add new error case, vm_error_not_enough_values. * libguile/vm-i-system.c (goto/nargs, call/nargs): So, in these cases, if we get too many values, we don't truncate the values like we do in the single-value continuation case, or in the mvbind case. What to do? I guess we either truncate them here, or only allow the correct number of values. Dunno. Mark the code as a fixme. (truncate-values): New instruction, for mv-bind: checks that the number of values on the stack is compatible with the number of bindings we have arranged for them, truncating if necessary. * module/language/scheme/translate.scm (custom-transformer-table): Compile receive as a primary form -- not so much because it is a primary form, but more to test the mv-bind machinery. Also it's more efficient, I think. * module/system/il/compile.scm (lift-variables!): New helper, factored out of `optimize'. (optimize): Add a few more cases. Adapt `lambda' optimization, which isn't much. I'm not happy with ghil as a mungeable language. Add a case for call-with-values with the second argument is a lambda: lift the lambda. Untested. (codegen): Refactor the push-bindings! code. Compile mv-bind. * module/system/il/ghil.scm (<ghil-mv-bind>): Add mv-bind construct, along with its procedures. * module/system/il/glil.scm (<glil-mv-bind>): Add mv-bind construct, different from the high-level one. It makes sense in the source, I think. * module/system/vm/assemble.scm (codegen): Assemble glil-mv-bind by pushing onto the bindings list, and actually push some code to truncate the values.
2008-09-18 22:49:55 +02:00
/* FIXME: should truncate values? */
goto vm_tail_call;
compile call-with-values, woot! * libguile/vm-engine.c (vm_run): Add another byte onto the bootstrap program, as the offset passed to mv-call now takes two bytes. * module/system/vm/frame.scm (bootstrap-frame?): Update for the new bootstrap length. Really we should just check for 'halt though. * libguile/vm-i-system.c (FETCH_OFFSET): New helper, used in BR(). (goto/nargs, call/nargs): Versions of goto/args and call, respectively, that take the number of arguments from a value on the top of the stack. (mv-call): Call FETCH_OFFSET to get the offset. * module/language/scheme/translate.scm (custom-transformer-table): Compile call-with-values to <ghil-mv-call>. There is some trickery because of the r4rs.scm call-with-values trampolines. * module/system/il/ghil.scm: Add <ghil-mv-call> and accessors. * module/system/il/compile.scm (codegen): Compile <ghil-mv-call>. * module/system/il/glil.scm: Add <glil-mv-call>, which needs some special assembly because of the label. Fix some typos. * module/system/vm/assemble.scm (byte-length): New helper, factored out and made more general. (codegen): Assemble mv-call, including the label. (check-length): New helper, makes sure that the addressing is consistent within the produced object code. (stack->bytes): Rewrite to be more generic -- now `br' instructions aren't the only ones jumping around in the instruction stream. * module/system/vm/conv.scm (make-byte-decoder): Return two values in the #f case. * module/system/vm/disasm.scm (disassemble-bytecode): Rewrite, because the previous implementation depended on a guile interpreter quirk: namely, that multiple values could be represented within one value, and destructured later.
2008-09-16 00:26:22 +02:00
}
VM_DEFINE_INSTRUCTION (61, call_nargs, "call/nargs", 0, 0, 1)
compile call-with-values, woot! * libguile/vm-engine.c (vm_run): Add another byte onto the bootstrap program, as the offset passed to mv-call now takes two bytes. * module/system/vm/frame.scm (bootstrap-frame?): Update for the new bootstrap length. Really we should just check for 'halt though. * libguile/vm-i-system.c (FETCH_OFFSET): New helper, used in BR(). (goto/nargs, call/nargs): Versions of goto/args and call, respectively, that take the number of arguments from a value on the top of the stack. (mv-call): Call FETCH_OFFSET to get the offset. * module/language/scheme/translate.scm (custom-transformer-table): Compile call-with-values to <ghil-mv-call>. There is some trickery because of the r4rs.scm call-with-values trampolines. * module/system/il/ghil.scm: Add <ghil-mv-call> and accessors. * module/system/il/compile.scm (codegen): Compile <ghil-mv-call>. * module/system/il/glil.scm: Add <glil-mv-call>, which needs some special assembly because of the label. Fix some typos. * module/system/vm/assemble.scm (byte-length): New helper, factored out and made more general. (codegen): Assemble mv-call, including the label. (check-length): New helper, makes sure that the addressing is consistent within the produced object code. (stack->bytes): Rewrite to be more generic -- now `br' instructions aren't the only ones jumping around in the instruction stream. * module/system/vm/conv.scm (make-byte-decoder): Return two values in the #f case. * module/system/vm/disasm.scm (disassemble-bytecode): Rewrite, because the previous implementation depended on a guile interpreter quirk: namely, that multiple values could be represented within one value, and destructured later.
2008-09-16 00:26:22 +02:00
{
SCM x;
POP (x);
nargs = scm_to_int (x);
lambda-lifting for (lambda () ...) as consumer of call-with-values * libguile/vm-engine.c (vm_run): Add new error case, vm_error_not_enough_values. * libguile/vm-i-system.c (goto/nargs, call/nargs): So, in these cases, if we get too many values, we don't truncate the values like we do in the single-value continuation case, or in the mvbind case. What to do? I guess we either truncate them here, or only allow the correct number of values. Dunno. Mark the code as a fixme. (truncate-values): New instruction, for mv-bind: checks that the number of values on the stack is compatible with the number of bindings we have arranged for them, truncating if necessary. * module/language/scheme/translate.scm (custom-transformer-table): Compile receive as a primary form -- not so much because it is a primary form, but more to test the mv-bind machinery. Also it's more efficient, I think. * module/system/il/compile.scm (lift-variables!): New helper, factored out of `optimize'. (optimize): Add a few more cases. Adapt `lambda' optimization, which isn't much. I'm not happy with ghil as a mungeable language. Add a case for call-with-values with the second argument is a lambda: lift the lambda. Untested. (codegen): Refactor the push-bindings! code. Compile mv-bind. * module/system/il/ghil.scm (<ghil-mv-bind>): Add mv-bind construct, along with its procedures. * module/system/il/glil.scm (<glil-mv-bind>): Add mv-bind construct, different from the high-level one. It makes sense in the source, I think. * module/system/vm/assemble.scm (codegen): Assemble glil-mv-bind by pushing onto the bindings list, and actually push some code to truncate the values.
2008-09-18 22:49:55 +02:00
/* FIXME: should truncate values? */
compile call-with-values, woot! * libguile/vm-engine.c (vm_run): Add another byte onto the bootstrap program, as the offset passed to mv-call now takes two bytes. * module/system/vm/frame.scm (bootstrap-frame?): Update for the new bootstrap length. Really we should just check for 'halt though. * libguile/vm-i-system.c (FETCH_OFFSET): New helper, used in BR(). (goto/nargs, call/nargs): Versions of goto/args and call, respectively, that take the number of arguments from a value on the top of the stack. (mv-call): Call FETCH_OFFSET to get the offset. * module/language/scheme/translate.scm (custom-transformer-table): Compile call-with-values to <ghil-mv-call>. There is some trickery because of the r4rs.scm call-with-values trampolines. * module/system/il/ghil.scm: Add <ghil-mv-call> and accessors. * module/system/il/compile.scm (codegen): Compile <ghil-mv-call>. * module/system/il/glil.scm: Add <glil-mv-call>, which needs some special assembly because of the label. Fix some typos. * module/system/vm/assemble.scm (byte-length): New helper, factored out and made more general. (codegen): Assemble mv-call, including the label. (check-length): New helper, makes sure that the addressing is consistent within the produced object code. (stack->bytes): Rewrite to be more generic -- now `br' instructions aren't the only ones jumping around in the instruction stream. * module/system/vm/conv.scm (make-byte-decoder): Return two values in the #f case. * module/system/vm/disasm.scm (disassemble-bytecode): Rewrite, because the previous implementation depended on a guile interpreter quirk: namely, that multiple values could be represented within one value, and destructured later.
2008-09-16 00:26:22 +02:00
goto vm_call;
}
VM_DEFINE_INSTRUCTION (62, mv_call, "mv-call", 4, -1, 1)
{
scm_t_int32 offset;
scm_t_uint8 *mvra;
nargs = FETCH ();
compile call-with-values, woot! * libguile/vm-engine.c (vm_run): Add another byte onto the bootstrap program, as the offset passed to mv-call now takes two bytes. * module/system/vm/frame.scm (bootstrap-frame?): Update for the new bootstrap length. Really we should just check for 'halt though. * libguile/vm-i-system.c (FETCH_OFFSET): New helper, used in BR(). (goto/nargs, call/nargs): Versions of goto/args and call, respectively, that take the number of arguments from a value on the top of the stack. (mv-call): Call FETCH_OFFSET to get the offset. * module/language/scheme/translate.scm (custom-transformer-table): Compile call-with-values to <ghil-mv-call>. There is some trickery because of the r4rs.scm call-with-values trampolines. * module/system/il/ghil.scm: Add <ghil-mv-call> and accessors. * module/system/il/compile.scm (codegen): Compile <ghil-mv-call>. * module/system/il/glil.scm: Add <glil-mv-call>, which needs some special assembly because of the label. Fix some typos. * module/system/vm/assemble.scm (byte-length): New helper, factored out and made more general. (codegen): Assemble mv-call, including the label. (check-length): New helper, makes sure that the addressing is consistent within the produced object code. (stack->bytes): Rewrite to be more generic -- now `br' instructions aren't the only ones jumping around in the instruction stream. * module/system/vm/conv.scm (make-byte-decoder): Return two values in the #f case. * module/system/vm/disasm.scm (disassemble-bytecode): Rewrite, because the previous implementation depended on a guile interpreter quirk: namely, that multiple values could be represented within one value, and destructured later.
2008-09-16 00:26:22 +02:00
FETCH_OFFSET (offset);
mvra = ip + offset;
vm_mv_call:
program = sp[-nargs];
VM_HANDLE_INTERRUPTS;
if (SCM_UNLIKELY (!SCM_PROGRAM_P (program)))
{
if (SCM_STRUCTP (program) && SCM_STRUCT_APPLICABLE_P (program))
{
sp[-nargs] = SCM_STRUCT_PROCEDURE (program);
goto vm_mv_call;
}
else if (SCM_NIMP (program) && SCM_TYP7 (program) == scm_tc7_smob
&& SCM_SMOB_APPLICABLE_P (program))
{
SYNC_REGISTER ();
sp[-nargs] = scm_i_smob_apply_trampoline (program);
goto vm_mv_call;
}
else
goto vm_error_wrong_type_apply;
}
CACHE_PROGRAM ();
{
SCM *old_fp = fp;
fp = sp - nargs + 1;
ASSERT (SCM_FRAME_DYNAMIC_LINK (fp) == 0);
ASSERT (SCM_FRAME_RETURN_ADDRESS (fp) == 0);
ASSERT (SCM_FRAME_MV_RETURN_ADDRESS (fp) == 0);
SCM_FRAME_SET_DYNAMIC_LINK (fp, old_fp);
SCM_FRAME_SET_RETURN_ADDRESS (fp, ip);
SCM_FRAME_SET_MV_RETURN_ADDRESS (fp, mvra);
}
ip = SCM_C_OBJCODE_BASE (bp);
PUSH_CONTINUATION_HOOK ();
APPLY_HOOK ();
NEXT;
}
VM_DEFINE_INSTRUCTION (63, apply, "apply", 1, -1, 1)
2001-04-07 09:39:38 +00:00
{
2001-04-07 23:32:03 +00:00
int len;
SCM ls;
POP (ls);
nargs = FETCH ();
ASSERT (nargs >= 2);
2001-04-07 23:32:03 +00:00
len = scm_ilength (ls);
if (SCM_UNLIKELY (len < 0))
{
finish_args = ls;
goto vm_error_apply_to_non_list;
}
2001-04-07 23:32:03 +00:00
PUSH_LIST (ls, SCM_NULL_OR_NIL_P);
2001-04-07 23:32:03 +00:00
nargs += len - 2;
goto vm_call;
2001-04-07 09:39:38 +00:00
}
VM_DEFINE_INSTRUCTION (64, tail_apply, "tail-apply", 1, -1, 1)
{
int len;
SCM ls;
POP (ls);
nargs = FETCH ();
ASSERT (nargs >= 2);
len = scm_ilength (ls);
if (SCM_UNLIKELY (len < 0))
{
finish_args = ls;
goto vm_error_apply_to_non_list;
}
PUSH_LIST (ls, SCM_NULL_OR_NIL_P);
nargs += len - 2;
goto vm_tail_call;
}
VM_DEFINE_INSTRUCTION (65, call_cc, "call/cc", 0, 1, 1)
2001-04-01 05:03:41 +00:00
{
int first;
continuations return multiple values on the stack * libguile/vm.h (struct scm_vm_cont): Instead of saving the "IP", save "RA" and "MVRA". That is, save singly-valued and multiply-valued return addresses, so that we can return multiple values on the stack. (scm_i_vm_reinstate_continuation): Remove. * libguile/vm.c (vm_capture_continuation): Rename from capture_vm_cont, and change the prototype so we can capture the RA and MVRA, and so that tail calls to call/cc can capture a continuation without the call/cc application frame. (vm_return_to_continuation): Rename from reinstate_vm_cont, and take arguments to return to the continuation. Handles returning to single or multiple-value RA. (scm_i_vm_capture_continuation): Change to invoke vm_capture_continuation. Kept around for the benefit of make-stack. * libguile/vm-i-system.c (continuation-call): Handle reinstatement of the VM stack, with arguments. (call/cc, tail-call/cc): Adapt to new vm_capture_continuation prototype. tail-call/cc captures tail continuations. * libguile/stacks.c (scm_make_stack): Update for scm_vm_cont structure change. * libguile/continuations.h (struct scm_contregs): Remove throw_value member, which was used to return a value to a continuation. (scm_i_check_continuation): New internal function, checks that a continuation may be reinstated. (scm_i_reinstate_continuation): Replaces scm_i_continuation_call; just reinstates the C stack. (scm_i_contregs_vm, scm_i_contregs_vm_cont): New internal accessors. * libguile/continuations.c (scm_i_make_continuation): Return SCM_UNDEFINED if we are returning again. (grow_stack, copy_stack_and_call, scm_dynthrow): Remove extra arg, as vm opcodes handle value returns. (copy_stack): No need to instate VM continuation. (scm_i_reinstate_continuation): Adapt.
2010-02-08 22:59:25 +01:00
SCM proc, vm_cont, cont;
POP (proc);
SYNC_ALL ();
vm_cont = scm_i_vm_capture_stack (vp->stack_base, fp, sp, ip, NULL, 0);
continuations return multiple values on the stack * libguile/vm.h (struct scm_vm_cont): Instead of saving the "IP", save "RA" and "MVRA". That is, save singly-valued and multiply-valued return addresses, so that we can return multiple values on the stack. (scm_i_vm_reinstate_continuation): Remove. * libguile/vm.c (vm_capture_continuation): Rename from capture_vm_cont, and change the prototype so we can capture the RA and MVRA, and so that tail calls to call/cc can capture a continuation without the call/cc application frame. (vm_return_to_continuation): Rename from reinstate_vm_cont, and take arguments to return to the continuation. Handles returning to single or multiple-value RA. (scm_i_vm_capture_continuation): Change to invoke vm_capture_continuation. Kept around for the benefit of make-stack. * libguile/vm-i-system.c (continuation-call): Handle reinstatement of the VM stack, with arguments. (call/cc, tail-call/cc): Adapt to new vm_capture_continuation prototype. tail-call/cc captures tail continuations. * libguile/stacks.c (scm_make_stack): Update for scm_vm_cont structure change. * libguile/continuations.h (struct scm_contregs): Remove throw_value member, which was used to return a value to a continuation. (scm_i_check_continuation): New internal function, checks that a continuation may be reinstated. (scm_i_reinstate_continuation): Replaces scm_i_continuation_call; just reinstates the C stack. (scm_i_contregs_vm, scm_i_contregs_vm_cont): New internal accessors. * libguile/continuations.c (scm_i_make_continuation): Return SCM_UNDEFINED if we are returning again. (grow_stack, copy_stack_and_call, scm_dynthrow): Remove extra arg, as vm opcodes handle value returns. (copy_stack): No need to instate VM continuation. (scm_i_reinstate_continuation): Adapt.
2010-02-08 22:59:25 +01:00
cont = scm_i_make_continuation (&first, vm, vm_cont);
if (first)
{
PUSH (0); /* dynamic link */
PUSH (0); /* mvra */
PUSH (0); /* ra */
PUSH (proc);
PUSH (cont);
nargs = 1;
goto vm_call;
}
continuations return multiple values on the stack * libguile/vm.h (struct scm_vm_cont): Instead of saving the "IP", save "RA" and "MVRA". That is, save singly-valued and multiply-valued return addresses, so that we can return multiple values on the stack. (scm_i_vm_reinstate_continuation): Remove. * libguile/vm.c (vm_capture_continuation): Rename from capture_vm_cont, and change the prototype so we can capture the RA and MVRA, and so that tail calls to call/cc can capture a continuation without the call/cc application frame. (vm_return_to_continuation): Rename from reinstate_vm_cont, and take arguments to return to the continuation. Handles returning to single or multiple-value RA. (scm_i_vm_capture_continuation): Change to invoke vm_capture_continuation. Kept around for the benefit of make-stack. * libguile/vm-i-system.c (continuation-call): Handle reinstatement of the VM stack, with arguments. (call/cc, tail-call/cc): Adapt to new vm_capture_continuation prototype. tail-call/cc captures tail continuations. * libguile/stacks.c (scm_make_stack): Update for scm_vm_cont structure change. * libguile/continuations.h (struct scm_contregs): Remove throw_value member, which was used to return a value to a continuation. (scm_i_check_continuation): New internal function, checks that a continuation may be reinstated. (scm_i_reinstate_continuation): Replaces scm_i_continuation_call; just reinstates the C stack. (scm_i_contregs_vm, scm_i_contregs_vm_cont): New internal accessors. * libguile/continuations.c (scm_i_make_continuation): Return SCM_UNDEFINED if we are returning again. (grow_stack, copy_stack_and_call, scm_dynthrow): Remove extra arg, as vm opcodes handle value returns. (copy_stack): No need to instate VM continuation. (scm_i_reinstate_continuation): Adapt.
2010-02-08 22:59:25 +01:00
else
{
/* Otherwise, the vm continuation was reinstated, and
vm_return_to_continuation pushed on one value. We know only one
value was returned because we are in value context -- the
previous block jumped to vm_call, not vm_mv_call, after all.
So, pull our regs back down from the vp, and march on to the
next instruction. */
continuations return multiple values on the stack * libguile/vm.h (struct scm_vm_cont): Instead of saving the "IP", save "RA" and "MVRA". That is, save singly-valued and multiply-valued return addresses, so that we can return multiple values on the stack. (scm_i_vm_reinstate_continuation): Remove. * libguile/vm.c (vm_capture_continuation): Rename from capture_vm_cont, and change the prototype so we can capture the RA and MVRA, and so that tail calls to call/cc can capture a continuation without the call/cc application frame. (vm_return_to_continuation): Rename from reinstate_vm_cont, and take arguments to return to the continuation. Handles returning to single or multiple-value RA. (scm_i_vm_capture_continuation): Change to invoke vm_capture_continuation. Kept around for the benefit of make-stack. * libguile/vm-i-system.c (continuation-call): Handle reinstatement of the VM stack, with arguments. (call/cc, tail-call/cc): Adapt to new vm_capture_continuation prototype. tail-call/cc captures tail continuations. * libguile/stacks.c (scm_make_stack): Update for scm_vm_cont structure change. * libguile/continuations.h (struct scm_contregs): Remove throw_value member, which was used to return a value to a continuation. (scm_i_check_continuation): New internal function, checks that a continuation may be reinstated. (scm_i_reinstate_continuation): Replaces scm_i_continuation_call; just reinstates the C stack. (scm_i_contregs_vm, scm_i_contregs_vm_cont): New internal accessors. * libguile/continuations.c (scm_i_make_continuation): Return SCM_UNDEFINED if we are returning again. (grow_stack, copy_stack_and_call, scm_dynthrow): Remove extra arg, as vm opcodes handle value returns. (copy_stack): No need to instate VM continuation. (scm_i_reinstate_continuation): Adapt.
2010-02-08 22:59:25 +01:00
CACHE_REGISTER ();
program = SCM_FRAME_PROGRAM (fp);
CACHE_PROGRAM ();
RESTORE_CONTINUATION_HOOK ();
NEXT;
}
2000-08-22 15:54:19 +00:00
}
VM_DEFINE_INSTRUCTION (66, tail_call_cc, "tail-call/cc", 0, 1, 1)
{
int first;
continuations return multiple values on the stack * libguile/vm.h (struct scm_vm_cont): Instead of saving the "IP", save "RA" and "MVRA". That is, save singly-valued and multiply-valued return addresses, so that we can return multiple values on the stack. (scm_i_vm_reinstate_continuation): Remove. * libguile/vm.c (vm_capture_continuation): Rename from capture_vm_cont, and change the prototype so we can capture the RA and MVRA, and so that tail calls to call/cc can capture a continuation without the call/cc application frame. (vm_return_to_continuation): Rename from reinstate_vm_cont, and take arguments to return to the continuation. Handles returning to single or multiple-value RA. (scm_i_vm_capture_continuation): Change to invoke vm_capture_continuation. Kept around for the benefit of make-stack. * libguile/vm-i-system.c (continuation-call): Handle reinstatement of the VM stack, with arguments. (call/cc, tail-call/cc): Adapt to new vm_capture_continuation prototype. tail-call/cc captures tail continuations. * libguile/stacks.c (scm_make_stack): Update for scm_vm_cont structure change. * libguile/continuations.h (struct scm_contregs): Remove throw_value member, which was used to return a value to a continuation. (scm_i_check_continuation): New internal function, checks that a continuation may be reinstated. (scm_i_reinstate_continuation): Replaces scm_i_continuation_call; just reinstates the C stack. (scm_i_contregs_vm, scm_i_contregs_vm_cont): New internal accessors. * libguile/continuations.c (scm_i_make_continuation): Return SCM_UNDEFINED if we are returning again. (grow_stack, copy_stack_and_call, scm_dynthrow): Remove extra arg, as vm opcodes handle value returns. (copy_stack): No need to instate VM continuation. (scm_i_reinstate_continuation): Adapt.
2010-02-08 22:59:25 +01:00
SCM proc, vm_cont, cont;
POP (proc);
SYNC_ALL ();
continuations return multiple values on the stack * libguile/vm.h (struct scm_vm_cont): Instead of saving the "IP", save "RA" and "MVRA". That is, save singly-valued and multiply-valued return addresses, so that we can return multiple values on the stack. (scm_i_vm_reinstate_continuation): Remove. * libguile/vm.c (vm_capture_continuation): Rename from capture_vm_cont, and change the prototype so we can capture the RA and MVRA, and so that tail calls to call/cc can capture a continuation without the call/cc application frame. (vm_return_to_continuation): Rename from reinstate_vm_cont, and take arguments to return to the continuation. Handles returning to single or multiple-value RA. (scm_i_vm_capture_continuation): Change to invoke vm_capture_continuation. Kept around for the benefit of make-stack. * libguile/vm-i-system.c (continuation-call): Handle reinstatement of the VM stack, with arguments. (call/cc, tail-call/cc): Adapt to new vm_capture_continuation prototype. tail-call/cc captures tail continuations. * libguile/stacks.c (scm_make_stack): Update for scm_vm_cont structure change. * libguile/continuations.h (struct scm_contregs): Remove throw_value member, which was used to return a value to a continuation. (scm_i_check_continuation): New internal function, checks that a continuation may be reinstated. (scm_i_reinstate_continuation): Replaces scm_i_continuation_call; just reinstates the C stack. (scm_i_contregs_vm, scm_i_contregs_vm_cont): New internal accessors. * libguile/continuations.c (scm_i_make_continuation): Return SCM_UNDEFINED if we are returning again. (grow_stack, copy_stack_and_call, scm_dynthrow): Remove extra arg, as vm opcodes handle value returns. (copy_stack): No need to instate VM continuation. (scm_i_reinstate_continuation): Adapt.
2010-02-08 22:59:25 +01:00
/* In contrast to call/cc, tail-call/cc captures the continuation without the
stack frame. */
vm_cont = scm_i_vm_capture_stack (vp->stack_base,
SCM_FRAME_DYNAMIC_LINK (fp),
SCM_FRAME_LOWER_ADDRESS (fp) - 1,
SCM_FRAME_RETURN_ADDRESS (fp),
SCM_FRAME_MV_RETURN_ADDRESS (fp),
0);
continuations return multiple values on the stack * libguile/vm.h (struct scm_vm_cont): Instead of saving the "IP", save "RA" and "MVRA". That is, save singly-valued and multiply-valued return addresses, so that we can return multiple values on the stack. (scm_i_vm_reinstate_continuation): Remove. * libguile/vm.c (vm_capture_continuation): Rename from capture_vm_cont, and change the prototype so we can capture the RA and MVRA, and so that tail calls to call/cc can capture a continuation without the call/cc application frame. (vm_return_to_continuation): Rename from reinstate_vm_cont, and take arguments to return to the continuation. Handles returning to single or multiple-value RA. (scm_i_vm_capture_continuation): Change to invoke vm_capture_continuation. Kept around for the benefit of make-stack. * libguile/vm-i-system.c (continuation-call): Handle reinstatement of the VM stack, with arguments. (call/cc, tail-call/cc): Adapt to new vm_capture_continuation prototype. tail-call/cc captures tail continuations. * libguile/stacks.c (scm_make_stack): Update for scm_vm_cont structure change. * libguile/continuations.h (struct scm_contregs): Remove throw_value member, which was used to return a value to a continuation. (scm_i_check_continuation): New internal function, checks that a continuation may be reinstated. (scm_i_reinstate_continuation): Replaces scm_i_continuation_call; just reinstates the C stack. (scm_i_contregs_vm, scm_i_contregs_vm_cont): New internal accessors. * libguile/continuations.c (scm_i_make_continuation): Return SCM_UNDEFINED if we are returning again. (grow_stack, copy_stack_and_call, scm_dynthrow): Remove extra arg, as vm opcodes handle value returns. (copy_stack): No need to instate VM continuation. (scm_i_reinstate_continuation): Adapt.
2010-02-08 22:59:25 +01:00
cont = scm_i_make_continuation (&first, vm, vm_cont);
if (first)
{
PUSH (proc);
PUSH (cont);
nargs = 1;
goto vm_tail_call;
}
else
{
continuations return multiple values on the stack * libguile/vm.h (struct scm_vm_cont): Instead of saving the "IP", save "RA" and "MVRA". That is, save singly-valued and multiply-valued return addresses, so that we can return multiple values on the stack. (scm_i_vm_reinstate_continuation): Remove. * libguile/vm.c (vm_capture_continuation): Rename from capture_vm_cont, and change the prototype so we can capture the RA and MVRA, and so that tail calls to call/cc can capture a continuation without the call/cc application frame. (vm_return_to_continuation): Rename from reinstate_vm_cont, and take arguments to return to the continuation. Handles returning to single or multiple-value RA. (scm_i_vm_capture_continuation): Change to invoke vm_capture_continuation. Kept around for the benefit of make-stack. * libguile/vm-i-system.c (continuation-call): Handle reinstatement of the VM stack, with arguments. (call/cc, tail-call/cc): Adapt to new vm_capture_continuation prototype. tail-call/cc captures tail continuations. * libguile/stacks.c (scm_make_stack): Update for scm_vm_cont structure change. * libguile/continuations.h (struct scm_contregs): Remove throw_value member, which was used to return a value to a continuation. (scm_i_check_continuation): New internal function, checks that a continuation may be reinstated. (scm_i_reinstate_continuation): Replaces scm_i_continuation_call; just reinstates the C stack. (scm_i_contregs_vm, scm_i_contregs_vm_cont): New internal accessors. * libguile/continuations.c (scm_i_make_continuation): Return SCM_UNDEFINED if we are returning again. (grow_stack, copy_stack_and_call, scm_dynthrow): Remove extra arg, as vm opcodes handle value returns. (copy_stack): No need to instate VM continuation. (scm_i_reinstate_continuation): Adapt.
2010-02-08 22:59:25 +01:00
/* Otherwise, cache regs and NEXT, as above. Invoking the continuation
does a return from the frame, either to the RA or
MVRA. */
continuations return multiple values on the stack * libguile/vm.h (struct scm_vm_cont): Instead of saving the "IP", save "RA" and "MVRA". That is, save singly-valued and multiply-valued return addresses, so that we can return multiple values on the stack. (scm_i_vm_reinstate_continuation): Remove. * libguile/vm.c (vm_capture_continuation): Rename from capture_vm_cont, and change the prototype so we can capture the RA and MVRA, and so that tail calls to call/cc can capture a continuation without the call/cc application frame. (vm_return_to_continuation): Rename from reinstate_vm_cont, and take arguments to return to the continuation. Handles returning to single or multiple-value RA. (scm_i_vm_capture_continuation): Change to invoke vm_capture_continuation. Kept around for the benefit of make-stack. * libguile/vm-i-system.c (continuation-call): Handle reinstatement of the VM stack, with arguments. (call/cc, tail-call/cc): Adapt to new vm_capture_continuation prototype. tail-call/cc captures tail continuations. * libguile/stacks.c (scm_make_stack): Update for scm_vm_cont structure change. * libguile/continuations.h (struct scm_contregs): Remove throw_value member, which was used to return a value to a continuation. (scm_i_check_continuation): New internal function, checks that a continuation may be reinstated. (scm_i_reinstate_continuation): Replaces scm_i_continuation_call; just reinstates the C stack. (scm_i_contregs_vm, scm_i_contregs_vm_cont): New internal accessors. * libguile/continuations.c (scm_i_make_continuation): Return SCM_UNDEFINED if we are returning again. (grow_stack, copy_stack_and_call, scm_dynthrow): Remove extra arg, as vm opcodes handle value returns. (copy_stack): No need to instate VM continuation. (scm_i_reinstate_continuation): Adapt.
2010-02-08 22:59:25 +01:00
CACHE_REGISTER ();
program = SCM_FRAME_PROGRAM (fp);
CACHE_PROGRAM ();
/* Unfortunately we don't know whether we are at the RA, and thus
have one value without an nvalues marker, or we are at the
MVRA and thus have multiple values and the nvalues
marker. Instead of adding heuristics here, we will let hook
client code do that. */
RESTORE_CONTINUATION_HOOK ();
continuations return multiple values on the stack * libguile/vm.h (struct scm_vm_cont): Instead of saving the "IP", save "RA" and "MVRA". That is, save singly-valued and multiply-valued return addresses, so that we can return multiple values on the stack. (scm_i_vm_reinstate_continuation): Remove. * libguile/vm.c (vm_capture_continuation): Rename from capture_vm_cont, and change the prototype so we can capture the RA and MVRA, and so that tail calls to call/cc can capture a continuation without the call/cc application frame. (vm_return_to_continuation): Rename from reinstate_vm_cont, and take arguments to return to the continuation. Handles returning to single or multiple-value RA. (scm_i_vm_capture_continuation): Change to invoke vm_capture_continuation. Kept around for the benefit of make-stack. * libguile/vm-i-system.c (continuation-call): Handle reinstatement of the VM stack, with arguments. (call/cc, tail-call/cc): Adapt to new vm_capture_continuation prototype. tail-call/cc captures tail continuations. * libguile/stacks.c (scm_make_stack): Update for scm_vm_cont structure change. * libguile/continuations.h (struct scm_contregs): Remove throw_value member, which was used to return a value to a continuation. (scm_i_check_continuation): New internal function, checks that a continuation may be reinstated. (scm_i_reinstate_continuation): Replaces scm_i_continuation_call; just reinstates the C stack. (scm_i_contregs_vm, scm_i_contregs_vm_cont): New internal accessors. * libguile/continuations.c (scm_i_make_continuation): Return SCM_UNDEFINED if we are returning again. (grow_stack, copy_stack_and_call, scm_dynthrow): Remove extra arg, as vm opcodes handle value returns. (copy_stack): No need to instate VM continuation. (scm_i_reinstate_continuation): Adapt.
2010-02-08 22:59:25 +01:00
NEXT;
}
}
VM_DEFINE_INSTRUCTION (67, return, "return", 0, 1, 1)
2000-08-22 15:54:19 +00:00
{
vm_return:
POP_CONTINUATION_HOOK (1);
VM_HANDLE_INTERRUPTS;
{
SCM ret;
POP (ret);
runtime and debugging support for callee-parsed procedure args * libguile/objcodes.h: Bump for metadata format change. * libguile/frames.h: Rework so we don't frob the program's nargs, nlocs, etc at runtime. Instead we don't really know what's a local var, an argument, or an intermediate value. It's a little unfortunate, but this will allow for case-lambda, and eventually for good polymorphic generic dispatch; and the nlocs etc can be heuristically reconstructed. Such a reconstruction would be better done at the Scheme level, though. (SCM_FRAME_STACK_ADDRESS): New macro, the pointer to the base of the stack elements (not counting the program). (SCM_FRAME_UPPER_ADDRESS): Repurpose to be the address of the last element in the bookkeeping part of the stack -- i.e. to point to the return address. * libguile/vm-engine.h: * libguile/vm-i-system.c: Adapt to removal of stack_base. Though we still detect stack-smashing underflow, we don't do so as precisely as we did before, because now we only detect overwriting of the frame metadata. * libguile/vm-engine.c (vm_engine): Remove the stack_base variable. It is unnecessary, and difficult to keep track of in the face of case-lambda. Also fix miscommented "ra" and "mvra" pushes. Push the vp->ip as the first ra... * libguile/vm-i-system.c (halt): ...because here we can restore the vp->ip instead of setting ip to 0. Allows us to introspect ips all down the stack, including in recursive VM invocations. * libguile/frames.h: * libguile/frames.c (scm_vm_frame_stack): Removed, because it's getting more difficult to tell what's an argument and what's a temporary stack element. (scm_vm_frame_num_locals): New accessor. (scm_vm_frame_instruction_pointer): New accessor. (scm_vm_frame_arguments): Defer to an implementation in Scheme. (scm_vm_frame_num_locals scm_vm_frame_local_ref) (scm_vm_frame_local_set_x): Since we can get not-yet-active frames on the stack now, with our current calling convention, we have to add a heuristic here to jump over those frames -- because frames have pointers in them, not Scheme values. * libguile/programs.h: * libguile/programs.c (scm_program_arity): Remove, in favor of.. (scm_program_arities): ...this, which a list of arities, in a new format, occupying a slot in the metadata. * module/language/assembly/decompile-bytecode.scm (decode-load-program): Fix mv-call decompilation. * module/system/vm/frame.scm (vm-frame-bindings, vm-frame-binding-ref) (vm-frame-binding-set!): New functions, to access bindings by name in a frame. (vm-frame-arguments): Function now implemented in Scheme. Commented fairly extensively. * module/system/vm/program.scm (program-bindings-by-index) (program-bindings-for-ip): New accessors, parsing the program bindings metadata into something more useful. (program-arities, program-arguments): In a case-lambda world, we have to assume that programs can have multiple arities. But it's tough to detect this algorithmically; instead we're going to require that the program metadata include information about the arities, and the parts of the program that that metadata applies to. (program-lambda-list): New accessor. (write-program): Show multiple arities. * module/language/glil/compile-assembly.scm (glil->assembly): Add "arities" to the state of the compiler, and add arities entries as appropriate.
2009-09-27 19:25:58 -04:00
#ifdef VM_ENABLE_STACK_NULLING
SCM *old_sp = sp;
#endif
/* Restore registers */
sp = SCM_FRAME_LOWER_ADDRESS (fp);
ip = SCM_FRAME_RETURN_ADDRESS (fp);
fp = SCM_FRAME_DYNAMIC_LINK (fp);
runtime and debugging support for callee-parsed procedure args * libguile/objcodes.h: Bump for metadata format change. * libguile/frames.h: Rework so we don't frob the program's nargs, nlocs, etc at runtime. Instead we don't really know what's a local var, an argument, or an intermediate value. It's a little unfortunate, but this will allow for case-lambda, and eventually for good polymorphic generic dispatch; and the nlocs etc can be heuristically reconstructed. Such a reconstruction would be better done at the Scheme level, though. (SCM_FRAME_STACK_ADDRESS): New macro, the pointer to the base of the stack elements (not counting the program). (SCM_FRAME_UPPER_ADDRESS): Repurpose to be the address of the last element in the bookkeeping part of the stack -- i.e. to point to the return address. * libguile/vm-engine.h: * libguile/vm-i-system.c: Adapt to removal of stack_base. Though we still detect stack-smashing underflow, we don't do so as precisely as we did before, because now we only detect overwriting of the frame metadata. * libguile/vm-engine.c (vm_engine): Remove the stack_base variable. It is unnecessary, and difficult to keep track of in the face of case-lambda. Also fix miscommented "ra" and "mvra" pushes. Push the vp->ip as the first ra... * libguile/vm-i-system.c (halt): ...because here we can restore the vp->ip instead of setting ip to 0. Allows us to introspect ips all down the stack, including in recursive VM invocations. * libguile/frames.h: * libguile/frames.c (scm_vm_frame_stack): Removed, because it's getting more difficult to tell what's an argument and what's a temporary stack element. (scm_vm_frame_num_locals): New accessor. (scm_vm_frame_instruction_pointer): New accessor. (scm_vm_frame_arguments): Defer to an implementation in Scheme. (scm_vm_frame_num_locals scm_vm_frame_local_ref) (scm_vm_frame_local_set_x): Since we can get not-yet-active frames on the stack now, with our current calling convention, we have to add a heuristic here to jump over those frames -- because frames have pointers in them, not Scheme values. * libguile/programs.h: * libguile/programs.c (scm_program_arity): Remove, in favor of.. (scm_program_arities): ...this, which a list of arities, in a new format, occupying a slot in the metadata. * module/language/assembly/decompile-bytecode.scm (decode-load-program): Fix mv-call decompilation. * module/system/vm/frame.scm (vm-frame-bindings, vm-frame-binding-ref) (vm-frame-binding-set!): New functions, to access bindings by name in a frame. (vm-frame-arguments): Function now implemented in Scheme. Commented fairly extensively. * module/system/vm/program.scm (program-bindings-by-index) (program-bindings-for-ip): New accessors, parsing the program bindings metadata into something more useful. (program-arities, program-arguments): In a case-lambda world, we have to assume that programs can have multiple arities. But it's tough to detect this algorithmically; instead we're going to require that the program metadata include information about the arities, and the parts of the program that that metadata applies to. (program-lambda-list): New accessor. (write-program): Show multiple arities. * module/language/glil/compile-assembly.scm (glil->assembly): Add "arities" to the state of the compiler, and add arities entries as appropriate.
2009-09-27 19:25:58 -04:00
precise stack marking, fix some missed references, still imperfect * libguile/vm-engine.h (CHECK_STACK_LEAK, NULLSTACK): Add a new mode, VM_ENABLE_STACK_NULLING, that tries to ensure that all stack data past the top of the stack is NULL. This helps to verify the VM's consistency. If VM_ENABLE_STACK_NULLING is not defined, there is no overhead. (DROP, DROPN): Hook into NULLSTACK. (POP_LIST): Hoo, fix a good bug: if CONS triggered a GC, the elements of the list that had not yet been consed would not be marked, because the sp was already below them. (NEXT): Hook into CHECK_STACK_LEAK. (INIT_ARGS): Add a note that consing the rest arg can cause GC. (NEW_FRAME): Cons up the external data after initializing the frame, so that if GC is triggered, the precise marker sees a well-formed frame. * libguile/vm-i-loader.c (load-program): In the four-integers case, use the POP macro so that we can hook into NULLSTACK (if necessary). * libguile/vm-i-scheme.c (ARGS2, ARGS3): Hook into NULLSTACK. * libguile/vm-i-system.c (halt): Null the nvalues. Rework some asserts into using ASSERT, and null the stack when we free the frame. (variable-set): Use DROPN instead of sp -= 2. (BR): Hook into NULLSTACK. (goto/args): Hook into NULLSTACK. In the non-self case, delay updating the frame until after INIT_ARGS so that GC sees a well-formed frame. Delay consing the externals until after the frame is set up, as in NEW_FRAME. (call/cc): Add some asserts. (return): Rework some asserts into ASSERT, and hook into NULLSTACK. (return/values): Hook into NULLSTACK, and use ASSERT. (return/values*) Use ASSERT. * libguile/vm.c (VM_ENABLE_ASSERTIONS, VM_ENABLE_STACK_NULLING): These are the variables that control assertions and nulling. Perhaps we can do these per-engine when we start compiling the debug engine separate from a speedy engine. (vm_mark_stack): Add a precise stack marker. Yay! (vm_cont_mark): Mark the continuation stack precisely. (capture_vm_cont): Record the difference from the vp's stack_base too, so that we can translate the dynamic links when marking the continuation stack. Memset the stack to NULL if we are doing nulling. (reinstate_vm_cont): If we are nulling, null out the relevant part of the stack. (vm_reset_stack): When resetting sp due to a nonlocal exit, null out the stack too. (vm_mark): If we are nulling, assert that there are no extra values on the stack. Mark the stack precisely.
2008-10-03 16:00:30 +02:00
#ifdef VM_ENABLE_STACK_NULLING
runtime and debugging support for callee-parsed procedure args * libguile/objcodes.h: Bump for metadata format change. * libguile/frames.h: Rework so we don't frob the program's nargs, nlocs, etc at runtime. Instead we don't really know what's a local var, an argument, or an intermediate value. It's a little unfortunate, but this will allow for case-lambda, and eventually for good polymorphic generic dispatch; and the nlocs etc can be heuristically reconstructed. Such a reconstruction would be better done at the Scheme level, though. (SCM_FRAME_STACK_ADDRESS): New macro, the pointer to the base of the stack elements (not counting the program). (SCM_FRAME_UPPER_ADDRESS): Repurpose to be the address of the last element in the bookkeeping part of the stack -- i.e. to point to the return address. * libguile/vm-engine.h: * libguile/vm-i-system.c: Adapt to removal of stack_base. Though we still detect stack-smashing underflow, we don't do so as precisely as we did before, because now we only detect overwriting of the frame metadata. * libguile/vm-engine.c (vm_engine): Remove the stack_base variable. It is unnecessary, and difficult to keep track of in the face of case-lambda. Also fix miscommented "ra" and "mvra" pushes. Push the vp->ip as the first ra... * libguile/vm-i-system.c (halt): ...because here we can restore the vp->ip instead of setting ip to 0. Allows us to introspect ips all down the stack, including in recursive VM invocations. * libguile/frames.h: * libguile/frames.c (scm_vm_frame_stack): Removed, because it's getting more difficult to tell what's an argument and what's a temporary stack element. (scm_vm_frame_num_locals): New accessor. (scm_vm_frame_instruction_pointer): New accessor. (scm_vm_frame_arguments): Defer to an implementation in Scheme. (scm_vm_frame_num_locals scm_vm_frame_local_ref) (scm_vm_frame_local_set_x): Since we can get not-yet-active frames on the stack now, with our current calling convention, we have to add a heuristic here to jump over those frames -- because frames have pointers in them, not Scheme values. * libguile/programs.h: * libguile/programs.c (scm_program_arity): Remove, in favor of.. (scm_program_arities): ...this, which a list of arities, in a new format, occupying a slot in the metadata. * module/language/assembly/decompile-bytecode.scm (decode-load-program): Fix mv-call decompilation. * module/system/vm/frame.scm (vm-frame-bindings, vm-frame-binding-ref) (vm-frame-binding-set!): New functions, to access bindings by name in a frame. (vm-frame-arguments): Function now implemented in Scheme. Commented fairly extensively. * module/system/vm/program.scm (program-bindings-by-index) (program-bindings-for-ip): New accessors, parsing the program bindings metadata into something more useful. (program-arities, program-arguments): In a case-lambda world, we have to assume that programs can have multiple arities. But it's tough to detect this algorithmically; instead we're going to require that the program metadata include information about the arities, and the parts of the program that that metadata applies to. (program-lambda-list): New accessor. (write-program): Show multiple arities. * module/language/glil/compile-assembly.scm (glil->assembly): Add "arities" to the state of the compiler, and add arities entries as appropriate.
2009-09-27 19:25:58 -04:00
NULLSTACK (old_sp - sp);
precise stack marking, fix some missed references, still imperfect * libguile/vm-engine.h (CHECK_STACK_LEAK, NULLSTACK): Add a new mode, VM_ENABLE_STACK_NULLING, that tries to ensure that all stack data past the top of the stack is NULL. This helps to verify the VM's consistency. If VM_ENABLE_STACK_NULLING is not defined, there is no overhead. (DROP, DROPN): Hook into NULLSTACK. (POP_LIST): Hoo, fix a good bug: if CONS triggered a GC, the elements of the list that had not yet been consed would not be marked, because the sp was already below them. (NEXT): Hook into CHECK_STACK_LEAK. (INIT_ARGS): Add a note that consing the rest arg can cause GC. (NEW_FRAME): Cons up the external data after initializing the frame, so that if GC is triggered, the precise marker sees a well-formed frame. * libguile/vm-i-loader.c (load-program): In the four-integers case, use the POP macro so that we can hook into NULLSTACK (if necessary). * libguile/vm-i-scheme.c (ARGS2, ARGS3): Hook into NULLSTACK. * libguile/vm-i-system.c (halt): Null the nvalues. Rework some asserts into using ASSERT, and null the stack when we free the frame. (variable-set): Use DROPN instead of sp -= 2. (BR): Hook into NULLSTACK. (goto/args): Hook into NULLSTACK. In the non-self case, delay updating the frame until after INIT_ARGS so that GC sees a well-formed frame. Delay consing the externals until after the frame is set up, as in NEW_FRAME. (call/cc): Add some asserts. (return): Rework some asserts into ASSERT, and hook into NULLSTACK. (return/values): Hook into NULLSTACK, and use ASSERT. (return/values*) Use ASSERT. * libguile/vm.c (VM_ENABLE_ASSERTIONS, VM_ENABLE_STACK_NULLING): These are the variables that control assertions and nulling. Perhaps we can do these per-engine when we start compiling the debug engine separate from a speedy engine. (vm_mark_stack): Add a precise stack marker. Yay! (vm_cont_mark): Mark the continuation stack precisely. (capture_vm_cont): Record the difference from the vp's stack_base too, so that we can translate the dynamic links when marking the continuation stack. Memset the stack to NULL if we are doing nulling. (reinstate_vm_cont): If we are nulling, null out the relevant part of the stack. (vm_reset_stack): When resetting sp due to a nonlocal exit, null out the stack too. (vm_mark): If we are nulling, assert that there are no extra values on the stack. Mark the stack precisely.
2008-10-03 16:00:30 +02:00
#endif
/* Set return value (sp is already pushed) */
*sp = ret;
}
2001-04-01 05:03:41 +00:00
2001-04-06 10:06:32 +00:00
/* Restore the last program */
2001-04-23 04:28:13 +00:00
program = SCM_FRAME_PROGRAM (fp);
2001-04-06 05:00:10 +00:00
CACHE_PROGRAM ();
CHECK_IP ();
2000-08-22 15:54:19 +00:00
NEXT;
}
2001-04-01 05:03:41 +00:00
VM_DEFINE_INSTRUCTION (68, return_values, "return/values", 1, -1, -1)
{
/* nvalues declared at top level, because for some reason gcc seems to think
that perhaps it might be used without declaration. Fooey to that, I say. */
nvalues = FETCH ();
vm_return_values:
POP_CONTINUATION_HOOK (nvalues);
VM_HANDLE_INTERRUPTS;
if (nvalues != 1 && SCM_FRAME_MV_RETURN_ADDRESS (fp))
{
runtime and debugging support for callee-parsed procedure args * libguile/objcodes.h: Bump for metadata format change. * libguile/frames.h: Rework so we don't frob the program's nargs, nlocs, etc at runtime. Instead we don't really know what's a local var, an argument, or an intermediate value. It's a little unfortunate, but this will allow for case-lambda, and eventually for good polymorphic generic dispatch; and the nlocs etc can be heuristically reconstructed. Such a reconstruction would be better done at the Scheme level, though. (SCM_FRAME_STACK_ADDRESS): New macro, the pointer to the base of the stack elements (not counting the program). (SCM_FRAME_UPPER_ADDRESS): Repurpose to be the address of the last element in the bookkeeping part of the stack -- i.e. to point to the return address. * libguile/vm-engine.h: * libguile/vm-i-system.c: Adapt to removal of stack_base. Though we still detect stack-smashing underflow, we don't do so as precisely as we did before, because now we only detect overwriting of the frame metadata. * libguile/vm-engine.c (vm_engine): Remove the stack_base variable. It is unnecessary, and difficult to keep track of in the face of case-lambda. Also fix miscommented "ra" and "mvra" pushes. Push the vp->ip as the first ra... * libguile/vm-i-system.c (halt): ...because here we can restore the vp->ip instead of setting ip to 0. Allows us to introspect ips all down the stack, including in recursive VM invocations. * libguile/frames.h: * libguile/frames.c (scm_vm_frame_stack): Removed, because it's getting more difficult to tell what's an argument and what's a temporary stack element. (scm_vm_frame_num_locals): New accessor. (scm_vm_frame_instruction_pointer): New accessor. (scm_vm_frame_arguments): Defer to an implementation in Scheme. (scm_vm_frame_num_locals scm_vm_frame_local_ref) (scm_vm_frame_local_set_x): Since we can get not-yet-active frames on the stack now, with our current calling convention, we have to add a heuristic here to jump over those frames -- because frames have pointers in them, not Scheme values. * libguile/programs.h: * libguile/programs.c (scm_program_arity): Remove, in favor of.. (scm_program_arities): ...this, which a list of arities, in a new format, occupying a slot in the metadata. * module/language/assembly/decompile-bytecode.scm (decode-load-program): Fix mv-call decompilation. * module/system/vm/frame.scm (vm-frame-bindings, vm-frame-binding-ref) (vm-frame-binding-set!): New functions, to access bindings by name in a frame. (vm-frame-arguments): Function now implemented in Scheme. Commented fairly extensively. * module/system/vm/program.scm (program-bindings-by-index) (program-bindings-for-ip): New accessors, parsing the program bindings metadata into something more useful. (program-arities, program-arguments): In a case-lambda world, we have to assume that programs can have multiple arities. But it's tough to detect this algorithmically; instead we're going to require that the program metadata include information about the arities, and the parts of the program that that metadata applies to. (program-lambda-list): New accessor. (write-program): Show multiple arities. * module/language/glil/compile-assembly.scm (glil->assembly): Add "arities" to the state of the compiler, and add arities entries as appropriate.
2009-09-27 19:25:58 -04:00
/* A multiply-valued continuation */
SCM *vals = sp - nvalues;
int i;
/* Restore registers */
sp = SCM_FRAME_LOWER_ADDRESS (fp) - 1;
ip = SCM_FRAME_MV_RETURN_ADDRESS (fp);
fp = SCM_FRAME_DYNAMIC_LINK (fp);
/* Push return values, and the number of values */
for (i = 0; i < nvalues; i++)
runtime and debugging support for callee-parsed procedure args * libguile/objcodes.h: Bump for metadata format change. * libguile/frames.h: Rework so we don't frob the program's nargs, nlocs, etc at runtime. Instead we don't really know what's a local var, an argument, or an intermediate value. It's a little unfortunate, but this will allow for case-lambda, and eventually for good polymorphic generic dispatch; and the nlocs etc can be heuristically reconstructed. Such a reconstruction would be better done at the Scheme level, though. (SCM_FRAME_STACK_ADDRESS): New macro, the pointer to the base of the stack elements (not counting the program). (SCM_FRAME_UPPER_ADDRESS): Repurpose to be the address of the last element in the bookkeeping part of the stack -- i.e. to point to the return address. * libguile/vm-engine.h: * libguile/vm-i-system.c: Adapt to removal of stack_base. Though we still detect stack-smashing underflow, we don't do so as precisely as we did before, because now we only detect overwriting of the frame metadata. * libguile/vm-engine.c (vm_engine): Remove the stack_base variable. It is unnecessary, and difficult to keep track of in the face of case-lambda. Also fix miscommented "ra" and "mvra" pushes. Push the vp->ip as the first ra... * libguile/vm-i-system.c (halt): ...because here we can restore the vp->ip instead of setting ip to 0. Allows us to introspect ips all down the stack, including in recursive VM invocations. * libguile/frames.h: * libguile/frames.c (scm_vm_frame_stack): Removed, because it's getting more difficult to tell what's an argument and what's a temporary stack element. (scm_vm_frame_num_locals): New accessor. (scm_vm_frame_instruction_pointer): New accessor. (scm_vm_frame_arguments): Defer to an implementation in Scheme. (scm_vm_frame_num_locals scm_vm_frame_local_ref) (scm_vm_frame_local_set_x): Since we can get not-yet-active frames on the stack now, with our current calling convention, we have to add a heuristic here to jump over those frames -- because frames have pointers in them, not Scheme values. * libguile/programs.h: * libguile/programs.c (scm_program_arity): Remove, in favor of.. (scm_program_arities): ...this, which a list of arities, in a new format, occupying a slot in the metadata. * module/language/assembly/decompile-bytecode.scm (decode-load-program): Fix mv-call decompilation. * module/system/vm/frame.scm (vm-frame-bindings, vm-frame-binding-ref) (vm-frame-binding-set!): New functions, to access bindings by name in a frame. (vm-frame-arguments): Function now implemented in Scheme. Commented fairly extensively. * module/system/vm/program.scm (program-bindings-by-index) (program-bindings-for-ip): New accessors, parsing the program bindings metadata into something more useful. (program-arities, program-arguments): In a case-lambda world, we have to assume that programs can have multiple arities. But it's tough to detect this algorithmically; instead we're going to require that the program metadata include information about the arities, and the parts of the program that that metadata applies to. (program-lambda-list): New accessor. (write-program): Show multiple arities. * module/language/glil/compile-assembly.scm (glil->assembly): Add "arities" to the state of the compiler, and add arities entries as appropriate.
2009-09-27 19:25:58 -04:00
*++sp = vals[i+1];
*++sp = SCM_I_MAKINUM (nvalues);
runtime and debugging support for callee-parsed procedure args * libguile/objcodes.h: Bump for metadata format change. * libguile/frames.h: Rework so we don't frob the program's nargs, nlocs, etc at runtime. Instead we don't really know what's a local var, an argument, or an intermediate value. It's a little unfortunate, but this will allow for case-lambda, and eventually for good polymorphic generic dispatch; and the nlocs etc can be heuristically reconstructed. Such a reconstruction would be better done at the Scheme level, though. (SCM_FRAME_STACK_ADDRESS): New macro, the pointer to the base of the stack elements (not counting the program). (SCM_FRAME_UPPER_ADDRESS): Repurpose to be the address of the last element in the bookkeeping part of the stack -- i.e. to point to the return address. * libguile/vm-engine.h: * libguile/vm-i-system.c: Adapt to removal of stack_base. Though we still detect stack-smashing underflow, we don't do so as precisely as we did before, because now we only detect overwriting of the frame metadata. * libguile/vm-engine.c (vm_engine): Remove the stack_base variable. It is unnecessary, and difficult to keep track of in the face of case-lambda. Also fix miscommented "ra" and "mvra" pushes. Push the vp->ip as the first ra... * libguile/vm-i-system.c (halt): ...because here we can restore the vp->ip instead of setting ip to 0. Allows us to introspect ips all down the stack, including in recursive VM invocations. * libguile/frames.h: * libguile/frames.c (scm_vm_frame_stack): Removed, because it's getting more difficult to tell what's an argument and what's a temporary stack element. (scm_vm_frame_num_locals): New accessor. (scm_vm_frame_instruction_pointer): New accessor. (scm_vm_frame_arguments): Defer to an implementation in Scheme. (scm_vm_frame_num_locals scm_vm_frame_local_ref) (scm_vm_frame_local_set_x): Since we can get not-yet-active frames on the stack now, with our current calling convention, we have to add a heuristic here to jump over those frames -- because frames have pointers in them, not Scheme values. * libguile/programs.h: * libguile/programs.c (scm_program_arity): Remove, in favor of.. (scm_program_arities): ...this, which a list of arities, in a new format, occupying a slot in the metadata. * module/language/assembly/decompile-bytecode.scm (decode-load-program): Fix mv-call decompilation. * module/system/vm/frame.scm (vm-frame-bindings, vm-frame-binding-ref) (vm-frame-binding-set!): New functions, to access bindings by name in a frame. (vm-frame-arguments): Function now implemented in Scheme. Commented fairly extensively. * module/system/vm/program.scm (program-bindings-by-index) (program-bindings-for-ip): New accessors, parsing the program bindings metadata into something more useful. (program-arities, program-arguments): In a case-lambda world, we have to assume that programs can have multiple arities. But it's tough to detect this algorithmically; instead we're going to require that the program metadata include information about the arities, and the parts of the program that that metadata applies to. (program-lambda-list): New accessor. (write-program): Show multiple arities. * module/language/glil/compile-assembly.scm (glil->assembly): Add "arities" to the state of the compiler, and add arities entries as appropriate.
2009-09-27 19:25:58 -04:00
/* Finally null the end of the stack */
NULLSTACK (vals + nvalues - sp);
}
else if (nvalues >= 1)
{
/* Multiple values for a single-valued continuation -- here's where I
break with guile tradition and try and do something sensible. (Also,
this block handles the single-valued return to an mv
continuation.) */
runtime and debugging support for callee-parsed procedure args * libguile/objcodes.h: Bump for metadata format change. * libguile/frames.h: Rework so we don't frob the program's nargs, nlocs, etc at runtime. Instead we don't really know what's a local var, an argument, or an intermediate value. It's a little unfortunate, but this will allow for case-lambda, and eventually for good polymorphic generic dispatch; and the nlocs etc can be heuristically reconstructed. Such a reconstruction would be better done at the Scheme level, though. (SCM_FRAME_STACK_ADDRESS): New macro, the pointer to the base of the stack elements (not counting the program). (SCM_FRAME_UPPER_ADDRESS): Repurpose to be the address of the last element in the bookkeeping part of the stack -- i.e. to point to the return address. * libguile/vm-engine.h: * libguile/vm-i-system.c: Adapt to removal of stack_base. Though we still detect stack-smashing underflow, we don't do so as precisely as we did before, because now we only detect overwriting of the frame metadata. * libguile/vm-engine.c (vm_engine): Remove the stack_base variable. It is unnecessary, and difficult to keep track of in the face of case-lambda. Also fix miscommented "ra" and "mvra" pushes. Push the vp->ip as the first ra... * libguile/vm-i-system.c (halt): ...because here we can restore the vp->ip instead of setting ip to 0. Allows us to introspect ips all down the stack, including in recursive VM invocations. * libguile/frames.h: * libguile/frames.c (scm_vm_frame_stack): Removed, because it's getting more difficult to tell what's an argument and what's a temporary stack element. (scm_vm_frame_num_locals): New accessor. (scm_vm_frame_instruction_pointer): New accessor. (scm_vm_frame_arguments): Defer to an implementation in Scheme. (scm_vm_frame_num_locals scm_vm_frame_local_ref) (scm_vm_frame_local_set_x): Since we can get not-yet-active frames on the stack now, with our current calling convention, we have to add a heuristic here to jump over those frames -- because frames have pointers in them, not Scheme values. * libguile/programs.h: * libguile/programs.c (scm_program_arity): Remove, in favor of.. (scm_program_arities): ...this, which a list of arities, in a new format, occupying a slot in the metadata. * module/language/assembly/decompile-bytecode.scm (decode-load-program): Fix mv-call decompilation. * module/system/vm/frame.scm (vm-frame-bindings, vm-frame-binding-ref) (vm-frame-binding-set!): New functions, to access bindings by name in a frame. (vm-frame-arguments): Function now implemented in Scheme. Commented fairly extensively. * module/system/vm/program.scm (program-bindings-by-index) (program-bindings-for-ip): New accessors, parsing the program bindings metadata into something more useful. (program-arities, program-arguments): In a case-lambda world, we have to assume that programs can have multiple arities. But it's tough to detect this algorithmically; instead we're going to require that the program metadata include information about the arities, and the parts of the program that that metadata applies to. (program-lambda-list): New accessor. (write-program): Show multiple arities. * module/language/glil/compile-assembly.scm (glil->assembly): Add "arities" to the state of the compiler, and add arities entries as appropriate.
2009-09-27 19:25:58 -04:00
SCM *vals = sp - nvalues;
/* Restore registers */
sp = SCM_FRAME_LOWER_ADDRESS (fp) - 1;
ip = SCM_FRAME_RETURN_ADDRESS (fp);
fp = SCM_FRAME_DYNAMIC_LINK (fp);
/* Push first value */
runtime and debugging support for callee-parsed procedure args * libguile/objcodes.h: Bump for metadata format change. * libguile/frames.h: Rework so we don't frob the program's nargs, nlocs, etc at runtime. Instead we don't really know what's a local var, an argument, or an intermediate value. It's a little unfortunate, but this will allow for case-lambda, and eventually for good polymorphic generic dispatch; and the nlocs etc can be heuristically reconstructed. Such a reconstruction would be better done at the Scheme level, though. (SCM_FRAME_STACK_ADDRESS): New macro, the pointer to the base of the stack elements (not counting the program). (SCM_FRAME_UPPER_ADDRESS): Repurpose to be the address of the last element in the bookkeeping part of the stack -- i.e. to point to the return address. * libguile/vm-engine.h: * libguile/vm-i-system.c: Adapt to removal of stack_base. Though we still detect stack-smashing underflow, we don't do so as precisely as we did before, because now we only detect overwriting of the frame metadata. * libguile/vm-engine.c (vm_engine): Remove the stack_base variable. It is unnecessary, and difficult to keep track of in the face of case-lambda. Also fix miscommented "ra" and "mvra" pushes. Push the vp->ip as the first ra... * libguile/vm-i-system.c (halt): ...because here we can restore the vp->ip instead of setting ip to 0. Allows us to introspect ips all down the stack, including in recursive VM invocations. * libguile/frames.h: * libguile/frames.c (scm_vm_frame_stack): Removed, because it's getting more difficult to tell what's an argument and what's a temporary stack element. (scm_vm_frame_num_locals): New accessor. (scm_vm_frame_instruction_pointer): New accessor. (scm_vm_frame_arguments): Defer to an implementation in Scheme. (scm_vm_frame_num_locals scm_vm_frame_local_ref) (scm_vm_frame_local_set_x): Since we can get not-yet-active frames on the stack now, with our current calling convention, we have to add a heuristic here to jump over those frames -- because frames have pointers in them, not Scheme values. * libguile/programs.h: * libguile/programs.c (scm_program_arity): Remove, in favor of.. (scm_program_arities): ...this, which a list of arities, in a new format, occupying a slot in the metadata. * module/language/assembly/decompile-bytecode.scm (decode-load-program): Fix mv-call decompilation. * module/system/vm/frame.scm (vm-frame-bindings, vm-frame-binding-ref) (vm-frame-binding-set!): New functions, to access bindings by name in a frame. (vm-frame-arguments): Function now implemented in Scheme. Commented fairly extensively. * module/system/vm/program.scm (program-bindings-by-index) (program-bindings-for-ip): New accessors, parsing the program bindings metadata into something more useful. (program-arities, program-arguments): In a case-lambda world, we have to assume that programs can have multiple arities. But it's tough to detect this algorithmically; instead we're going to require that the program metadata include information about the arities, and the parts of the program that that metadata applies to. (program-lambda-list): New accessor. (write-program): Show multiple arities. * module/language/glil/compile-assembly.scm (glil->assembly): Add "arities" to the state of the compiler, and add arities entries as appropriate.
2009-09-27 19:25:58 -04:00
*++sp = vals[1];
runtime and debugging support for callee-parsed procedure args * libguile/objcodes.h: Bump for metadata format change. * libguile/frames.h: Rework so we don't frob the program's nargs, nlocs, etc at runtime. Instead we don't really know what's a local var, an argument, or an intermediate value. It's a little unfortunate, but this will allow for case-lambda, and eventually for good polymorphic generic dispatch; and the nlocs etc can be heuristically reconstructed. Such a reconstruction would be better done at the Scheme level, though. (SCM_FRAME_STACK_ADDRESS): New macro, the pointer to the base of the stack elements (not counting the program). (SCM_FRAME_UPPER_ADDRESS): Repurpose to be the address of the last element in the bookkeeping part of the stack -- i.e. to point to the return address. * libguile/vm-engine.h: * libguile/vm-i-system.c: Adapt to removal of stack_base. Though we still detect stack-smashing underflow, we don't do so as precisely as we did before, because now we only detect overwriting of the frame metadata. * libguile/vm-engine.c (vm_engine): Remove the stack_base variable. It is unnecessary, and difficult to keep track of in the face of case-lambda. Also fix miscommented "ra" and "mvra" pushes. Push the vp->ip as the first ra... * libguile/vm-i-system.c (halt): ...because here we can restore the vp->ip instead of setting ip to 0. Allows us to introspect ips all down the stack, including in recursive VM invocations. * libguile/frames.h: * libguile/frames.c (scm_vm_frame_stack): Removed, because it's getting more difficult to tell what's an argument and what's a temporary stack element. (scm_vm_frame_num_locals): New accessor. (scm_vm_frame_instruction_pointer): New accessor. (scm_vm_frame_arguments): Defer to an implementation in Scheme. (scm_vm_frame_num_locals scm_vm_frame_local_ref) (scm_vm_frame_local_set_x): Since we can get not-yet-active frames on the stack now, with our current calling convention, we have to add a heuristic here to jump over those frames -- because frames have pointers in them, not Scheme values. * libguile/programs.h: * libguile/programs.c (scm_program_arity): Remove, in favor of.. (scm_program_arities): ...this, which a list of arities, in a new format, occupying a slot in the metadata. * module/language/assembly/decompile-bytecode.scm (decode-load-program): Fix mv-call decompilation. * module/system/vm/frame.scm (vm-frame-bindings, vm-frame-binding-ref) (vm-frame-binding-set!): New functions, to access bindings by name in a frame. (vm-frame-arguments): Function now implemented in Scheme. Commented fairly extensively. * module/system/vm/program.scm (program-bindings-by-index) (program-bindings-for-ip): New accessors, parsing the program bindings metadata into something more useful. (program-arities, program-arguments): In a case-lambda world, we have to assume that programs can have multiple arities. But it's tough to detect this algorithmically; instead we're going to require that the program metadata include information about the arities, and the parts of the program that that metadata applies to. (program-lambda-list): New accessor. (write-program): Show multiple arities. * module/language/glil/compile-assembly.scm (glil->assembly): Add "arities" to the state of the compiler, and add arities entries as appropriate.
2009-09-27 19:25:58 -04:00
/* Finally null the end of the stack */
NULLSTACK (vals + nvalues - sp);
}
else
goto vm_error_no_values;
/* Restore the last program */
program = SCM_FRAME_PROGRAM (fp);
CACHE_PROGRAM ();
CHECK_IP ();
NEXT;
}
VM_DEFINE_INSTRUCTION (69, return_values_star, "return/values*", 1, -1, -1)
{
SCM l;
nvalues = FETCH ();
precise stack marking, fix some missed references, still imperfect * libguile/vm-engine.h (CHECK_STACK_LEAK, NULLSTACK): Add a new mode, VM_ENABLE_STACK_NULLING, that tries to ensure that all stack data past the top of the stack is NULL. This helps to verify the VM's consistency. If VM_ENABLE_STACK_NULLING is not defined, there is no overhead. (DROP, DROPN): Hook into NULLSTACK. (POP_LIST): Hoo, fix a good bug: if CONS triggered a GC, the elements of the list that had not yet been consed would not be marked, because the sp was already below them. (NEXT): Hook into CHECK_STACK_LEAK. (INIT_ARGS): Add a note that consing the rest arg can cause GC. (NEW_FRAME): Cons up the external data after initializing the frame, so that if GC is triggered, the precise marker sees a well-formed frame. * libguile/vm-i-loader.c (load-program): In the four-integers case, use the POP macro so that we can hook into NULLSTACK (if necessary). * libguile/vm-i-scheme.c (ARGS2, ARGS3): Hook into NULLSTACK. * libguile/vm-i-system.c (halt): Null the nvalues. Rework some asserts into using ASSERT, and null the stack when we free the frame. (variable-set): Use DROPN instead of sp -= 2. (BR): Hook into NULLSTACK. (goto/args): Hook into NULLSTACK. In the non-self case, delay updating the frame until after INIT_ARGS so that GC sees a well-formed frame. Delay consing the externals until after the frame is set up, as in NEW_FRAME. (call/cc): Add some asserts. (return): Rework some asserts into ASSERT, and hook into NULLSTACK. (return/values): Hook into NULLSTACK, and use ASSERT. (return/values*) Use ASSERT. * libguile/vm.c (VM_ENABLE_ASSERTIONS, VM_ENABLE_STACK_NULLING): These are the variables that control assertions and nulling. Perhaps we can do these per-engine when we start compiling the debug engine separate from a speedy engine. (vm_mark_stack): Add a precise stack marker. Yay! (vm_cont_mark): Mark the continuation stack precisely. (capture_vm_cont): Record the difference from the vp's stack_base too, so that we can translate the dynamic links when marking the continuation stack. Memset the stack to NULL if we are doing nulling. (reinstate_vm_cont): If we are nulling, null out the relevant part of the stack. (vm_reset_stack): When resetting sp due to a nonlocal exit, null out the stack too. (vm_mark): If we are nulling, assert that there are no extra values on the stack. Mark the stack precisely.
2008-10-03 16:00:30 +02:00
ASSERT (nvalues >= 1);
nvalues--;
POP (l);
while (scm_is_pair (l))
{
PUSH (SCM_CAR (l));
l = SCM_CDR (l);
nvalues++;
}
if (SCM_UNLIKELY (!SCM_NULL_OR_NIL_P (l))) {
finish_args = scm_list_1 (l);
goto vm_error_improper_list;
}
goto vm_return_values;
}
VM_DEFINE_INSTRUCTION (70, return_nvalues, "return/nvalues", 0, 1, -1)
{
SCM n;
POP (n);
nvalues = scm_to_int (n);
ASSERT (nvalues >= 0);
goto vm_return_values;
}
VM_DEFINE_INSTRUCTION (71, truncate_values, "truncate-values", 2, -1, -1)
lambda-lifting for (lambda () ...) as consumer of call-with-values * libguile/vm-engine.c (vm_run): Add new error case, vm_error_not_enough_values. * libguile/vm-i-system.c (goto/nargs, call/nargs): So, in these cases, if we get too many values, we don't truncate the values like we do in the single-value continuation case, or in the mvbind case. What to do? I guess we either truncate them here, or only allow the correct number of values. Dunno. Mark the code as a fixme. (truncate-values): New instruction, for mv-bind: checks that the number of values on the stack is compatible with the number of bindings we have arranged for them, truncating if necessary. * module/language/scheme/translate.scm (custom-transformer-table): Compile receive as a primary form -- not so much because it is a primary form, but more to test the mv-bind machinery. Also it's more efficient, I think. * module/system/il/compile.scm (lift-variables!): New helper, factored out of `optimize'. (optimize): Add a few more cases. Adapt `lambda' optimization, which isn't much. I'm not happy with ghil as a mungeable language. Add a case for call-with-values with the second argument is a lambda: lift the lambda. Untested. (codegen): Refactor the push-bindings! code. Compile mv-bind. * module/system/il/ghil.scm (<ghil-mv-bind>): Add mv-bind construct, along with its procedures. * module/system/il/glil.scm (<glil-mv-bind>): Add mv-bind construct, different from the high-level one. It makes sense in the source, I think. * module/system/vm/assemble.scm (codegen): Assemble glil-mv-bind by pushing onto the bindings list, and actually push some code to truncate the values.
2008-09-18 22:49:55 +02:00
{
SCM x;
int nbinds, rest;
POP (x);
nvalues = scm_to_int (x);
nbinds = FETCH ();
rest = FETCH ();
if (rest)
nbinds--;
if (nvalues < nbinds)
goto vm_error_not_enough_values;
if (rest)
POP_LIST (nvalues - nbinds);
else
DROPN (nvalues - nbinds);
NEXT;
}
VM_DEFINE_INSTRUCTION (72, box, "box", 1, 1, 0)
{
SCM val;
POP (val);
SYNC_BEFORE_GC ();
LOCAL_SET (FETCH (), scm_cell (scm_tc7_variable, SCM_UNPACK (val)));
NEXT;
}
/* for letrec:
(let ((a *undef*) (b *undef*) ...)
(set! a (lambda () (b ...)))
...)
*/
VM_DEFINE_INSTRUCTION (73, empty_box, "empty-box", 1, 0, 0)
{
SYNC_BEFORE_GC ();
LOCAL_SET (FETCH (),
scm_cell (scm_tc7_variable, SCM_UNPACK (SCM_UNDEFINED)));
NEXT;
}
VM_DEFINE_INSTRUCTION (74, local_boxed_ref, "local-boxed-ref", 1, 0, 1)
{
SCM v = LOCAL_REF (FETCH ());
ASSERT_BOUND_VARIABLE (v);
PUSH (VARIABLE_REF (v));
NEXT;
}
VM_DEFINE_INSTRUCTION (75, local_boxed_set, "local-boxed-set", 1, 1, 0)
{
SCM v, val;
v = LOCAL_REF (FETCH ());
POP (val);
ASSERT_VARIABLE (v);
VARIABLE_SET (v, val);
NEXT;
}
VM_DEFINE_INSTRUCTION (76, free_ref, "free-ref", 1, 0, 1)
{
scm_t_uint8 idx = FETCH ();
CHECK_FREE_VARIABLE (idx);
PUSH (FREE_VARIABLE_REF (idx));
NEXT;
}
/* no free-set -- if a var is assigned, it should be in a box */
VM_DEFINE_INSTRUCTION (77, free_boxed_ref, "free-boxed-ref", 1, 0, 1)
{
SCM v;
scm_t_uint8 idx = FETCH ();
CHECK_FREE_VARIABLE (idx);
v = FREE_VARIABLE_REF (idx);
ASSERT_BOUND_VARIABLE (v);
PUSH (VARIABLE_REF (v));
NEXT;
}
VM_DEFINE_INSTRUCTION (78, free_boxed_set, "free-boxed-set", 1, 1, 0)
{
SCM v, val;
scm_t_uint8 idx = FETCH ();
POP (val);
CHECK_FREE_VARIABLE (idx);
v = FREE_VARIABLE_REF (idx);
ASSERT_BOUND_VARIABLE (v);
VARIABLE_SET (v, val);
NEXT;
}
VM_DEFINE_INSTRUCTION (79, make_closure, "make-closure", 2, -1, 1)
{
size_t n, len;
SCM closure;
len = FETCH ();
len <<= 8;
len += FETCH ();
SYNC_BEFORE_GC ();
closure = scm_words (scm_tc7_program | (len<<16), len + 3);
SCM_SET_CELL_OBJECT_1 (closure, SCM_PROGRAM_OBJCODE (sp[-len]));
SCM_SET_CELL_OBJECT_2 (closure, SCM_PROGRAM_OBJTABLE (sp[-len]));
sp[-len] = closure;
for (n = 0; n < len; n++)
SCM_PROGRAM_FREE_VARIABLE_SET (closure, n, sp[-len + 1 + n]);
DROPN (len);
NEXT;
}
VM_DEFINE_INSTRUCTION (80, make_variable, "make-variable", 0, 0, 1)
{
SYNC_BEFORE_GC ();
/* fixme underflow */
PUSH (scm_cell (scm_tc7_variable, SCM_UNPACK (SCM_UNDEFINED)));
NEXT;
}
VM_DEFINE_INSTRUCTION (81, fix_closure, "fix-closure", 2, -1, 0)
{
SCM x;
unsigned int i = FETCH ();
size_t n, len;
i <<= 8;
i += FETCH ();
/* FIXME CHECK_LOCAL (i) */
x = LOCAL_REF (i);
/* FIXME ASSERT_PROGRAM (x); */
len = SCM_PROGRAM_NUM_FREE_VARIABLES (x);
for (n = 0; n < len; n++)
SCM_PROGRAM_FREE_VARIABLE_SET (x, n, sp[-len + 1 + n]);
DROPN (len);
NEXT;
}
VM_DEFINE_INSTRUCTION (82, define, "define", 0, 0, 2)
rework the vm support for wide strings * libguile/_scm.h (SCM_OBJCODE_MINOR_VERSION): Bump. * libguile/vm-engine.c (vm_error_bad_wide_string_length): New error case. * libguile/vm-i-loader.c (load-unsigned-integer, load-integer) (load-keyword): Remove these instructions. The former two are obsoleted by make-int64/make-uint64, the latter via make-keyword. (load-string): Only handle narrow strings. (load-symbol): Only handle narrow symbols. The wide case is handled via make-symbol. (load-wide-string): New instruction, for wide strings. * libguile/vm-i-system.c (define): Move here from loaders.c, as now it just takes a sym on the stack. (make-keyword, make-symbol): New instructions. * module/language/assembly.scm: Remove removed instructions. No more width byte in load-string etc. * module/language/assembly/compile-bytecode.scm (write-bytecode): Adapt to change in instruction set. * module/language/glil/compile-assembly.scm (glil->assembly): Compile define by pushing the sym then emitting (define). (dump-object): Dump narrow and wide strings differently. Use make-keyword and make-symbol as appropriate. * module/language/tree-il/compile-glil.scm (flatten): When compiling a ref to a primitive (not a call), first see if the primitive is actually bound in the root module. (That's not the case with e.g. bytevector-u8-ref). * module/system/xref.scm (program-callee-rev-vars): Don't parse out "nexts". * test-suite/tests/asm-to-bytecode.test ("compiler"): Adapt to bytecode format change.
2009-08-12 16:33:49 +02:00
{
SCM sym, val;
POP2 (sym, val);
rework the vm support for wide strings * libguile/_scm.h (SCM_OBJCODE_MINOR_VERSION): Bump. * libguile/vm-engine.c (vm_error_bad_wide_string_length): New error case. * libguile/vm-i-loader.c (load-unsigned-integer, load-integer) (load-keyword): Remove these instructions. The former two are obsoleted by make-int64/make-uint64, the latter via make-keyword. (load-string): Only handle narrow strings. (load-symbol): Only handle narrow symbols. The wide case is handled via make-symbol. (load-wide-string): New instruction, for wide strings. * libguile/vm-i-system.c (define): Move here from loaders.c, as now it just takes a sym on the stack. (make-keyword, make-symbol): New instructions. * module/language/assembly.scm: Remove removed instructions. No more width byte in load-string etc. * module/language/assembly/compile-bytecode.scm (write-bytecode): Adapt to change in instruction set. * module/language/glil/compile-assembly.scm (glil->assembly): Compile define by pushing the sym then emitting (define). (dump-object): Dump narrow and wide strings differently. Use make-keyword and make-symbol as appropriate. * module/language/tree-il/compile-glil.scm (flatten): When compiling a ref to a primitive (not a call), first see if the primitive is actually bound in the root module. (That's not the case with e.g. bytevector-u8-ref). * module/system/xref.scm (program-callee-rev-vars): Don't parse out "nexts". * test-suite/tests/asm-to-bytecode.test ("compiler"): Adapt to bytecode format change.
2009-08-12 16:33:49 +02:00
SYNC_REGISTER ();
VARIABLE_SET (scm_sym2var (sym, scm_current_module_lookup_closure (),
SCM_BOOL_T),
val);
NEXT;
}
VM_DEFINE_INSTRUCTION (83, make_keyword, "make-keyword", 0, 1, 1)
rework the vm support for wide strings * libguile/_scm.h (SCM_OBJCODE_MINOR_VERSION): Bump. * libguile/vm-engine.c (vm_error_bad_wide_string_length): New error case. * libguile/vm-i-loader.c (load-unsigned-integer, load-integer) (load-keyword): Remove these instructions. The former two are obsoleted by make-int64/make-uint64, the latter via make-keyword. (load-string): Only handle narrow strings. (load-symbol): Only handle narrow symbols. The wide case is handled via make-symbol. (load-wide-string): New instruction, for wide strings. * libguile/vm-i-system.c (define): Move here from loaders.c, as now it just takes a sym on the stack. (make-keyword, make-symbol): New instructions. * module/language/assembly.scm: Remove removed instructions. No more width byte in load-string etc. * module/language/assembly/compile-bytecode.scm (write-bytecode): Adapt to change in instruction set. * module/language/glil/compile-assembly.scm (glil->assembly): Compile define by pushing the sym then emitting (define). (dump-object): Dump narrow and wide strings differently. Use make-keyword and make-symbol as appropriate. * module/language/tree-il/compile-glil.scm (flatten): When compiling a ref to a primitive (not a call), first see if the primitive is actually bound in the root module. (That's not the case with e.g. bytevector-u8-ref). * module/system/xref.scm (program-callee-rev-vars): Don't parse out "nexts". * test-suite/tests/asm-to-bytecode.test ("compiler"): Adapt to bytecode format change.
2009-08-12 16:33:49 +02:00
{
CHECK_UNDERFLOW ();
SYNC_REGISTER ();
*sp = scm_symbol_to_keyword (*sp);
NEXT;
}
VM_DEFINE_INSTRUCTION (84, make_symbol, "make-symbol", 0, 1, 1)
rework the vm support for wide strings * libguile/_scm.h (SCM_OBJCODE_MINOR_VERSION): Bump. * libguile/vm-engine.c (vm_error_bad_wide_string_length): New error case. * libguile/vm-i-loader.c (load-unsigned-integer, load-integer) (load-keyword): Remove these instructions. The former two are obsoleted by make-int64/make-uint64, the latter via make-keyword. (load-string): Only handle narrow strings. (load-symbol): Only handle narrow symbols. The wide case is handled via make-symbol. (load-wide-string): New instruction, for wide strings. * libguile/vm-i-system.c (define): Move here from loaders.c, as now it just takes a sym on the stack. (make-keyword, make-symbol): New instructions. * module/language/assembly.scm: Remove removed instructions. No more width byte in load-string etc. * module/language/assembly/compile-bytecode.scm (write-bytecode): Adapt to change in instruction set. * module/language/glil/compile-assembly.scm (glil->assembly): Compile define by pushing the sym then emitting (define). (dump-object): Dump narrow and wide strings differently. Use make-keyword and make-symbol as appropriate. * module/language/tree-il/compile-glil.scm (flatten): When compiling a ref to a primitive (not a call), first see if the primitive is actually bound in the root module. (That's not the case with e.g. bytevector-u8-ref). * module/system/xref.scm (program-callee-rev-vars): Don't parse out "nexts". * test-suite/tests/asm-to-bytecode.test ("compiler"): Adapt to bytecode format change.
2009-08-12 16:33:49 +02:00
{
CHECK_UNDERFLOW ();
SYNC_REGISTER ();
*sp = scm_string_to_symbol (*sp);
NEXT;
}
VM_DEFINE_INSTRUCTION (85, prompt, "prompt", 4, 2, 0)
{
scm_t_int32 offset;
scm_t_uint8 escape_only_p;
SCM k, prompt;
escape_only_p = FETCH ();
FETCH_OFFSET (offset);
POP (k);
SYNC_REGISTER ();
/* Push the prompt onto the dynamic stack. */
prompt = scm_c_make_prompt (k, fp, sp, ip + offset, escape_only_p, vm_cookie,
scm_i_dynwinds ());
scm_i_set_dynwinds (scm_cons (prompt, SCM_PROMPT_DYNWINDS (prompt)));
if (SCM_PROMPT_SETJMP (prompt))
{
/* The prompt exited nonlocally. Cache the regs back from the vp, and go
to the handler.
Note, at this point, we must assume that any variable local to
vm_engine that can be assigned *has* been assigned. So we need to pull
all our state back from the ip/fp/sp.
*/
CACHE_REGISTER ();
program = SCM_FRAME_PROGRAM (fp);
CACHE_PROGRAM ();
/* The stack contains the values returned to this prompt, along
with a number-of-values marker -- like an MV return. */
ABORT_CONTINUATION_HOOK ();
NEXT;
}
/* Otherwise setjmp returned for the first time, so we go to execute the
prompt's body. */
NEXT;
}
VM_DEFINE_INSTRUCTION (86, wind, "wind", 0, 2, 0)
{
SCM wind, unwind;
POP2 (unwind, wind);
SYNC_REGISTER ();
/* Push wind and unwind procedures onto the dynamic stack. Note that neither
are actually called; the compiler should emit calls to wind and unwind for
the normal dynamic-wind control flow. */
if (SCM_UNLIKELY (scm_is_false (scm_thunk_p (wind))))
{
finish_args = wind;
goto vm_error_not_a_thunk;
}
if (SCM_UNLIKELY (scm_is_false (scm_thunk_p (unwind))))
{
finish_args = unwind;
goto vm_error_not_a_thunk;
}
scm_i_set_dynwinds (scm_cons (scm_cons (wind, unwind), scm_i_dynwinds ()));
NEXT;
}
VM_DEFINE_INSTRUCTION (87, abort, "abort", 1, -1, -1)
{
unsigned n = FETCH ();
SYNC_REGISTER ();
abort always dispatches to VM bytecode, to detect same-invocation aborts * libguile/control.h: * libguile/control.c (scm_c_make_prompt): Take an extra arg, a cookie. Continuations will be rewindable only if the abort has the same cookie as the prompt. (scm_at_abort): Redefine from scm_abort, and instead of taking rest args, take the abort values as a list directly. Also, don't allow rewinding, because we won't support rewinding the C stack with delimited continuations. * libguile/eval.c (eval): Adapt to scm_c_make_prompt change. * libguile/vm-engine.c (vm_engine): Use vp->cookie to get a unique value corresponding to this VM invocation. * libguile/vm-i-system.c (prompt): Pass the cookie to scm_c_make_prompt. (abort): Take an additional tail arg. * libguile/vm.c (vm_abort): Parse out the abort tail arg. This is for the @abort case, or the (apply abort ...) case. (make_vm): Initialize the cookie to 0. * libguile/vm.h (struct scm_vm): Add cookie. * module/ice-9/boot-9.scm (abort): Define here as a trampoline to @abort. Needed to make sure that a call to abort dispatches to a VM opcode, so the cookie will be the same. * module/language/tree-il.scm (<tree-il>): Add a "tail" field to <abort>, for the (apply abort ...) case, or (@abort tag args). Should be #<const ()> in the normal case. Add support throughout. * module/language/tree-il/analyze.scm (analyze-lexicals): Add abort-tail support here too. * module/language/tree-il/compile-glil.scm (flatten): Compile the tail argument appropriately. * module/language/tree-il/primitives.scm (*primitive-expand-table*): Fix @abort and abort cases to pass the tail arg to make-abort.
2010-02-22 21:53:24 +01:00
if (sp - n - 2 <= SCM_FRAME_UPPER_ADDRESS (fp))
goto vm_error_stack_underflow;
vm_abort (vm, n, vm_cookie);
/* vm_abort should not return */
abort ();
}
VM_DEFINE_INSTRUCTION (88, unwind, "unwind", 0, 0, 0)
{
/* A normal exit from the dynamic extent of an expression. Pop the top entry
off of the dynamic stack. */
scm_i_set_dynwinds (scm_cdr (scm_i_dynwinds ()));
NEXT;
}
VM_DEFINE_INSTRUCTION (89, wind_fluids, "wind-fluids", 1, -1, 0)
{
unsigned n = FETCH ();
SCM wf;
SYNC_REGISTER ();
sp -= 2 * n;
CHECK_UNDERFLOW ();
wf = scm_i_make_with_fluids (n, sp + 1, sp + 1 + n);
NULLSTACK (2 * n);
scm_i_swap_with_fluids (wf, current_thread->dynamic_state);
scm_i_set_dynwinds (scm_cons (wf, scm_i_dynwinds ()));
NEXT;
}
VM_DEFINE_INSTRUCTION (90, unwind_fluids, "unwind-fluids", 0, 0, 0)
{
SCM wf;
wf = scm_car (scm_i_dynwinds ());
scm_i_set_dynwinds (scm_cdr (scm_i_dynwinds ()));
scm_i_swap_with_fluids (wf, current_thread->dynamic_state);
NEXT;
}
VM_DEFINE_INSTRUCTION (91, fluid_ref, "fluid-ref", 0, 1, 1)
{
size_t num;
SCM fluids;
CHECK_UNDERFLOW ();
fluids = SCM_I_DYNAMIC_STATE_FLUIDS (current_thread->dynamic_state);
if (SCM_UNLIKELY (!SCM_FLUID_P (*sp))
|| ((num = SCM_I_FLUID_NUM (*sp)) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
{
/* Punt dynstate expansion and error handling to the C proc. */
SYNC_REGISTER ();
*sp = scm_fluid_ref (*sp);
}
else
{
SCM val = SCM_SIMPLE_VECTOR_REF (fluids, num);
if (SCM_UNLIKELY (scm_is_eq (val, SCM_UNDEFINED)))
{
finish_args = *sp;
goto vm_error_unbound_fluid;
}
*sp = val;
}
NEXT;
}
VM_DEFINE_INSTRUCTION (92, fluid_set, "fluid-set", 0, 2, 0)
{
size_t num;
SCM val, fluid, fluids;
POP2 (val, fluid);
fluids = SCM_I_DYNAMIC_STATE_FLUIDS (current_thread->dynamic_state);
if (SCM_UNLIKELY (!SCM_FLUID_P (fluid))
|| ((num = SCM_I_FLUID_NUM (fluid)) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
{
/* Punt dynstate expansion and error handling to the C proc. */
SYNC_REGISTER ();
scm_fluid_set_x (fluid, val);
}
else
SCM_SIMPLE_VECTOR_SET (fluids, num, val);
NEXT;
}
VM_DEFINE_INSTRUCTION (93, assert_nargs_ee_locals, "assert-nargs-ee/locals", 1, 0, 0)
{
scm_t_ptrdiff n;
SCM *old_sp;
/* nargs = n & 0x7, nlocs = nargs + (n >> 3) */
n = FETCH ();
if (SCM_UNLIKELY (sp - (fp - 1) != (n & 0x7)))
goto vm_error_wrong_num_args;
old_sp = sp;
sp += (n >> 3);
CHECK_OVERFLOW ();
while (old_sp < sp)
*++old_sp = SCM_UNDEFINED;
NEXT;
}
static opcodes; refactor program/objcode division; use new assembly pipeline * gdbinit: Untested attempts to get the stack fondling macros to deal with the new program representation. * libguile/frames.c (scm_vm_frame_arguments, scm_vm_frame_source) (scm_vm_frame_local_ref, scm_vm_frame_local_set_x): SCM_PROGRAM_DATA is a struct scm_objcode*. * libguile/instructions.h: * libguile/instructions.c: Hide the instruction table and the struct scm_instruction structure; all access to instructions now goes through procedures. This is because instructions are no longer in a packed array indexed by opcode. Also, declare a mask that all instructions should fit in. * libguile/objcodes.h: * libguile/objcodes.c: Rewrite so that object code directly maps its arity and length from its bytecode. This makes it unnecessary to keep this information in programs, allowing programs to be simple conses between the code (objcodes) and data (the object table and the closure variables). * libguile/programs.c (scm_make_program): Rework so that make-program takes objcode, an object table, and externals as arguments. It's much clearer this way, and we avoid malloc(). * libguile/stacks.c (is_vm_bootstrap_frame): Update for program/objcode changes. * libguile/vm-engine.c (vm_run): Initialize the jump table on the first run, with the opcodes declared in the instruction sources, and with bad instructions raising an error instead of wandering off into the Unknown. * libguile/vm-engine.h (FETCH_LENGTH): Always represent lengths as 3 bytes. The old code was too error-prone. (NEXT_JUMP): Mask the instruction with SCM_VM_INSTRUCTION_MASK. (NEW_FRAME): Update for program/objcode changes. * libguile/vm-expand.h (VM_DEFINE_FUNCTION, VM_DEFINE_INSTRUCTION) (VM_DEFINE_LOADER): Update so that we explicitly specify opcodes, so that we have a stable bytecode API. * libguile/vm-i-loader.c: Update license to LGPLv2+. Explicitly declare opcodes. (load-integer): Use an int instead of a long as the accumulator; still need to revisit this code at some point, I think. (load-program): Simplify, thankfully!! Just creates the objcode slice and rolls with it. * libguile/vm-i-scheme.c: Number the opcodes explicitly. * libguile/vm-i-system.c: Update license to LGPLv2+. Explicitly declare opcodes. (make-closure): Update for new program API. * libguile/vm.c (vm_make_boot_program): Update for new program/objcode API. Still a bit ugly. (scm_load_compiled_with_vm): Update for new program/objcode API. * module/language/assembly.scm (byte-length): Fix byte-length calculation for loaders, and load-program. (code-pack, code-unpack): Start to move things from (system vm conv) here. (object->code, code->object): More things from conv.scm. * module/language/glil.scm (<glil-program>): Add a new field, closure-level. (make-glil-program, compute-closure-level): Calculate the "closure level" when making a glil program. This is the maximum depth of external binding refs in this closure. (unparse-glil): Fix label serialization. * module/language/glil/compile-assembly.scm (make-meta): Prepend #f for the meta's object table, though maybe in the future we can avoid creating assembly in the first place. (assoc-ref-or-acons, object-index-and-alist): GRRR! Caught again by the different sets of arguments to assoc and assoc-ref! (glil->assembly): Attempt to make the <glil-program> case more readable, and fix the bugs. Sorry I don't know how to comment this change any more than this. (glil->assembly): For <glil-module> serialize the whole key, not just the name. (dump-object): subprogram-code is already a list. Serialize integers as strings, not u8vectors. Fix the order of lists and vectors. * module/language/glil/spec.scm (glil): Switch orders, so we prefer glil -> assembly -> objcode. Actually glil->objcode doesn't work any more, needs to be removed I think. * module/language/objcode/spec.scm (objcode->value): s/objcode->program/make-program/. * module/language/scheme/inline.scm: Add acons inline. * module/system/vm/conv.scm (make-byte-decoder): Skip the first 8 bytes, they are header. Handle subprograms properly. Still needs help though. (decode-length): Lengths are always 3 bytes now. * module/system/vm/disasm.scm: Superficial changes to keep things working. I'd like to fix this better in the future. * module/system/vm/frame.scm (bootstrap-frame?): Fixes for program-bytecode. * module/system/vm/program.scm: Export make-program. It's program-objcode now, no more program-bytecode. * module/system/vm/vm.scm (vm-load): Use make-program. * test-suite/tests/asm-to-bytecode.test: New test, very minimal. * module/system/vm/objcode.scm: Export word-size, byte-order, and write-objcode.
2009-01-29 21:09:04 +01:00
/*
(defun renumber-ops ()
"start from top of buffer and renumber 'VM_DEFINE_FOO (\n' sequences"
(interactive "")
(save-excursion
(let ((counter -1)) (goto-char (point-min))
(while (re-search-forward "^VM_DEFINE_[^ ]+ (\\([^,]+\\)," (point-max) t)
(replace-match
(number-to-string (setq counter (1+ counter)))
t t nil 1)))))
(renumber-ops)
static opcodes; refactor program/objcode division; use new assembly pipeline * gdbinit: Untested attempts to get the stack fondling macros to deal with the new program representation. * libguile/frames.c (scm_vm_frame_arguments, scm_vm_frame_source) (scm_vm_frame_local_ref, scm_vm_frame_local_set_x): SCM_PROGRAM_DATA is a struct scm_objcode*. * libguile/instructions.h: * libguile/instructions.c: Hide the instruction table and the struct scm_instruction structure; all access to instructions now goes through procedures. This is because instructions are no longer in a packed array indexed by opcode. Also, declare a mask that all instructions should fit in. * libguile/objcodes.h: * libguile/objcodes.c: Rewrite so that object code directly maps its arity and length from its bytecode. This makes it unnecessary to keep this information in programs, allowing programs to be simple conses between the code (objcodes) and data (the object table and the closure variables). * libguile/programs.c (scm_make_program): Rework so that make-program takes objcode, an object table, and externals as arguments. It's much clearer this way, and we avoid malloc(). * libguile/stacks.c (is_vm_bootstrap_frame): Update for program/objcode changes. * libguile/vm-engine.c (vm_run): Initialize the jump table on the first run, with the opcodes declared in the instruction sources, and with bad instructions raising an error instead of wandering off into the Unknown. * libguile/vm-engine.h (FETCH_LENGTH): Always represent lengths as 3 bytes. The old code was too error-prone. (NEXT_JUMP): Mask the instruction with SCM_VM_INSTRUCTION_MASK. (NEW_FRAME): Update for program/objcode changes. * libguile/vm-expand.h (VM_DEFINE_FUNCTION, VM_DEFINE_INSTRUCTION) (VM_DEFINE_LOADER): Update so that we explicitly specify opcodes, so that we have a stable bytecode API. * libguile/vm-i-loader.c: Update license to LGPLv2+. Explicitly declare opcodes. (load-integer): Use an int instead of a long as the accumulator; still need to revisit this code at some point, I think. (load-program): Simplify, thankfully!! Just creates the objcode slice and rolls with it. * libguile/vm-i-scheme.c: Number the opcodes explicitly. * libguile/vm-i-system.c: Update license to LGPLv2+. Explicitly declare opcodes. (make-closure): Update for new program API. * libguile/vm.c (vm_make_boot_program): Update for new program/objcode API. Still a bit ugly. (scm_load_compiled_with_vm): Update for new program/objcode API. * module/language/assembly.scm (byte-length): Fix byte-length calculation for loaders, and load-program. (code-pack, code-unpack): Start to move things from (system vm conv) here. (object->code, code->object): More things from conv.scm. * module/language/glil.scm (<glil-program>): Add a new field, closure-level. (make-glil-program, compute-closure-level): Calculate the "closure level" when making a glil program. This is the maximum depth of external binding refs in this closure. (unparse-glil): Fix label serialization. * module/language/glil/compile-assembly.scm (make-meta): Prepend #f for the meta's object table, though maybe in the future we can avoid creating assembly in the first place. (assoc-ref-or-acons, object-index-and-alist): GRRR! Caught again by the different sets of arguments to assoc and assoc-ref! (glil->assembly): Attempt to make the <glil-program> case more readable, and fix the bugs. Sorry I don't know how to comment this change any more than this. (glil->assembly): For <glil-module> serialize the whole key, not just the name. (dump-object): subprogram-code is already a list. Serialize integers as strings, not u8vectors. Fix the order of lists and vectors. * module/language/glil/spec.scm (glil): Switch orders, so we prefer glil -> assembly -> objcode. Actually glil->objcode doesn't work any more, needs to be removed I think. * module/language/objcode/spec.scm (objcode->value): s/objcode->program/make-program/. * module/language/scheme/inline.scm: Add acons inline. * module/system/vm/conv.scm (make-byte-decoder): Skip the first 8 bytes, they are header. Handle subprograms properly. Still needs help though. (decode-length): Lengths are always 3 bytes now. * module/system/vm/disasm.scm: Superficial changes to keep things working. I'd like to fix this better in the future. * module/system/vm/frame.scm (bootstrap-frame?): Fixes for program-bytecode. * module/system/vm/program.scm: Export make-program. It's program-objcode now, no more program-bytecode. * module/system/vm/vm.scm (vm-load): Use make-program. * test-suite/tests/asm-to-bytecode.test: New test, very minimal. * module/system/vm/objcode.scm: Export word-size, byte-order, and write-objcode.
2009-01-29 21:09:04 +01:00
*/
2001-04-01 05:03:41 +00:00
/*
Local Variables:
c-file-style: "gnu"
End:
*/