bytecode validator: check "constant" annotations on variable references

Bytecode changes in two small ways to help the validator:
 * a cross-module variable reference preserves the compiler's
   annotation on whether the reference is constant, fixed, or other
 * lifted procedures now appear in the module body just before the
   definitions that use them, instead of at the beginning of the
   module body
This commit is contained in:
Matthew Flatt 2012-10-19 07:09:56 -06:00
parent 839408e6f7
commit e59066debe
18 changed files with 1727 additions and 1300 deletions

View File

@ -73,7 +73,7 @@
[(? symbol?) (string->symbol (format "_~a" tl))]
[(struct global-bucket (name))
(string->symbol (format "_~a" name))]
[(struct module-variable (modidx sym pos phase))
[(struct module-variable (modidx sym pos phase constantness))
(if (and (module-path-index? modidx)
(let-values ([(n b) (module-path-index-split modidx)])
(and (not n) (not b))))

View File

@ -59,7 +59,7 @@
(define (compute-new-modvar mv rw)
(match mv
[(struct module-variable (modidx sym pos phase))
[(struct module-variable (modidx sym pos phase constantness))
(match rw
[(struct modvar-rewrite (self-modidx provide->toplevel))
(log-debug (format "Rewriting ~a of ~S" pos (mpi->path* modidx)))
@ -76,7 +76,7 @@
[remap empty])
([tl (in-list mod-toplevels)])
(match tl
[(and mv (struct module-variable (modidx sym pos phase)))
[(and mv (struct module-variable (modidx sym pos phase constantness)))
(define rw ((current-get-modvar-rewrite) modidx))
; XXX We probably don't need to deal with #f phase
(unless (or (not phase) (zero? phase))

View File

@ -118,7 +118,7 @@
(define new-prefix prefix)
; Cache all the mpi paths
(for-each (match-lambda
[(and mv (struct module-variable (modidx sym pos phase)))
[(and mv (struct module-variable (modidx sym pos phase constantness)))
(mpi->path! modidx)]
[tl
(void)])

View File

@ -603,10 +603,14 @@
(out-byte CPT_FALSE out)]
[(? void?)
(out-byte CPT_VOID out)]
[(struct module-variable (modidx sym pos phase))
[(struct module-variable (modidx sym pos phase constantness))
(out-byte CPT_MODULE_VAR out)
(out-anything modidx out)
(out-anything sym out)
(case constantness
[(constant) (out-number -4 out)]
[(fixed) (out-number -5 out)]
[else (void)])
(unless (zero? phase)
(out-number -2 out)
(out-number phase out))

View File

@ -857,11 +857,21 @@
(let ([mod (read-compact cp)]
[var (read-compact cp)]
[pos (read-compact-number cp)])
(let-values ([(mod-phase pos)
(if (= pos -2)
(values (read-compact-number cp) (read-compact-number cp))
(values 0 pos))])
(make-module-variable mod var pos mod-phase)))]
(let-values ([(flags mod-phase pos)
(let loop ([pos pos])
(cond
[(pos . < . -3)
(let ([real-pos (read-compact-number cp)])
(define-values (_ m p) (loop real-pos))
(values (- (+ pos 3)) m p))]
[(= pos -2)
(values 0 (read-compact-number cp) (read-compact-number cp))]
[else (values 0 0 pos)]))])
(make-module-variable mod var pos mod-phase
(cond
[(not (zero? (bitwise-and #x1 flags))) 'constant]
[(not (zero? (bitwise-and #x2 flags))) 'fixed]
[else #f]))))]
[(local-unbox)
(let* ([p* (read-compact-number cp)]
[p (if (< p* 0) (- (add1 p*)) p*)]

View File

@ -43,7 +43,8 @@
(define-form-struct module-variable ([modidx module-path-index?]
[sym symbol?]
[pos exact-integer?]
[phase exact-nonnegative-integer?]))
[phase exact-nonnegative-integer?]
[constantness (or/c #f 'constant 'fixed)]))
;; Syntax object
(define ((alist/c k? v?) l)

View File

@ -72,12 +72,19 @@ structures that are produced by @racket[zo-parse] and consumed by
([modidx module-path-index?]
[sym symbol?]
[pos exact-integer?]
[phase exact-nonnegative-integer?])]{
[phase exact-nonnegative-integer?]
[constantness (or/c #f 'constant 'fixed)])]{
Represents a top-level variable, and used only in a @racket[prefix].
The @racket[pos] may record the variable's offset within its module,
or it can be @racket[-1] if the variable is always located by name.
The @racket[phase] indicates the phase level of the definition within
its module.}
its module. The @racket[constantness] field is either @racket['constant]
to indicate that
variable's value is always the same for every instantiation of its module,
@racket['fixed] to indicate
that it doesn't change within a particular instantiation of the module,
or @racket[#f] to indicate that the variable's value
can change even for one particular instantiation of its module.}
@defstruct+[(stx zo) ([encoded wrapped?])]{

View File

@ -6,7 +6,8 @@
(require racket/flonum
racket/fixnum
racket/unsafe/ops
compiler/zo-parse)
compiler/zo-parse
compiler/zo-marshal)
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -2219,5 +2220,65 @@
(test #t (dynamic-require ''check-tail-call-by-jit-for-struct-predicate 'go))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Test bytecode validator's checking of constantness
(let ()
(define c1
'(module c1 racket/base
(void ((if (zero? (random 1))
(lambda (f) (displayln (f)))
#f)
(lambda ()
;; This access of i should raise an exception:
i)))
(define i (random 1))))
(define o (open-output-bytes))
(parameterize ([current-namespace (make-base-namespace)])
(write (compile c1) o))
(define m (zo-parse (open-input-bytes (get-output-bytes o))))
(define o2 (open-output-bytes))
;; construct bytecode that is broken by claiming that `i' is constant
;; in the too-early reference:
(void
(write-bytes
(zo-marshal
(match m
[(compilation-top max-let-depth prefix code)
(compilation-top max-let-depth prefix
(let ([body (mod-body code)])
(struct-copy mod code [body
(match body
[(list a b)
(list (match a
[(application rator (list rand))
(application
rator
(list
(match rand
[(application rator (list rand))
(application
rator
(list
(struct-copy
lam rand
[body
(match (lam-body rand)
[(toplevel depth pos const? ready?)
(toplevel depth pos #t #t)])])))])))])
b)])])))]))
o2))
;; validator should reject this at read or eval time (depending on how lazy validation is):
(err/rt-test (parameterize ([current-namespace (make-base-namespace)]
[read-accept-compiled #t])
(eval (read (open-input-bytes (get-output-bytes o2)))))
exn:fail:read?))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(report-errs)

View File

@ -1,3 +1,6 @@
Version 5.3.1.2
compiler/zo-structs: added a constantness field to module-variable
Version 5.3.1.1
Added arguments to impersonate-prompt-tag and chaperone-prompt-tag
to support interposition on non-composable continuation results

File diff suppressed because it is too large Load Diff

View File

@ -787,7 +787,8 @@ static Scheme_Object *link_module_variable(Scheme_Object *modidx,
int pos, int mod_phase,
Scheme_Env *env,
Scheme_Object **exprs, int which,
char *import_map)
char *import_map,
int flags)
{
Scheme_Object *modname;
Scheme_Env *menv;
@ -840,14 +841,35 @@ static Scheme_Object *link_module_variable(Scheme_Object *modidx,
bkt = scheme_global_bucket(varname, menv);
if (!self) {
const char *bad_reason = NULL;
if (!bkt->val) {
bad_reason = "uninitialized";
} else if (flags) {
if (flags & SCHEME_MODVAR_CONST) {
/* The fact that the link target is consistent is a fine
sanity check, but the check is not good enough for the JIT
to rely on it. To be useful for the JIT, we'd have to make
sure that every link goes to the same value. Since we can't
currently guarantee that, all the JIT assumes is that the
value is "fixed". */
if (!(((Scheme_Bucket_With_Flags *)bkt)->flags & GLOB_IS_CONSISTENT))
bad_reason = "not constant across all instantiations";
} else {
if (!(((Scheme_Bucket_With_Flags *)bkt)->flags & GLOB_IS_IMMUTATED))
bad_reason = "not constant";
}
}
if (bad_reason) {
scheme_wrong_syntax("link", NULL, varname,
"bad variable linkage;\n"
" reference to a variable that is uninitialized\n"
" reference to a variable that is %s\n"
" reference phase level: %d\n"
" variable module: %D\n"
" variable phase: %d\n"
" reference in module: %D",
bad_reason,
env->phase,
modname,
mod_phase,
@ -909,7 +931,8 @@ static Scheme_Object *link_toplevel(Scheme_Object **exprs, int which, Scheme_Env
-1, mod_phase,
env,
NULL, 0,
import_map);
import_map,
0);
} else if (SAME_TYPE(SCHEME_TYPE(expr), scheme_variable_type)) {
Scheme_Bucket *b = (Scheme_Bucket *)expr;
Scheme_Env *home;
@ -925,7 +948,7 @@ static Scheme_Object *link_toplevel(Scheme_Object **exprs, int which, Scheme_Env
-1, home->mod_phase,
env,
exprs, which,
import_map);
import_map, 0);
} else {
Module_Variable *mv = (Module_Variable *)expr;
@ -939,7 +962,8 @@ static Scheme_Object *link_toplevel(Scheme_Object **exprs, int which, Scheme_Env
mv->pos, mv->mod_phase,
env,
exprs, which,
import_map);
import_map,
SCHEME_MODVAR_FLAGS(mv) & 0x3);
}
}
@ -1924,7 +1948,8 @@ define_execute_with_dynamic_state(Scheme_Object *vec, int delta, int defmacro,
int flags = GLOB_IS_IMMUTATED;
if (SCHEME_PROCP(vals_expr)
|| SAME_TYPE(SCHEME_TYPE(vals_expr), scheme_unclosed_procedure_type)
|| SAME_TYPE(SCHEME_TYPE(vals_expr), scheme_case_lambda_sequence_type))
|| SAME_TYPE(SCHEME_TYPE(vals_expr), scheme_case_lambda_sequence_type)
|| SAME_TYPE(SCHEME_TYPE(vals_expr), scheme_inline_variant_type))
flags |= GLOB_IS_CONSISTENT;
((Scheme_Bucket_With_Flags *)b)->flags |= flags;
}
@ -2401,6 +2426,10 @@ void scheme_delay_load_closure(Scheme_Closure_Data *data)
(SCHEME_TRUEP(SCHEME_VEC_ELS(vinfo)[8])
? (void *)SCHEME_VEC_ELS(vinfo)[8]
: NULL),
(SCHEME_TRUEP(SCHEME_VEC_ELS(vinfo)[9])
? (mzshort *)(SCHEME_VEC_ELS(vinfo)[9])
: NULL),
SCHEME_INT_VAL(SCHEME_VEC_ELS(vinfo)[10]),
SCHEME_INT_VAL(SCHEME_VEC_ELS(vinfo)[6]),
(SCHEME_TRUEP(SCHEME_VEC_ELS(vinfo)[7])
? (Scheme_Hash_Tree *)SCHEME_VEC_ELS(vinfo)[7]
@ -4000,6 +4029,7 @@ static void *compile_k(void)
top->prefix->num_stxes,
top->prefix->num_lifts,
NULL,
NULL,
0);
}
}

View File

@ -202,6 +202,24 @@ static void note_match(int actual, int expected, Optimize_Info *warn_info)
}
}
int scheme_is_functional_primitive(Scheme_Object *rator, int num_args, int expected_vals)
/* return 2 => results are a constant when arguments are constants */
{
if (SCHEME_PRIMP(rator)
&& (SCHEME_PRIM_PROC_FLAGS(rator) & (SCHEME_PRIM_IS_OMITABLE | SCHEME_PRIM_IS_UNSAFE_NONMUTATING))
&& (num_args >= ((Scheme_Primitive_Proc *)rator)->mina)
&& (num_args <= ((Scheme_Primitive_Proc *)rator)->mu.maxa)
&& ((expected_vals < 0)
|| ((expected_vals == 1) && !(SCHEME_PRIM_PROC_FLAGS(rator) & SCHEME_PRIM_IS_MULTI_RESULT))
|| (SAME_OBJ(scheme_values_func, rator)
&& (expected_vals == num_args)))) {
if (SAME_OBJ(scheme_values_func, rator))
return 2;
return 1;
} else
return 0;
}
int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved,
Optimize_Info *warn_info, int deeper_than, int no_id)
/* Checks whether the bytecode `o' returns `vals' values with no
@ -373,13 +391,7 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved,
}
if (SCHEME_PRIMP(app->args[0])) {
if ((SCHEME_PRIM_PROC_FLAGS(app->args[0]) & (SCHEME_PRIM_IS_OMITABLE | SCHEME_PRIM_IS_UNSAFE_NONMUTATING))
&& (app->num_args >= ((Scheme_Primitive_Proc *)app->args[0])->mina)
&& (app->num_args <= ((Scheme_Primitive_Proc *)app->args[0])->mu.maxa)
&& ((vals < 0)
|| ((vals == 1) && !(SCHEME_PRIM_PROC_FLAGS(app->args[0]) & SCHEME_PRIM_IS_MULTI_RESULT))
|| (SAME_OBJ(scheme_values_func, app->args[0])
&& (vals == app->num_args)))) {
if (scheme_is_functional_primitive(app->args[0], app->num_args, vals)) {
int i;
for (i = app->num_args; i--; ) {
if (!scheme_omittable_expr(app->args[i + 1], 1, fuel - 1, resolved, warn_info,
@ -400,12 +412,7 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved,
if (vtype == scheme_application2_type) {
Scheme_App2_Rec *app = (Scheme_App2_Rec *)o;
if (SCHEME_PRIMP(app->rator)) {
if ((SCHEME_PRIM_PROC_FLAGS(app->rator) & (SCHEME_PRIM_IS_OMITABLE | SCHEME_PRIM_IS_UNSAFE_NONMUTATING))
&& (1 >= ((Scheme_Primitive_Proc *)app->rator)->mina)
&& (1 <= ((Scheme_Primitive_Proc *)app->rator)->mu.maxa)
&& ((vals < 0)
|| ((vals == 1) && !(SCHEME_PRIM_PROC_FLAGS(app->rator) & SCHEME_PRIM_IS_MULTI_RESULT))
|| ((vals == 1) && SAME_OBJ(scheme_values_func, app->rator)))) {
if (scheme_is_functional_primitive(app->rator, 1, vals)) {
if (scheme_omittable_expr(app->rand, 1, fuel - 1, resolved, warn_info,
deeper_than + (resolved ? 1 : 0), 0))
return 1;
@ -420,12 +427,7 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved,
if (vtype == scheme_application3_type) {
Scheme_App3_Rec *app = (Scheme_App3_Rec *)o;
if (SCHEME_PRIMP(app->rator)) {
if ((SCHEME_PRIM_PROC_FLAGS(app->rator) & (SCHEME_PRIM_IS_OMITABLE | SCHEME_PRIM_IS_UNSAFE_NONMUTATING))
&& (2 >= ((Scheme_Primitive_Proc *)app->rator)->mina)
&& (2 <= ((Scheme_Primitive_Proc *)app->rator)->mu.maxa)
&& ((vals < 0)
|| ((vals == 1) && !(SCHEME_PRIM_PROC_FLAGS(app->rator) & SCHEME_PRIM_IS_MULTI_RESULT))
|| ((vals == 2) && SAME_OBJ(scheme_values_func, app->rator)))) {
if (scheme_is_functional_primitive(app->rator, 2, vals)) {
if (scheme_omittable_expr(app->rand1, 1, fuel - 1, resolved, warn_info,
deeper_than + (resolved ? 2 : 0), 0)
&& scheme_omittable_expr(app->rand2, 1, fuel - 1, resolved, warn_info,
@ -1800,7 +1802,7 @@ static Scheme_Object *lookup_constant_proc(Optimize_Info *info, Scheme_Object *r
c = SCHEME_BOX_VAL(c);
while (SAME_TYPE(SCHEME_TYPE(c), scheme_compiled_let_void_type)) {
/* This must be (let ([x <proc>]) <proc>); see scheme_is_statically_proc() */
/* This must be (let ([x <omittable>]) <proc>); see scheme_is_statically_proc() */
Scheme_Let_Header *lh = (Scheme_Let_Header *)c;
Scheme_Compiled_Let_Value *lv = (Scheme_Compiled_Let_Value *)lh->body;
c = lv->body;
@ -3095,7 +3097,7 @@ int scheme_is_statically_proc(Scheme_Object *value, Optimize_Info *info)
else if (SAME_TYPE(SCHEME_TYPE(value), scheme_case_lambda_sequence_type)) {
return 1;
} else if (SAME_TYPE(SCHEME_TYPE(value), scheme_compiled_let_void_type)) {
/* Look for (let ([x <proc>]) <proc>), which is generated for optional arguments. */
/* Look for (let ([x <omittable>]) <proc>), which is generated for optional arguments. */
Scheme_Let_Header *lh = (Scheme_Let_Header *)value;
if (lh->num_clauses == 1) {
Scheme_Compiled_Let_Value *lv = (Scheme_Compiled_Let_Value *)lh->body;

View File

@ -2885,10 +2885,10 @@ print(Scheme_Object *obj, int notdisplay, int compact, Scheme_Hash_Table *ht,
if (idx) {
print_symtab_ref(pp, idx);
} else {
Module_Variable *mv;
Module_Variable *mv = (Module_Variable *)obj;
int flags = SCHEME_MODVAR_FLAGS(mv);
print_compact(pp, CPT_MODULE_VAR);
mv = (Module_Variable *)obj;
if (SAME_TYPE(SCHEME_TYPE(mv->modidx), scheme_resolved_module_path_type)
&& SCHEME_SYMBOLP(SCHEME_PTR_VAL(mv->modidx))) {
print(SCHEME_PTR_VAL(mv->modidx), notdisplay, 1, ht, mt, pp);
@ -2896,6 +2896,9 @@ print(Scheme_Object *obj, int notdisplay, int compact, Scheme_Hash_Table *ht,
print(mv->modidx, notdisplay, 1, ht, mt, pp);
}
print(mv->sym, notdisplay, 1, ht, mt, pp);
if (flags & 0x3) {
print_compact_number(pp, -3-(flags&0x3));
}
if (((Module_Variable *)obj)->mod_phase) {
print_compact_number(pp, -2);
print_compact_number(pp, mv->mod_phase);

View File

@ -4705,6 +4705,11 @@ static Scheme_Object *read_compact(CPort *port, int use_stack)
mod = scheme_intern_resolved_module_path(mod);
mv->modidx = mod;
mv->sym = var;
if (pos < -3) {
pos = -(pos + 3);
SCHEME_MODVAR_FLAGS(mv) = pos;
pos = read_compact_number(port);
}
if (pos == -2) {
pos = read_compact_number(port);
mv->mod_phase = pos;
@ -5366,6 +5371,7 @@ static Scheme_Object *read_compiled(Scheme_Object *port,
top->prefix->num_stxes,
top->prefix->num_lifts,
NULL,
NULL,
0);
/* If no exception, the resulting code is ok. */

View File

@ -2239,7 +2239,7 @@ static Scheme_Object *
module_expr_resolve(Scheme_Object *data, Resolve_Info *old_rslv)
{
Scheme_Module *m = (Scheme_Module *)data;
Scheme_Object *b, *lift_vec;
Scheme_Object *b, *lift_vec, *body = scheme_null;
Resolve_Prefix *rp;
Resolve_Info *rslv;
int i, cnt;
@ -2264,19 +2264,27 @@ module_expr_resolve(Scheme_Object *data, Resolve_Info *old_rslv)
for (i = 0; i < cnt; i++) {
Scheme_Object *e;
e = scheme_resolve_expr(SCHEME_VEC_ELS(m->bodies[0])[i], rslv);
SCHEME_VEC_ELS(m->bodies[0])[i] = e;
/* add lift just before the expression that introduced it;
this ordering is needed for bytecode validation of
constantness for top-level references */
lift_vec = rslv->lifts;
if (!SCHEME_NULLP(SCHEME_VEC_ELS(lift_vec)[0])) {
body = scheme_append(SCHEME_VEC_ELS(lift_vec)[0], body);
SCHEME_VEC_ELS(lift_vec)[0] = scheme_null;
}
body = scheme_make_pair(e, body);
}
m->max_let_depth = rslv->max_let_depth;
lift_vec = rslv->lifts;
if (!SCHEME_NULLP(SCHEME_VEC_ELS(lift_vec)[0])) {
b = scheme_append(SCHEME_VEC_ELS(lift_vec)[0], scheme_vector_to_list(m->bodies[0]));
b = scheme_list_to_vector(b);
m->bodies[0] = b;
}
rp->num_lifts = SCHEME_INT_VAL(SCHEME_VEC_ELS(lift_vec)[1]);
body = scheme_list_to_vector(scheme_reverse(body));
m->bodies[0] = body;
rp = scheme_remap_prefix(rp, rslv);
m->prefix = rp;

View File

@ -2346,21 +2346,6 @@ typedef struct Scheme_Object *
typedef struct CPort Mz_CPort;
typedef mzshort **Validate_TLS;
struct Validate_Clearing;
typedef void (*Scheme_Syntax_Validater)(Scheme_Object *data, Mz_CPort *port,
char *stack, Validate_TLS tls,
int depth, int letlimit, int delta,
int num_toplevels, int num_stxes, int num_lifts,
void *tl_use_map, int result_ignored,
struct Validate_Clearing *vc, int tailpos,
Scheme_Hash_Tree *procs);
typedef struct Scheme_Object *(*Scheme_Syntax_Executer)(struct Scheme_Object *data);
typedef struct Scheme_Object *(*Scheme_Syntax_Jitter)(struct Scheme_Object *data);
typedef struct Scheme_Closure_Data
{
Scheme_Inclhash_Object iso; /* keyex used for flags */
@ -2883,6 +2868,7 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved,
Optimize_Info *warn_info, int deeper_than, int no_id);
int scheme_might_invoke_call_cc(Scheme_Object *value);
int scheme_is_liftable(Scheme_Object *o, int bind_count, int fuel, int as_rator);
int scheme_is_functional_primitive(Scheme_Object *rator, int num_args, int expected_vals);
int scheme_is_env_variable_boxed(Scheme_Comp_Env *env, int which);
@ -2922,23 +2908,16 @@ Scheme_Env *scheme_environment_from_dummy(Scheme_Object *dummy);
void scheme_validate_code(Mz_CPort *port, Scheme_Object *code,
int depth,
int num_toplevels, int num_stxes, int num_lifts, void *tl_use_map,
Scheme_Object **toplevels,
int code_vec);
void scheme_validate_expr(Mz_CPort *port, Scheme_Object *expr,
char *stack, Validate_TLS tls,
int depth, int letlimit, int delta,
int num_toplevels, int num_stxes, int num_lifts, void *tl_use_map,
Scheme_Object *app_rator, int proc_with_refs_ok,
int result_ignored, struct Validate_Clearing *vc,
int tailpos, int need_flonum, Scheme_Hash_Tree *procs);
int scheme_validate_rator_wants_box(Scheme_Object *app_rator, int pos,
int hope,
Validate_TLS tls,
int num_toplevels, int num_stxes, int num_lifts, void *tl_use_map);
typedef mzshort **Validate_TLS;
struct Validate_Clearing;
void scheme_validate_closure(Mz_CPort *port, Scheme_Object *expr,
char *new_stack, Validate_TLS tls,
char *closure_stack, Validate_TLS tls,
int num_toplevels, int num_stxes, int num_lifts, void *tl_use_map,
mzshort *tl_state, mzshort tl_timestamp,
int self_pos_in_closure, Scheme_Hash_Tree *procs);
#define TRACK_ILL_FORMED_CATCH_LINES 1

View File

@ -13,12 +13,12 @@
consistently.)
*/
#define MZSCHEME_VERSION "5.3.1.1"
#define MZSCHEME_VERSION "5.3.1.2"
#define MZSCHEME_VERSION_X 5
#define MZSCHEME_VERSION_Y 3
#define MZSCHEME_VERSION_Z 1
#define MZSCHEME_VERSION_W 1
#define MZSCHEME_VERSION_W 2
#define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y)
#define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W)

File diff suppressed because it is too large Load Diff