add ffi/unsafe/vm
Provide `vm-primitive` and `vm-eval` to regularize access to VM-level primitives. Document some of the issues for interoperating across the Racket and (Chez Scheme) VM layers. The library could have been implemented with just `compile-linklet` and `instantiate-linklet`, but using an underlying `primitive-lookup` function is a little nicer.
This commit is contained in:
parent
a01f9ada99
commit
69932f6f67
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
(define collection 'multi)
|
(define collection 'multi)
|
||||||
|
|
||||||
(define version "7.6.0.6")
|
(define version "7.6.0.7")
|
||||||
|
|
||||||
(define deps `("racket-lib"
|
(define deps `("racket-lib"
|
||||||
["racket" #:version ,version]))
|
["racket" #:version ,version]))
|
||||||
|
|
|
@ -24,3 +24,4 @@
|
||||||
@include-section["com.scrbl"]
|
@include-section["com.scrbl"]
|
||||||
@include-section["file.scrbl"]
|
@include-section["file.scrbl"]
|
||||||
@include-section["winapi.scrbl"]
|
@include-section["winapi.scrbl"]
|
||||||
|
@include-section["vm.scrbl"]
|
||||||
|
|
102
pkgs/racket-doc/scribblings/foreign/vm.scrbl
Normal file
102
pkgs/racket-doc/scribblings/foreign/vm.scrbl
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
#lang scribble/doc
|
||||||
|
@(require "utils.rkt" (for-label ffi/unsafe/vm
|
||||||
|
racket/linklet))
|
||||||
|
|
||||||
|
@title[#:tag "vm"]{Virtual Machine Primitives}
|
||||||
|
|
||||||
|
@defmodule[ffi/unsafe/vm]{The
|
||||||
|
@racketmodname[ffi/unsafe/vm] library provides access to functionality
|
||||||
|
in the underlying virtual machine that is used to implement Racket.}
|
||||||
|
|
||||||
|
@history[#:added "7.6.0.7"]
|
||||||
|
|
||||||
|
@defproc[(vm-primitive [name symbol?]) any/c]{
|
||||||
|
|
||||||
|
Accesses a primitive values at the level of the running Racket virtual
|
||||||
|
machine, or returns @racket[#f] if @racket[name] is not the name of a
|
||||||
|
primitive.
|
||||||
|
|
||||||
|
Virtual-machine primitives are the ones that can be referenced in a
|
||||||
|
@tech[#:doc reference.scrbl]{linklet} body. The specific set of
|
||||||
|
primitives depends on the virtual machine. Many ``primitives'' at the
|
||||||
|
@racketmodname[racket/base] level are not primitives at the
|
||||||
|
virtual-machine level. For example, if @racket['eval] is available as
|
||||||
|
a primitive, it is not the @racket[eval] from
|
||||||
|
@racketmodname[racket/base].
|
||||||
|
|
||||||
|
In general, primitives are unsafe and can only be used with enough
|
||||||
|
knowledge about Racket's implementation. Here are some tips for
|
||||||
|
currently available virtual machines:
|
||||||
|
|
||||||
|
@itemlist[
|
||||||
|
|
||||||
|
@item{@racket[(system-type 'vm)] is @racket['racket] --- The
|
||||||
|
primitives in this virtual machine are mostly the same as the
|
||||||
|
ones available from libraries like @racketmodname[racket/base]
|
||||||
|
and @racketmodname[racket/unsafe/ops]. As a result, accessing
|
||||||
|
virtual machine primitives with @racket[vm-primitive] is rarely
|
||||||
|
useful.}
|
||||||
|
|
||||||
|
@item{@racket[(system-type 'vm)] is @racket['chez-scheme] --- The
|
||||||
|
primitives in this virtual machine are Chez Scheme primitives,
|
||||||
|
except as replaced by a Racket compatibility layer. The
|
||||||
|
@racket['eval] primitive is Chez Scheme's @racketidfont{eval}.
|
||||||
|
|
||||||
|
Beware of directly calling a Chez Scheme primitive that uses
|
||||||
|
Chez Scheme parameters or @racketidfont{dynamic-wind}
|
||||||
|
internally. Note that @racketidfont{eval}, in particular, is
|
||||||
|
such a primitive. The problem is that Chez Scheme's
|
||||||
|
@racketidfont{dynamic-wind} does not automatically cooperate
|
||||||
|
with Racket's continuations or threads. To call such
|
||||||
|
primitives, use the @racketidfont{call-with-system-wind}
|
||||||
|
primitive, which takes a procedure of no arguments to run in a
|
||||||
|
context that bridges Chez Scheme's @racketidfont{dynamic-wind}
|
||||||
|
and Racket continuations and threads. For example,
|
||||||
|
|
||||||
|
@racketblock[
|
||||||
|
(define primitive-eval (vm-primitive 'eval))
|
||||||
|
(define call-with-system-wind (vm-primitive 'call-with-system-wind))
|
||||||
|
(define (vm-eval s)
|
||||||
|
(call-with-system-wind
|
||||||
|
(lambda ()
|
||||||
|
(primitive-eval s))))
|
||||||
|
]
|
||||||
|
|
||||||
|
is how @racket[vm-eval] is implemented on Chez Scheme.
|
||||||
|
|
||||||
|
Symbols, numbers, booleans, pairs, vectors, boxes, strings,
|
||||||
|
byte strings (i.e., bytevectors), and structures (i.e.,
|
||||||
|
records) are interchangeable between Racket and Chez Scheme. A
|
||||||
|
Chez Scheme procedure is a Racket procedure, but not all Racket
|
||||||
|
procedures are Chez Scheme procedures. To call a Racket
|
||||||
|
procedure from Chez Scheme, use the @racketidfont{#%app} form
|
||||||
|
that is defined in the Chez Scheme environment when it hosts
|
||||||
|
Racket.
|
||||||
|
|
||||||
|
Note that you can access Chez Scheme primitives, includes ones
|
||||||
|
that are shadowed by Racket's primitives, through the Chez
|
||||||
|
Scheme @racketidfont{$primitive} form. For example,
|
||||||
|
@racket[(vm-eval '($primitive call-with-current-continuation))]
|
||||||
|
accesses the Chez Scheme
|
||||||
|
@racketidfont{call-with-current-continuation} primitive instead
|
||||||
|
of Racket's replacement (where the replacement works with
|
||||||
|
Racket continuations and threads).}
|
||||||
|
|
||||||
|
]}
|
||||||
|
|
||||||
|
@defproc[(vm-eval [s-expr any/c]) any/c]{
|
||||||
|
|
||||||
|
Evaluates @racket[s-expr] using the most primitive available evaluator:
|
||||||
|
|
||||||
|
@itemlist[
|
||||||
|
|
||||||
|
@item{@racket[(system-type 'vm)] is @racket['racket] --- Uses
|
||||||
|
@racket[compile-linklet] and @racket[instantiate-linklet].}
|
||||||
|
|
||||||
|
@item{@racket[(system-type 'vm)] is @racket['chez-scheme] --- Uses
|
||||||
|
Chez Scheme's @racketidfont{eval}.}
|
||||||
|
|
||||||
|
]
|
||||||
|
|
||||||
|
See @racket[vm-primitive] for some information about bow
|
||||||
|
virtual-machine primitives interact with Racket.}
|
|
@ -805,6 +805,7 @@
|
||||||
[else
|
[else
|
||||||
(error 'zo-parse "bad file format specifier")]))
|
(error 'zo-parse "bad file format specifier")]))
|
||||||
|
|
||||||
|
;; returns a hash table representing linklet bundle content
|
||||||
(define (zo-parse-top port vm [check-end? #t])
|
(define (zo-parse-top port vm [check-end? #t])
|
||||||
|
|
||||||
;; Skip module hash code
|
;; Skip module hash code
|
||||||
|
|
23
racket/collects/ffi/unsafe/vm.rkt
Normal file
23
racket/collects/ffi/unsafe/vm.rkt
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#lang racket/base
|
||||||
|
(require '#%linklet)
|
||||||
|
|
||||||
|
(provide (protect-out vm-primitive
|
||||||
|
vm-eval))
|
||||||
|
|
||||||
|
(define (vm-primitive sym)
|
||||||
|
(unless (symbol? sym)
|
||||||
|
(raise-syntax-error 'vm-primitive "symbol?" sym))
|
||||||
|
(primitive-lookup sym))
|
||||||
|
|
||||||
|
(define (vm-eval s)
|
||||||
|
(case (system-type 'vm)
|
||||||
|
[(chez-scheme)
|
||||||
|
(define primitive-eval (vm-primitive 'eval))
|
||||||
|
(define call-with-system-wind (vm-primitive 'call-with-system-wind))
|
||||||
|
(call-with-system-wind
|
||||||
|
(lambda ()
|
||||||
|
(primitive-eval s)))]
|
||||||
|
[else
|
||||||
|
(instantiate-linklet (compile-linklet `(linklet () () ,s))
|
||||||
|
null
|
||||||
|
(make-instance 'eval))]))
|
|
@ -42,6 +42,7 @@
|
||||||
primitive->compiled-position
|
primitive->compiled-position
|
||||||
compiled-position->primitive
|
compiled-position->primitive
|
||||||
primitive-in-category?
|
primitive-in-category?
|
||||||
|
primitive-lookup
|
||||||
|
|
||||||
omit-debugging? ; not exported to racket
|
omit-debugging? ; not exported to racket
|
||||||
platform-independent-zo-mode? ; not exported to racket
|
platform-independent-zo-mode? ; not exported to racket
|
||||||
|
@ -150,6 +151,15 @@
|
||||||
(define (compiled-position->primitive pos) #f)
|
(define (compiled-position->primitive pos) #f)
|
||||||
(define (primitive-in-category? sym cat) #f)
|
(define (primitive-in-category? sym cat) #f)
|
||||||
|
|
||||||
|
(define (primitive-lookup sym)
|
||||||
|
(unless (symbol? sym)
|
||||||
|
(raise-argument-error 'primitive-lookup "symbol?" sym))
|
||||||
|
(call-with-system-wind
|
||||||
|
(lambda ()
|
||||||
|
(guard
|
||||||
|
(c [else #f])
|
||||||
|
(eval sym)))))
|
||||||
|
|
||||||
(define root-logger (|#%app| current-logger))
|
(define root-logger (|#%app| current-logger))
|
||||||
|
|
||||||
(define omit-debugging? (not (getenv "PLT_CS_DEBUG")))
|
(define omit-debugging? (not (getenv "PLT_CS_DEBUG")))
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
[make-instance (known-procedure -2)]
|
[make-instance (known-procedure -2)]
|
||||||
[primitive->compiled-position (known-procedure 2)]
|
[primitive->compiled-position (known-procedure 2)]
|
||||||
[primitive-table (known-procedure 6)]
|
[primitive-table (known-procedure 6)]
|
||||||
|
[primitive-lookup (known-procedure 2)]
|
||||||
[linklet-virtual-machine-bytes (known-procedure 1)]
|
[linklet-virtual-machine-bytes (known-procedure 1)]
|
||||||
[read-linklet-bundle-hash (known-procedure 2)]
|
[read-linklet-bundle-hash (known-procedure 2)]
|
||||||
[write-linklet-bundle-hash (known-procedure 2)]
|
[write-linklet-bundle-hash (known-procedure 2)]
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
primitive->compiled-position
|
primitive->compiled-position
|
||||||
compiled-position->primitive
|
compiled-position->primitive
|
||||||
primitive-in-category?
|
primitive-in-category?
|
||||||
|
primitive-lookup
|
||||||
|
|
||||||
linklet?
|
linklet?
|
||||||
compile-linklet ; result is serializable
|
compile-linklet ; result is serializable
|
||||||
|
|
|
@ -135,6 +135,8 @@
|
||||||
(define (compiled-position->primitive pos) #f)
|
(define (compiled-position->primitive pos) #f)
|
||||||
(define (primitive-in-category? name cat-sym) #f)
|
(define (primitive-in-category? name cat-sym) #f)
|
||||||
|
|
||||||
|
(define (primitive-lookup sym) #f)
|
||||||
|
|
||||||
;; ----------------------------------------
|
;; ----------------------------------------
|
||||||
|
|
||||||
(struct variable-reference (instance primitive-varref))
|
(struct variable-reference (instance primitive-varref))
|
||||||
|
|
|
@ -32,6 +32,7 @@ static Scheme_Object *primitive_table(int argc, Scheme_Object **argv);
|
||||||
static Scheme_Object *primitive_to_position(int argc, Scheme_Object **argv);
|
static Scheme_Object *primitive_to_position(int argc, Scheme_Object **argv);
|
||||||
static Scheme_Object *position_to_primitive(int argc, Scheme_Object **argv);
|
static Scheme_Object *position_to_primitive(int argc, Scheme_Object **argv);
|
||||||
static Scheme_Object *primitive_in_category_p(int argc, Scheme_Object **argv);
|
static Scheme_Object *primitive_in_category_p(int argc, Scheme_Object **argv);
|
||||||
|
static Scheme_Object *primitive_lookup(int argc, Scheme_Object **argv);
|
||||||
|
|
||||||
static Scheme_Object *linklet_p(int argc, Scheme_Object **argv);
|
static Scheme_Object *linklet_p(int argc, Scheme_Object **argv);
|
||||||
static Scheme_Object *compile_linklet(int argc, Scheme_Object **argv);
|
static Scheme_Object *compile_linklet(int argc, Scheme_Object **argv);
|
||||||
|
@ -130,6 +131,7 @@ void scheme_init_linklet(Scheme_Startup_Env *env)
|
||||||
ADD_IMMED_PRIM("primitive->compiled-position", primitive_to_position, 1, 1, env);
|
ADD_IMMED_PRIM("primitive->compiled-position", primitive_to_position, 1, 1, env);
|
||||||
ADD_IMMED_PRIM("compiled-position->primitive", position_to_primitive, 1, 1, env);
|
ADD_IMMED_PRIM("compiled-position->primitive", position_to_primitive, 1, 1, env);
|
||||||
ADD_IMMED_PRIM("primitive-in-category?", primitive_in_category_p, 2, 2, env);
|
ADD_IMMED_PRIM("primitive-in-category?", primitive_in_category_p, 2, 2, env);
|
||||||
|
ADD_IMMED_PRIM("primitive-lookup", primitive_lookup, 1, 1, env);
|
||||||
|
|
||||||
ADD_FOLDING_PRIM("linklet?", linklet_p, 1, 1, 1, env);
|
ADD_FOLDING_PRIM("linklet?", linklet_p, 1, 1, 1, env);
|
||||||
ADD_PRIM_W_ARITY2("compile-linklet", compile_linklet, 1, 5, 2, 2, env);
|
ADD_PRIM_W_ARITY2("compile-linklet", compile_linklet, 1, 5, 2, 2, env);
|
||||||
|
@ -310,6 +312,18 @@ static Scheme_Object *primitive_in_category_p(int argc, Scheme_Object **argv)
|
||||||
return (r ? scheme_true : scheme_false);
|
return (r ? scheme_true : scheme_false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Scheme_Object *primitive_lookup(int argc, Scheme_Object **argv)
|
||||||
|
{
|
||||||
|
Scheme_Object *v;
|
||||||
|
|
||||||
|
if (!SCHEME_SYMBOLP(argv[0]))
|
||||||
|
scheme_wrong_contract("primitive-lookup", "symbol?", 0, argc, argv);
|
||||||
|
|
||||||
|
v = scheme_hash_get(scheme_startup_env->all_primitives_table, argv[0]);
|
||||||
|
|
||||||
|
return (v ? v : scheme_false);
|
||||||
|
}
|
||||||
|
|
||||||
static Scheme_Object *linklet_p(int argc, Scheme_Object **argv)
|
static Scheme_Object *linklet_p(int argc, Scheme_Object **argv)
|
||||||
{
|
{
|
||||||
return (SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_linklet_type)
|
return (SAME_TYPE(SCHEME_TYPE(argv[0]), scheme_linklet_type)
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
#define USE_COMPILED_STARTUP 1
|
#define USE_COMPILED_STARTUP 1
|
||||||
|
|
||||||
#define EXPECTED_PRIM_COUNT 1464
|
#define EXPECTED_PRIM_COUNT 1465
|
||||||
|
|
||||||
#ifdef MZSCHEME_SOMETHING_OMITTED
|
#ifdef MZSCHEME_SOMETHING_OMITTED
|
||||||
# undef USE_COMPILED_STARTUP
|
# undef USE_COMPILED_STARTUP
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#define MZSCHEME_VERSION_X 7
|
#define MZSCHEME_VERSION_X 7
|
||||||
#define MZSCHEME_VERSION_Y 6
|
#define MZSCHEME_VERSION_Y 6
|
||||||
#define MZSCHEME_VERSION_Z 0
|
#define MZSCHEME_VERSION_Z 0
|
||||||
#define MZSCHEME_VERSION_W 6
|
#define MZSCHEME_VERSION_W 7
|
||||||
|
|
||||||
/* A level of indirection makes `#` work as needed: */
|
/* A level of indirection makes `#` work as needed: */
|
||||||
#define AS_a_STR_HELPER(x) #x
|
#define AS_a_STR_HELPER(x) #x
|
||||||
|
|
|
@ -12382,6 +12382,7 @@ static const char *startup_source =
|
||||||
"(define-values(1/primitive->compiled-position) primitive->compiled-position)"
|
"(define-values(1/primitive->compiled-position) primitive->compiled-position)"
|
||||||
"(define-values(1/compiled-position->primitive) compiled-position->primitive)"
|
"(define-values(1/compiled-position->primitive) compiled-position->primitive)"
|
||||||
"(define-values(1/primitive-in-category?) primitive-in-category?)"
|
"(define-values(1/primitive-in-category?) primitive-in-category?)"
|
||||||
|
"(define-values(1/primitive-lookup) primitive-lookup)"
|
||||||
"(define-values(1/linklet?) linklet?)"
|
"(define-values(1/linklet?) linklet?)"
|
||||||
"(define-values(1/compile-linklet) compile-linklet)"
|
"(define-values(1/compile-linklet) compile-linklet)"
|
||||||
"(define-values(1/recompile-linklet) recompile-linklet)"
|
"(define-values(1/recompile-linklet) recompile-linklet)"
|
||||||
|
@ -46163,7 +46164,7 @@ static const char *startup_source =
|
||||||
"(void))"
|
"(void))"
|
||||||
" new-s_0)))))))))))"
|
" new-s_0)))))))))))"
|
||||||
"(case-lambda"
|
"(case-lambda"
|
||||||
"((s_0)(do-make-syntax-introducer_0 s_0 'flip))"
|
"((s_0)(begin 'do-make-syntax-introducer(do-make-syntax-introducer_0 s_0 'flip)))"
|
||||||
"((s_0 mode56_0)(do-make-syntax-introducer_0 s_0 mode56_0)))))))"
|
"((s_0 mode56_0)(do-make-syntax-introducer_0 s_0 mode56_0)))))))"
|
||||||
"(define-values"
|
"(define-values"
|
||||||
"(1/make-syntax-delta-introducer)"
|
"(1/make-syntax-delta-introducer)"
|
||||||
|
@ -46313,7 +46314,10 @@ static const char *startup_source =
|
||||||
"(void))"
|
"(void))"
|
||||||
" new-s_0))))))))))"
|
" new-s_0))))))))))"
|
||||||
"(case-lambda"
|
"(case-lambda"
|
||||||
"((s_0)(make-syntax-delta-introducer_0 s_0 'add))"
|
"((s_0)"
|
||||||
|
"(begin"
|
||||||
|
" 'make-syntax-delta-introducer"
|
||||||
|
"(make-syntax-delta-introducer_0 s_0 'add)))"
|
||||||
"((s_0 mode63_0)"
|
"((s_0 mode63_0)"
|
||||||
"(make-syntax-delta-introducer_0"
|
"(make-syntax-delta-introducer_0"
|
||||||
" s_0"
|
" s_0"
|
||||||
|
@ -64985,6 +64989,8 @@ static const char *startup_source =
|
||||||
" 1/compiled-position->primitive"
|
" 1/compiled-position->primitive"
|
||||||
" 'primitive-in-category?"
|
" 'primitive-in-category?"
|
||||||
" 1/primitive-in-category?"
|
" 1/primitive-in-category?"
|
||||||
|
" 'primitive-lookup"
|
||||||
|
" 1/primitive-lookup"
|
||||||
" 'linklet?"
|
" 'linklet?"
|
||||||
" 1/linklet?"
|
" 1/linklet?"
|
||||||
" 'compile-linklet"
|
" 'compile-linklet"
|
||||||
|
@ -72914,7 +72920,7 @@ static const char *startup_source =
|
||||||
"(parsed-top-id4.1 id_0 b_0 #f)"
|
"(parsed-top-id4.1 id_0 b_0 #f)"
|
||||||
" s_0)))))))))))))))))))))))"
|
" s_0)))))))))))))))))))))))"
|
||||||
"(case-lambda"
|
"(case-lambda"
|
||||||
"((s_0 ctx_0)(...nder/expand/expr.rkt:562:1_0 s_0 ctx_0 #f))"
|
"((s_0 ctx_0)(begin '...nder/expand/expr.rkt:562:1(...nder/expand/expr.rkt:562:1_0 s_0 ctx_0 #f)))"
|
||||||
"((s_0 ctx_0 implicit-omitted?362_0)(...nder/expand/expr.rkt:562:1_0 s_0 ctx_0 implicit-omitted?362_0))))))"
|
"((s_0 ctx_0 implicit-omitted?362_0)(...nder/expand/expr.rkt:562:1_0 s_0 ctx_0 implicit-omitted?362_0))))))"
|
||||||
"(void"
|
"(void"
|
||||||
"(add-core-form!*"
|
"(add-core-form!*"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user