diff --git a/pkgs/base/info.rkt b/pkgs/base/info.rkt index 87526ac8dc..effd327adf 100644 --- a/pkgs/base/info.rkt +++ b/pkgs/base/info.rkt @@ -12,7 +12,7 @@ (define collection 'multi) -(define version "6.4.0.7") +(define version "6.4.0.8") (define deps `("racket-lib" ["racket" #:version ,version])) diff --git a/pkgs/racket-test-core/tests/racket/optimize.rktl b/pkgs/racket-test-core/tests/racket/optimize.rktl index 8efbaf3a83..8854ef9bdc 100644 --- a/pkgs/racket-test-core/tests/racket/optimize.rktl +++ b/pkgs/racket-test-core/tests/racket/optimize.rktl @@ -879,20 +879,22 @@ )) -(define (comp=? c1 c2) +(define (comp=? c1 c2 want-same?) (let ([s1 (open-output-bytes)] [s2 (open-output-bytes)]) (write c1 s1) (write c2 s2) (let ([t1 (get-output-bytes s1)] [t2 (get-output-bytes s2)]) - (or (bytes=? t1 t2) - (begin - (printf "~s\n~s\n" - (zo-parse (open-input-bytes t1)) - (zo-parse (open-input-bytes t2))) - #f - ))))) + (define same? (bytes=? t1 t2)) + (when (and (not same?) want-same?) + (printf "~s\n~s\n" + (zo-parse (open-input-bytes t1)) + (zo-parse (open-input-bytes t2)))) + (unless (equal? same? want-same?) + ;; Unquote to cause a failure to stop + 'stop) + same?))) (define test-comp (case-lambda @@ -902,7 +904,7 @@ ;; Give `s` a minimal location, so that other macro locations ;; don't bleed through: (datum->syntax #f s (vector 'here #f #f #f #f))) - (test same? `(compile ,same? ,expr2) (comp=? (compile (->stx expr1)) (compile (->stx expr2))))])) + (test same? `(compile ,same? ,expr2) (comp=? (compile (->stx expr1)) (compile (->stx expr2)) same?))])) (let ([x (compile '(lambda (x) x))]) (test #t 'fixpt (eq? x (compile x)))) @@ -1742,7 +1744,6 @@ (begin (quote-syntax foo) 3))]) x) '3) - (test-comp '(if (lambda () 10) 'ok (quote-syntax no!)) @@ -2139,7 +2140,7 @@ (define z (random)) (define (f) (let-values ([(a b) (values (cons 1 z) (cons 2 z))]) - (list a b))) + (list b a))) (set! z 5))) '(module m racket/base ;; Reference to a ready module-level variable shouldn't @@ -2147,7 +2148,7 @@ (#%plain-module-begin (define z (random)) (define (f) - (list (cons 1 z) (cons 2 z))) + (list (cons 2 z) (cons 1 z))) (set! z 5))) #f) @@ -3095,38 +3096,45 @@ (test-comp '(lambda (n) (let ([p (fl+ n n)]) - (list + (list + p p (flonum? p) (flonum? (begin (random) p)) (flonum? (letrec ([x (lambda (t) x)]) (x x) p))))) '(lambda (n) (let ([p (fl+ n n)]) (list - #t + p p + #t (begin (random) #t) (letrec ([x (lambda (t) x)]) (x x) #t))))) + (test-comp '(lambda (n) (let ([p (fx+ n n)]) - (list + (list + p p (fixnum? p) (fixnum? (begin (random) p)) (fixnum? (letrec ([x (lambda (t) x)]) (x x) p))))) '(lambda (n) (let ([p (fx+ n n)]) (list + p p #t (begin (random) #t) (letrec ([x (lambda (t) x)]) (x x) #t))))) (test-comp '(lambda (n) (let ([p (extfl+ n n)]) - (list + (list + p p (extflonum? p) (extflonum? (begin (random) p)) (extflonum? (letrec ([x (lambda (t) x)]) (x x) p))))) '(lambda (n) (let ([p (extfl+ n n)]) (list - #t + p p + #t (begin (random) #t) (letrec ([x (lambda (t) x)]) (x x) #t))))) diff --git a/pkgs/racket-test/tests/generic/base-interfaces.rkt b/pkgs/racket-test/tests/generic/base-interfaces.rkt index 15deb83d9b..d3ea803b19 100644 --- a/pkgs/racket-test/tests/generic/base-interfaces.rkt +++ b/pkgs/racket-test/tests/generic/base-interfaces.rkt @@ -27,5 +27,5 @@ ;; ok if these don't raise unbound id errors (check-equal? (with-output-to-string (lambda () (write (tuple 5)))) "#0=#0#") (check-equal? (tuple 5) (tuple 5)) - (check-equal? (equal-hash-code (tuple 5)) 54) - (check-equal? (equal-secondary-hash-code (tuple 5)) 45)) + (check-equal? (equal-hash-code (tuple 5)) 55) + (check-equal? (equal-secondary-hash-code (tuple 5)) 46)) diff --git a/pkgs/racket-test/tests/generic/equal+hash.rkt b/pkgs/racket-test/tests/generic/equal+hash.rkt index a72707c6e8..8523d2bfd8 100644 --- a/pkgs/racket-test/tests/generic/equal+hash.rkt +++ b/pkgs/racket-test/tests/generic/equal+hash.rkt @@ -16,5 +16,5 @@ (check-false (equal? (kons 1 2) 2)) (check-false (equal? 2 (kons 1 2))) (check-false (equal? (kons 1 2) (kons 3 4))) - (check-equal? (equal-hash-code (kons 1 2)) 61) + (check-equal? (equal-hash-code (kons 1 2)) 62) ) diff --git a/racket/src/racket/src/compenv.c b/racket/src/racket/src/compenv.c index 7ee37f5a05..9402994feb 100644 --- a/racket/src/racket/src/compenv.c +++ b/racket/src/racket/src/compenv.c @@ -35,16 +35,12 @@ READ_ONLY static Scheme_Object *scheme_local[MAX_CONST_LOCAL_POS][MAX_CONST_LOCAL_TYPES][MAX_CONST_LOCAL_FLAG_VAL + 1]; READ_ONLY static Scheme_Object *toplevels[MAX_CONST_TOPLEVEL_DEPTH][MAX_CONST_TOPLEVEL_POS][SCHEME_TOPLEVEL_FLAGS_MASK + 1]; +ROSYM static Scheme_Object *undefined_error_name_symbol; + /* If locked, these are probably sharable: */ THREAD_LOCAL_DECL(static Scheme_Hash_Table *toplevels_ht); THREAD_LOCAL_DECL(static Scheme_Hash_Table *locals_ht[2]); -#define ARBITRARY_USE 0x1 -#define CONSTRAINED_USE 0x2 -#define WAS_SET_BANGED 0x4 -#define ONE_ARBITRARY_USE 0x8 -/* See also SCHEME_USE_COUNT_MASK */ - static void init_compile_data(Scheme_Comp_Env *env); static void init_scheme_local(); @@ -82,6 +78,8 @@ void scheme_init_compenv_places(void) void scheme_init_compenv_symbol(void) { + REGISTER_SO(undefined_error_name_symbol); + undefined_error_name_symbol = scheme_intern_symbol("undefined-error-name"); } /*========================================================================*/ @@ -223,20 +221,7 @@ void scheme_init_expand_observe(Scheme_Env *env) static void init_compile_data(Scheme_Comp_Env *env) { - int i, c, *use; - - c = env->num_bindings; - if (c) - use = MALLOC_N_ATOMIC(int, c); - else - use = NULL; - - env->use = use; - for (i = 0; i < c; i++) { - use[i] = 0; - } - - env->min_use = c; + env->max_use = -1; } Scheme_Comp_Env *scheme_new_compilation_frame(int num_bindings, int flags, Scheme_Object *scopes, Scheme_Comp_Env *base) @@ -339,16 +324,6 @@ int scheme_is_sub_env(Scheme_Comp_Env *stx_env, Scheme_Comp_Env *env) return SAME_OBJ(se, env); } -int scheme_used_ever(Scheme_Comp_Env *env, int which) -{ - return !!env->use[which]; -} - -int scheme_is_env_variable_boxed(Scheme_Comp_Env *env, int which) -{ - return !!(env->use[which] & WAS_SET_BANGED); -} - void scheme_add_compilation_binding(int index, Scheme_Object *val, Scheme_Comp_Env *frame) { @@ -901,36 +876,101 @@ Scheme_Object *scheme_make_local(Scheme_Type type, int pos, int flags) return v; } -static Scheme_Local *get_frame_loc(Scheme_Comp_Env *frame, - int i, int j, int p, int flags) -/* Generates a Scheme_Local record for a static distance coodinate, and also +static Scheme_Object *get_local_name(Scheme_Object *id) +{ + Scheme_Object *name; + + name = scheme_stx_property(id, undefined_error_name_symbol, NULL); + if (name && SCHEME_SYMBOLP(name)) + return name; + else + return SCHEME_STX_VAL(id); +} + +static Scheme_Compiled_Local *make_variable(Scheme_Object *id) +{ + Scheme_Compiled_Local *var; + + var = MALLOC_ONE_TAGGED(Scheme_Compiled_Local); + var->so.type = scheme_compiled_local_type; + if (id) { + id = get_local_name(id); + var->name = id; + } + + return var; +} + +static Scheme_Compiled_Local *get_frame_loc(Scheme_Comp_Env *frame, + int i, int j, int p, int flags) +/* Generates a Scheme_Compiled_Local record as needed, and also marks the variable as used for closures. */ { - int cnt, u; + if (!frame->vars) { + Scheme_Compiled_Local **vars; + vars = MALLOC_N(Scheme_Compiled_Local*, frame->num_bindings); + frame->vars = vars; + } - u = frame->use[i]; + if (!frame->vars[i]) { + Scheme_Compiled_Local *var; + var = make_variable(frame->binders ? frame->binders[i] : NULL); + frame->vars[i] = var; + } - // flags -= (flags & SCHEME_APP_POS); - - u |= (((flags & (SCHEME_APP_POS | SCHEME_SETTING)) - ? CONSTRAINED_USE - : ((u & (ARBITRARY_USE | ONE_ARBITRARY_USE)) ? ARBITRARY_USE : ONE_ARBITRARY_USE)) - | ((flags & (SCHEME_SETTING | SCHEME_LINKING_REF)) - ? WAS_SET_BANGED - : 0)); - - cnt = ((u & SCHEME_USE_COUNT_MASK) >> SCHEME_USE_COUNT_SHIFT); - if (cnt < SCHEME_USE_COUNT_INF) - cnt++; - u -= (u & SCHEME_USE_COUNT_MASK); - u |= (cnt << SCHEME_USE_COUNT_SHIFT); + if (frame->vars[i]->use_count < SCHEME_USE_COUNT_INF) + frame->vars[i]->use_count++; + if (flags & (SCHEME_SETTING | SCHEME_LINKING_REF)) + frame->vars[i]->mutated = 1; + if (!(flags & (SCHEME_APP_POS | SCHEME_SETTING))) + if (frame->vars[i]->non_app_count < SCHEME_USE_COUNT_INF) + frame->vars[i]->non_app_count++; - frame->use[i] = u; - if (i < frame->min_use) - frame->min_use = i; + if (i > frame->max_use) + frame->max_use = i; frame->any_use = 1; - return (Scheme_Local *)scheme_make_local(scheme_local_type, p + i, 0); + return frame->vars[i]; +} + +void scheme_env_make_variables(Scheme_Comp_Env *frame) +{ + Scheme_Compiled_Local *var, **vars; + int i; + + if (!frame->num_bindings) + return; + + if (!frame->vars) { + vars = MALLOC_N(Scheme_Compiled_Local*, frame->num_bindings); + frame->vars = vars; + } + + for (i = 0; i < frame->num_bindings; i++) { + if (!frame->vars[i]) { + var = make_variable(frame->binders ? frame->binders[i] : NULL); + frame->vars[i] = var; + } + } +} + +void scheme_set_compilation_variables(Scheme_Comp_Env *frame, Scheme_Compiled_Local **vars, + int pos, int count) +{ + int i; + + MZ_ASSERT((pos + count) <= frame->num_bindings); + + if (!frame->vars) { + Scheme_Compiled_Local **fvars; + fvars = MALLOC_N(Scheme_Compiled_Local*, frame->num_bindings); + frame->vars = fvars; + } + + for (i = 0; i < count; i++) { + MZ_ASSERT(!frame->vars[i+pos]); + frame->vars[i+pos] = vars[i]; + } } Scheme_Object *scheme_hash_module_variable(Scheme_Env *env, Scheme_Object *modidx, @@ -1155,7 +1195,7 @@ static void set_binder(Scheme_Object **_binder, Scheme_Object *ref, Scheme_Objec scheme_macro_id_type (id was bound to a rename-transformer), - scheme_local_type (id was lexical), + scheme_compiled_local_type (id was lexical), scheme_variable_type (id is a global or module-bound variable), or @@ -1263,7 +1303,7 @@ scheme_compile_lookup(Scheme_Object *find_id, Scheme_Comp_Env *env, int flags, if (!frame->vals) { if (flags & SCHEME_DONT_MARK_USE) - return scheme_make_local(scheme_local_type, p+i, 0); + return (Scheme_Object *)make_variable(NULL); else return (Scheme_Object *)get_frame_loc(frame, i, j, p, flags); } else { @@ -1279,7 +1319,7 @@ scheme_compile_lookup(Scheme_Object *find_id, Scheme_Comp_Env *env, int flags, /* Corresponds to a run-time binding (but will be replaced later through a renaming to a different binding) */ if (flags & (SCHEME_OUT_OF_CONTEXT_LOCAL | SCHEME_SETTING)) - return scheme_make_local(scheme_local_type, 0, 0); + return (Scheme_Object *)make_variable(NULL); return NULL; } @@ -1309,7 +1349,7 @@ scheme_compile_lookup(Scheme_Object *find_id, Scheme_Comp_Env *env, int flags, } if (flags & SCHEME_OUT_OF_CONTEXT_LOCAL) - return scheme_make_local(scheme_local_type, 0, 0); + return (Scheme_Object *)make_variable(NULL); return NULL; } else { @@ -1951,49 +1991,21 @@ int scheme_env_check_reset_any_use(Scheme_Comp_Env *frame) return any_use; } -int scheme_env_min_use_below(Scheme_Comp_Env *frame, int pos) +int scheme_env_max_use_above(Scheme_Comp_Env *frame, int pos) { - return frame->min_use < pos; + return frame->max_use >= pos; } void scheme_mark_all_use(Scheme_Comp_Env *frame) { /* Mark all variables as used for the purposes of `letrec-syntaxes+values` splitting */ - while (frame && (frame->min_use > -1)) { - frame->min_use = -1; + while (frame && (frame->max_use < frame->num_bindings)) { + frame->max_use = frame->num_bindings; frame = frame->next; } } -int *scheme_env_get_flags(Scheme_Comp_Env *frame, int start, int count) -{ - int *v, i; - - v = MALLOC_N_ATOMIC(int, count); - memcpy(v, frame->use + start, sizeof(int) * count); - - for (i = count; i--; ) { - int old; - old = v[i]; - v[i] = 0; - if (old & (ARBITRARY_USE | ONE_ARBITRARY_USE | CONSTRAINED_USE)) { - v[i] |= SCHEME_WAS_USED; - if (!(old & (ARBITRARY_USE | WAS_SET_BANGED))) { - if (old & ONE_ARBITRARY_USE) - v[i] |= SCHEME_WAS_APPLIED_EXCEPT_ONCE; - else - v[i] |= SCHEME_WAS_ONLY_APPLIED; - } - } - if (old & WAS_SET_BANGED) - v[i] |= SCHEME_WAS_SET_BANGED; - v[i] |= (old & SCHEME_USE_COUNT_MASK); - } - - return v; -} - /*========================================================================*/ /* macro hooks */ /*========================================================================*/ diff --git a/racket/src/racket/src/compile.c b/racket/src/racket/src/compile.c index 5aefc655d1..8630c152fc 100644 --- a/racket/src/racket/src/compile.c +++ b/racket/src/racket/src/compile.c @@ -65,8 +65,8 @@ ROSYM static Scheme_Object *letrec_syntaxes_symbol; ROSYM static Scheme_Object *values_symbol; ROSYM static Scheme_Object *call_with_values_symbol; ROSYM static Scheme_Object *inferred_name_symbol; -ROSYM static Scheme_Object *undefined_error_name_symbol; ROSYM static Scheme_Object *local_keyword; +ROSYM static Scheme_Object *existing_variables_symbol; THREAD_LOCAL_DECL(static Scheme_Object *quick_stx); @@ -179,10 +179,11 @@ void scheme_init_compile (Scheme_Env *env) REGISTER_SO(compiler_inline_hint_symbol); REGISTER_SO(inferred_name_symbol); - REGISTER_SO(undefined_error_name_symbol); REGISTER_SO(local_keyword); + REGISTER_SO(existing_variables_symbol); + scheme_undefined->type = scheme_undefined_type; lambda_symbol = scheme_intern_symbol("lambda"); @@ -196,10 +197,11 @@ void scheme_init_compile (Scheme_Env *env) compiler_inline_hint_symbol = scheme_intern_symbol("compiler-hint:cross-module-inline"); inferred_name_symbol = scheme_intern_symbol("inferred-name"); - undefined_error_name_symbol = scheme_intern_symbol("undefined-error-name"); local_keyword = scheme_intern_exact_keyword("local", 5); + existing_variables_symbol = scheme_make_symbol("existing-variables"); + scheme_define_values_syntax = scheme_make_compiled_syntax(define_values_syntax, define_values_expand); scheme_define_syntaxes_syntax = scheme_make_compiled_syntax(define_syntaxes_syntax, @@ -432,17 +434,6 @@ Scheme_Object *scheme_check_name_property(Scheme_Object *code, Scheme_Object *cu return current_val; } -static Scheme_Object *get_local_name(Scheme_Object *id) -{ - Scheme_Object *name; - - name = scheme_stx_property(id, undefined_error_name_symbol, NULL); - if (name && SCHEME_SYMBOLP(name)) - return name; - else - return SCHEME_STX_VAL(id); -} - /**********************************************************************/ /* lambda utils */ /**********************************************************************/ @@ -660,6 +651,8 @@ make_closure_compilation(Scheme_Comp_Env *env, Scheme_Object *code, params = SCHEME_STX_CDR (params); } + scheme_env_make_variables(frame); + if (SCHEME_STX_NULLP(forms)) scheme_wrong_syntax(NULL, NULL, code, "empty body not allowed"); @@ -686,11 +679,7 @@ make_closure_compilation(Scheme_Comp_Env *env, Scheme_Object *code, cl = MALLOC_ONE_RT(Closure_Info); SET_REQUIRED_TAG(cl->type = scheme_rt_closure_info); - { - int *local_flags; - local_flags = scheme_env_get_flags(frame, 0, data->num_params); - cl->local_flags = local_flags; - } + cl->vars = frame->vars; data->closure_map = (mzshort *)cl; return (Scheme_Object *)data; @@ -1577,7 +1566,7 @@ ref_syntax (Scheme_Object *form, Scheme_Comp_Env *env, Scheme_Compile_Info *rec, if (!imported && env->genv->module && !rec[drec].testing_constantness) SCHEME_TOPLEVEL_FLAGS(var) |= SCHEME_TOPLEVEL_MUTATED; } - } else if (SAME_TYPE(SCHEME_TYPE(var), scheme_local_type)) { + } else if (SAME_TYPE(SCHEME_TYPE(var), scheme_compiled_local_type)) { /* ok */ } else { scheme_wrong_syntax(NULL, name, form, "identifier does not refer to a variable"); @@ -1885,238 +1874,6 @@ static Scheme_Let_Header *make_header(Scheme_Object *first, int num_bindings, in return head; } -static Scheme_Object *shift_compiled_expression(Scheme_Object *v, int delta, int skip); - -static Scheme_Object *shift_compiled_expression_k(void) -{ - Scheme_Thread *p = scheme_current_thread; - Scheme_Object *v = (Scheme_Object *)p->ku.k.p1; - - p->ku.k.p1 = NULL; - - return (void *)shift_compiled_expression(v, p->ku.k.i1, p->ku.k.i2); -} - -static Scheme_Object *shift_compiled_expression(Scheme_Object *v, int delta, int skip) -{ - if (!delta || (SCHEME_TYPE(v) > _scheme_compiled_values_types_)) - return v; - - if (delta < 0) scheme_signal_error("internal error: bad shift delta"); - -#ifdef DO_STACK_CHECK - { -# include "mzstkchk.h" - { - Scheme_Thread *p = scheme_current_thread; - - p->ku.k.p1 = (void *)v; - p->ku.k.i1 = delta; - p->ku.k.i2 = skip; - - return scheme_handle_stack_overflow(shift_compiled_expression_k); - } - } -#endif - - /* Perform simple shifts directly. We want to avoid adding - extra `let' ayers if possible, since it might interefere - with optimizations. */ - - switch (SCHEME_TYPE(v)) { - case scheme_compiled_toplevel_type: - case scheme_compiled_quote_syntax_type: - return v; - case scheme_local_type: - { - int pos = SCHEME_LOCAL_POS(v); - if (pos < skip) - return v; - else - return scheme_make_local(scheme_local_type, pos - delta, 0); - } - case scheme_application_type: - { - Scheme_App_Rec *app = (Scheme_App_Rec *)v; - int i; - - for (i = app->num_args + 1; i--; ) { - v = shift_compiled_expression(app->args[i], delta, skip); - app->args[i] = v; - } - - return (Scheme_Object *)app; - } - case scheme_application2_type: - { - Scheme_App2_Rec *app = (Scheme_App2_Rec *)v; - - v = shift_compiled_expression(app->rator, delta, skip); - app->rator = v; - v = shift_compiled_expression(app->rand, delta, skip); - app->rand = v; - - return (Scheme_Object *)app; - } - case scheme_application3_type: - { - Scheme_App3_Rec *app = (Scheme_App3_Rec *)v; - - v = shift_compiled_expression(app->rator, delta, skip); - app->rator = v; - v = shift_compiled_expression(app->rand1, delta, skip); - app->rand1 = v; - v = shift_compiled_expression(app->rand2, delta, skip); - app->rand2 = v; - - return (Scheme_Object *)app; - } - case scheme_branch_type: - { - Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)v; - - v = shift_compiled_expression(b->test, delta, skip); - b->test = v; - v = shift_compiled_expression(b->tbranch, delta, skip); - b->tbranch = v; - v = shift_compiled_expression(b->fbranch, delta, skip); - b->fbranch = v; - - return (Scheme_Object *)b; - } - case scheme_with_cont_mark_type: - { - Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)v; - - v = shift_compiled_expression(wcm->key, delta, skip); - wcm->key = v; - v = shift_compiled_expression(wcm->val, delta, skip); - wcm->val = v; - v = shift_compiled_expression(wcm->body, delta, skip); - wcm->body = v; - - return (Scheme_Object *)wcm; - } - case scheme_sequence_type: - case scheme_begin0_sequence_type: - { - Scheme_Sequence *s = (Scheme_Sequence *)v; - int i; - - for (i = s->count; i--; ) { - v = shift_compiled_expression(s->array[i], delta, skip); - s->array[i] = v; - } - - return (Scheme_Object *)s; - } - case scheme_apply_values_type: - { - Scheme_Object *v2; - - v2 = shift_compiled_expression(SCHEME_PTR1_VAL(v), delta, skip); - SCHEME_PTR1_VAL(v) = v2; - v2 = shift_compiled_expression(SCHEME_PTR2_VAL(v), delta, skip); - SCHEME_PTR2_VAL(v) = v2; - - return v; - } - case scheme_with_immed_mark_type: - { - Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)v; - Scheme_Object *v2; - - v2 = shift_compiled_expression(wcm->key, delta, skip); - wcm->key = v2; - v2 = shift_compiled_expression(wcm->val, delta, skip); - wcm->val = v2; - v2 = shift_compiled_expression(wcm->body, delta, skip+1); - wcm->body = v2; - - return v; - } - case scheme_set_bang_type: - { - Scheme_Set_Bang *sb = (Scheme_Set_Bang *)v; - - v = shift_compiled_expression(sb->var, delta, skip); - sb->var = v; - v = shift_compiled_expression(sb->val, delta, skip); - sb->val = v; - - return (Scheme_Object *)sb; - } - case scheme_compiled_unclosed_procedure_type: - { - Scheme_Closure_Data *data = (Scheme_Closure_Data *)v; - - v = shift_compiled_expression(data->code, delta, skip + data->num_params); - data->code = v; - - return (Scheme_Object *)data; - } - case scheme_case_lambda_sequence_type: - { - Scheme_Case_Lambda *cl = (Scheme_Case_Lambda *)v; - int i; - - for (i = cl->count; i--; ) { - v = shift_compiled_expression(cl->array[i], delta, skip); - cl->array[i] = v; - } - - return (Scheme_Object *)cl; - } - case scheme_compiled_let_void_type: - { - Scheme_Let_Header *lh = (Scheme_Let_Header *)v; - Scheme_Compiled_Let_Value *clv; - int post_bind = !(SCHEME_LET_FLAGS(lh) & (SCHEME_LET_RECURSIVE | SCHEME_LET_STAR)); - int i; - - if (!post_bind) skip += lh->count; - - clv = (Scheme_Compiled_Let_Value *)lh->body; - i = lh->num_clauses; - while (1) { - v = shift_compiled_expression(clv->value, delta, skip); - clv->value = v; - if (--i) - clv = (Scheme_Compiled_Let_Value *)clv->body; - else - break; - } - - if (post_bind) skip += lh->count; - - if (!lh->num_clauses) { - v = shift_compiled_expression(lh->body, delta, skip); - lh->body = v; - } else { - v = shift_compiled_expression(clv->body, delta, skip); - clv->body = v; - } - - return (Scheme_Object *)lh; - } - case scheme_varref_form_type: - { - Scheme_Object *sv; - - sv = shift_compiled_expression(SCHEME_PTR1_VAL(v), delta, skip); - SCHEME_PTR1_VAL(v) = sv; - - sv = shift_compiled_expression(SCHEME_PTR2_VAL(v), delta, skip); - SCHEME_PTR2_VAL(v) = sv; - - return v; - } - default: - scheme_signal_error("internal error: compile-time shift failed: %d", SCHEME_TYPE(v)); - return NULL; - } -} - static Scheme_Object *force_traditional_letrec(Scheme_Object *result, Scheme_Comp_Env *env) { /* Force `letrec'-style binding by adding a forward @@ -2259,15 +2016,15 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname, int recursive, int multi, Scheme_Compile_Info *rec, int drec, Scheme_Comp_Env *frame_already) { - Scheme_Object *bindings, *l, *binding, *name, **names, **clv_names, *forms, *defname, *scope; + Scheme_Object *bindings, *l, *binding, *name, **names, *forms, *defname, *scope; int num_clauses, num_bindings, i, j, k, m, pre_k; Scheme_Comp_Env *frame, *env, *rhs_env; Scheme_Compile_Info *recs; - Scheme_Object *first = NULL; + Scheme_Object *first = NULL, *existing_vars; Scheme_Compiled_Let_Value *last = NULL, *lv; DupCheckRecord r; int rec_env_already = rec[drec].env_already, body_block; - int rev_bind_order, post_bind, already_compiled_body; + int already_compiled_body; Scheme_Let_Header *head; form = scheme_stx_taint_disarm(form, NULL); @@ -2294,9 +2051,6 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname, if (num_clauses < 0) scheme_wrong_syntax(NULL, bindings, form, NULL); - post_bind = !recursive; - rev_bind_order = recursive; - /* forms ends up being the let body */ forms = SCHEME_STX_CDR(form); forms = SCHEME_STX_CDR(forms); @@ -2343,7 +2097,7 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname, scheme_wrong_syntax(NULL, clause, form, NULL); names = SCHEME_STX_CAR(clause); - + num_names = scheme_stx_proper_list_length(names); if (num_names < 0) scheme_wrong_syntax(NULL, names, form, NULL); @@ -2372,7 +2126,7 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname, frame_already = frame; } env = frame; - if (post_bind) + if (!recursive) rhs_env = scheme_no_defines(origenv); else rhs_env = env; @@ -2389,15 +2143,7 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname, scheme_begin_dup_symbol_check(&r, env); } - /* For `letrec', we bind the first set of identifiers at the deepest - position. That order makes it easier to peel off a prefix into a - separate `letrec'. For `let' and `let*', the first set of - identifiers is at the shallowest position. */ - - if (rev_bind_order) - k = num_bindings; - else - k = 0; + k = 0; for (i = 0; i < num_clauses; i++) { if (!SCHEME_STX_PAIRP(bindings)) @@ -2412,20 +2158,11 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname, if (!SCHEME_STX_NULLP(SCHEME_STX_CDR(rest))) scheme_wrong_syntax(NULL, binding, form, NULL); } - - if (rev_bind_order) { - if (multi) { - name = SCHEME_STX_CAR(binding); - while (!SCHEME_STX_NULLP(name)) { - name = SCHEME_STX_CDR(name); - k--; - } - } else - k--; - } pre_k = k; + existing_vars = scheme_stx_property(binding, existing_variables_symbol, NULL); + name = SCHEME_STX_CAR(binding); if (multi) { while (!SCHEME_STX_NULLP(name)) { @@ -2464,19 +2201,6 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname, last->body = (Scheme_Object *)lv; last = lv; lv->count = (k - pre_k); - lv->position = pre_k; - - if (recursive) { - /* The names are only used for recursive bindings (in letrec_check), - currently. It would be ok if we record extra names, though. */ - clv_names = MALLOC_N(Scheme_Object*, lv->count); - for (m = pre_k; m < k; m++) { - Scheme_Object *ln; - ln = get_local_name(names[m]); - clv_names[m - pre_k] = ln; - } - lv->names = clv_names; - } if (lv->count == 1) rhs_env->value_name = SCHEME_STX_SYM(names[pre_k]); @@ -2495,17 +2219,20 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname, } rhs_env->value_name = NULL; - + if (recursive) { for (m = pre_k; m < k; m++) { scheme_add_compilation_binding(m, names[m], frame); } } + + if (SCHEME_TRUEP(existing_vars)) { + /* Install variables already generated by a lift: */ + scheme_set_compilation_variables(frame, (Scheme_Compiled_Local **)SCHEME_CDR(existing_vars), + pre_k, k - pre_k); + } bindings = SCHEME_STX_CDR(bindings); - - if (rev_bind_order) - k = pre_k; } if (!recursive) { @@ -2514,14 +2241,31 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname, } } + scheme_env_make_variables(env); + + k = 0; + lv = (Scheme_Compiled_Let_Value *)first; + for (i = 0; i < num_clauses; i++) { + Scheme_Compiled_Local **vars; + + vars = MALLOC_N(Scheme_Compiled_Local*, lv->count); + lv->vars = vars; + for (j = lv->count; j--; ) { + vars[j] = env->vars[k+j]; + } + + k += lv->count; + lv = (Scheme_Compiled_Let_Value *)lv->body; + } + head = make_header(first, num_bindings, num_clauses, (recursive ? SCHEME_LET_RECURSIVE : 0)); if (recursive) { - Scheme_Let_Header *current_head = head; int prev_might_invoke = 0; - int group_clauses = 0, group_count = 0; + int group_clauses = 0; + k = 0; lv = (Scheme_Compiled_Let_Value *)first; for (i = 0; i < num_clauses; i++, lv = (Scheme_Compiled_Let_Value *)lv->body) { Scheme_Object *ce, *rhs; @@ -2529,63 +2273,72 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname, if (scope) rhs = scheme_stx_add_scope(rhs, scope, scheme_env_phase(env->genv)); if (lv->count == 1) - env->value_name = lv->names[0]; + env->value_name = lv->vars[0]->name; else env->value_name = NULL; ce = scheme_compile_expr(rhs, env, recs, i); env->value_name = NULL; lv->value = ce; - - /* Record the fact that this binding doesn't use any or later + + /* Record when this binding doesn't use any or later bindings in the same set. In internal-definition mode, - break bindings into smaller sets based on this - information; otherwise, the `let' optimizer and resolver - may do so, but we have to be more conservative as reflected - by scheme_might_invoke_call_cc(). */ + always break bindings into smaller sets based on this + information; otherwise, we have to be more conservative as reflected + by scheme_might_invoke_call_cc(), so record with + SCHEME_CLV_NO_GROUP_LATER_USES and check again at the end. */ if ((rec_env_already == 2) /* int def: semantics is `let' */ || (!prev_might_invoke && !scheme_might_invoke_call_cc(ce))) { - if (!scheme_env_check_reset_any_use(env)) - SCHEME_CLV_FLAGS(lv) |= SCHEME_CLV_NO_GROUP_USES; - if ((rec_env_already == 2) - && !group_clauses - && !scheme_env_min_use_below(env, lv->position + lv->count)) { + group_clauses++; + if ((group_clauses == 1) + && !scheme_env_max_use_above(env, k)) { /* A clause that should be in its own `let' */ - Scheme_Let_Header *next_head; - next_head = make_header(lv->body, - current_head->count - lv->count, - current_head->num_clauses - 1, - SCHEME_LET_RECURSIVE); - current_head->num_clauses = 1; - current_head->count = lv->count; - current_head->body = (Scheme_Object *)next_head; - SCHEME_LET_FLAGS(current_head) -= SCHEME_LET_RECURSIVE; - current_head = next_head; - } else if (!scheme_env_min_use_below(env, lv->position)) { + SCHEME_CLV_FLAGS(lv) |= SCHEME_CLV_NO_GROUP_USES; + group_clauses = 0; + } else if (!scheme_env_max_use_above(env, k + lv->count)) { /* End a recursive `letrec' group */ SCHEME_CLV_FLAGS(lv) |= SCHEME_CLV_NO_GROUP_LATER_USES; - - if (rec_env_already == 2) { - Scheme_Let_Header *next_head; - group_clauses++; - group_count += lv->count; + group_clauses = 0; + } + } else + prev_might_invoke = 1; + + k += lv->count; + } + + if (!prev_might_invoke) { + Scheme_Let_Header *current_head = head; + Scheme_Compiled_Let_Value *next = NULL; + int group_count = 0; + lv = (Scheme_Compiled_Let_Value *)first; + group_clauses = 0; + for (i = 0; i < num_clauses; i++, lv = next) { + next = (Scheme_Compiled_Let_Value *)lv->body; + group_clauses++; + group_count += lv->count; + if (SCHEME_CLV_FLAGS(lv) & (SCHEME_CLV_NO_GROUP_USES + | SCHEME_CLV_NO_GROUP_LATER_USES)) { + /* A clause that should be in its own `let' */ + Scheme_Let_Header *next_head; + int single = (SCHEME_CLV_FLAGS(lv) & SCHEME_CLV_NO_GROUP_USES); + MZ_ASSERT(!single || (group_clauses == 1)); + if (current_head->num_clauses - group_clauses) { next_head = make_header(lv->body, current_head->count - group_count, current_head->num_clauses - group_clauses, SCHEME_LET_RECURSIVE); + lv->body = (Scheme_Object *)next_head; current_head->num_clauses = group_clauses; current_head->count = group_count; - current_head->body = (Scheme_Object *)next_head; - current_head = next_head; - } + } else + next_head = NULL; + if (single) + SCHEME_LET_FLAGS(current_head) -= SCHEME_LET_RECURSIVE; + current_head = next_head; group_clauses = 0; group_count = 0; - } else { - group_clauses++; - group_count += lv->count; } - } else - prev_might_invoke = 1; + } } } @@ -2606,74 +2359,6 @@ gen_let_syntax (Scheme_Object *form, Scheme_Comp_Env *origenv, char *formname, } env->value_name = NULL; - /* Save flags: */ - lv = (Scheme_Compiled_Let_Value *)first; - for (i = 0; i < num_clauses; i++, lv = (Scheme_Compiled_Let_Value *)lv->body) { - int *flags; - flags = scheme_env_get_flags(env, lv->position, lv->count); - lv->flags = flags; - } - - if (rec_env_already == 2) { - /* `head' is a chain of group headers; splice them into the lv - chain, and adjust coordinates in each lv->value due to - grouping */ - Scheme_Let_Header *current_head = head, *next_head = (Scheme_Let_Header *)head->body; - Scheme_Object *rhs, *next = NULL; - int num_group_clauses = 0; - - head->body = first; - lv = (Scheme_Compiled_Let_Value *)first; - for (i = 0; i < num_clauses; i++, lv = (Scheme_Compiled_Let_Value *)next) { - rhs = shift_compiled_expression(lv->value, - ((SCHEME_LET_FLAGS(current_head) & SCHEME_LET_RECURSIVE) - ? num_bindings - current_head->count - : num_bindings), - 0); - lv->value = rhs; - lv->position -= (num_bindings - current_head->count); - next = lv->body; - - num_group_clauses++; - if (current_head->num_clauses == num_group_clauses) { - num_bindings -= current_head->count; - current_head = next_head; - next_head = (Scheme_Let_Header *)current_head->body; - if ((i + 1) < num_clauses) { - current_head->body = lv->body; - lv->body = (Scheme_Object *)current_head; - } - num_group_clauses = 0; - } - } - } - - if (!already_compiled_body) { - /* Help the optimizer by removing unused expressions right away */ - lv = (Scheme_Compiled_Let_Value *)head->body; - for (i = 0; i < head->num_clauses; i++, lv = (Scheme_Compiled_Let_Value *)lv->body) { - for (j = lv->count; j--; ) { - if (lv->flags[j] & SCHEME_WAS_USED) - break; - } - if (j < 0) { - if (scheme_omittable_expr(lv->value, lv->count, 10, 0, NULL, NULL, 0, 0, 1)) { - if (lv->count == 1) { - lv->value = scheme_false; - } else { - Scheme_Object *app; - app = scheme_null; - for (k = lv->count; k--; ) { - app = scheme_make_pair(scheme_false, app); - } - app = scheme_make_application(scheme_make_pair(scheme_values_func, app), NULL); - lv->value = app; - } - } - } - } - } - scheme_merge_compile_recs(rec, drec, recs, num_clauses + 1); return (Scheme_Object *)head; @@ -2684,7 +2369,8 @@ do_let_expand(Scheme_Object *orig_form, Scheme_Comp_Env *origenv, Scheme_Expand_ const char *formname, int letrec, int multi, Scheme_Comp_Env *env_already) { - Scheme_Object *vars, *body, *first, *last, *name, *v, *vs, *vlist, *boundname, *form, *pre_set, *scope; + Scheme_Object *vars, *body, *first, *last, *name, *v, *vs, *boundname, *form, *pre_set, *scope; + Scheme_Object *vlist_first, *vlist_last; Scheme_Comp_Env *use_env, *env; Scheme_Expand_Info erec1; DupCheckRecord r; @@ -2724,7 +2410,8 @@ do_let_expand(Scheme_Object *orig_form, Scheme_Comp_Env *origenv, Scheme_Expand_ if (!env_already && !rec_env_already) scheme_begin_dup_symbol_check(&r, origenv); - vlist = scheme_null; + vlist_first = scheme_null; + vlist_last = NULL; vs = vars; while (SCHEME_STX_PAIRP(vs)) { Scheme_Object *v2; @@ -2747,7 +2434,13 @@ do_let_expand(Scheme_Object *orig_form, Scheme_Comp_Env *origenv, Scheme_Expand_ name = SCHEME_STX_CAR(names); scheme_check_identifier(NULL, name, NULL, origenv, form); - vlist = cons(name, vlist); + + v = scheme_make_pair(name, scheme_null); + if (vlist_last) + SCHEME_CDR(vlist_last) = v; + else + vlist_first = v; + vlist_last = v; if (!env_already && !rec_env_already) { scheme_dup_symbol_check(&r2, NULL, name, "clause binding", form); @@ -2774,7 +2467,7 @@ do_let_expand(Scheme_Object *orig_form, Scheme_Comp_Env *origenv, Scheme_Expand_ scope = NULL; else scope = scheme_new_scope(SCHEME_STX_LOCAL_BIND_SCOPE); - env = scheme_add_compilation_frame(vlist, + env = scheme_add_compilation_frame(vlist_first, scope, origenv, (rec_env_already ? SCHEME_INTDEF_SHADOW : 0)); @@ -2799,9 +2492,6 @@ do_let_expand(Scheme_Object *orig_form, Scheme_Comp_Env *origenv, Scheme_Expand_ name = SCHEME_STX_CAR(v); if (scope) name = scheme_stx_add_scope(name, scope, scheme_env_phase(env->genv)); - if (rec_env_already == 2) - forward_ref_boundary += scheme_stx_proper_list_length(name); - rhs = SCHEME_STX_CDR(v); rhs = SCHEME_STX_CAR(rhs); if (scope && letrec) rhs = scheme_stx_add_scope(rhs, scope, scheme_env_phase(env->genv)); @@ -2872,18 +2562,18 @@ do_let_expand(Scheme_Object *orig_form, Scheme_Comp_Env *origenv, Scheme_Expand_ int cnt; cnt = scheme_stx_proper_list_length(name); if (SCHEME_NULLP(SCHEME_CDR(first)) - && !scheme_env_min_use_below(use_env, forward_ref_boundary)) { + && !scheme_env_max_use_above(use_env, forward_ref_boundary)) { /* no self or forward references */ first = scheme_datum_to_syntax(first, vs, vs, 0, 1); pre_set = cons(cons(let_values_symbol, first), pre_set); first = NULL; - } else if (!scheme_env_min_use_below(use_env, forward_ref_boundary - cnt)) { + } else if (!scheme_env_max_use_above(use_env, forward_ref_boundary + cnt)) { /* no (further) forward references */ first = scheme_datum_to_syntax(first, vs, vs, 0, 1); pre_set = cons(cons(letrec_values_symbol, first), pre_set); first = NULL; } - forward_ref_boundary -= cnt; + forward_ref_boundary += cnt; } vars = SCHEME_STX_CDR(vars); @@ -2982,7 +2672,7 @@ static Scheme_Object *compile_sequence(Scheme_Object *forms, body = compile_block(forms, env, rec, drec); else body = compile_list(forms, env, rec, drec); - return scheme_make_sequence_compilation(body, 1); + return scheme_make_sequence_compilation(body, 1, 0); } } @@ -3062,7 +2752,7 @@ do_begin_syntax(char *name, body = compile_list(forms, env, rec, drec); } - forms = scheme_make_sequence_compilation(body, zero ? -1 : 1); + forms = scheme_make_sequence_compilation(body, zero ? -1 : 1, 0); if (!zero && SAME_TYPE(SCHEME_TYPE(forms), scheme_sequence_type) @@ -3093,7 +2783,7 @@ Scheme_Sequence *scheme_malloc_sequence(int count) * sizeof(Scheme_Object *)); } -Scheme_Object *scheme_make_sequence_compilation(Scheme_Object *seq, int opt) +Scheme_Object *scheme_make_sequence_compilation(Scheme_Object *seq, int opt, int resolved) { /* We have to be defensive in processing `seq'; it might be bad due to a bad .zo */ @@ -3121,7 +2811,9 @@ Scheme_Object *scheme_make_sequence_compilation(Scheme_Object *seq, int opt) total++; } else if (opt && (((opt > 0) && !last) || ((opt < 0) && !first)) - && scheme_omittable_expr(v, -1, -1, 0, NULL, NULL, 0, 0, 1)) { + && scheme_omittable_expr(v, -1, -1, + (resolved ? OMITTABLE_RESOLVED : OMITTABLE_KEEP_VARS), + NULL, NULL)) { /* A value that is not the result. We'll drop it. */ total++; } else { @@ -3147,7 +2839,10 @@ Scheme_Object *scheme_make_sequence_compilation(Scheme_Object *seq, int opt) if (count == 1) { if (opt < -1) { /* can't optimize away a begin0 reading a .zo time */ - } else if ((opt < 0) && !scheme_omittable_expr(SCHEME_CAR(seq), 1, -1, 0, NULL, NULL, 0, 0, 1)) { + } else if ((opt < 0) + && !scheme_omittable_expr(SCHEME_CAR(seq), 1, -1, + (resolved ? OMITTABLE_RESOLVED : OMITTABLE_KEEP_VARS), + NULL, NULL)) { /* We can't optimize (begin0 expr cont) to expr because exp is not in tail position in the original (so we'd mess up continuation marks). */ @@ -3177,7 +2872,9 @@ Scheme_Object *scheme_make_sequence_compilation(Scheme_Object *seq, int opt) } else if (opt && (((opt > 0) && (k < total)) || ((opt < 0) && k)) - && scheme_omittable_expr(v, -1, -1, 0, NULL, NULL, 0, 0, 1)) { + && scheme_omittable_expr(v, -1, -1, + (resolved ? OMITTABLE_RESOLVED : OMITTABLE_KEEP_VARS), + NULL, NULL)) { /* Value not the result. Do nothing. */ } else o->array[i++] = v; @@ -3201,7 +2898,7 @@ stratified_body_syntax (Scheme_Object *form, Scheme_Comp_Env *env, Scheme_Compil if (SCHEME_NULLP(SCHEME_CDR(body))) return SCHEME_CAR(body); else - return scheme_make_sequence_compilation(body, 1); + return scheme_make_sequence_compilation(body, 1, 0); } static Scheme_Object * @@ -3734,7 +3431,7 @@ static Scheme_Object *eval_letmacro_rhs(Scheme_Object *a, Scheme_Comp_Env *rhs_e save_runstack = scheme_push_prefix(NULL, rp, NULL, NULL, phase, phase, rhs_env->genv, NULL); - if (scheme_omittable_expr(a, 1, -1, 0, NULL, NULL, 0, 0, 0)) { + if (scheme_omittable_expr(a, 1, -1, OMITTABLE_RESOLVED, NULL, NULL)) { /* short cut */ a = _scheme_eval_linked_expr_multi(a); } else { @@ -4052,24 +3749,9 @@ do_letrec_syntaxes(const char *where, cnt = (i ? var_cnt : stx_cnt); if (cnt > 0) { /* Add new syntax/variable names to the environment: */ - if (i) { - /* values in reverse order across clauses, in order within a clause */ - j = var_cnt; - } else - j = 0; + j = 0; for (v = (i ? var_bindings : bindings); SCHEME_STX_PAIRP(v); v = SCHEME_STX_CDR(v)) { Scheme_Object *a, *l; - int pre_j; - - if (i) { - a = SCHEME_STX_CAR(v); - for (l = SCHEME_STX_CAR(a); SCHEME_STX_PAIRP(l); l = SCHEME_STX_CDR(l)) { - j--; - } - pre_j = j; - } else - pre_j = 0; - a = SCHEME_STX_CAR(v); for (l = SCHEME_STX_CAR(a); SCHEME_STX_PAIRP(l); l = SCHEME_STX_CDR(l)) { a = SCHEME_STX_CAR(l); @@ -4080,8 +3762,6 @@ do_letrec_syntaxes(const char *where, } else scheme_set_local_syntax(j++, a, NULL, stx_env, 0); } - - if (i) j = pre_j; } } } @@ -4181,7 +3861,7 @@ do_letrec_syntaxes(const char *where, v = compile_list(body, var_env, rec, drec); else v = compile_block(body, var_env, rec, drec); - v = scheme_make_sequence_compilation(v, 1); + v = scheme_make_sequence_compilation(v, 1, 0); } else { if (env_already) v = expand_list(body, var_env, rec, drec); @@ -4278,7 +3958,8 @@ int scheme_get_eval_type(Scheme_Object *obj) if (type > _scheme_values_types_) return SCHEME_EVAL_CONSTANT; - else if (SAME_TYPE(type, scheme_local_type)) + else if (SAME_TYPE(type, scheme_compiled_local_type) + || SAME_TYPE(type, scheme_local_type)) return SCHEME_EVAL_LOCAL; else if (SAME_TYPE(type, scheme_local_unbox_type)) return SCHEME_EVAL_LOCAL_UNBOX; @@ -5024,8 +4705,7 @@ compile_expand_expr(Scheme_Object *form, Scheme_Comp_Env *env, /* apply to global variable: compile it normally */ orig_unbound_name = find_name; has_orig_unbound = 1; - } else if (SAME_TYPE(SCHEME_TYPE(var), scheme_local_type) - || SAME_TYPE(SCHEME_TYPE(var), scheme_local_unbox_type)) { + } else if (SAME_TYPE(SCHEME_TYPE(var), scheme_compiled_local_type)) { /* apply to local variable: compile it normally */ } else { if (SAME_TYPE(SCHEME_TYPE(var), scheme_macro_type)) { @@ -5751,33 +5431,35 @@ Scheme_Object *scheme_pair_lifted(Scheme_Object *_ip, Scheme_Object **_ids, Sche } Scheme_Object *scheme_add_lifts_as_let(Scheme_Object *obj, Scheme_Object *l, Scheme_Comp_Env *env, - Scheme_Object *orig_form, int comp_rev) + Scheme_Object *orig_form, int comp) { - Scheme_Object *revl, *a; + Scheme_Object *revl, *reve, *a; if (SCHEME_NULLP(l)) return obj; revl = scheme_reverse(l); - if (comp_rev) { - /* We've already compiled the body of this let - with the bindings in reverse order. So insert a series of `lets' - to match that order: */ - if (!SCHEME_NULLP(SCHEME_CDR(l))) { - for (; SCHEME_PAIRP(l); l = SCHEME_CDR(l)) { - a = scheme_reverse(SCHEME_CAR(SCHEME_CAR(l))); - for (; !SCHEME_NULLP(a); a = SCHEME_CDR(a)) { - obj = icons(scheme_datum_to_syntax(let_values_symbol, scheme_false, scheme_sys_wraps(env), 0, 0), - icons(icons(icons(icons(SCHEME_CAR(a), scheme_null), icons(SCHEME_CAR(a), scheme_null)), - scheme_null), - icons(obj, scheme_null))); - } - } + reve = NULL; + if (comp) { + for (; !SCHEME_NULLP(l); l = SCHEME_CDR(l)) { + reve = scheme_make_raw_pair((Scheme_Object *)env, reve); + env = env->next; } } for (; SCHEME_PAIRP(revl); revl = SCHEME_CDR(revl)) { a = SCHEME_CAR(revl); + if (comp) { + /* propagate previously generated variables for re-compile */ + a = scheme_datum_to_syntax(a, scheme_false, scheme_false, 0, 0); + env = (Scheme_Comp_Env *)SCHEME_CAR(reve); + reve = SCHEME_CDR(reve); + MZ_ASSERT(env->flags & SCHEME_CAPTURE_LIFTED); + if (env->vars) + a = scheme_stx_property(a, existing_variables_symbol, + scheme_make_raw_pair(scheme_make_integer(env->num_bindings), + (Scheme_Object *)env->vars)); + } obj = icons(scheme_datum_to_syntax(let_values_symbol, scheme_false, scheme_sys_wraps(env), 0, 0), icons(icons(a, scheme_null), icons(obj, scheme_null))); @@ -5787,7 +5469,7 @@ Scheme_Object *scheme_add_lifts_as_let(Scheme_Object *obj, Scheme_Object *l, Sch return obj; } - + static Scheme_Object *compile_expand_expr_lift_to_let_k(void); static Scheme_Object * @@ -5798,27 +5480,6 @@ compile_expand_expr_lift_to_let(Scheme_Object *form, Scheme_Comp_Env *env, Scheme_Object *l, *orig_form = form, *context_key; Scheme_Comp_Env *inserted, **ip; - /* This function only works when `env' has no lexical bindings, - because we might insert new ones at the beginning. In - particular, we might insert frames between `inserted' and - `env'. - - This function also relies on the way that compilation of `let' - works. A let-bound variable is compiled to a count of the frames - to skip and the index within the frame, so we can insert new - frames without affecting lookups computed so far. Inserting each - new frame before any previous one turns out to be consistent with - the nested `let's that we generate at the end. - - Some optimizations can happen later, for example constant - propagate. But these optimizations take place on the result of - this function, so we don't have to worry about them. - - Don't generate a `let*' expression instead of nested `let's, - because the compiler actually takes shortcuts (that are - inconsistent with our frame nesting) instead of expanding `let*' - to `let'. */ - #ifdef DO_STACK_CHECK { # include "mzstkchk.h" @@ -5875,7 +5536,7 @@ compile_expand_expr_lift_to_let(Scheme_Object *form, Scheme_Comp_Env *env, SCHEME_IPTR_VAL(o) = form; } else o = form; - form = scheme_add_lifts_as_let(o, l, env, orig_form, rec[drec].comp); + form = scheme_add_lifts_as_let(o, l, inserted->next, orig_form, rec[drec].comp); if (!rec[drec].comp) { SCHEME_EXPAND_OBSERVE_LETLIFT_LOOP(env->observer, form); } diff --git a/racket/src/racket/src/cstartup.inc b/racket/src/racket/src/cstartup.inc index fff472d4f6..78e6c9c0a2 100644 --- a/racket/src/racket/src/cstartup.inc +++ b/racket/src/racket/src/cstartup.inc @@ -1,5 +1,5 @@ { - SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,52,46,48,46,54,84,0,0,0,0,0,0,0,0,0,0, + SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,52,46,48,46,56,84,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,54,0,0,0,1,0,0,8,0,18,0, 22,0,26,0,31,0,38,0,42,0,47,0,59,0,66,0,69,0,82,0,89, 0,94,0,103,0,109,0,123,0,137,0,140,0,146,0,157,0,159,0,173,0, @@ -72,37 +72,37 @@ 22,168,4,196,249,22,161,4,80,143,42,39,28,248,22,66,248,22,162,4,248, 22,83,197,250,22,92,2,27,248,22,92,248,22,173,20,199,248,22,104,198,27, 248,22,162,4,248,22,173,20,197,250,22,92,2,27,248,22,92,248,22,83,197, -250,22,93,2,24,248,22,174,20,199,248,22,174,20,202,145,39,9,20,121,145, +250,22,93,2,24,248,22,174,20,199,248,22,174,20,202,145,39,9,20,122,145, 2,1,39,16,1,11,16,0,20,27,15,61,9,2,2,2,2,2,3,11,11, -11,11,9,9,11,11,11,10,39,80,143,39,39,20,121,145,2,1,39,16,0, +11,11,9,9,11,11,11,10,39,80,143,39,39,20,122,145,2,1,39,16,0, 16,0,41,42,39,16,0,39,16,0,39,11,11,11,16,11,2,4,2,5,2, 6,2,7,2,8,2,9,2,10,2,11,2,12,2,13,2,14,16,11,11,11, 11,11,11,11,11,11,11,11,11,16,11,2,4,2,5,2,6,2,7,2,8, 2,9,2,10,2,11,2,12,2,13,2,14,39,50,40,16,0,39,16,1,2, 15,40,11,11,11,16,0,16,0,16,0,39,39,11,12,11,11,16,0,16,0, 16,0,39,39,16,12,16,5,11,20,15,16,2,20,14,144,39,39,40,80,143, -39,39,39,20,121,145,2,1,39,16,1,2,15,16,1,33,36,10,16,5,2, -13,88,148,8,36,40,56,40,9,223,0,33,37,39,20,121,145,2,1,39,16, +39,39,39,20,122,145,2,1,39,16,1,2,15,16,1,33,36,10,16,5,2, +13,88,148,8,36,40,56,40,9,223,0,33,37,39,20,122,145,2,1,39,16, 1,2,15,16,0,11,16,5,2,14,88,148,8,36,40,56,40,9,223,0,33, -38,39,20,121,145,2,1,39,16,1,2,15,16,0,11,16,5,2,4,88,148, -8,36,40,56,42,9,223,0,33,39,39,20,121,145,2,1,39,16,1,2,15, +38,39,20,122,145,2,1,39,16,1,2,15,16,0,11,16,5,2,4,88,148, +8,36,40,56,42,9,223,0,33,39,39,20,122,145,2,1,39,16,1,2,15, 16,1,33,40,11,16,5,2,11,88,148,8,36,40,59,42,9,223,0,33,41, -39,20,121,145,2,1,39,16,1,2,15,16,1,33,42,11,16,5,2,7,88, -148,8,36,40,61,40,9,223,0,33,45,39,20,121,145,2,1,39,16,1,2, +39,20,122,145,2,1,39,16,1,2,15,16,1,33,42,11,16,5,2,7,88, +148,8,36,40,61,40,9,223,0,33,45,39,20,122,145,2,1,39,16,1,2, 15,16,0,11,16,5,2,10,88,148,8,36,40,56,40,9,223,0,33,47,39, -20,121,145,2,1,39,16,1,2,15,16,0,11,16,5,2,8,88,148,8,36, -40,57,40,9,223,0,33,48,39,20,121,145,2,1,39,16,1,2,15,16,0, -11,16,5,2,9,88,148,8,36,40,57,40,9,223,0,33,49,39,20,121,145, +20,122,145,2,1,39,16,1,2,15,16,0,11,16,5,2,8,88,148,8,36, +40,57,40,9,223,0,33,48,39,20,122,145,2,1,39,16,1,2,15,16,0, +11,16,5,2,9,88,148,8,36,40,57,40,9,223,0,33,49,39,20,122,145, 2,1,39,16,1,2,15,16,0,11,16,5,2,12,88,148,8,36,40,59,40, -9,223,0,33,50,39,20,121,145,2,1,39,16,1,2,15,16,0,11,16,5, -2,5,88,148,8,36,40,61,42,9,223,0,33,51,39,20,121,145,2,1,39, +9,223,0,33,50,39,20,122,145,2,1,39,16,1,2,15,16,0,11,16,5, +2,5,88,148,8,36,40,61,42,9,223,0,33,51,39,20,122,145,2,1,39, 16,1,2,15,16,1,33,52,11,16,5,2,6,88,148,8,36,40,57,40,9, -223,0,33,53,39,20,121,145,2,1,39,16,1,2,15,16,0,11,16,0,94, +223,0,33,53,39,20,122,145,2,1,39,16,1,2,15,16,0,11,16,0,94, 2,17,2,18,93,2,17,9,9,39,9,0}; EVAL_ONE_SIZED_STR((char *)expr, 2090); } { - SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,52,46,48,46,54,84,0,0,0,0,0,0,0,0,0,0, + SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,52,46,48,46,56,84,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,194,0,0,0,1,0,0,8,0,16,0, 29,0,34,0,51,0,63,0,85,0,114,0,158,0,164,0,178,0,193,0,211, 0,223,0,239,0,253,0,19,1,39,1,73,1,90,1,107,1,130,1,145,1, @@ -948,9 +948,9 @@ 159,16,2,56,11,11,27,248,22,143,4,23,199,1,27,28,23,194,2,23,194, 1,86,94,23,194,1,39,27,248,22,143,4,23,202,1,249,22,144,6,23,198, 1,20,20,95,88,148,8,36,39,51,11,9,224,3,2,33,128,3,23,195,1, -23,196,1,248,80,144,41,8,54,42,193,145,39,9,20,121,145,2,1,39,16, +23,196,1,248,80,144,41,8,54,42,193,145,39,9,20,122,145,2,1,39,16, 1,11,16,0,20,27,15,56,9,2,2,2,2,29,11,11,11,11,11,11,11, -9,9,11,11,11,10,46,80,143,39,39,20,121,145,2,1,54,16,40,2,3, +9,9,11,11,11,10,46,80,143,39,39,20,122,145,2,1,54,16,40,2,3, 2,4,2,5,2,6,2,7,2,8,2,9,30,2,11,1,20,112,97,114,97, 109,101,116,101,114,105,122,97,116,105,111,110,45,107,101,121,11,6,30,2,11, 1,23,101,120,116,101,110,100,45,112,97,114,97,109,101,116,101,114,105,122,97, @@ -1047,7 +1047,7 @@ EVAL_ONE_SIZED_STR((char *)expr, 19773); } { - SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,52,46,48,46,54,84,0,0,0,0,0,0,0,0,0,0, + SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,52,46,48,46,56,84,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,15,0,0,0,1,0,0,8,0,23,0, 48,0,65,0,83,0,105,0,128,0,149,0,171,0,180,0,189,0,196,0,205, 0,212,0,0,0,248,1,0,0,3,1,5,105,110,115,112,48,76,35,37,112, @@ -1060,9 +1060,9 @@ 45,99,104,97,110,110,101,108,45,105,110,1,20,84,72,45,112,108,97,99,101, 45,99,104,97,110,110,101,108,45,111,117,116,249,80,143,41,42,23,196,1,39, 249,80,143,41,42,23,196,1,39,249,80,143,41,42,195,39,249,80,143,41,42, -23,196,1,40,249,80,143,41,42,195,40,145,39,9,20,121,145,2,1,39,16, +23,196,1,40,249,80,143,41,42,195,40,145,39,9,20,122,145,2,1,39,16, 1,11,16,0,20,27,15,56,9,2,2,2,2,29,11,11,11,11,11,11,11, -9,9,11,11,11,10,48,80,143,39,39,20,121,145,2,1,39,16,7,2,3, +9,9,11,11,11,10,48,80,143,39,39,20,122,145,2,1,39,16,7,2,3, 2,4,2,5,2,6,2,7,2,8,2,9,16,0,40,42,39,16,0,39,16, 2,2,6,2,7,41,11,11,11,16,5,2,4,2,8,2,9,2,5,2,3, 16,5,11,11,11,11,11,16,5,2,4,2,8,2,9,2,5,2,3,44,44, @@ -1078,7 +1078,7 @@ EVAL_ONE_SIZED_STR((char *)expr, 576); } { - SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,52,46,48,46,54,84,0,0,0,0,0,0,0,0,0,0, + SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,52,46,48,46,56,84,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,100,0,0,0,1,0,0,8,0,15,0, 26,0,53,0,59,0,73,0,86,0,112,0,129,0,151,0,159,0,171,0,186, 0,202,0,220,0,241,0,253,0,13,1,36,1,60,1,72,1,103,1,108,1, @@ -1492,8 +1492,8 @@ 144,40,40,42,248,22,148,15,80,144,40,48,42,20,18,144,11,80,143,39,59, 248,80,144,40,8,27,40,249,22,31,11,80,144,42,41,40,20,18,144,11,80, 143,39,59,248,80,144,40,8,27,40,249,22,31,11,80,144,42,41,40,145,39, -9,20,121,145,2,1,39,16,1,11,16,0,20,27,15,56,9,2,2,2,2, -29,11,11,11,11,11,11,11,9,9,11,11,11,10,41,80,143,39,39,20,121, +9,20,122,145,2,1,39,16,1,11,16,0,20,27,15,56,9,2,2,2,2, +29,11,11,11,11,11,11,11,9,9,11,11,11,10,41,80,143,39,39,20,122, 145,2,1,44,16,28,2,3,2,4,30,2,6,1,20,112,97,114,97,109,101, 116,101,114,105,122,97,116,105,111,110,45,107,101,121,11,6,30,2,6,1,23, 101,120,116,101,110,100,45,112,97,114,97,109,101,116,101,114,105,122,97,116,105, @@ -1547,7 +1547,7 @@ EVAL_ONE_SIZED_STR((char *)expr, 9765); } { - SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,52,46,48,46,54,84,0,0,0,0,0,0,0,0,0,0, + SHARED_OK static MZCOMPILED_STRING_FAR unsigned char expr[] = {35,126,7,54,46,52,46,48,46,56,84,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,17,0,0,0,1,0,0,8,0,18,0, 24,0,38,0,52,0,64,0,84,0,98,0,113,0,126,0,131,0,135,0,147, 0,231,0,238,0,8,1,0,0,199,1,0,0,3,1,5,105,110,115,112,48, @@ -1563,9 +1563,9 @@ 2,15,16,4,2,8,39,39,2,1,143,2,15,16,4,2,9,39,39,2,1, 143,2,15,16,4,2,10,39,39,2,1,16,0,38,15,143,2,14,2,11,18, 143,16,2,143,10,16,3,9,2,11,2,13,143,11,16,3,9,9,2,13,16, -3,9,9,9,145,39,9,20,121,145,2,1,39,16,1,11,16,0,20,27,15, +3,9,9,9,145,39,9,20,122,145,2,1,39,16,1,11,16,0,20,27,15, 56,9,2,2,2,2,29,11,11,11,11,11,11,11,9,9,11,11,11,33,16, -39,80,143,39,39,20,121,145,2,1,39,16,0,16,0,40,42,39,16,0,39, +39,80,143,39,39,20,122,145,2,1,39,16,0,16,0,40,42,39,16,0,39, 16,0,39,11,11,11,16,0,16,0,16,0,39,39,40,12,11,11,16,0,16, 0,16,0,39,39,11,12,11,11,16,0,16,0,16,0,39,39,16,0,104,2, 4,2,5,29,94,2,3,71,35,37,102,111,114,101,105,103,110,11,29,94,2, diff --git a/racket/src/racket/src/jitarith.c b/racket/src/racket/src/jitarith.c index 926c791d69..fcd92f139b 100644 --- a/racket/src/racket/src/jitarith.c +++ b/racket/src/racket/src/jitarith.c @@ -36,7 +36,7 @@ int scheme_jit_is_fixnum(Scheme_Object *rand) || (SAME_TYPE(SCHEME_TYPE(rand), scheme_local_type) && (SCHEME_GET_LOCAL_TYPE(rand) == SCHEME_LOCAL_TYPE_FIXNUM))) return 1; - else if (scheme_expr_produces_local_type(rand) == SCHEME_LOCAL_TYPE_FIXNUM) + else if (scheme_expr_produces_local_type(rand, NULL) == SCHEME_LOCAL_TYPE_FIXNUM) return 1; else return 0; diff --git a/racket/src/racket/src/letrec_check.c b/racket/src/racket/src/letrec_check.c index e705bed2c8..6819d4f21b 100644 --- a/racket/src/racket/src/letrec_check.c +++ b/racket/src/racket/src/letrec_check.c @@ -109,7 +109,6 @@ void scheme_init_letrec_check() #define LET_CHECKED (0x1 << 2) #define FRAME_TYPE_LETREC 1 -#define FRAME_TYPE_LETSTAR 2 #define FRAME_TYPE_LET 3 #define FRAME_TYPE_CLOSURE 4 #define FRAME_TYPE_TOP 5 @@ -140,9 +139,6 @@ typedef struct Letrec_Check_Frame { been wrapped with an # check */ int *ref; - /* so we can get to variable names */ - Scheme_Let_Header *head; - /* we keep a list of all deferred expressions, only so that we can drop the body for any that are not processed (which means that they won't be used) */ @@ -178,12 +174,13 @@ static Letrec_Check_Frame *init_letrec_check_frame(int frame_type, int subexpr, mzshort count, Letrec_Check_Frame *prev, Letrec_Check_Frame *share_with, - Scheme_Let_Header *head) + Scheme_Let_Header *head, + Scheme_Closure_Data *data) { Scheme_Deferred_Expr **chain; Letrec_Check_Frame *frame; Scheme_Object **def; - int *ref, i; + int *ref, i, j, pos; frame = (Letrec_Check_Frame *)MALLOC_ONE_RT(Letrec_Check_Frame); #ifdef MZTAG_REQUIRED @@ -195,7 +192,23 @@ static Letrec_Check_Frame *init_letrec_check_frame(int frame_type, int subexpr, frame->count = count; frame->next = prev; - frame->head = head; + if (head) { + Scheme_Compiled_Let_Value *clv = (Scheme_Compiled_Let_Value *)head->body; + pos = 0; + for (i = head->num_clauses; i--; clv = (Scheme_Compiled_Let_Value *)clv->body) { + for (j = 0; j < clv->count; j++) { + clv->vars[j]->mode = SCHEME_VAR_MODE_LETREC_CHECK; + clv->vars[j]->letrec_check.frame = frame; + clv->vars[j]->letrec_check.frame_pos = pos++; + } + } + } else if (data) { + for (j = data->num_params; j--; ) { + ((Closure_Info *)data->closure_map)->vars[j]->mode = SCHEME_VAR_MODE_LETREC_CHECK; + ((Closure_Info *)data->closure_map)->vars[j]->letrec_check.frame = frame; + ((Closure_Info *)data->closure_map)->vars[j]->letrec_check.frame_pos = j; + } + } if (share_with) { /* Moving from RHS phase to BODY phase for `let[rec]`, @@ -256,33 +269,10 @@ static Letrec_Check_Frame *get_nearest_rhs(Letrec_Check_Frame *frame) /* returns the frame that was created when pos was created, and changes pos to be relative to that frame */ -static Letrec_Check_Frame *get_relative_frame(int *pos, Letrec_Check_Frame *frame) +static Letrec_Check_Frame *get_relative_frame(int *pos, Scheme_Compiled_Local *var) { - while (1) { - /* we've gone wrong if pos_int is negative or if the frame has - become NULL because pos should have be a valid LHS variable - reference */ - SCHEME_ASSERT(*pos >= 0, "get_relative_frame: pos is negative"); - SCHEME_ASSERT(frame, "get_relative_frame: frame is NULL"); - - /* if we're in the RHS of a let, no bindings for the LHS variables - have been pushed yet, pos can't possibly be in this frame. so - don't do any offsetting and look in the next frame */ - if ((frame->frame_type == FRAME_TYPE_LET) - && (frame->subexpr == LET_RHS_EXPR)) { - frame = frame->next; - /* recur */ - } else { - if (*pos >= frame->count) { - /* we're not in the right frame yet, so offset pos by the - number of bindings in this frame */ - (*pos) -= frame->count; - frame = frame->next; - /* recur */ - } else - return frame; - } - } + *pos = var->letrec_check.frame_pos; + return var->letrec_check.frame; } /* adds expr to the deferred bindings of lhs */ @@ -325,7 +315,7 @@ static void letrec_check_lets_resume(Letrec_Check_Frame *frame, Scheme_Let_Heade { Scheme_Compiled_Let_Value *clv; Scheme_Object *body; - int i, j, k, *clv_flags; + int i, j, k; int was_checked; body = head->body; @@ -337,62 +327,36 @@ static void letrec_check_lets_resume(Letrec_Check_Frame *frame, Scheme_Let_Heade k = head->count; for (i = head->num_clauses; i--;) { clv = (Scheme_Compiled_Let_Value *) body; - clv_flags = clv->flags; k -= clv->count; for (j = 0; j < clv->count; j++) { was_checked = (frame->ref[k + j] & LET_CHECKED); - if (was_checked) { - clv_flags[j] -= (clv_flags[j] & SCHEME_WAS_ONLY_APPLIED); - clv_flags[j] -= (clv_flags[j] & SCHEME_WAS_APPLIED_EXCEPT_ONCE); - } + if (was_checked) + clv->vars[j]->non_app_count = clv->vars[j]->use_count; } - clv->flags = clv_flags; - clv->names = NULL; /* not used in later passes */ body = clv->body; } } } /* records that we have seen a reference to loc */ -static Scheme_Object *record_checked(Scheme_Local *loc, Letrec_Check_Frame *frame) +static Scheme_Object *record_checked(Scheme_Compiled_Local *loc, Letrec_Check_Frame *frame) { - int position = SCHEME_LOCAL_POS(loc), k; - Scheme_Object *obj; - - frame = get_relative_frame(&position, frame); + int position; + + frame = get_relative_frame(&position, loc); frame->ref[position] |= LET_CHECKED; - obj = frame->head->body; - k = frame->head->count; - - while (1) { - Scheme_Compiled_Let_Value *clv = (Scheme_Compiled_Let_Value *)obj; - - SCHEME_ASSERT(SAME_TYPE(SCHEME_TYPE(obj), scheme_compiled_let_value_type), "not a clv"); - SCHEME_ASSERT(position >= 0, "position went negative"); - - k -= clv->count; - - if (position >= k) - return clv->names[position - k]; - - obj = clv->body; - } - - ESCAPED_BEFORE_HERE; + return loc->name; } static Scheme_Object *letrec_check_local(Scheme_Object *o, Letrec_Check_Frame *frame, Scheme_Object *pos) { Letrec_Check_Frame *in_frame; - Scheme_Local *loc = (Scheme_Local *)o; - int position, in_position; + Scheme_Compiled_Local *loc = (Scheme_Compiled_Local *)o; + int in_position; - position = SCHEME_LOCAL_POS(loc); - - in_position = position; - in_frame = get_relative_frame(&in_position, frame); + in_frame = get_relative_frame(&in_position, loc); if (SCHEME_FALSEP(pos)) { /* mark as potentially applied (i.e., in an "unsafe" context) @@ -604,7 +568,7 @@ static Scheme_Object *letrec_check_closure_compilation(Scheme_Object *o, Letrec_ num_params = data->num_params; new_frame = init_letrec_check_frame(FRAME_TYPE_CLOSURE, LET_BODY_EXPR, num_params, frame, NULL, - NULL); + NULL, data); SCHEME_ASSERT(num_params >= 0, "lambda has negative arguments what do"); @@ -675,7 +639,7 @@ static void letrec_check_deferred_expr(Scheme_Object *o) new_frame = init_letrec_check_frame(FRAME_TYPE_CLOSURE, LET_BODY_EXPR, num_params, inner, NULL, - NULL); + NULL, data); val = letrec_check_expr(data->code, new_frame, scheme_false); data->code = val; @@ -751,8 +715,6 @@ static Scheme_Object *letrec_check_lets(Scheme_Object *o, Letrec_Check_Frame *ol if (header_flags & SCHEME_LET_RECURSIVE) frame_type = FRAME_TYPE_LETREC; - else if (header_flags & SCHEME_LET_STAR) - frame_type = FRAME_TYPE_LETSTAR; else frame_type = FRAME_TYPE_LET; @@ -761,23 +723,17 @@ static Scheme_Object *letrec_check_lets(Scheme_Object *o, Letrec_Check_Frame *ol resolving local-variable offsets */ frame = init_letrec_check_frame(frame_type, LET_RHS_EXPR, count, old_frame, NULL, - head); + head, NULL); body = head->body; - if (frame_type == FRAME_TYPE_LETREC) - k = head->count; - else - k = 0; + k = 0; /* loops through every right hand side */ clv = NULL; for (i = num_clauses; i--;) { clv = (Scheme_Compiled_Let_Value *)body; - if (frame_type == FRAME_TYPE_LETREC) - k -= clv->count; - if (clv->count == 0) { val = letrec_check_expr(clv->value, frame, /* deferred closures get attached to no variables, @@ -806,14 +762,13 @@ static Scheme_Object *letrec_check_lets(Scheme_Object *o, Letrec_Check_Frame *ol val = letrec_check_expr(clv->value, frame, new_pos); } - if (frame_type != FRAME_TYPE_LETREC) - k += clv->count; - if (frame_type == FRAME_TYPE_LETREC) { for (j = 0; j < clv->count; j++) { frame->ref[j + k] |= LET_READY; } } + + k += clv->count; clv->value = val; @@ -826,7 +781,7 @@ static Scheme_Object *letrec_check_lets(Scheme_Object *o, Letrec_Check_Frame *ol information) */ body_frame = init_letrec_check_frame(frame_type, LET_BODY_EXPR, count, old_frame, frame, - head); + head, NULL); val = letrec_check_expr(body, body_frame, pos); @@ -883,12 +838,12 @@ static Scheme_Object *letrec_check_set(Scheme_Object *o, Letrec_Check_Frame *fra val = letrec_check_expr(val, frame, rhs_pos); sb->val = val; - if (SAME_TYPE(SCHEME_TYPE(sb->var), scheme_local_type)) { + if (SAME_TYPE(SCHEME_TYPE(sb->var), scheme_compiled_local_type)) { /* We may need to insert a definedness check before the assignment */ Letrec_Check_Frame *in_frame; - int position = SCHEME_LOCAL_POS(sb->var); + int position; - in_frame = get_relative_frame(&position, frame); + in_frame = get_relative_frame(&position, (Scheme_Compiled_Local *)sb->var); if (in_frame->ref && !(in_frame->ref[position] & LET_READY)) { @@ -897,7 +852,7 @@ static Scheme_Object *letrec_check_set(Scheme_Object *o, Letrec_Check_Frame *fra Scheme_Object *name; Scheme_Sequence *seq; - name = record_checked((Scheme_Local *)sb->var, frame); + name = record_checked((Scheme_Compiled_Local *)sb->var, frame); app3 = MALLOC_ONE_TAGGED(Scheme_App3_Rec); app3->iso.so.type = scheme_application3_type; @@ -1040,7 +995,7 @@ static Scheme_Object *letrec_check_expr(Scheme_Object *expr, Letrec_Check_Frame SCHEME_USE_FUEL(1); switch (type) { - case scheme_local_type: + case scheme_compiled_local_type: return letrec_check_local(expr, frame, pos); case scheme_application_type: return letrec_check_application(expr, frame, pos); @@ -1103,7 +1058,7 @@ Scheme_Object *scheme_letrec_check_expr(Scheme_Object *expr) frame = init_letrec_check_frame(FRAME_TYPE_TOP, LET_BODY_EXPR, 0, NULL, NULL, - NULL); + NULL, NULL); /* (Grep "EXPL-3" for information): The `pos` argument, starting here as `init_pos`, represents whether we're in a non-application diff --git a/racket/src/racket/src/marshal.c b/racket/src/racket/src/marshal.c index 68721d5cc4..fbf5660d98 100644 --- a/racket/src/racket/src/marshal.c +++ b/racket/src/racket/src/marshal.c @@ -649,17 +649,17 @@ static Scheme_Object *write_sequence(Scheme_Object *obj) static Scheme_Object *read_sequence(Scheme_Object *obj) { - return scheme_make_sequence_compilation(obj, 1); + return scheme_make_sequence_compilation(obj, 1, 1); } static Scheme_Object *read_sequence_save_first(Scheme_Object *obj) { - return scheme_make_sequence_compilation(obj, -2); + return scheme_make_sequence_compilation(obj, -2, 1); } static Scheme_Object *read_sequence_splice(Scheme_Object *obj) { - obj = scheme_make_sequence_compilation(obj, 1); + obj = scheme_make_sequence_compilation(obj, 1, 1); if (!obj) return NULL; if (SAME_TYPE(SCHEME_TYPE(obj), scheme_sequence_type)) diff --git a/racket/src/racket/src/module.c b/racket/src/racket/src/module.c index 564453d10c..7efde80dbc 100644 --- a/racket/src/racket/src/module.c +++ b/racket/src/racket/src/module.c @@ -9255,7 +9255,7 @@ static Scheme_Object *do_module_begin_at_phase(Scheme_Object *form, Scheme_Comp_ body_lists = SCHEME_CDR(m); m = SCHEME_CAR(m); /* turn list of compiled expressions into a splice: */ - m = scheme_make_sequence_compilation(m, 0); + m = scheme_make_sequence_compilation(m, 0, 0); if (m->type == scheme_sequence_type) m->type = scheme_splice_sequence_type; } else { @@ -9727,7 +9727,7 @@ static Scheme_Object *do_module_begin_at_phase(Scheme_Object *form, Scheme_Comp_ Scheme_Object *prev = NULL, *next; for (p = first; !SCHEME_NULLP(p); p = next) { next = SCHEME_CDR(p); - if (scheme_omittable_expr(SCHEME_CAR(p), -1, -1, 0, NULL, NULL, 0, 0, 0)) { + if (scheme_omittable_expr(SCHEME_CAR(p), -1, -1, 0, NULL, NULL)) { if (prev) SCHEME_CDR(prev) = next; else diff --git a/racket/src/racket/src/mzmark_compenv.inc b/racket/src/racket/src/mzmark_compenv.inc index ddcbeff3ba..4c97201a10 100644 --- a/racket/src/racket/src/mzmark_compenv.inc +++ b/racket/src/racket/src/mzmark_compenv.inc @@ -23,6 +23,7 @@ static int mark_comp_env_MARK(void *p, struct NewGC *gc) { gcMARK2(e->bindings, gc); gcMARK2(e->vals, gc); gcMARK2(e->shadower_deltas, gc); + gcMARK2(e->vars, gc); gcMARK2(e->dup_check, gc); gcMARK2(e->intdef_name, gc); gcMARK2(e->in_modidx, gc); @@ -60,6 +61,7 @@ static int mark_comp_env_FIXUP(void *p, struct NewGC *gc) { gcFIXUP2(e->bindings, gc); gcFIXUP2(e->vals, gc); gcFIXUP2(e->shadower_deltas, gc); + gcFIXUP2(e->vars, gc); gcFIXUP2(e->dup_check, gc); gcFIXUP2(e->intdef_name, gc); gcFIXUP2(e->in_modidx, gc); diff --git a/racket/src/racket/src/mzmark_fun.inc b/racket/src/racket/src/mzmark_fun.inc index 85356880c5..08bad2932f 100644 --- a/racket/src/racket/src/mzmark_fun.inc +++ b/racket/src/racket/src/mzmark_fun.inc @@ -12,8 +12,8 @@ static int mark_closure_info_MARK(void *p, struct NewGC *gc) { #ifndef GC_NO_MARK_PROCEDURE_NEEDED Closure_Info *i = (Closure_Info *)p; - gcMARK2(i->local_flags, gc); - gcMARK2(i->base_closure_map, gc); + gcMARK2(i->base_closure, gc); + gcMARK2(i->vars, gc); gcMARK2(i->local_type_map, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS @@ -29,8 +29,8 @@ static int mark_closure_info_FIXUP(void *p, struct NewGC *gc) { #ifndef GC_NO_FIXUP_PROCEDURE_NEEDED Closure_Info *i = (Closure_Info *)p; - gcFIXUP2(i->local_flags, gc); - gcFIXUP2(i->base_closure_map, gc); + gcFIXUP2(i->base_closure, gc); + gcFIXUP2(i->vars, gc); gcFIXUP2(i->local_type_map, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS diff --git a/racket/src/racket/src/mzmark_letrec_check.inc b/racket/src/racket/src/mzmark_letrec_check.inc index 4182a6c9ee..d3ce8e75bc 100644 --- a/racket/src/racket/src/mzmark_letrec_check.inc +++ b/racket/src/racket/src/mzmark_letrec_check.inc @@ -15,7 +15,6 @@ static int mark_letrec_check_frame_MARK(void *p, struct NewGC *gc) { gcMARK2(frame->def, gc); gcMARK2(frame->next, gc); gcMARK2(frame->ref, gc); - gcMARK2(frame->head, gc); gcMARK2(frame->deferred_chain, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS @@ -34,7 +33,6 @@ static int mark_letrec_check_frame_FIXUP(void *p, struct NewGC *gc) { gcFIXUP2(frame->def, gc); gcFIXUP2(frame->next, gc); gcFIXUP2(frame->ref, gc); - gcFIXUP2(frame->head, gc); gcFIXUP2(frame->deferred_chain, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS diff --git a/racket/src/racket/src/mzmark_optimize.inc b/racket/src/racket/src/mzmark_optimize.inc index 81e923f94b..a3567bcaca 100644 --- a/racket/src/racket/src/mzmark_optimize.inc +++ b/racket/src/racket/src/mzmark_optimize.inc @@ -12,18 +12,15 @@ static int mark_optimize_info_MARK(void *p, struct NewGC *gc) { #ifndef GC_NO_MARK_PROCEDURE_NEEDED Optimize_Info *i = (Optimize_Info *)p; - gcMARK2(i->stat_dists, gc); - gcMARK2(i->sd_depths, gc); gcMARK2(i->next, gc); - gcMARK2(i->use, gc); gcMARK2(i->consts, gc); gcMARK2(i->cp, gc); gcMARK2(i->top_level_consts, gc); - gcMARK2(i->transitive_use, gc); - gcMARK2(i->transitive_use_len, gc); + gcMARK2(i->transitive_use_var, gc); gcMARK2(i->context, gc); gcMARK2(i->logger, gc); gcMARK2(i->types, gc); + gcMARK2(i->uses, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS return 0; @@ -38,18 +35,15 @@ static int mark_optimize_info_FIXUP(void *p, struct NewGC *gc) { #ifndef GC_NO_FIXUP_PROCEDURE_NEEDED Optimize_Info *i = (Optimize_Info *)p; - gcFIXUP2(i->stat_dists, gc); - gcFIXUP2(i->sd_depths, gc); gcFIXUP2(i->next, gc); - gcFIXUP2(i->use, gc); gcFIXUP2(i->consts, gc); gcFIXUP2(i->cp, gc); gcFIXUP2(i->top_level_consts, gc); - gcFIXUP2(i->transitive_use, gc); - gcFIXUP2(i->transitive_use_len, gc); + gcFIXUP2(i->transitive_use_var, gc); gcFIXUP2(i->context, gc); gcFIXUP2(i->logger, gc); gcFIXUP2(i->types, gc); + gcFIXUP2(i->uses, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS return 0; @@ -76,8 +70,7 @@ static int mark_once_used_MARK(void *p, struct NewGC *gc) { #ifndef GC_NO_MARK_PROCEDURE_NEEDED Scheme_Once_Used *o = (Scheme_Once_Used *)p; gcMARK2(o->expr, gc); - gcMARK2(o->info, gc); - gcMARK2(o->next, gc); + gcMARK2(o->var, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS return 0; # else @@ -91,8 +84,7 @@ static int mark_once_used_FIXUP(void *p, struct NewGC *gc) { #ifndef GC_NO_FIXUP_PROCEDURE_NEEDED Scheme_Once_Used *o = (Scheme_Once_Used *)p; gcFIXUP2(o->expr, gc); - gcFIXUP2(o->info, gc); - gcFIXUP2(o->next, gc); + gcFIXUP2(o->var, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS return 0; # else diff --git a/racket/src/racket/src/mzmark_resolve.inc b/racket/src/racket/src/mzmark_resolve.inc index 0b99119966..d9134a53cd 100644 --- a/racket/src/racket/src/mzmark_resolve.inc +++ b/racket/src/racket/src/mzmark_resolve.inc @@ -15,12 +15,9 @@ static int mark_resolve_info_MARK(void *p, struct NewGC *gc) { gcMARK2(i->prefix, gc); gcMARK2(i->stx_map, gc); gcMARK2(i->tl_map, gc); - gcMARK2(i->old_pos, gc); - gcMARK2(i->new_pos, gc); gcMARK2(i->old_stx_pos, gc); - gcMARK2(i->flags, gc); + gcMARK2(i->redirects, gc); gcMARK2(i->lifts, gc); - gcMARK2(i->lifted, gc); gcMARK2(i->next, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS @@ -39,12 +36,9 @@ static int mark_resolve_info_FIXUP(void *p, struct NewGC *gc) { gcFIXUP2(i->prefix, gc); gcFIXUP2(i->stx_map, gc); gcFIXUP2(i->tl_map, gc); - gcFIXUP2(i->old_pos, gc); - gcFIXUP2(i->new_pos, gc); gcFIXUP2(i->old_stx_pos, gc); - gcFIXUP2(i->flags, gc); + gcFIXUP2(i->redirects, gc); gcFIXUP2(i->lifts, gc); - gcFIXUP2(i->lifted, gc); gcFIXUP2(i->next, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS @@ -72,16 +66,13 @@ static int mark_unresolve_info_MARK(void *p, struct NewGC *gc) { #ifndef GC_NO_MARK_PROCEDURE_NEEDED Unresolve_Info *i = (Unresolve_Info *)p; - gcMARK2(i->flags, gc); - gcMARK2(i->depths, gc); + gcMARK2(i->vars, gc); gcMARK2(i->prefix, gc); gcMARK2(i->closures, gc); - gcMARK2(i->closures, gc); gcMARK2(i->module, gc); gcMARK2(i->comp_prefix, gc); gcMARK2(i->toplevels, gc); gcMARK2(i->definitions, gc); - gcMARK2(i->ref_args, gc); gcMARK2(i->ref_lifts, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS @@ -97,16 +88,13 @@ static int mark_unresolve_info_FIXUP(void *p, struct NewGC *gc) { #ifndef GC_NO_FIXUP_PROCEDURE_NEEDED Unresolve_Info *i = (Unresolve_Info *)p; - gcFIXUP2(i->flags, gc); - gcFIXUP2(i->depths, gc); + gcFIXUP2(i->vars, gc); gcFIXUP2(i->prefix, gc); gcFIXUP2(i->closures, gc); - gcFIXUP2(i->closures, gc); gcFIXUP2(i->module, gc); gcFIXUP2(i->comp_prefix, gc); gcFIXUP2(i->toplevels, gc); gcFIXUP2(i->definitions, gc); - gcFIXUP2(i->ref_args, gc); gcFIXUP2(i->ref_lifts, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS diff --git a/racket/src/racket/src/mzmark_type.inc b/racket/src/racket/src/mzmark_type.inc index dab3b02a16..50fbbee16d 100644 --- a/racket/src/racket/src/mzmark_type.inc +++ b/racket/src/racket/src/mzmark_type.inc @@ -947,6 +947,78 @@ static int with_cont_mark_FIXUP(void *p, struct NewGC *gc) { #define with_cont_mark_IS_CONST_SIZE 1 +static int comp_local_SIZE(void *p, struct NewGC *gc) { +#ifndef GC_NO_SIZE_NEEDED_FROM_PROCS + gcBYTES_TO_WORDS(sizeof(Scheme_Compiled_Local)); +#else + return 0; +#endif +} + +static int comp_local_MARK(void *p, struct NewGC *gc) { +#ifndef GC_NO_MARK_PROCEDURE_NEEDED + Scheme_Compiled_Local *var = (Scheme_Compiled_Local *)p; + + gcMARK2(var->name, gc); + switch (var->mode) { + case SCHEME_VAR_MODE_LETREC_CHECK: + gcMARK2(var->letrec_check.frame, gc); + break; + case SCHEME_VAR_MODE_OPTIMIZE: + gcMARK2(var->optimize.known_val, gc); + gcMARK2(var->optimize.transitive_uses, gc); + gcMARK2(var->optimize.transitive_uses_to, gc); + break; + case SCHEME_VAR_MODE_RESOLVE: + gcMARK2(var->resolve.lifted, gc); + break; + default: + break; + } + +# ifdef GC_NO_SIZE_NEEDED_FROM_PROCS + return 0; +# else + return + gcBYTES_TO_WORDS(sizeof(Scheme_Compiled_Local)); +# endif +#endif +} + +static int comp_local_FIXUP(void *p, struct NewGC *gc) { +#ifndef GC_NO_FIXUP_PROCEDURE_NEEDED + Scheme_Compiled_Local *var = (Scheme_Compiled_Local *)p; + + gcFIXUP2(var->name, gc); + switch (var->mode) { + case SCHEME_VAR_MODE_LETREC_CHECK: + gcFIXUP2(var->letrec_check.frame, gc); + break; + case SCHEME_VAR_MODE_OPTIMIZE: + gcFIXUP2(var->optimize.known_val, gc); + gcFIXUP2(var->optimize.transitive_uses, gc); + gcFIXUP2(var->optimize.transitive_uses_to, gc); + break; + case SCHEME_VAR_MODE_RESOLVE: + gcFIXUP2(var->resolve.lifted, gc); + break; + default: + break; + } + +# ifdef GC_NO_SIZE_NEEDED_FROM_PROCS + return 0; +# else + return + gcBYTES_TO_WORDS(sizeof(Scheme_Compiled_Local)); +# endif +#endif +} + +#define comp_local_IS_ATOMIC 0 +#define comp_local_IS_CONST_SIZE 1 + + static int comp_let_value_SIZE(void *p, struct NewGC *gc) { #ifndef GC_NO_SIZE_NEEDED_FROM_PROCS gcBYTES_TO_WORDS(sizeof(Scheme_Compiled_Let_Value)); @@ -959,10 +1031,9 @@ static int comp_let_value_MARK(void *p, struct NewGC *gc) { #ifndef GC_NO_MARK_PROCEDURE_NEEDED Scheme_Compiled_Let_Value *c = (Scheme_Compiled_Let_Value *)p; - gcMARK2(c->flags, gc); gcMARK2(c->value, gc); gcMARK2(c->body, gc); - gcMARK2(c->names, gc); + gcMARK2(c->vars, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS return 0; @@ -977,10 +1048,9 @@ static int comp_let_value_FIXUP(void *p, struct NewGC *gc) { #ifndef GC_NO_FIXUP_PROCEDURE_NEEDED Scheme_Compiled_Let_Value *c = (Scheme_Compiled_Let_Value *)p; - gcFIXUP2(c->flags, gc); gcFIXUP2(c->value, gc); gcFIXUP2(c->body, gc); - gcFIXUP2(c->names, gc); + gcFIXUP2(c->vars, gc); # ifdef GC_NO_SIZE_NEEDED_FROM_PROCS return 0; diff --git a/racket/src/racket/src/mzmarksrc.c b/racket/src/racket/src/mzmarksrc.c index efe40de46c..d81df6b8e9 100644 --- a/racket/src/racket/src/mzmarksrc.c +++ b/racket/src/racket/src/mzmarksrc.c @@ -228,14 +228,38 @@ with_cont_mark { gcBYTES_TO_WORDS(sizeof(Scheme_With_Continuation_Mark)); } +comp_local { + mark: + Scheme_Compiled_Local *var = (Scheme_Compiled_Local *)p; + + gcMARK2(var->name, gc); + switch (var->mode) { + case SCHEME_VAR_MODE_LETREC_CHECK: + gcMARK2(var->letrec_check.frame, gc); + break; + case SCHEME_VAR_MODE_OPTIMIZE: + gcMARK2(var->optimize.known_val, gc); + gcMARK2(var->optimize.transitive_uses, gc); + gcMARK2(var->optimize.transitive_uses_to, gc); + break; + case SCHEME_VAR_MODE_RESOLVE: + gcMARK2(var->resolve.lifted, gc); + break; + default: + break; + } + + size: + gcBYTES_TO_WORDS(sizeof(Scheme_Compiled_Local)); +} + comp_let_value { mark: Scheme_Compiled_Let_Value *c = (Scheme_Compiled_Let_Value *)p; - gcMARK2(c->flags, gc); gcMARK2(c->value, gc); gcMARK2(c->body, gc); - gcMARK2(c->names, gc); + gcMARK2(c->vars, gc); size: gcBYTES_TO_WORDS(sizeof(Scheme_Compiled_Let_Value)); @@ -1268,6 +1292,7 @@ mark_comp_env { gcMARK2(e->bindings, gc); gcMARK2(e->vals, gc); gcMARK2(e->shadower_deltas, gc); + gcMARK2(e->vars, gc); gcMARK2(e->dup_check, gc); gcMARK2(e->intdef_name, gc); gcMARK2(e->in_modidx, gc); @@ -1298,12 +1323,9 @@ mark_resolve_info { gcMARK2(i->prefix, gc); gcMARK2(i->stx_map, gc); gcMARK2(i->tl_map, gc); - gcMARK2(i->old_pos, gc); - gcMARK2(i->new_pos, gc); gcMARK2(i->old_stx_pos, gc); - gcMARK2(i->flags, gc); + gcMARK2(i->redirects, gc); gcMARK2(i->lifts, gc); - gcMARK2(i->lifted, gc); gcMARK2(i->next, gc); size: @@ -1314,16 +1336,13 @@ mark_unresolve_info { mark: Unresolve_Info *i = (Unresolve_Info *)p; - gcMARK2(i->flags, gc); - gcMARK2(i->depths, gc); + gcMARK2(i->vars, gc); gcMARK2(i->prefix, gc); gcMARK2(i->closures, gc); - gcMARK2(i->closures, gc); gcMARK2(i->module, gc); gcMARK2(i->comp_prefix, gc); gcMARK2(i->toplevels, gc); gcMARK2(i->definitions, gc); - gcMARK2(i->ref_args, gc); gcMARK2(i->ref_lifts, gc); size: @@ -1361,7 +1380,6 @@ mark_letrec_check_frame { gcMARK2(frame->def, gc); gcMARK2(frame->next, gc); gcMARK2(frame->ref, gc); - gcMARK2(frame->head, gc); gcMARK2(frame->deferred_chain, gc); size: @@ -1390,18 +1408,15 @@ mark_optimize_info { mark: Optimize_Info *i = (Optimize_Info *)p; - gcMARK2(i->stat_dists, gc); - gcMARK2(i->sd_depths, gc); gcMARK2(i->next, gc); - gcMARK2(i->use, gc); gcMARK2(i->consts, gc); gcMARK2(i->cp, gc); gcMARK2(i->top_level_consts, gc); - gcMARK2(i->transitive_use, gc); - gcMARK2(i->transitive_use_len, gc); + gcMARK2(i->transitive_use_var, gc); gcMARK2(i->context, gc); gcMARK2(i->logger, gc); gcMARK2(i->types, gc); + gcMARK2(i->uses, gc); size: gcBYTES_TO_WORDS(sizeof(Optimize_Info)); @@ -1411,8 +1426,7 @@ mark_once_used { mark: Scheme_Once_Used *o = (Scheme_Once_Used *)p; gcMARK2(o->expr, gc); - gcMARK2(o->info, gc); - gcMARK2(o->next, gc); + gcMARK2(o->var, gc); size: gcBYTES_TO_WORDS(sizeof(Scheme_Once_Used)); } @@ -1461,8 +1475,8 @@ mark_closure_info { mark: Closure_Info *i = (Closure_Info *)p; - gcMARK2(i->local_flags, gc); - gcMARK2(i->base_closure_map, gc); + gcMARK2(i->base_closure, gc); + gcMARK2(i->vars, gc); gcMARK2(i->local_type_map, gc); size: diff --git a/racket/src/racket/src/optimize.c b/racket/src/racket/src/optimize.c index 70ef407194..d9f707e96f 100644 --- a/racket/src/racket/src/optimize.c +++ b/racket/src/racket/src/optimize.c @@ -31,6 +31,8 @@ #include "schrunst.h" #include "schmach.h" +static ROSYM Scheme_Hash_Tree *empty_eq_hash_tree; + #define cons(a,b) scheme_make_pair(a,b) /* Controls for inlining algorithm: */ @@ -71,7 +73,7 @@ struct Optimize_Info for constraining the movement of allocation operations */ int sclock; /* virtual clock that ticks when space consumption is potentially observed */ int psize; - short inline_fuel, shift_fuel, flatten_fuel; + short inline_fuel, flatten_fuel; char letrec_not_twice, enforce_const, use_psize, has_nonleaf; Scheme_Hash_Table *top_level_consts; @@ -83,74 +85,54 @@ struct Optimize_Info that single_result and preserves_marks are also 1, and that it's not necessary to use optimize_ignored before including the expression. */ - char **stat_dists; /* (pos, depth) => used? */ - int *sd_depths; + int lambda_depth; int used_toplevel; - char *use; - int transitive_use_pos; /* set to pos + 1 when optimizing a letrec-bound procedure */ - mzshort **transitive_use; - int *transitive_use_len; + Scheme_Compiled_Local *transitive_use_var; /* set when optimizing a letrec-bound procedure */ Scheme_Object *context; /* for logging */ Scheme_Logger *logger; Scheme_Hash_Tree *types; /* maps position (from this frame) to predicate */ int no_types; + + Scheme_Hash_Table *uses; /* used variables, accumulated for closures */ }; typedef struct Optimize_Info_Sequence { - int init_shift_fuel, min_shift_fuel; int init_flatten_fuel, min_flatten_fuel; } Optimize_Info_Sequence; -#define OPT_IS_MUTATED 0x1 -#define OPT_ESCAPES_AFTER_K_TICK 0x2 -#define OPT_LOCAL_TYPE_ARG_SHIFT 2 -#define OPT_LOCAL_TYPE_VAL_SHIFT (OPT_LOCAL_TYPE_ARG_SHIFT + SCHEME_MAX_LOCAL_TYPE_BITS) - static char *get_closure_local_type_map(Scheme_Closure_Data *data, int arg_n, int *ok); static void set_closure_local_type_map(Scheme_Closure_Data *data, char *local_type_map); static void merge_closure_local_type_map(Scheme_Closure_Data *data1, Scheme_Closure_Data *data2); static int closure_body_size(Scheme_Closure_Data *data, int check_assign, Optimize_Info *info, int *is_leaf); static int closure_has_top_level(Scheme_Closure_Data *data); -static int closure_argument_flags(Scheme_Closure_Data *data, int i); static int wants_local_type_arguments(Scheme_Object *rator, int argpos); static void add_types_for_f_branch(Scheme_Object *t, Optimize_Info *info, int fuel); -static int optimize_info_is_ready(Optimize_Info *info, int pos); - -static void optimize_propagate(Optimize_Info *info, int pos, Scheme_Object *value, int single_use); -static Scheme_Object *optimize_info_lookup(Optimize_Info *info, int pos, int *closure_offset, int *single_use, +static Scheme_Object *optimize_info_lookup(Optimize_Info *info, Scheme_Object *var, int closure_ok, int *single_use, int once_used_ok, int context, int *potential_size, int *_mutated); -static Scheme_Object *optimize_info_mutated_lookup(Optimize_Info *info, int pos, int *is_mutated); static void optimize_info_used_top(Optimize_Info *info); -static Scheme_Object *do_optimize_get_predicate(Optimize_Info *info, int pos, int ignore_no_types); -static Scheme_Object *optimize_get_predicate(Optimize_Info *info, int pos); -static void add_type(Optimize_Info *info, int pos, Scheme_Object *pred); -static void merge_types(Optimize_Info *src_info, Optimize_Info *info, int delta); -static Scheme_Object *lookup_constant_proc(Optimize_Info *info, Scheme_Object *rand, int delta); +static Scheme_Object *do_optimize_get_predicate(Optimize_Info *info, Scheme_Object *var, int ignore_no_types); +static Scheme_Object *optimize_get_predicate(Optimize_Info *info, Scheme_Object *var); +static void add_type(Optimize_Info *info, Scheme_Object *var, Scheme_Object *pred); +static void merge_types(Optimize_Info *src_info, Optimize_Info *info, Scheme_Hash_Tree *skip_vars); +static Scheme_Object *lookup_constant_proc(Optimize_Info *info, Scheme_Object *rand); static int predicate_to_local_type(Scheme_Object *pred); -static Scheme_Object *expr_implies_predicate(Scheme_Object *expr, Optimize_Info *info, int delta, int fuel); -static void optimize_mutated(Optimize_Info *info, int pos); -static void optimize_produces_local_type(Optimize_Info *info, int pos, int ct); +static Scheme_Object *expr_implies_predicate(Scheme_Object *expr, Optimize_Info *info, + int *_involves_k_cross, int fuel); static int produces_local_type(Scheme_Object *rator, int argc); -static Scheme_Object *optimize_reverse(Optimize_Info *info, int pos, int unless_mutated, int disrupt_single_use); -static int optimize_is_used(Optimize_Info *info, int pos); -static int optimize_any_uses(Optimize_Info *info, int start_pos, int end_pos); -static int optimize_is_mutated(Optimize_Info *info, int pos); -static int optimize_escapes_after_k_tick(Optimize_Info *info, int pos); -static int optimize_is_local_type_arg(Optimize_Info *info, int pos, int depth); -static int optimize_is_local_type_valued(Optimize_Info *info, int pos); -static void optimize_set_not_single_use(Optimize_Info *info, int pos); +static int optimize_any_uses(Optimize_Info *info, Scheme_Compiled_Let_Value *at_clv, int n); +static void propagate_used_variables(Optimize_Info *info); static int env_uses_toplevel(Optimize_Info *frame); -static void env_make_closure_map(Optimize_Info *frame, mzshort *size, mzshort **map); +static Scheme_Compiled_Local *clone_variable(Scheme_Compiled_Local *var); +static void increment_use_count(Scheme_Compiled_Local *var, int as_rator); static Optimize_Info *optimize_info_add_frame(Optimize_Info *info, int orig, int current, int flags); -static int optimize_info_get_shift(Optimize_Info *info, int pos); static void optimize_info_done(Optimize_Info *info, Optimize_Info *parent); static void optimize_info_seq_init(Optimize_Info *info, Optimize_Info_Sequence *info_seq); @@ -160,15 +142,14 @@ static void optimize_info_seq_done(Optimize_Info *info, Optimize_Info_Sequence * static Scheme_Object *estimate_closure_size(Scheme_Object *e); static Scheme_Object *no_potential_size(Scheme_Object *value); -static Scheme_Object *optimize_clone(int dup_ok, Scheme_Object *obj, Optimize_Info *info, int delta, int closure_depth); -static Scheme_Object *optimize_shift(Scheme_Object *obj, int delta, int after_depth); +static Scheme_Object *optimize_clone(int single_use, Scheme_Object *obj, Optimize_Info *info, Scheme_Hash_Tree *var_map, int as_rator); static int relevant_predicate(Scheme_Object *pred); static int single_valued_noncm_expression(Scheme_Object *expr, int fuel); -static Scheme_Object *optimize_ignored(Scheme_Object *e, Optimize_Info *info, int id_offset, +static Scheme_Object *optimize_ignored(Scheme_Object *e, Optimize_Info *info, int expected_vals, int maybe_omittable, int fuel); -static int movable_expression(Scheme_Object *expr, Optimize_Info *info, int delta, +static int movable_expression(Scheme_Object *expr, Optimize_Info *info, int cross_lambda, int cross_k, int cross_s, int check_space, int fuel); @@ -184,24 +165,17 @@ static int compiled_proc_body_size(Scheme_Object *o, int less_args); typedef struct Scheme_Once_Used { Scheme_Object so; Scheme_Object *expr; - int pos; + Scheme_Compiled_Local *var; int vclock; int aclock; int kclock; int sclock; int spans_k; /* potentially captures a continuation */ - - int used; - int delta; - int cross_lambda; - Optimize_Info *info; - - struct Scheme_Once_Used *next; + int moved; } Scheme_Once_Used; -static Scheme_Once_Used *make_once_used(Scheme_Object *val, int pos, - int vclock, int aclock, int kclock, int sclock, int spans_k, - Scheme_Once_Used *prev); +static Scheme_Once_Used *make_once_used(Scheme_Object *val, Scheme_Compiled_Local *var, + int vclock, int aclock, int kclock, int sclock, int spans_k); #ifdef MZ_PRECISE_GC static void register_traversers(void); @@ -209,6 +183,9 @@ static void register_traversers(void); void scheme_init_optimize() { + REGISTER_SO(empty_eq_hash_tree); + empty_eq_hash_tree = scheme_make_hash_tree(0); + #ifdef MZ_PRECISE_GC register_traversers(); #endif @@ -218,6 +195,13 @@ void scheme_init_optimize() /* utils */ /*========================================================================*/ +static void set_optimize_mode(Scheme_Compiled_Local *var) +{ + MZ_ASSERT(SAME_TYPE(var->so.type, scheme_compiled_local_type)); + memset(&var->optimize, 0, sizeof(var->optimize)); + var->mode = SCHEME_VAR_MODE_OPTIMIZE; +} + int scheme_is_functional_nonfailing_primitive(Scheme_Object *rator, int num_args, int expected_vals) /* return 2 => results are a constant when arguments are constants */ { @@ -305,29 +289,23 @@ static Scheme_Object *extract_specialized_proc(Scheme_Object *le, Scheme_Object return default_val; } -int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved, - Optimize_Info *opt_info, Optimize_Info *warn_info, - int min_id_depth, int id_offset, int no_id) - /* Checks whether the bytecode `o' returns `vals' values with no +int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int flags, + Optimize_Info *opt_info, Optimize_Info *warn_info) + /* Checks whether the bytecode `o` returns `vals` values with no side-effects and without pushing and using continuation marks. - -1 for vals means that any return count is ok. + A -1 for `vals` means that any return count is ok. Also used with fully resolved expression by `module' to check - for "functional" bodies. - If warn_info is supplied, complain when a mismatch is detected. - The min_id_depth argument (plus id_ofset) indicates the minimum - depth allowed for local-variable reference; use this to disallow - access to the first N variables that represent bindings being set up, - for example. - The id_offset value indicates an offset for local variables relative - to opt_info; id_offset is also implicitly added to min_id_depth. - If no_id is NO_ID_OMIT (= 1), then an identifier doesn't count as omittable, - unless the identifier is a consistent top-level; the no_id mode - is used by the "compile" phase before letrec checks are inserted - (where referencing a variable might raise an exception) and to - imply the absence of a continuation-mark impersonator. - If no_id is NO_MUTABLE_ID_OMIT (= -1), then an identifier doesn't - count as omittable if it's mutable, because the expression may be reordered - instead of omitted; opt_info must be provided to check mutability. */ + for "functional" bodies, in which case `flags` includes + `OMITTABLE_RESOLVED`. + The `opt_info` argument is used only to access module-level + information, not local bindings. + If `warn_info` is supplied, complain when a mismatch is detected. + We rely on the letrec-check pass to avoid omitting early references + to letrec-bound variables, but `flags` can include `OMITTABLE_KEEP_VARS` + to keep all variable references. + If flags includes `OMITTABLE_KEEP_MUTABLE_VARS`, then references + to mutable variables are kept, which allows this function to be + a conservative approximation for "reorderable". */ { Scheme_Type vtype; @@ -338,15 +316,16 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved, vtype = SCHEME_TYPE(o); if ((vtype > _scheme_compiled_values_types_) + || ((vtype == scheme_compiled_local_type) + && !(flags & OMITTABLE_KEEP_VARS) + && (!(flags & OMITTABLE_KEEP_MUTABLE_VARS) + || !SCHEME_VAR(o)->mutated)) || ((vtype == scheme_local_type) - && (no_id <= 0) - && !(SCHEME_GET_LOCAL_FLAGS(o) == SCHEME_LOCAL_CLEAR_ON_READ) - && (SCHEME_LOCAL_POS(o) >= (min_id_depth + id_offset)) - && (!no_id || !optimize_is_mutated(opt_info, SCHEME_LOCAL_POS(o) - id_offset))) + && !(flags & OMITTABLE_KEEP_VARS) + && !(SCHEME_GET_LOCAL_FLAGS(o) == SCHEME_LOCAL_CLEAR_ON_READ)) || ((vtype == scheme_local_unbox_type) - && !no_id - && !(SCHEME_GET_LOCAL_FLAGS(o) == SCHEME_LOCAL_CLEAR_ON_READ) - && (SCHEME_LOCAL_POS(o) >= (min_id_depth + id_offset))) + && !(flags & (OMITTABLE_KEEP_VARS | OMITTABLE_KEEP_MUTABLE_VARS)) + && !(SCHEME_GET_LOCAL_FLAGS(o) == SCHEME_LOCAL_CLEAR_ON_READ)) || (vtype == scheme_unclosed_procedure_type) || (vtype == scheme_compiled_unclosed_procedure_type) || (vtype == scheme_inline_variant_type) @@ -360,7 +339,7 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved, if (vtype == scheme_toplevel_type) { note_match(1, vals, warn_info); - if (!no_id && resolved && ((vals == 1) || (vals < 0))) { + if (!(flags & OMITTABLE_KEEP_VARS) && (flags & OMITTABLE_RESOLVED) && ((vals == 1) || (vals < 0))) { if (SCHEME_TOPLEVEL_FLAGS(o) & SCHEME_TOPLEVEL_FLAGS_MASK) return 1; else @@ -371,7 +350,8 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved, if (vtype == scheme_compiled_toplevel_type) { note_match(1, vals, warn_info); if ((vals == 1) || (vals < 0)) { - if (!no_id && ((SCHEME_TOPLEVEL_FLAGS(o) & SCHEME_TOPLEVEL_FLAGS_MASK) >= SCHEME_TOPLEVEL_READY)) + if (!(flags & OMITTABLE_KEEP_VARS) + && ((SCHEME_TOPLEVEL_FLAGS(o) & SCHEME_TOPLEVEL_FLAGS_MASK) >= SCHEME_TOPLEVEL_READY)) return 1; else if ((SCHEME_TOPLEVEL_FLAGS(o) & SCHEME_TOPLEVEL_FLAGS_MASK) >= SCHEME_TOPLEVEL_FIXED) return 1; @@ -383,63 +363,51 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved, if (vtype == scheme_branch_type) { Scheme_Branch_Rec *b; b = (Scheme_Branch_Rec *)o; - return (scheme_omittable_expr(b->test, 1, fuel - 1, resolved, opt_info, warn_info, min_id_depth, id_offset, no_id) - && scheme_omittable_expr(b->tbranch, vals, fuel - 1, resolved, opt_info, warn_info, min_id_depth, id_offset, no_id) - && scheme_omittable_expr(b->fbranch, vals, fuel - 1, resolved, opt_info, warn_info, min_id_depth, id_offset, no_id)); + return (scheme_omittable_expr(b->test, 1, fuel - 1, flags, opt_info, warn_info) + && scheme_omittable_expr(b->tbranch, vals, fuel - 1, flags, opt_info, warn_info) + && scheme_omittable_expr(b->fbranch, vals, fuel - 1, flags, opt_info, warn_info)); } -#if 0 - /* We can't do this because a set! to a lexical is turned into - a let_value_type! */ - if (vtype == scheme_let_value_type) { - Scheme_Let_Value *lv = (Scheme_Let_Value *)o; - return (scheme_omittable_expr(lv->value, lv->count, fuel - 1, resolved, opt_info, warn_info, min_id_depth, id_offset, no_id) - && scheme_omittable_expr(lv->body, vals, fuel - 1, resolved, opt_info, warn_info, min_id_depth, id_offset, no_id)); - } -#endif - if (vtype == scheme_let_one_type) { Scheme_Let_One *lo = (Scheme_Let_One *)o; - return (scheme_omittable_expr(lo->value, 1, fuel - 1, resolved, opt_info, warn_info, min_id_depth, id_offset + 1, no_id) - && scheme_omittable_expr(lo->body, vals, fuel - 1, resolved, opt_info, warn_info, min_id_depth, id_offset + 1, no_id)); + return (scheme_omittable_expr(lo->value, 1, fuel - 1, flags, opt_info, warn_info) + && scheme_omittable_expr(lo->body, vals, fuel - 1, flags, opt_info, warn_info)); } if (vtype == scheme_let_void_type) { Scheme_Let_Void *lv = (Scheme_Let_Void *)o; /* recognize (letrec ([x ]) ...): */ + MZ_ASSERT(flags & OMITTABLE_RESOLVED); if (SAME_TYPE(SCHEME_TYPE(lv->body), scheme_let_value_type)) { Scheme_Let_Value *lv2 = (Scheme_Let_Value *)lv->body; if ((lv2->count == 1) && (lv2->position == 0) - && scheme_omittable_expr(lv2->value, 1, fuel - 1, resolved, opt_info, warn_info, - min_id_depth, id_offset + 1 + lv->count, - no_id)) { + && scheme_omittable_expr(lv2->value, 1, fuel - 1, flags, opt_info, warn_info)) { o = lv2->body; - id_offset += 1; } else o = lv->body; } else o = lv->body; - id_offset += lv->count; goto try_again; } if (vtype == scheme_compiled_let_void_type) { /* recognize another (let ([x ]) ...) pattern: */ Scheme_Let_Header *lh = (Scheme_Let_Header *)o; - if ((lh->count == 1) && (lh->num_clauses == 1)) { - if (SAME_TYPE(SCHEME_TYPE(lh->body), scheme_compiled_let_value_type)) { - Scheme_Compiled_Let_Value *lv = (Scheme_Compiled_Let_Value *)lh->body; - if (scheme_omittable_expr(lv->value, 1, fuel - 1, resolved, opt_info, warn_info, min_id_depth, id_offset + 1, no_id)) { - o = lv->body; - id_offset++; - goto try_again; - } - } + int i; + MZ_ASSERT(!(flags & OMITTABLE_RESOLVED)); + o = lh->body; + for (i = 0; i < lh->num_clauses; i++) { + Scheme_Compiled_Let_Value *lv = (Scheme_Compiled_Let_Value *)o; + if (!scheme_omittable_expr(lv->value, lv->count, fuel - 1, flags, opt_info, warn_info)) + return 0; + o = lv->body; } + goto try_again; } if (vtype == scheme_letrec_type) { + MZ_ASSERT(flags & OMITTABLE_RESOLVED); o = ((Scheme_Letrec *)o)->body; goto try_again; } @@ -456,8 +424,7 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved, || scheme_is_struct_functional(app->args[0], app->num_args, opt_info, vals)) { int i; for (i = app->num_args; i--; ) { - if (!scheme_omittable_expr(app->args[i + 1], 1, fuel - 1, resolved, opt_info, warn_info, - min_id_depth, id_offset + (resolved ? app->num_args : 0), no_id)) + if (!scheme_omittable_expr(app->args[i + 1], 1, fuel - 1, flags, opt_info, warn_info)) return 0; } return 1; @@ -476,8 +443,7 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved, Scheme_App2_Rec *app = (Scheme_App2_Rec *)o; if (scheme_is_functional_nonfailing_primitive(app->rator, 1, vals) || scheme_is_struct_functional(app->rator, 1, opt_info, vals)) { - if (scheme_omittable_expr(app->rand, 1, fuel - 1, resolved, opt_info, warn_info, - min_id_depth, id_offset + (resolved ? 1 : 0), no_id)) + if (scheme_omittable_expr(app->rand, 1, fuel - 1, flags, opt_info, warn_info)) return 1; } else if (SAME_OBJ(app->rator, scheme_make_vector_proc) && (vals == 1 || vals == -1) @@ -501,18 +467,15 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved, Scheme_App3_Rec *app = (Scheme_App3_Rec *)o; if (scheme_is_functional_nonfailing_primitive(app->rator, 2, vals) || scheme_is_struct_functional(app->rator, 2, opt_info, vals)) { - if (scheme_omittable_expr(app->rand1, 1, fuel - 1, resolved, opt_info, warn_info, - min_id_depth, id_offset + (resolved ? 2 : 0), no_id) - && scheme_omittable_expr(app->rand2, 1, fuel - 1, resolved, opt_info, warn_info, - min_id_depth, id_offset + (resolved ? 2 : 0), no_id)) + if (scheme_omittable_expr(app->rand1, 1, fuel - 1, flags, opt_info, warn_info) + && scheme_omittable_expr(app->rand2, 1, fuel - 1, flags, opt_info, warn_info)) return 1; } else if (SAME_OBJ(app->rator, scheme_make_vector_proc) && (vals == 1 || vals == -1) && (SCHEME_INTP(app->rand1) && (SCHEME_INT_VAL(app->rand1) >= 0) && IN_FIXNUM_RANGE_ON_ALL_PLATFORMS(SCHEME_INT_VAL(app->rand1))) - && scheme_omittable_expr(app->rand2, 1, fuel - 1, resolved, opt_info, warn_info, - min_id_depth, id_offset + (resolved ? 2 : 0), no_id)) { + && scheme_omittable_expr(app->rand2, 1, fuel - 1, flags, opt_info, warn_info)) { return 1; } else if (SCHEME_PRIMP(app->rator)) { if (!(SCHEME_PRIM_PROC_FLAGS(app->rator) & SCHEME_PRIM_IS_MULTI_RESULT)) { @@ -531,20 +494,22 @@ int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved, && SAME_TYPE(scheme_local_type, SCHEME_TYPE(sb->val)) && (SCHEME_LOCAL_POS(sb->var) == SCHEME_LOCAL_POS(sb->val))) return 1; + else if (SAME_TYPE(scheme_compiled_local_type, SCHEME_TYPE(sb->var)) + && SAME_OBJ(sb->var, sb->val)) + return 1; } /* check for struct-type declaration: */ { Scheme_Object *auto_e; int auto_e_depth; - auto_e = scheme_is_simple_make_struct_type(o, vals, resolved, 0, &auto_e_depth, + auto_e = scheme_is_simple_make_struct_type(o, vals, flags, 0, &auto_e_depth, NULL, (opt_info ? opt_info->top_level_consts : NULL), NULL, NULL, 0, NULL, NULL, 5); if (auto_e) { - if (scheme_omittable_expr(auto_e, 1, fuel - 1, resolved, opt_info, warn_info, - min_id_depth, id_offset + auto_e_depth, no_id)) + if (scheme_omittable_expr(auto_e, 1, fuel - 1, flags, opt_info, warn_info)) return 1; } } @@ -566,7 +531,7 @@ static Scheme_Object *ensure_single_value(Scheme_Object *e) } static Scheme_Object *do_make_discarding_sequence(Scheme_Object *e1, Scheme_Object *e2, - Optimize_Info *info, int id_offset, + Optimize_Info *info, int ignored, int rev) /* Evaluate `e1` then `e2` (or opposite order if rev), and each must produce a single value. The result of `e1` is ignored and the @@ -575,44 +540,45 @@ static Scheme_Object *do_make_discarding_sequence(Scheme_Object *e1, Scheme_Obje { int e2_omit; - e2_omit = scheme_omittable_expr(e2, 1, 5, 0, info, NULL, 0, id_offset, ID_OMIT); + e2_omit = scheme_omittable_expr(e2, 1, 5, 0, info, NULL); if (!e2_omit && !single_valued_noncm_expression(e2, 5)) e2 = ensure_single_value(e2); - if (scheme_omittable_expr(e1, 1, 5, 0, info, NULL, 0, id_offset, ID_OMIT)) + if (scheme_omittable_expr(e1, 1, 5, 0, info, NULL)) return e2; else if (single_valued_noncm_expression(e1, 5)) - e1 = optimize_ignored(e1, info, id_offset, 1, 0, 5); + e1 = optimize_ignored(e1, info, 1, 0, 5); else - e1 = ensure_single_value(optimize_ignored(e1, info, id_offset, 1, 0, 5)); + e1 = ensure_single_value(optimize_ignored(e1, info, 1, 0, 5)); if (e2_omit && ignored) return e1; /* use `begin` instead of `begin0` if we can swap the order: */ - if (rev && movable_expression(e2, info, -id_offset, 0, 1, 1, 0, 50)) + if (rev && movable_expression(e2, info, 0, 1, 1, 0, 50)) rev = 0; return scheme_make_sequence_compilation(scheme_make_pair((rev ? e2 : e1), scheme_make_pair((rev ? e1 : e2), scheme_null)), - rev ? -1 : 1); + rev ? -1 : 1, + 0); } static Scheme_Object *make_discarding_sequence(Scheme_Object *e1, Scheme_Object *e2, - Optimize_Info *info, int id_offset) + Optimize_Info *info) { - return do_make_discarding_sequence(e1, e2, info, id_offset, 0, 0); + return do_make_discarding_sequence(e1, e2, info, 0, 0); } static Scheme_Object *make_discarding_reverse_sequence(Scheme_Object *e1, Scheme_Object *e2, - Optimize_Info *info, int id_offset) + Optimize_Info *info) { - return do_make_discarding_sequence(e1, e2, info, id_offset, 0, 1); + return do_make_discarding_sequence(e1, e2, info, 0, 1); } static Scheme_Object *make_discarding_app_sequence(Scheme_App_Rec *appr, int result_pos, Scheme_Object *result, - Optimize_Info *info, int id_offset) + Optimize_Info *info) /* Generalize do_make_discarding_sequence() to a sequence of argument expressions, where `result_pos` is the position of the returned argument. If `result_pos` is -1, then all argument results will be @@ -628,16 +594,16 @@ static Scheme_Object *make_discarding_app_sequence(Scheme_App_Rec *appr, int res for (i = appr->num_args; i; i--) { e = appr->args[i]; - if (scheme_omittable_expr(e, 1, 5, 0, info, NULL, 0, 0, ID_OMIT)) { + if (scheme_omittable_expr(e, 1, 5, 0, info, NULL)) { /* drop if not result pos */ } else if (single_valued_noncm_expression(e, 5)) { if (i != result_pos) { - l = scheme_make_pair(optimize_ignored(e, info, id_offset, 1, 0, 5), l); + l = scheme_make_pair(optimize_ignored(e, info, 1, 0, 5), l); } } else if (i == result_pos) { e = ensure_single_value(e); } else if (i != result_pos) { - e = ensure_single_value(optimize_ignored(e, info, id_offset, 1, 0, 5)); + e = ensure_single_value(optimize_ignored(e, info, 1, 0, 5)); l = scheme_make_pair(e, l); } @@ -645,7 +611,7 @@ static Scheme_Object *make_discarding_app_sequence(Scheme_App_Rec *appr, int res if (SCHEME_NULLP(l)) { l = scheme_make_pair(e, scheme_null); } else { - l = scheme_make_sequence_compilation(scheme_make_pair(e, l), -1); + l = scheme_make_sequence_compilation(scheme_make_pair(e, l), -1, 0); l = scheme_make_pair(l, scheme_null); } } @@ -657,10 +623,10 @@ static Scheme_Object *make_discarding_app_sequence(Scheme_App_Rec *appr, int res if (SCHEME_NULLP(SCHEME_CDR(l))) return SCHEME_CAR(l); - return scheme_make_sequence_compilation(l, 1); + return scheme_make_sequence_compilation(l, 1, 0); } -static Scheme_Object *optimize_ignored(Scheme_Object *e, Optimize_Info *info, int id_offset, +static Scheme_Object *optimize_ignored(Scheme_Object *e, Optimize_Info *info, int expected_vals, int maybe_omittable, int fuel) /* Simplify an expression whose result will be ignored. The @@ -668,7 +634,7 @@ static Scheme_Object *optimize_ignored(Scheme_Object *e, Optimize_Info *info, in NULL to dincate that it can be omitted. */ { if (maybe_omittable) { - if (scheme_omittable_expr(e, expected_vals, 5, 0, info, NULL, 0, id_offset, ID_OMIT)) + if (scheme_omittable_expr(e, expected_vals, 5, 0, info, NULL)) return NULL; } @@ -682,7 +648,7 @@ static Scheme_Object *optimize_ignored(Scheme_Object *e, Optimize_Info *info, in if (!SAME_OBJ(app->rator, scheme_values_func)) /* `values` is probably here to ensure a single result */ if (scheme_is_functional_nonfailing_primitive(app->rator, 1, expected_vals)) - return do_make_discarding_sequence(app->rand, scheme_void, info, id_offset, 1, 0); + return do_make_discarding_sequence(app->rand, scheme_void, info, 1, 0); /* (make-vector ) => */ if (SAME_OBJ(app->rator, scheme_make_vector_proc) @@ -700,9 +666,9 @@ static Scheme_Object *optimize_ignored(Scheme_Object *e, Optimize_Info *info, in return do_make_discarding_sequence(app->rand1, do_make_discarding_sequence(app->rand2, scheme_void, - info, id_offset, + info, 1, 0), - info, id_offset, + info, 1, 0); /* (make-vector ) => */ @@ -711,9 +677,9 @@ static Scheme_Object *optimize_ignored(Scheme_Object *e, Optimize_Info *info, in && (SCHEME_INT_VAL(app->rand1) >= 0)) && IN_FIXNUM_RANGE_ON_ALL_PLATFORMS(SCHEME_INT_VAL(app->rand1))) { if (single_valued_noncm_expression(app->rand2, 5)) - return optimize_ignored(app->rand2, info, id_offset, 1, maybe_omittable, 5); + return optimize_ignored(app->rand2, info, 1, maybe_omittable, 5); else - return ensure_single_value(optimize_ignored(app->rand2, info, id_offset, 1, 0, 5)); + return ensure_single_value(optimize_ignored(app->rand2, info, 1, 0, 5)); } } break; @@ -722,7 +688,7 @@ static Scheme_Object *optimize_ignored(Scheme_Object *e, Optimize_Info *info, in Scheme_App_Rec *app = (Scheme_App_Rec *)e; if (scheme_is_functional_nonfailing_primitive(app->args[0], app->num_args, expected_vals)) - return make_discarding_app_sequence(app, -1, NULL, info, id_offset); + return make_discarding_app_sequence(app, -1, NULL, info); } break; } @@ -733,15 +699,15 @@ static Scheme_Object *optimize_ignored(Scheme_Object *e, Optimize_Info *info, in static Scheme_Object *make_sequence_2(Scheme_Object *a, Scheme_Object *b) { - return scheme_make_sequence_compilation(scheme_make_pair(a, scheme_make_pair(b, scheme_null)), 1); + return scheme_make_sequence_compilation(scheme_make_pair(a, scheme_make_pair(b, scheme_null)), 1, 0); } static Scheme_Object *make_discarding_first_sequence(Scheme_Object *e1, Scheme_Object *e2, - Optimize_Info *info, int id_offset) + Optimize_Info *info) /* Like make_discarding_sequence(), but second expression is not constrained to a single result. */ { - e1 = optimize_ignored(e1, info, id_offset, 1, 1, 5); + e1 = optimize_ignored(e1, info, 1, 1, 5); if (!e1) return e2; if (!single_valued_noncm_expression(e1, 5)) @@ -761,7 +727,8 @@ static Scheme_Object *make_application_3(Scheme_Object *a, Scheme_Object *b, Sch info); } -static Scheme_Object *replace_tail_inside(Scheme_Object *alt, Scheme_Object *inside, Scheme_Object *orig) { +static Scheme_Object *replace_tail_inside(Scheme_Object *alt, Scheme_Object *inside, Scheme_Object *orig) +{ if (inside) { switch (SCHEME_TYPE(inside)) { case scheme_sequence_type: @@ -784,15 +751,16 @@ static Scheme_Object *replace_tail_inside(Scheme_Object *alt, Scheme_Object *ins return alt; } -static void extract_tail_inside(Scheme_Object **_t2, Scheme_Object **_inside, int *_id_offset) +static void extract_tail_inside(Scheme_Object **_t2, Scheme_Object **_inside) { + /* replace_tail_inside() needs to be consistent with this function */ + while (1) { if (SAME_TYPE(SCHEME_TYPE(*_t2), scheme_compiled_let_void_type)) { Scheme_Let_Header *head = (Scheme_Let_Header *)*_t2; int i; *_inside = *_t2; *_t2 = head->body; - *_id_offset += head->count; for (i = head->num_clauses; i--; ) { *_inside = *_t2; *_t2 = ((Scheme_Compiled_Let_Value *)*_t2)->body; @@ -849,11 +817,21 @@ static int is_proc_spec_proc(Scheme_Object *p) return 0; } -static int is_local_ref(Scheme_Object *e, int p, int r) +static int is_local_ref(Scheme_Object *e, int p, int r, Scheme_Compiled_Local **vars) { - return (SAME_TYPE(SCHEME_TYPE(e), scheme_local_type) - && (SCHEME_LOCAL_POS(e) >= p) - && (SCHEME_LOCAL_POS(e) < (p + r))); + if (!vars && SAME_TYPE(SCHEME_TYPE(e), scheme_local_type)) { + if ((SCHEME_LOCAL_POS(e) >= p) + && (SCHEME_LOCAL_POS(e) < (p + r))) + return 1; + } else if (vars && SAME_TYPE(SCHEME_TYPE(e), scheme_compiled_local_type)) { + int i; + for (i = p; i < p + r; i++) { + if (SAME_OBJ(e, (Scheme_Object *)vars[i])) + return 1; + } + } + + return 0; } static int is_int_list(Scheme_Object *o, int up_to) @@ -882,12 +860,12 @@ static int is_int_list(Scheme_Object *o, int up_to) } static int ok_proc_creator_args(Scheme_Object *rator, Scheme_Object *rand1, Scheme_Object *rand2, Scheme_Object *rand3, - int delta2, int field_count) + int delta2, int field_count, Scheme_Compiled_Local **vars) { if ((SAME_OBJ(rator, scheme_make_struct_field_accessor_proc) - && is_local_ref(rand1, delta2+3, 1)) + && is_local_ref(rand1, delta2+3, 1, vars)) || (SAME_OBJ(rator, scheme_make_struct_field_mutator_proc) - && is_local_ref(rand1, delta2+4, 1))) { + && is_local_ref(rand1, delta2+4, 1, vars))) { if (SCHEME_INTP(rand2) && (SCHEME_INT_VAL(rand2) >= 0) && (SCHEME_INT_VAL(rand2) < field_count) @@ -899,8 +877,9 @@ static int ok_proc_creator_args(Scheme_Object *rator, Scheme_Object *rand1, Sche return 0; } -static int is_values_with_accessors_and_mutators(Scheme_Object *e, int vals, int resolved, - Simple_Stuct_Type_Info *_stinfo) +static int is_values_with_accessors_and_mutators(Scheme_Object *e, int vals, int resolved, + Simple_Stuct_Type_Info *_stinfo, + Scheme_Compiled_Local **vars) { if (SAME_TYPE(SCHEME_TYPE(e), scheme_application_type)) { Scheme_App_Rec *app = (Scheme_App_Rec *)e; @@ -908,12 +887,12 @@ static int is_values_with_accessors_and_mutators(Scheme_Object *e, int vals, int if (SAME_OBJ(app->args[0], scheme_values_func) && (app->num_args == vals) && (app->num_args >= 3) - && is_local_ref(app->args[1], delta, 1) - && is_local_ref(app->args[2], delta+1, 1) - && is_local_ref(app->args[3], delta+2, 1)) { + && is_local_ref(app->args[1], delta, 1, vars) + && is_local_ref(app->args[2], delta+1, 1, vars) + && is_local_ref(app->args[3], delta+2, 1, vars)) { int i, num_gets = 0, num_sets = 0, normal_ops = 1; for (i = app->num_args; i > 3; i--) { - if (is_local_ref(app->args[i], delta, 5)) { + if (is_local_ref(app->args[i], delta, 5, vars)) { normal_ops = 0; } else if (SAME_TYPE(SCHEME_TYPE(app->args[i]), scheme_application_type) && _stinfo->normal_ops && !_stinfo->indexed_ops) { @@ -921,7 +900,7 @@ static int is_values_with_accessors_and_mutators(Scheme_Object *e, int vals, int int delta2 = delta + (resolved ? app3->num_args : 0); if (app3->num_args == 3) { if (!ok_proc_creator_args(app3->args[0], app3->args[1], app3->args[2], app3->args[3], - delta2, _stinfo->field_count)) + delta2, _stinfo->field_count, vars)) break; if (SAME_OBJ(app3->args[0], scheme_make_struct_field_mutator_proc)) { if (num_gets) normal_ops = 0; @@ -935,7 +914,7 @@ static int is_values_with_accessors_and_mutators(Scheme_Object *e, int vals, int Scheme_App3_Rec *app3 = (Scheme_App3_Rec *)app->args[i]; int delta2 = delta + (resolved ? 2 : 0); if (!ok_proc_creator_args(app3->rator, app3->rand1, app3->rand2, NULL, - delta2, _stinfo->field_count)) + delta2, _stinfo->field_count, vars)) break; if (SAME_OBJ(app3->rator, scheme_make_struct_field_mutator_proc)) { if (num_gets) normal_ops = 0; @@ -1094,7 +1073,7 @@ Scheme_Object *scheme_is_simple_make_struct_type(Scheme_Object *e, int vals, int && ((app->num_args < 5) /* auto-field value: */ || !check_auto - || scheme_omittable_expr(app->args[5], 1, 3, resolved, NULL, NULL, 0, 0, ID_OMIT)) + || scheme_omittable_expr(app->args[5], 1, 3, (resolved ? OMITTABLE_RESOLVED : 0), NULL, NULL)) && ((app->num_args < 6) /* no properties: */ || SCHEME_NULLP(app->args[6])) @@ -1152,22 +1131,17 @@ Scheme_Object *scheme_is_simple_make_struct_type(Scheme_Object *e, int vals, int if (SAME_TYPE(SCHEME_TYPE(lv->value), scheme_application_type)) { Scheme_Object *auto_e; Simple_Stuct_Type_Info stinfo; - int lh_delta = ((SCHEME_LET_FLAGS(lh) & (SCHEME_LET_RECURSIVE | SCHEME_LET_STAR)) - ? lh->count - : 0); if (!_stinfo) _stinfo = &stinfo; auto_e = scheme_is_simple_make_struct_type(lv->value, 5, resolved, check_auto, _auto_e_depth, _stinfo, top_level_consts, top_level_table, - runstack, rs_delta + lh_delta, + runstack, rs_delta, symbols, symbol_table, fuel-1); if (auto_e) { /* We have (let-values ([... (make-struct-type)]) ....), so make sure body just uses `make-struct-field-{accessor,mutator}'. */ - if (is_values_with_accessors_and_mutators(lv->body, vals, resolved, _stinfo)) { - if (_auto_e_depth && lh_delta) - *_auto_e_depth += lh_delta; + if (is_values_with_accessors_and_mutators(lv->body, vals, resolved, _stinfo, lv->vars)) { return auto_e; } } @@ -1199,7 +1173,7 @@ Scheme_Object *scheme_is_simple_make_struct_type(Scheme_Object *e, int vals, int /* We have (let-values ([... (make-struct-type)]) ....), so make sure body just uses `make-struct-field-{accessor,mutator}'. */ e2 = skip_clears(lv->body); - if (is_values_with_accessors_and_mutators(e2, vals, resolved, _stinfo)) { + if (is_values_with_accessors_and_mutators(e2, vals, resolved, _stinfo, NULL)) { if (_auto_e_depth) *_auto_e_depth += lvd->count; return auto_e; } @@ -1259,8 +1233,12 @@ static int single_valued_noncm_expression(Scheme_Object *expr, int fuel) int num_args = 0; switch (SCHEME_TYPE(expr)) { + case scheme_compiled_local_type: + return 1; case scheme_local_type: return 1; + case scheme_local_unbox_type: + return 1; case scheme_compiled_toplevel_type: return 1; case scheme_application_type: @@ -1299,9 +1277,8 @@ static int single_valued_noncm_expression(Scheme_Object *expr, int fuel) /* for scheme_compiled_let_void_type and scheme_begin_sequence_type */ if (fuel > 0) { - int offset = 0; Scheme_Object *tail = expr, *inside = NULL; - extract_tail_inside(&tail, &inside, &offset); + extract_tail_inside(&tail, &inside); if (inside) return single_valued_noncm_expression(tail, fuel - 1); } @@ -1363,7 +1340,7 @@ static int is_movable_prim(Scheme_Object *rator, int n, int cross_lambda, int cr return 0; } -static int movable_expression(Scheme_Object *expr, Optimize_Info *info, int delta, +static int movable_expression(Scheme_Object *expr, Optimize_Info *info, int cross_lambda, int cross_k, int cross_s, int check_space, int fuel) /* An expression that can't necessarily be constant-folded, @@ -1380,15 +1357,12 @@ static int movable_expression(Scheme_Object *expr, Optimize_Info *info, int delt return ((SCHEME_TOPLEVEL_FLAGS(expr) & SCHEME_TOPLEVEL_FLAGS_MASK) >= SCHEME_TOPLEVEL_FIXED); case scheme_compiled_quote_syntax_type: return 1; - case scheme_local_type: + case scheme_compiled_local_type: { /* Ok if not mutable */ - int pos = SCHEME_LOCAL_POS(expr); - if (pos + delta < 0) - return 0; /* assume non-movable */ - else if (!optimize_is_mutated(info, pos + delta)) { + if (!SCHEME_VAR(expr)->mutated) { if (check_space) { - if (optimize_is_local_type_valued(info, pos + delta)) + if (SCHEME_VAR(expr)->val_type) return 1; /* the value of the identifier might be something that would retain significant memory, so we can't delay evaluation */ @@ -1404,7 +1378,7 @@ static int movable_expression(Scheme_Object *expr, Optimize_Info *info, int delt if (can_move) { int i; for (i = ((Scheme_App_Rec *)expr)->num_args; i--; ) { - if (!movable_expression(((Scheme_App_Rec *)expr)->args[i+1], info, delta, + if (!movable_expression(((Scheme_App_Rec *)expr)->args[i+1], info, cross_lambda, cross_k, cross_s, check_space || (cross_s && (can_move < 0)), fuel - 1)) return 0; @@ -1415,7 +1389,7 @@ static int movable_expression(Scheme_Object *expr, Optimize_Info *info, int delt case scheme_application2_type: can_move = is_movable_prim(((Scheme_App2_Rec *)expr)->rator, 1, cross_lambda, cross_k, info); if (can_move) { - if (movable_expression(((Scheme_App2_Rec *)expr)->rand, info, delta, + if (movable_expression(((Scheme_App2_Rec *)expr)->rand, info, cross_lambda, cross_k, cross_s, check_space || (cross_s && (can_move < 0)), fuel - 1)) return 1; @@ -1424,10 +1398,10 @@ static int movable_expression(Scheme_Object *expr, Optimize_Info *info, int delt case scheme_application3_type: can_move = is_movable_prim(((Scheme_App3_Rec *)expr)->rator, 2, cross_lambda, cross_k, info); if (can_move) { - if (movable_expression(((Scheme_App3_Rec *)expr)->rand1, info, delta, + if (movable_expression(((Scheme_App3_Rec *)expr)->rand1, info, cross_lambda, cross_k, cross_s, check_space || (cross_s && (can_move < 0)), fuel - 1) - && movable_expression(((Scheme_App3_Rec *)expr)->rand2, info, delta, + && movable_expression(((Scheme_App3_Rec *)expr)->rand2, info, cross_lambda, cross_k, cross_s, check_space || (cross_s && (can_move < 0)), fuel - 1)) return 1; @@ -1436,9 +1410,9 @@ static int movable_expression(Scheme_Object *expr, Optimize_Info *info, int delt case scheme_branch_type: { Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)expr; - if (movable_expression(b->test, info, delta, cross_lambda, cross_k, cross_s, check_space, fuel-1) - && movable_expression(b->tbranch, info, delta, cross_lambda, cross_k, cross_s, check_space, fuel-1) - && movable_expression(b->fbranch, info, delta, cross_lambda, cross_k, cross_s, check_space, fuel-1)) + if (movable_expression(b->test, info, cross_lambda, cross_k, cross_s, check_space, fuel-1) + && movable_expression(b->tbranch, info, cross_lambda, cross_k, cross_s, check_space, fuel-1) + && movable_expression(b->fbranch, info, cross_lambda, cross_k, cross_s, check_space, fuel-1)) return 1; } break; @@ -1535,7 +1509,7 @@ static int estimate_expr_size(Scheme_Object *expr, int sz, int fuel) t = SCHEME_TYPE(expr); switch(t) { - case scheme_local_type: + case scheme_compiled_local_type: { sz += 1; break; @@ -1655,17 +1629,19 @@ static Scheme_Object *no_potential_size(Scheme_Object *v) return v; } -static Scheme_Object *apply_inlined(Scheme_Object *p, Scheme_Closure_Data *data, Optimize_Info *info, +static Scheme_Object *apply_inlined(Scheme_Object *p, Optimize_Info *info, int argc, Scheme_App_Rec *app, Scheme_App2_Rec *app2, Scheme_App3_Rec *app3, - int context, - int nested_count, Scheme_Object *orig, Scheme_Object *le_prev) + int context, Scheme_Object *orig, Scheme_Object *le_prev) { Scheme_Let_Header *lh; Scheme_Compiled_Let_Value *lv, *prev = NULL; Scheme_Object *val; int i, expected; - int *flags, flag; Optimize_Info *sub_info; + Scheme_Compiled_Local **vars; + Scheme_Closure_Data *data = (Scheme_Closure_Data *)p; + + p = data->code; expected = data->num_params; @@ -1676,7 +1652,7 @@ static Scheme_Object *apply_inlined(Scheme_Object *p, Scheme_Closure_Data *data, info->single_result = sub_info->single_result; info->preserves_marks = sub_info->preserves_marks; optimize_info_done(sub_info, NULL); - merge_types(sub_info, info, 0); + merge_types(sub_info, info, NULL); return replace_tail_inside(p, le_prev, orig); } @@ -1690,7 +1666,10 @@ static Scheme_Object *apply_inlined(Scheme_Object *p, Scheme_Closure_Data *data, lv = MALLOC_ONE_TAGGED(Scheme_Compiled_Let_Value); lv->iso.so.type = scheme_compiled_let_value_type; lv->count = 1; - lv->position = i; + + vars = MALLOC_N(Scheme_Compiled_Local*, 1); + vars[0] = ((Closure_Info *)data->closure_map)->vars[i]; + lv->vars = vars; if ((i == expected - 1) && (SCHEME_CLOSURE_DATA_FLAGS(data) & CLOS_HAS_REST)) { @@ -1718,15 +1697,8 @@ static Scheme_Object *apply_inlined(Scheme_Object *p, Scheme_Closure_Data *data, else val = app2->rand; - if (nested_count) - val = optimize_shift(val, nested_count, 0); lv->value = val; - flag = closure_argument_flags(data, i); - flags = (int *)scheme_malloc_atomic(sizeof(int)); - flags[0] = flag; - lv->flags = flags; - if (prev) prev->body = (Scheme_Object *)lv; else @@ -1747,7 +1719,7 @@ static Scheme_Object *apply_inlined(Scheme_Object *p, Scheme_Closure_Data *data, info->single_result = sub_info->single_result; info->preserves_marks = sub_info->preserves_marks; optimize_info_done(sub_info, NULL); - merge_types(sub_info, info, 0); + merge_types(sub_info, info, NULL); return replace_tail_inside(p, le_prev, orig); } @@ -1777,29 +1749,26 @@ int scheme_check_leaf_rator(Scheme_Object *le, int *_flags) Scheme_Object *optimize_for_inline(Optimize_Info *info, Scheme_Object *le, int argc, Scheme_App_Rec *app, Scheme_App2_Rec *app2, Scheme_App3_Rec *app3, - int *_flags, int context, int optimized_rator, int id_offset) + int *_flags, int context, int optimized_rator) /* Zero or one of app, app2 and app3 should be non-NULL. If app, we're inlining a general application. If app2, we're inlining an application with a single argument and if app3, we're inlining an application with two arguments. If not app, app2, or app3, just return a known procedure, if any, - and do not check arity. - The id_offset can be non 0 only when app, app2 and app3 are NULL and optimized_rator is 1. */ + and do not check arity. */ { - int offset = 0, single_use = 0, psize = 0; + int single_use = 0, psize = 0; Scheme_Object *bad_app = NULL, *prev = NULL, *orig_le = le; - int outside_nested = 0, already_opt = optimized_rator, nonleaf, noapp; + int outside_nested = 0, already_opt = optimized_rator, nonleaf, noapp, via_local = 0; noapp = !app && !app2 && !app3; - if (id_offset && !noapp) - return NULL; if ((info->inline_fuel < 0) && info->has_nonleaf && !noapp) return NULL; /* Move inside `let' bindings, so we can convert ((let (....) proc) arg ...) to (let (....) (proc arg ...)) */ if (already_opt) - extract_tail_inside(&le, &prev, &id_offset); + extract_tail_inside(&le, &prev); le = extract_specialized_proc(le, le); @@ -1808,25 +1777,12 @@ Scheme_Object *optimize_for_inline(Optimize_Info *info, Scheme_Object *le, int a single_use = 1; } - if (SAME_TYPE(SCHEME_TYPE(le), scheme_local_type)) { + if (SAME_TYPE(SCHEME_TYPE(le), scheme_compiled_local_type)) { /* Check for inlining: */ - int pos = SCHEME_LOCAL_POS(le); - - if (already_opt) { - if (pos >= id_offset) - le = optimize_reverse(info, pos - id_offset, 0, 0); - else - le = NULL; - if (!le) - return NULL; - already_opt = 0; - id_offset = 0; - pos = SCHEME_LOCAL_POS(le); - } - - le = optimize_info_lookup(info, pos - id_offset, &offset, &single_use, 0, 0, &psize, NULL); + le = optimize_info_lookup(info, le, 1, &single_use, 0, 0, &psize, NULL); outside_nested = 1; already_opt = 1; + via_local = 1; } if (le) { @@ -1939,20 +1895,10 @@ Scheme_Object *optimize_for_inline(Optimize_Info *info, Scheme_Object *le, int a /* Do we have enough fuel? */ if ((sz >= 0) && (single_use || (sz <= threshold))) { Optimize_Info *sub_info; - if (id_offset) { - sub_info = optimize_info_add_frame(info, id_offset, id_offset, 0); - /* We only go into `let` and `begin` only for an optimized rator, so - the virtual clock was already incremented as needed. */ - /* We could propagate bound values in sub_info, but relevant inlining - and propagatation has probably already happened when the rator was - optimized. */ - } else - sub_info = info; + sub_info = info; /* If optimize_clone succeeds, inlining succeeds. */ - le = optimize_clone(single_use, data->code, sub_info, - offset + (outside_nested ? id_offset : 0), - data->num_params); + le = optimize_clone(single_use, (Scheme_Object *)data, sub_info, empty_eq_hash_tree, 0); if (le) { LOG_INLINE(fprintf(stderr, "Inline %d[%d]<=%d@%d %d %s\n", sz, is_leaf, threshold, info->inline_fuel, @@ -1965,12 +1911,8 @@ Scheme_Object *optimize_for_inline(Optimize_Info *info, Scheme_Object *le, int a sz, threshold, scheme_optimize_context_to_string(info->context)); - le = apply_inlined(le, data, sub_info, argc, app, app2, app3, context, - id_offset, orig_le, prev); - if (id_offset) { - optimize_info_done(sub_info, NULL); - merge_types(sub_info, info, -id_offset); - } + le = apply_inlined(le, sub_info, argc, app, app2, app3, context, + orig_le, prev); return le; } else { LOG_INLINE(fprintf(stderr, "No inline %s\n", scheme_write_to_string(data->name ? data->name : scheme_false, NULL))); @@ -2051,7 +1993,7 @@ Scheme_Object *optimize_for_inline(Optimize_Info *info, Scheme_Object *le, int a static int is_local_type_expression(Scheme_Object *expr, Optimize_Info *info) { - return predicate_to_local_type(expr_implies_predicate(expr, info, 0, 5)); + return predicate_to_local_type(expr_implies_predicate(expr, info, NULL, 5)); } static void register_local_argument_types(Scheme_App_Rec *app, Scheme_App2_Rec *app2, Scheme_App3_Rec *app3, @@ -2071,11 +2013,9 @@ static void register_local_argument_types(Scheme_App_Rec *app, Scheme_App2_Rec * n = 2; } - if (SAME_TYPE(SCHEME_TYPE(rator), scheme_local_type)) { - rator = optimize_reverse(info, SCHEME_LOCAL_POS(rator), 1, 0); - if (rator) { - int offset, single_use; - le = optimize_info_lookup(info, SCHEME_LOCAL_POS(rator), &offset, &single_use, 0, 0, NULL, NULL); + if (SAME_TYPE(SCHEME_TYPE(rator), scheme_compiled_local_type)) { + { + le = optimize_info_lookup(info, rator, 1, NULL, 0, 0, NULL, NULL); if (le && SAME_TYPE(SCHEME_TYPE(le), scheme_compiled_unclosed_procedure_type)) { Scheme_Closure_Data *data = (Scheme_Closure_Data *)le; char *map; @@ -2229,36 +2169,19 @@ static Scheme_Object *check_app_let_rator(Scheme_Object *app, Scheme_Object *rat pattern again in optimize_for_inline() after optimizing a rator. */ { Scheme_Object *orig_rator = rator, *inside = NULL; - int id_shift = 0; - extract_tail_inside(&rator, &inside, &id_shift); + extract_tail_inside(&rator, &inside); if (!inside) return NULL; - /* Handle ((let ([f ...]) f) arg ...) specially, so we can adjust the flags for `f': */ - if (SAME_TYPE(SCHEME_TYPE(inside), scheme_compiled_let_value_type)) { - Scheme_Compiled_Let_Value *clv = (Scheme_Compiled_Let_Value *)inside; - if ((clv->count == 1) - && (clv->position == 0) - && SAME_TYPE(SCHEME_TYPE(rator), scheme_local_type) - && (SCHEME_LOCAL_POS(rator) == 0) - && scheme_is_compiled_procedure(clv->value, 1, 1)) { - - /* get a new rator with flags = 0 */ - rator = scheme_make_local(scheme_local_type, 0, 0); - - if (clv->flags[0] & SCHEME_WAS_APPLIED_EXCEPT_ONCE) { - clv->flags[0] -= SCHEME_WAS_APPLIED_EXCEPT_ONCE; - clv->flags[0] |= SCHEME_WAS_ONLY_APPLIED; - } - } + /* Moving a variable into application position: */ + if (SAME_TYPE(SCHEME_TYPE(rator), scheme_compiled_local_type)) { + Scheme_Compiled_Local *var = SCHEME_VAR(rator); + if (var->non_app_count < SCHEME_USE_COUNT_INF) + --var->non_app_count; } - if (id_shift) { - reset_rator(app, scheme_false); - app = optimize_shift(app, id_shift, 0); - } reset_rator(app, rator); orig_rator = replace_tail_inside(app, inside, orig_rator); @@ -2290,7 +2213,7 @@ static int is_primitive_allocating(Scheme_Object *rator, int n) static int is_noncapturing_primitive(Scheme_Object *rator, int n) { if (SCHEME_PRIMP(rator)) { - int opt; + int opt, t; opt = ((Scheme_Prim_Proc_Header *)rator)->flags & SCHEME_PRIM_OPT_MASK; if (opt >= SCHEME_PRIM_OPT_IMMEDIATE) return 1; @@ -2300,6 +2223,9 @@ static int is_noncapturing_primitive(Scheme_Object *rator, int n) return 1; } } + t = (((Scheme_Primitive_Proc *)rator)->pp.flags & SCHEME_PRIM_OTHER_TYPE_MASK); + if (!n && (t == SCHEME_PRIM_TYPE_PARAMETER)) + return 1; } return 0; @@ -2394,9 +2320,10 @@ static int predicate_to_local_type(Scheme_Object *pred) return 0; } -int scheme_expr_produces_local_type(Scheme_Object *expr) +int scheme_expr_produces_local_type(Scheme_Object *expr, int *_involves_k_cross) { - return predicate_to_local_type(expr_implies_predicate(expr, NULL, 0, 10)); + if (_involves_k_cross) *_involves_k_cross = 0; + return predicate_to_local_type(expr_implies_predicate(expr, NULL, _involves_k_cross, 10)); } static Scheme_Object *rator_implies_predicate(Scheme_Object *rator, int argc) @@ -2440,7 +2367,8 @@ static Scheme_Object *rator_implies_predicate(Scheme_Object *rator, int argc) return NULL; } -static Scheme_Object *expr_implies_predicate(Scheme_Object *expr, Optimize_Info *info, int delta, int fuel) +static Scheme_Object *expr_implies_predicate(Scheme_Object *expr, Optimize_Info *info, + int *_involves_k_cross, int fuel) /* can be called by the JIT with info = NULL; in that case, beware that the validator must be able to reconstruct the result in a shallow way, so don't @@ -2450,25 +2378,24 @@ static Scheme_Object *expr_implies_predicate(Scheme_Object *expr, Optimize_Info return NULL; switch (SCHEME_TYPE(expr)) { - case scheme_local_type: + case scheme_compiled_local_type: { - Scheme_Object *p; - int pos = SCHEME_LOCAL_POS(expr); - pos -= delta; - if (pos < 0) - return NULL; + if (!SCHEME_VAR(expr)->mutated) { + Scheme_Object *p; - if (!info) - return NULL; + if (info) { + p = optimize_get_predicate(info, expr); + if (p) + return p; + } - if (!optimize_is_mutated(info, pos)){ - p = optimize_get_predicate(info, pos); - if (p) - return p; - - p = local_type_to_predicate(optimize_is_local_type_valued(info, pos)); - if (p) + p = local_type_to_predicate(SCHEME_VAR(expr)->val_type); + if (p) { + if (_involves_k_cross + && SCHEME_VAR(expr)->escapes_after_k_tick) + *_involves_k_cross = 1; return p; + } } } break; @@ -2517,9 +2444,9 @@ static Scheme_Object *expr_implies_predicate(Scheme_Object *expr, Optimize_Info { Scheme_Object *l, *r; Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)expr; - l = expr_implies_predicate(b->tbranch, info, delta, fuel-1); + l = expr_implies_predicate(b->tbranch, info, _involves_k_cross, fuel-1); if (l) { - r = expr_implies_predicate(b->fbranch, info, delta, fuel-1); + r = expr_implies_predicate(b->fbranch, info, _involves_k_cross, fuel-1); if (SAME_OBJ(l, r)) return l; } @@ -2529,25 +2456,24 @@ static Scheme_Object *expr_implies_predicate(Scheme_Object *expr, Optimize_Info { Scheme_Sequence *seq = (Scheme_Sequence *)expr; - return expr_implies_predicate(seq->array[seq->count-1], info, delta, fuel-1); + return expr_implies_predicate(seq->array[seq->count-1], info, _involves_k_cross, fuel-1); } case scheme_compiled_let_void_type: { Scheme_Let_Header *lh = (Scheme_Let_Header *)expr; int i; - delta += lh->count; expr = lh->body; for (i = 0; i < lh->num_clauses; i++) { expr = ((Scheme_Compiled_Let_Value *)expr)->body; } - return expr_implies_predicate(expr, info, delta, fuel-1); + return expr_implies_predicate(expr, info, _involves_k_cross, fuel-1); } break; case scheme_begin0_sequence_type: { Scheme_Sequence *seq = (Scheme_Sequence *)expr; - return expr_implies_predicate(seq->array[0], info, delta, fuel-1); + return expr_implies_predicate(seq->array[0], info, _involves_k_cross, fuel-1); } case scheme_pair_type: return scheme_pair_p_proc; @@ -2591,8 +2517,8 @@ static Scheme_Object *expr_implies_predicate(Scheme_Object *expr, Optimize_Info if (!info) return NULL; - if (lookup_constant_proc(info, expr, delta) - || optimize_for_inline(info, expr, 1, NULL, NULL, NULL, &flags, sub_context, 1, delta)){ + if (lookup_constant_proc(info, expr) + || optimize_for_inline(info, expr, 1, NULL, NULL, NULL, &flags, sub_context, 1)){ return scheme_procedure_p_proc; } } @@ -2698,13 +2624,17 @@ static Scheme_Object *call_with_immed_mark(Scheme_Object *rator, && (((Scheme_Closure_Data *)rand2)->num_params == 1) && !(SCHEME_CLOSURE_DATA_FLAGS(((Scheme_Closure_Data *)rand2)) & CLOS_HAS_REST)) { Scheme_With_Continuation_Mark *wcm; + Scheme_Object *e; wcm = MALLOC_ONE_TAGGED(Scheme_With_Continuation_Mark); wcm->so.type = scheme_with_immed_mark_type; wcm->key = rand1; wcm->val = (rand3 ? rand3 : scheme_false); - wcm->body = ((Scheme_Closure_Data *)rand2)->code; + + e = (Scheme_Object *)((Closure_Info *)((Scheme_Closure_Data *)rand2)->closure_map)->vars[0]; + e = scheme_make_mutable_pair(e, ((Scheme_Closure_Data *)rand2)->code); + wcm->body = e; return (Scheme_Object *)wcm; } @@ -2742,7 +2672,7 @@ static Scheme_Object *optimize_application(Scheme_Object *o, Optimize_Info *info for (i = 0; i < n; i++) { if (!i) { - le = optimize_for_inline(info, app->args[i], n - 1, app, NULL, NULL, &rator_flags, context, 0, 0); + le = optimize_for_inline(info, app->args[i], n - 1, app, NULL, NULL, &rator_flags, context, 0); if (le) return le; } @@ -2767,19 +2697,19 @@ static Scheme_Object *optimize_application(Scheme_Object *o, Optimize_Info *info for (j = i - 1; j >= 0; j--) { e = app->args[j]; - e = optimize_ignored(e, info, 0, 1, 1, 5); + e = optimize_ignored(e, info, 1, 1, 5); if (e) { if (!single_valued_noncm_expression(e, 5)) e = ensure_single_value(e); l = scheme_make_pair(e, l); } } - return scheme_make_sequence_compilation(l, 1); + return scheme_make_sequence_compilation(l, 1, 0); } if (!i) { /* Maybe found "((lambda" after optimizing; try again */ - le = optimize_for_inline(info, app->args[i], n - 1, app, NULL, NULL, &rator_flags, context, 1, 0); + le = optimize_for_inline(info, app->args[i], n - 1, app, NULL, NULL, &rator_flags, context, 1); if (le) return le; if (SAME_OBJ(app->args[0], scheme_values_func) @@ -2852,7 +2782,7 @@ static int appn_flags(Scheme_Object *rator, Optimize_Info *info) } static void check_known(Optimize_Info *info, Scheme_Object *app, - Scheme_Object *rator, Scheme_Object *rand, int id_offset, + Scheme_Object *rator, Scheme_Object *rand, const char *who, Scheme_Object *expect_pred, Scheme_Object *unsafe) /* Replace the rator with an unsafe version if we know that it's ok. Alternatively, the rator implies a check, so add type information for subsequent expressions. @@ -2862,7 +2792,7 @@ static void check_known(Optimize_Info *info, Scheme_Object *app, if (SCHEME_PRIMP(rator) && IS_NAMED_PRIM(rator, who)) { Scheme_Object *pred; - pred = expr_implies_predicate(rand, info, id_offset, 5); + pred = expr_implies_predicate(rand, info, NULL, 5); if (pred) { if (SAME_OBJ(pred, expect_pred)) { if (unsafe) @@ -2871,41 +2801,33 @@ static void check_known(Optimize_Info *info, Scheme_Object *app, info->escapes = 1; } } else { - if (SAME_TYPE(SCHEME_TYPE(rand), scheme_local_type)) { - int pos = SCHEME_LOCAL_POS(rand); - if (pos >= id_offset) { - pos -= id_offset; - if (!optimize_is_mutated(info, pos)) - add_type(info, pos, expect_pred); - } + if (SAME_TYPE(SCHEME_TYPE(rand), scheme_compiled_local_type)) { + if (!SCHEME_VAR(rand)->mutated) + add_type(info, rand, expect_pred); } } } } -static void check_known_rator(Optimize_Info *info, Scheme_Object *rator, int id_offset) +static void check_known_rator(Optimize_Info *info, Scheme_Object *rator) /* Check that rator is a procedure or add type information for subsequent expressions. */ { Scheme_Object *pred; - pred = expr_implies_predicate(rator, info, id_offset, 5); + pred = expr_implies_predicate(rator, info, NULL, 5); if (pred) { if (!SAME_OBJ(pred, scheme_procedure_p_proc)) info->escapes = 1; } else { - if (SAME_TYPE(SCHEME_TYPE(rator), scheme_local_type)) { - int pos = SCHEME_LOCAL_POS(rator); - if (pos >= id_offset) { - pos -= id_offset; - if (!optimize_is_mutated(info, pos)) - add_type(info, pos, scheme_procedure_p_proc); - } + if (SAME_TYPE(SCHEME_TYPE(rator), scheme_compiled_local_type)) { + if (!SCHEME_VAR(rator)->mutated) + add_type(info, rator, scheme_procedure_p_proc); } } } static void check_known_try(Optimize_Info *info, Scheme_Object *app, - Scheme_Object *rator, Scheme_Object *rand, int id_offset, + Scheme_Object *rator, Scheme_Object *rand, const char *who, Scheme_Object *expect_pred, Scheme_Object *unsafe) /* Replace the rator with an unsafe version if rand have the right type. If not, don't save the type, nor mark this as an error */ @@ -2913,7 +2835,7 @@ static void check_known_try(Optimize_Info *info, Scheme_Object *app, if (SCHEME_PRIMP(rator) && IS_NAMED_PRIM(rator, who)) { Scheme_Object *pred; - pred = expr_implies_predicate(rand, info, id_offset, 5); + pred = expr_implies_predicate(rand, info, NULL, 5); if (pred && SAME_OBJ(pred, expect_pred)) reset_rator(app, unsafe); } @@ -2921,7 +2843,6 @@ static void check_known_try(Optimize_Info *info, Scheme_Object *app, static void check_known_both_try(Optimize_Info *info, Scheme_Object *app, Scheme_Object *rator, Scheme_Object *rand1, Scheme_Object *rand2, - int id_offset, const char *who, Scheme_Object *expect_pred, Scheme_Object *unsafe) /* Replace the rator with an unsafe version if both rands have the right type. If not, don't save the type, nor mark this as an error */ @@ -2929,9 +2850,9 @@ static void check_known_both_try(Optimize_Info *info, Scheme_Object *app, if (SCHEME_PRIMP(rator) && IS_NAMED_PRIM(rator, who)) { Scheme_Object *pred1, *pred2; - pred1 = expr_implies_predicate(rand1, info, id_offset, 5); + pred1 = expr_implies_predicate(rand1, info, NULL, 5); if (pred1 && SAME_OBJ(pred1, expect_pred)) { - pred2 = expr_implies_predicate(rand2, info, id_offset, 5); + pred2 = expr_implies_predicate(rand2, info, NULL, 5); if (pred2 && SAME_OBJ(pred2, expect_pred)) { reset_rator(app, unsafe); } @@ -2942,16 +2863,16 @@ static void check_known_both_try(Optimize_Info *info, Scheme_Object *app, static Scheme_Object *finish_optimize_any_application(Scheme_Object *app, Scheme_Object *rator, int argc, Optimize_Info *info, int context) { - check_known_rator(info, rator, 0); + check_known_rator(info, rator); if ((context & OPT_CONTEXT_BOOLEAN) && !info->escapes) if (rator_implies_predicate(rator, argc)){ Scheme_Object *val = SAME_OBJ(rator, scheme_not_prim) ? scheme_false : scheme_true; - return make_discarding_sequence(app, val, info, 0); + return make_discarding_sequence(app, val, info); } if (SAME_OBJ(rator, scheme_void_proc)) - return make_discarding_sequence(app, scheme_void, info, 0); + return make_discarding_sequence(app, scheme_void, info); if (is_allways_escaping_primitive(rator)) { info->escapes = 1; @@ -3033,14 +2954,14 @@ static Scheme_Object *finish_optimize_application(Scheme_App_Rec *app, Optimize_ if (app->num_args >= 1) { Scheme_Object *rand1 = app->args[1]; - check_known(info, app_o, rator, rand1, 0, "vector-set!", scheme_vector_p_proc, NULL); + check_known(info, app_o, rator, rand1, "vector-set!", scheme_vector_p_proc, NULL); - check_known(info, app_o, rator, rand1, 0, "procedure-arity-includes?", scheme_procedure_p_proc, NULL); + check_known(info, app_o, rator, rand1, "procedure-arity-includes?", scheme_procedure_p_proc, NULL); - check_known(info, app_o, rator, rand1, 0, "map", scheme_procedure_p_proc, NULL); - check_known(info, app_o, rator, rand1, 0, "for-each", scheme_procedure_p_proc, NULL); - check_known(info, app_o, rator, rand1, 0, "andmap", scheme_procedure_p_proc, NULL); - check_known(info, app_o, rator, rand1, 0, "ormap", scheme_procedure_p_proc, NULL); + check_known(info, app_o, rator, rand1, "map", scheme_procedure_p_proc, NULL); + check_known(info, app_o, rator, rand1, "for-each", scheme_procedure_p_proc, NULL); + check_known(info, app_o, rator, rand1, "andmap", scheme_procedure_p_proc, NULL); + check_known(info, app_o, rator, rand1, "ormap", scheme_procedure_p_proc, NULL); } } @@ -3053,22 +2974,15 @@ static Scheme_Object *finish_optimize_application(Scheme_App_Rec *app, Optimize_ info, context); } -static Scheme_Object *lookup_constant_proc(Optimize_Info *info, Scheme_Object *rand, int delta) +static Scheme_Object *lookup_constant_proc(Optimize_Info *info, Scheme_Object *rand) { Scheme_Object *c = NULL; if (SAME_TYPE(scheme_compiled_unclosed_procedure_type, SCHEME_TYPE(rand))) c = rand; - else if (SAME_TYPE(SCHEME_TYPE(rand), scheme_local_type)) { - int offset, pos; - Scheme_Object *expr; - pos = SCHEME_LOCAL_POS(rand); - if (pos >= delta) { - pos -= delta; - expr = optimize_reverse(info, pos, 0, 0); - c = optimize_info_lookup(info, SCHEME_LOCAL_POS(expr), &offset, NULL, 0, 0, NULL, NULL); - } - } else if (SAME_TYPE(SCHEME_TYPE(rand), scheme_compiled_toplevel_type)) { + else if (SAME_TYPE(SCHEME_TYPE(rand), scheme_compiled_local_type)) + c = optimize_info_lookup(info, rand, 1, NULL, 0, 0, NULL, NULL); + else if (SAME_TYPE(SCHEME_TYPE(rand), scheme_compiled_toplevel_type)) { if (info->top_level_consts) { int pos; @@ -3086,13 +3000,6 @@ static Scheme_Object *lookup_constant_proc(Optimize_Info *info, Scheme_Object *r if (c && SAME_TYPE(scheme_noninline_proc_type, SCHEME_TYPE(c))) { c = SCHEME_BOX_VAL(c); - - while (SAME_TYPE(SCHEME_TYPE(c), scheme_compiled_let_void_type)) { - /* This must be (let ([x ]) ); 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; - } } if (c && (SAME_TYPE(scheme_compiled_unclosed_procedure_type, SCHEME_TYPE(c)) @@ -3103,7 +3010,7 @@ static Scheme_Object *lookup_constant_proc(Optimize_Info *info, Scheme_Object *r } static Scheme_Object *try_reduce_predicate(Scheme_Object *rator, Scheme_Object *rand, - Optimize_Info *info, int id_offset) + Optimize_Info *info) /* Change (pair? (list X complex-Y Z)) => (begin complex-Y #t), etc. It's especially nice to avoid the constructions. */ { @@ -3114,7 +3021,7 @@ static Scheme_Object *try_reduce_predicate(Scheme_Object *rator, Scheme_Object * && (!SAME_OBJ(rator, scheme_list_p_proc))) return NULL; - pred = expr_implies_predicate(rand, info, id_offset, 5); + pred = expr_implies_predicate(rand, info, NULL, 5); if (!pred) return NULL; @@ -3131,7 +3038,7 @@ static Scheme_Object *try_reduce_predicate(Scheme_Object *rator, Scheme_Object * } } - return make_discarding_sequence(rand, (matches ? scheme_true : scheme_false), info, id_offset); + return make_discarding_sequence(rand, (matches ? scheme_true : scheme_false), info); } static Scheme_Object *check_ignored_call_cc(Scheme_Object *rator, Scheme_Object *rand, @@ -3144,15 +3051,15 @@ static Scheme_Object *check_ignored_call_cc(Scheme_Object *rator, Scheme_Object || IS_NAMED_PRIM(rator, "call-with-escape-continuation"))) { int rand_flags; Scheme_Object *proc; - proc = lookup_constant_proc(info, rand, 0); + proc = lookup_constant_proc(info, rand); if (!proc) - proc = optimize_for_inline(info, rand, 1, NULL, NULL, NULL, &rand_flags, context, 0, 0); + proc = optimize_for_inline(info, rand, 1, NULL, NULL, NULL, &rand_flags, context, 0); if (proc && SAME_TYPE(SCHEME_TYPE(proc), scheme_compiled_unclosed_procedure_type)) { Scheme_Closure_Data *data = (Scheme_Closure_Data *)proc; if (data->num_params == 1) { Closure_Info *cl = (Closure_Info *)data->closure_map; - if (((cl->local_flags[0] & SCHEME_USE_COUNT_MASK) >> SCHEME_USE_COUNT_SHIFT) == 0) { + if (!cl->vars[0]->use_count) { Scheme_Object *expr; info->vclock++; expr = make_application_2(rand, scheme_void, info); @@ -3207,7 +3114,7 @@ static Scheme_Object *optimize_application2(Scheme_Object *o, Optimize_Info *inf if (le) return le; - le = optimize_for_inline(info, app->rator, 1, NULL, app, NULL, &rator_flags, context, 0, 0); + le = optimize_for_inline(info, app->rator, 1, NULL, app, NULL, &rator_flags, context, 0); if (le) return le; @@ -3224,7 +3131,7 @@ static Scheme_Object *optimize_application2(Scheme_Object *o, Optimize_Info *inf { /* Maybe found "((lambda" after optimizing; try again */ - le = optimize_for_inline(info, app->rator, 1, NULL, app, NULL, &rator_flags, context, 1, 0); + le = optimize_for_inline(info, app->rator, 1, NULL, app, NULL, &rator_flags, context, 1); if (le) return le; rator_apply_escapes = info->escapes; @@ -3245,7 +3152,7 @@ static Scheme_Object *optimize_application2(Scheme_Object *o, Optimize_Info *inf optimize_info_seq_done(info, &info_seq); if (info->escapes) { info->size += 1; - return make_discarding_first_sequence(app->rator, app->rand, info, 0); + return make_discarding_first_sequence(app->rator, app->rand, info); } if (rator_apply_escapes) { @@ -3261,7 +3168,6 @@ static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimiz int flags; Scheme_Object *rator = app->rator; Scheme_Object *rand, *inside = NULL, *alt; - int id_offset = 0; info->size += 1; @@ -3277,7 +3183,7 @@ static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimiz /* We can go inside a `begin' and a `let', which is useful in case the argument was a function call that has been inlined. */ - extract_tail_inside(&rand, &inside, &id_offset); + extract_tail_inside(&rand, &inside); if (SCHEME_TYPE(rand) > _scheme_compiled_values_types_) { Scheme_Object *le; @@ -3298,7 +3204,7 @@ static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimiz if ((SAME_OBJ(scheme_values_func, rator) || SAME_OBJ(scheme_list_star_proc, rator)) && ((context & OPT_CONTEXT_SINGLED) - || scheme_omittable_expr(rand, 1, -1, 0, info, info, 0, id_offset, ID_OMIT) + || scheme_omittable_expr(rand, 1, -1, 0, info, info) || single_valued_noncm_expression(rand, 5))) { info->preserves_marks = 1; info->single_result = 1; @@ -3314,11 +3220,11 @@ static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimiz if (SAME_OBJ(scheme_list_proc, app2->rator)) { if (IS_NAMED_PRIM(rator, "car")) { /* (car (list X)) */ - alt = make_discarding_sequence(scheme_void, app2->rand, info, id_offset); + alt = make_discarding_sequence(scheme_void, app2->rand, info); return replace_tail_inside(alt, inside, app->rand); } else if (IS_NAMED_PRIM(rator, "cdr")) { /* (cdr (list X)) */ - alt = make_discarding_sequence(app2->rand, scheme_null, info, id_offset); + alt = make_discarding_sequence(app2->rand, scheme_null, info); return replace_tail_inside(alt, inside, app->rand); } } @@ -3333,7 +3239,7 @@ static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimiz || SAME_OBJ(scheme_list_proc, app3->rator) || SAME_OBJ(scheme_list_star_proc, app3->rator)) { /* (car ({cons|list|list*} X Y)) */ - alt = make_discarding_reverse_sequence(app3->rand2, app3->rand1, info, id_offset); + alt = make_discarding_reverse_sequence(app3->rand2, app3->rand1, info); return replace_tail_inside(alt, inside, app->rand); } } else if (IS_NAMED_PRIM(rator, "cdr")) { @@ -3341,19 +3247,19 @@ static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimiz || SAME_OBJ(scheme_unsafe_cons_list_proc, app3->rator) || SAME_OBJ(scheme_list_star_proc, app3->rator)) { /* (cdr ({cons|list*} X Y)) */ - alt = make_discarding_sequence(app3->rand1, app3->rand2, info, id_offset); + alt = make_discarding_sequence(app3->rand1, app3->rand2, info); return replace_tail_inside(alt, inside, app->rand); } else if (SAME_OBJ(scheme_list_proc, app3->rator)) { /* (cdr (list X Y)) */ alt = make_application_2(scheme_list_proc, app3->rand2, info); SCHEME_APPN_FLAGS(((Scheme_App_Rec *)alt)) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL); - alt = make_discarding_sequence(app3->rand1, alt, info, id_offset); + alt = make_discarding_sequence(app3->rand1, alt, info); return replace_tail_inside(alt, inside, app->rand); } } else if (IS_NAMED_PRIM(rator, "cadr")) { if (SAME_OBJ(scheme_list_proc, app3->rator)) { /* (cadr (list X Y)) */ - alt = make_discarding_sequence(app3->rand1, app3->rand2, info, id_offset); + alt = make_discarding_sequence(app3->rand1, app3->rand2, info); return replace_tail_inside(alt, inside, app->rand); } } @@ -3368,7 +3274,7 @@ static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimiz && (SAME_OBJ(scheme_list_proc, r) || SAME_OBJ(scheme_list_star_proc, r))) { /* (car ({list|list*} X Y ...)) */ - alt = make_discarding_app_sequence(appr, 0, NULL, info, id_offset); + alt = make_discarding_app_sequence(appr, 0, NULL, info); return replace_tail_inside(alt, inside, app->rand); } } else if (IS_NAMED_PRIM(rator, "cdr")) { @@ -3384,7 +3290,7 @@ static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimiz al = scheme_make_pair(r, al); alt = scheme_make_application(al, info); SCHEME_APPN_FLAGS(((Scheme_App_Rec *)alt)) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL); - alt = make_discarding_sequence(appr->args[1], alt, info, id_offset); + alt = make_discarding_sequence(appr->args[1], alt, info); return replace_tail_inside(alt, inside, app->rand); } } @@ -3392,7 +3298,7 @@ static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimiz } } - alt = try_reduce_predicate(rator, rand, info, id_offset); + alt = try_reduce_predicate(rator, rand, info); if (alt) return replace_tail_inside(alt, inside, app->rand); @@ -3433,7 +3339,7 @@ static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimiz Scheme_Object* pred; Scheme_App3_Rec *new; - pred = expr_implies_predicate(rand, info, id_offset, 5); + pred = expr_implies_predicate(rand, info, NULL, 5); if (pred && SAME_OBJ(pred, scheme_fixnum_p_proc)) { new = (Scheme_App3_Rec *)make_application_3(scheme_unsafe_fx_eq_proc, app->rand, scheme_make_integer(0), info); SCHEME_APPN_FLAGS(new) |= (APPN_FLAG_IMMED | APPN_FLAG_SFS_TAIL); @@ -3446,30 +3352,30 @@ static Scheme_Object *finish_optimize_application2(Scheme_App2_Rec *app, Optimiz /* Try to check the argument's type, and use the unsafe versions if possible. */ Scheme_Object *app_o = (Scheme_Object *)app; - check_known_try(info, app_o, rator, rand, id_offset, "bitwise-not", scheme_fixnum_p_proc, scheme_unsafe_fxnot_proc); - check_known_try(info, app_o, rator, rand, id_offset, "fxnot", scheme_fixnum_p_proc, scheme_unsafe_fxnot_proc); + check_known_try(info, app_o, rator, rand, "bitwise-not", scheme_fixnum_p_proc, scheme_unsafe_fxnot_proc); + check_known_try(info, app_o, rator, rand, "fxnot", scheme_fixnum_p_proc, scheme_unsafe_fxnot_proc); - check_known(info, app_o, rator, rand, id_offset, "car", scheme_pair_p_proc, scheme_unsafe_car_proc); - check_known(info, app_o, rator, rand, id_offset, "cdr", scheme_pair_p_proc, scheme_unsafe_cdr_proc); - check_known(info, app_o, rator, rand, id_offset, "mcar", scheme_mpair_p_proc, scheme_unsafe_mcar_proc); - check_known(info, app_o, rator, rand, id_offset, "mcdr", scheme_mpair_p_proc, scheme_unsafe_mcdr_proc); + check_known(info, app_o, rator, rand, "car", scheme_pair_p_proc, scheme_unsafe_car_proc); + check_known(info, app_o, rator, rand, "cdr", scheme_pair_p_proc, scheme_unsafe_cdr_proc); + check_known(info, app_o, rator, rand, "mcar", scheme_mpair_p_proc, scheme_unsafe_mcar_proc); + check_known(info, app_o, rator, rand, "mcdr", scheme_mpair_p_proc, scheme_unsafe_mcdr_proc); /* It's not clear that these are useful, since a chaperone check is needed anyway: */ - check_known(info, app_o, rator, rand, id_offset, "unbox", scheme_box_p_proc, scheme_unsafe_unbox_proc); - check_known(info, app_o, rator, rand, id_offset, "vector-length", scheme_vector_p_proc, scheme_unsafe_vector_length_proc); + check_known(info, app_o, rator, rand, "unbox", scheme_box_p_proc, scheme_unsafe_unbox_proc); + check_known(info, app_o, rator, rand, "vector-length", scheme_vector_p_proc, scheme_unsafe_vector_length_proc); /* These operation don't have an unsafe replacement. Check to record types and detect errors: */ - check_known(info, app_o, rator, rand, id_offset, "caar", scheme_pair_p_proc, NULL); - check_known(info, app_o, rator, rand, id_offset, "cadr", scheme_pair_p_proc, NULL); - check_known(info, app_o, rator, rand, id_offset, "cdar", scheme_pair_p_proc, NULL); - check_known(info, app_o, rator, rand, id_offset, "cddr", scheme_pair_p_proc, NULL); + check_known(info, app_o, rator, rand, "caar", scheme_pair_p_proc, NULL); + check_known(info, app_o, rator, rand, "cadr", scheme_pair_p_proc, NULL); + check_known(info, app_o, rator, rand, "cdar", scheme_pair_p_proc, NULL); + check_known(info, app_o, rator, rand, "cddr", scheme_pair_p_proc, NULL); - check_known(info, app_o, rator, rand, id_offset, "caddr", scheme_pair_p_proc, NULL); - check_known(info, app_o, rator, rand, id_offset, "cdddr", scheme_pair_p_proc, NULL); - check_known(info, app_o, rator, rand, id_offset, "cadddr", scheme_pair_p_proc, NULL); - check_known(info, app_o, rator, rand, id_offset, "cddddr", scheme_pair_p_proc, NULL); + check_known(info, app_o, rator, rand, "caddr", scheme_pair_p_proc, NULL); + check_known(info, app_o, rator, rand, "cdddr", scheme_pair_p_proc, NULL); + check_known(info, app_o, rator, rand, "cadddr", scheme_pair_p_proc, NULL); + check_known(info, app_o, rator, rand, "cddddr", scheme_pair_p_proc, NULL); - check_known(info, app_o, rator, rand, id_offset, "vector->list", scheme_vector_p_proc, NULL); - check_known(info, app_o, rator, rand, id_offset, "vector->values", scheme_vector_p_proc, NULL); + check_known(info, app_o, rator, rand, "vector->list", scheme_vector_p_proc, NULL); + check_known(info, app_o, rator, rand, "vector->values", scheme_vector_p_proc, NULL); /* Some of these may have changed app->rator. */ rator = app->rator; @@ -3537,7 +3443,7 @@ static Scheme_Object *optimize_application3(Scheme_Object *o, Optimize_Info *inf if (le) return le; - le = optimize_for_inline(info, app->rator, 2, NULL, NULL, app, &rator_flags, context, 0, 0); + le = optimize_for_inline(info, app->rator, 2, NULL, NULL, app, &rator_flags, context, 0); if (le) return le; @@ -3554,7 +3460,7 @@ static Scheme_Object *optimize_application3(Scheme_Object *o, Optimize_Info *inf { /* Maybe found "((lambda" after optimizing; try again */ - le = optimize_for_inline(info, app->rator, 2, NULL, NULL, app, &rator_flags, context, 1, 0); + le = optimize_for_inline(info, app->rator, 2, NULL, NULL, app, &rator_flags, context, 1); if (le) return le; rator_apply_escapes = info->escapes; @@ -3576,7 +3482,7 @@ static Scheme_Object *optimize_application3(Scheme_Object *o, Optimize_Info *inf app->rand1 = le; if (info->escapes) { info->size += 1; - return make_discarding_first_sequence(app->rator, app->rand1, info, 0); + return make_discarding_first_sequence(app->rator, app->rand1, info); } /* 2nd arg */ @@ -3596,8 +3502,8 @@ static Scheme_Object *optimize_application3(Scheme_Object *o, Optimize_Info *inf info->size += 1; return make_discarding_first_sequence(app->rator, make_discarding_first_sequence(app->rand1, app->rand2, - info, 0), - info, 0); + info), + info); } /* Check for (apply ... (list ...)) after some optimizations: */ @@ -3620,7 +3526,6 @@ static Scheme_Object *finish_optimize_application3(Scheme_App3_Rec *app, Optimiz int flags; Scheme_Object *le; int all_vals = 1; - int id_offset = 0; info->size += 1; @@ -3662,7 +3567,7 @@ static Scheme_Object *finish_optimize_application3(Scheme_App3_Rec *app, Optimiz Scheme_Case_Lambda *cl; int i, cnt; - proc = lookup_constant_proc(info, app->rand1, 0); + proc = lookup_constant_proc(info, app->rand1); if (proc) { if (SAME_TYPE(SCHEME_TYPE(proc), scheme_compiled_unclosed_procedure_type)) { cnt = 1; @@ -3722,9 +3627,9 @@ static Scheme_Object *finish_optimize_application3(Scheme_App3_Rec *app, Optimiz if (SAME_OBJ(app->rator, scheme_eq_prim)) { Scheme_Object *pred1, *pred2; - pred1 = expr_implies_predicate(app->rand1, info, 0, 5); + pred1 = expr_implies_predicate(app->rand1, info, NULL, 5); if (pred1) { - pred2 = expr_implies_predicate(app->rand2, info, 0, 5); + pred2 = expr_implies_predicate(app->rand2, info, NULL, 5); if (pred2) { if (!SAME_OBJ(pred1, pred2)) { info->preserves_marks = 1; @@ -3732,9 +3637,9 @@ static Scheme_Object *finish_optimize_application3(Scheme_App3_Rec *app, Optimiz return do_make_discarding_sequence(app->rand1, do_make_discarding_sequence(app->rand2, scheme_false, - info, 0, + info, 0, 0), - info, 0, + info, 0, 0); } } @@ -3768,9 +3673,9 @@ static Scheme_Object *finish_optimize_application3(Scheme_App3_Rec *app, Optimiz if (z1 && z2) return scheme_make_integer(0); else if (z2) - return make_discarding_sequence(app->rand1, scheme_make_integer(0), info, id_offset); + return make_discarding_sequence(app->rand1, scheme_make_integer(0), info); else - return make_discarding_sequence(app->rand2, scheme_make_integer(0), info, id_offset); + return make_discarding_sequence(app->rand2, scheme_make_integer(0), info); } if (SAME_OBJ(app->rand1, scheme_make_integer(1))) return app->rand2; @@ -3778,15 +3683,15 @@ static Scheme_Object *finish_optimize_application3(Scheme_App3_Rec *app, Optimiz return app->rand1; } else if (IS_NAMED_PRIM(app->rator, "unsafe-fxquotient")) { if (z1) - return make_discarding_sequence(app->rand2, scheme_make_integer(0), info, id_offset); + return make_discarding_sequence(app->rand2, scheme_make_integer(0), info); if (SAME_OBJ(app->rand2, scheme_make_integer(1))) return app->rand1; } else if (IS_NAMED_PRIM(app->rator, "unsafe-fxremainder") || IS_NAMED_PRIM(app->rator, "unsafe-fxmodulo")) { if (z1) - return make_discarding_sequence(app->rand2, scheme_make_integer(0), info, id_offset); + return make_discarding_sequence(app->rand2, scheme_make_integer(0), info); if (SAME_OBJ(app->rand2, scheme_make_integer(1))) - return make_discarding_sequence(app->rand1, scheme_make_integer(0), info, id_offset); + return make_discarding_sequence(app->rand1, scheme_make_integer(0), info); } z1 = (SCHEME_FLOATP(app->rand1) && (SCHEME_FLOAT_VAL(app->rand1) == 0.0)); @@ -3864,40 +3769,40 @@ static Scheme_Object *finish_optimize_application3(Scheme_App3_Rec *app, Optimiz if (SCHEME_PRIMP(app->rator)) { Scheme_Object *app_o = (Scheme_Object *)app, *rator = app->rator, *rand1 = app->rand1, *rand2 = app->rand2; - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "bitwise-and", scheme_fixnum_p_proc, scheme_unsafe_fxand_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "bitwise-ior", scheme_fixnum_p_proc, scheme_unsafe_fxior_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "bitwise-xor", scheme_fixnum_p_proc, scheme_unsafe_fxxor_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "bitwise-and", scheme_fixnum_p_proc, scheme_unsafe_fxand_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "bitwise-ior", scheme_fixnum_p_proc, scheme_unsafe_fxior_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "bitwise-xor", scheme_fixnum_p_proc, scheme_unsafe_fxxor_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "fxand", scheme_fixnum_p_proc, scheme_unsafe_fxand_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "fxior", scheme_fixnum_p_proc, scheme_unsafe_fxior_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "fxxor", scheme_fixnum_p_proc, scheme_unsafe_fxxor_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "fxand", scheme_fixnum_p_proc, scheme_unsafe_fxand_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "fxior", scheme_fixnum_p_proc, scheme_unsafe_fxior_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "fxxor", scheme_fixnum_p_proc, scheme_unsafe_fxxor_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "=", scheme_fixnum_p_proc, scheme_unsafe_fx_eq_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "<", scheme_fixnum_p_proc, scheme_unsafe_fx_lt_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, ">", scheme_fixnum_p_proc, scheme_unsafe_fx_gt_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "<=", scheme_fixnum_p_proc, scheme_unsafe_fx_lt_eq_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, ">=", scheme_fixnum_p_proc, scheme_unsafe_fx_gt_eq_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "min", scheme_fixnum_p_proc, scheme_unsafe_fx_min_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "max", scheme_fixnum_p_proc, scheme_unsafe_fx_max_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "=", scheme_fixnum_p_proc, scheme_unsafe_fx_eq_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "<", scheme_fixnum_p_proc, scheme_unsafe_fx_lt_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, ">", scheme_fixnum_p_proc, scheme_unsafe_fx_gt_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "<=", scheme_fixnum_p_proc, scheme_unsafe_fx_lt_eq_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, ">=", scheme_fixnum_p_proc, scheme_unsafe_fx_gt_eq_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "min", scheme_fixnum_p_proc, scheme_unsafe_fx_min_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "max", scheme_fixnum_p_proc, scheme_unsafe_fx_max_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "fx=", scheme_fixnum_p_proc, scheme_unsafe_fx_eq_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "fx<", scheme_fixnum_p_proc, scheme_unsafe_fx_lt_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "fx>", scheme_fixnum_p_proc, scheme_unsafe_fx_gt_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "fx<=", scheme_fixnum_p_proc, scheme_unsafe_fx_lt_eq_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "fx>=", scheme_fixnum_p_proc, scheme_unsafe_fx_gt_eq_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "fxmin", scheme_fixnum_p_proc, scheme_unsafe_fx_min_proc); - check_known_both_try(info, app_o, rator, rand1, rand2, 0, "fxmax", scheme_fixnum_p_proc, scheme_unsafe_fx_max_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "fx=", scheme_fixnum_p_proc, scheme_unsafe_fx_eq_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "fx<", scheme_fixnum_p_proc, scheme_unsafe_fx_lt_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "fx>", scheme_fixnum_p_proc, scheme_unsafe_fx_gt_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "fx<=", scheme_fixnum_p_proc, scheme_unsafe_fx_lt_eq_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "fx>=", scheme_fixnum_p_proc, scheme_unsafe_fx_gt_eq_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "fxmin", scheme_fixnum_p_proc, scheme_unsafe_fx_min_proc); + check_known_both_try(info, app_o, rator, rand1, rand2, "fxmax", scheme_fixnum_p_proc, scheme_unsafe_fx_max_proc); - check_known(info, app_o, rator, rand1, 0, "vector-ref", scheme_vector_p_proc, NULL); + check_known(info, app_o, rator, rand1, "vector-ref", scheme_vector_p_proc, NULL); - check_known(info, app_o, rator, rand1, 0, "procedure-closure-contents-eq?", scheme_procedure_p_proc, NULL); - check_known(info, app_o, rator, rand2, 0, "procedure-closure-contents-eq?", scheme_procedure_p_proc, NULL); - check_known(info, app_o, rator, rand1, 0, "procedure-arity-includes?", scheme_procedure_p_proc, NULL); + check_known(info, app_o, rator, rand1, "procedure-closure-contents-eq?", scheme_procedure_p_proc, NULL); + check_known(info, app_o, rator, rand2, "procedure-closure-contents-eq?", scheme_procedure_p_proc, NULL); + check_known(info, app_o, rator, rand1, "procedure-arity-includes?", scheme_procedure_p_proc, NULL); - check_known(info, app_o, rator, rand1, 0, "map", scheme_procedure_p_proc, NULL); - check_known(info, app_o, rator, rand1, 0, "for-each", scheme_procedure_p_proc, NULL); - check_known(info, app_o, rator, rand1, 0, "andmap", scheme_procedure_p_proc, NULL); - check_known(info, app_o, rator, rand1, 0, "ormap", scheme_procedure_p_proc, NULL); + check_known(info, app_o, rator, rand1, "map", scheme_procedure_p_proc, NULL); + check_known(info, app_o, rator, rand1, "for-each", scheme_procedure_p_proc, NULL); + check_known(info, app_o, rator, rand1, "andmap", scheme_procedure_p_proc, NULL); + check_known(info, app_o, rator, rand1, "ormap", scheme_procedure_p_proc, NULL); } register_local_argument_types(NULL, NULL, app, info); @@ -3921,18 +3826,14 @@ Scheme_Object *scheme_optimize_apply_values(Scheme_Object *f, Scheme_Object *e, info->single_result = 0; { - Scheme_Object *rev; - if (SAME_TYPE(SCHEME_TYPE(f), scheme_local_type)) { - rev = optimize_reverse(info, SCHEME_LOCAL_POS(f), 1, 0); - } else - rev = f; + Scheme_Object *rev = f; if (rev) { int rator2_flags; Scheme_Object *o_f; - o_f = lookup_constant_proc(info, rev, 0); + o_f = lookup_constant_proc(info, rev); if (!o_f) - o_f = optimize_for_inline(info, rev, 1, NULL, NULL, NULL, &rator2_flags, context, 0, 0); + o_f = optimize_for_inline(info, rev, 1, NULL, NULL, NULL, &rator2_flags, context, 0); if (o_f) { f_is_proc = rev; @@ -3959,19 +3860,14 @@ Scheme_Object *scheme_optimize_apply_values(Scheme_Object *f, Scheme_Object *e, app2 = MALLOC_ONE_TAGGED(Scheme_App2_Rec); app2->iso.so.type = scheme_application2_type; - /* We'd like to try to inline here. The problem is that - e (the argument) has been optimized already, - which means it's in the wrong coordinate system. - If we can shift-clone it, then it will be back in the right - coordinates. */ + /* Try to inline... */ - cloned = optimize_clone(1, e, info, 0, 0); + cloned = optimize_clone(1, e, info, empty_eq_hash_tree, 0); if (cloned) { if (SAME_TYPE(SCHEME_TYPE(f_is_proc), scheme_compiled_unclosed_procedure_type)) - f_cloned = optimize_clone(1, f_is_proc, info, 0, 0); + f_cloned = optimize_clone(1, f_is_proc, info, empty_eq_hash_tree, 0); else { - /* Otherwise, no clone is needed; in the case of a lexical - variable, we already reversed it. */ + /* Otherwise, no clone is needed. */ f_cloned = f_is_proc; } @@ -3998,11 +3894,13 @@ Scheme_Object *scheme_optimize_apply_values(Scheme_Object *f, Scheme_Object *e, } } -static Scheme_Object *flatten_sequence(Scheme_Object *o, Optimize_Info *info) +static Scheme_Object *optimize_sequence(Scheme_Object *o, Optimize_Info *info, int context, int sub_opt); + +static Scheme_Object *flatten_sequence(Scheme_Object *o, Optimize_Info *info, int context) { Scheme_Sequence *s = (Scheme_Sequence *)o, *s2, *s3; Scheme_Object *o3; - int i, j, k, count, extra = 0, split = 0, b0; + int i, j, k, count, extra = 0, split = 0, b0, move_to_let = 0, new_count; if (SAME_TYPE(SCHEME_TYPE(o), scheme_splice_sequence_type)) return o; @@ -4021,18 +3919,25 @@ static Scheme_Object *flatten_sequence(Scheme_Object *o, Optimize_Info *info) s3 = (Scheme_Sequence *)o3; extra += s3->count; split++; + } else if (SAME_TYPE(SCHEME_TYPE(o3), scheme_compiled_let_void_type) && !(!i && b0)) { + move_to_let = count - i - 1; + break; } } - if (!split) + if (!split && !move_to_let) return o; - + info->flatten_fuel--; info->size -= split; - s2 = scheme_malloc_sequence(s->count + extra - split); - s2->so.type = s->so.type; - s2->count = s->count + extra - split; + new_count = s->count + extra - split - move_to_let; + if (new_count > 0) { + s2 = scheme_malloc_sequence(new_count); + s2->so.type = s->so.type; + s2->count = new_count; + } else + s2 = NULL; k = 0; /* exceptions: (begin ... (begin0 ...)) and (begin0 (begin ...) ...) */ @@ -4044,17 +3949,52 @@ static Scheme_Object *flatten_sequence(Scheme_Object *o, Optimize_Info *info) for (j = 0; j < s3->count; j++) { s2->array[k++] = s3->array[j]; } + } else if (SAME_TYPE(SCHEME_TYPE(o3), scheme_compiled_let_void_type) && !(!i && b0)) { + /* move rest under `let`: */ + Scheme_Let_Header *head = (Scheme_Let_Header *)o3; + Scheme_Compiled_Let_Value *clv; + + if (s2) + s2->array[k++] = o3; + + s3 = scheme_malloc_sequence(move_to_let + 1); + s3->so.type = scheme_sequence_type; + s3->count = move_to_let + 1; + + for (j = 0; j < move_to_let; j++) { + s3->array[1 + j] = s->array[i + 1 + j]; + } + + clv = (Scheme_Compiled_Let_Value *)head->body; + for (j = 1; j < head->num_clauses; j++) { + clv = (Scheme_Compiled_Let_Value *)clv->body; + } + + s3->array[0] = clv->body; + + o3 = flatten_sequence((Scheme_Object *)s3, info, context); + clv->body = (Scheme_Object *)o3; + + return ((s2 && (s2->count > 1)) + ? (Scheme_Object *)s2 + : (Scheme_Object *)head); } else { s2->array[k++] = o3; } } - if (k != s2->count) scheme_signal_error("internal error: flatten failed"); + MZ_ASSERT(k == new_count); - return (Scheme_Object *)s2; + if (s2->count == 1) + return s2->array[0]; + + if (SAME_TYPE(SCHEME_TYPE(s2), scheme_sequence_type)) + return optimize_sequence((Scheme_Object *)s2, info, context, 0); + else + return (Scheme_Object *)s2; } -static Scheme_Object *optimize_sequence(Scheme_Object *o, Optimize_Info *info, int context) +static Scheme_Object *optimize_sequence(Scheme_Object *o, Optimize_Info *info, int context, int sub_opt) { Scheme_Sequence *s = (Scheme_Sequence *)o; Scheme_Object *le; @@ -4062,26 +4002,34 @@ static Scheme_Object *optimize_sequence(Scheme_Object *o, Optimize_Info *info, i int drop = 0, preserves_marks = 0, single_result = 0; Optimize_Info_Sequence info_seq; - optimize_info_seq_init(info, &info_seq); + /* If !sub_opt, then just inspect already-optimized results. Note + that `info` doesn't change in this mode, so we shouldn't try to + check whether an expression escapes, for example. */ + + if (sub_opt) + optimize_info_seq_init(info, &info_seq); count = s->count; for (i = 0; i < count; i++) { prev_size = info->size; - optimize_info_seq_step(info, &info_seq); - le = scheme_optimize_expr(s->array[i], info, - ((i + 1 == count) - ? scheme_optimize_tail_context(context) - : 0)); + if (sub_opt) { + optimize_info_seq_step(info, &info_seq); + le = scheme_optimize_expr(s->array[i], info, + ((i + 1 == count) + ? scheme_optimize_tail_context(context) + : 0)); + } else + le = s->array[i]; if (i + 1 == count) { single_result = info->single_result; preserves_marks = info->preserves_marks; s->array[i] = le; } else { - if (!info->escapes) { + if (!sub_opt || !info->escapes) { /* Inlining and constant propagation can expose omittable expressions. */ - le = optimize_ignored(le, info, 0, -1, 1, 5); + le = optimize_ignored(le, info, -1, 1, 5); if (!le) { drop++; info->size = prev_size; @@ -4105,7 +4053,8 @@ static Scheme_Object *optimize_sequence(Scheme_Object *o, Optimize_Info *info, i } } - optimize_info_seq_done(info, &info_seq); + if (sub_opt) + optimize_info_seq_done(info, &info_seq); info->preserves_marks = preserves_marks; info->single_result = single_result; @@ -4130,7 +4079,7 @@ static Scheme_Object *optimize_sequence(Scheme_Object *o, Optimize_Info *info, i s = s2; } - return flatten_sequence((Scheme_Object *)s, info); + return flatten_sequence((Scheme_Object *)s, info, context); } XFORM_NONGCING static int small_inline_number(Scheme_Object *o) @@ -4162,7 +4111,7 @@ int scheme_compiled_duplicate_ok(Scheme_Object *fb, int cross_module) || SCHEME_EOFP(fb) || SCHEME_INTP(fb) || SCHEME_NULLP(fb) - || (!cross_module && SAME_TYPE(SCHEME_TYPE(fb), scheme_local_type)) + || (!cross_module && SAME_TYPE(SCHEME_TYPE(fb), scheme_compiled_local_type)) || SCHEME_PRIMP(fb) /* Values that are hashed by the printer and/or interned on read to avoid duplication: */ @@ -4177,13 +4126,13 @@ int scheme_compiled_duplicate_ok(Scheme_Object *fb, int cross_module) || SAME_TYPE(SCHEME_TYPE(fb), scheme_ctype_type)); } -static Scheme_Object *collapse_local(int pos, Optimize_Info *info, int context) +static Scheme_Object *collapse_local(Scheme_Object *var, Optimize_Info *info, int context) /* pos is in new-frame counts */ { - if (!optimize_is_mutated(info, pos)) { + if (!SCHEME_VAR(var)->mutated) { Scheme_Object *pred; - pred = optimize_get_predicate(info, pos); + pred = optimize_get_predicate(info, var); if (pred) { if (SAME_OBJ(pred, scheme_not_prim)) return scheme_false; @@ -4210,25 +4159,20 @@ static Scheme_Object *equivalent_exprs(Scheme_Object *a, Scheme_Object *b, if (SAME_OBJ(a, b)) return a; - if (SAME_TYPE(SCHEME_TYPE(a), scheme_local_type) - && SAME_TYPE(SCHEME_TYPE(b), scheme_local_type) - && (SCHEME_LOCAL_POS(a) == SCHEME_LOCAL_POS(b))) - return a; - if (b_info - && SAME_TYPE(SCHEME_TYPE(a), scheme_local_type) + && SAME_TYPE(SCHEME_TYPE(a), scheme_compiled_local_type) && (SCHEME_TYPE(b) > _scheme_compiled_values_types_)) { Scheme_Object *n; - n = collapse_local(SCHEME_LOCAL_POS(a), b_info, context); + n = collapse_local(a, b_info, context); if (n && SAME_OBJ(n, b)) return a; } if (a_info - && SAME_TYPE(SCHEME_TYPE(b), scheme_local_type) + && SAME_TYPE(SCHEME_TYPE(b), scheme_compiled_local_type) && (SCHEME_TYPE(a) > _scheme_compiled_values_types_)) { Scheme_Object *n; - n = collapse_local(SCHEME_LOCAL_POS(b), a_info, context); + n = collapse_local(b, a_info, context); if (n && SAME_OBJ(n, a)) return b; } @@ -4236,31 +4180,29 @@ static Scheme_Object *equivalent_exprs(Scheme_Object *a, Scheme_Object *b, return NULL; } -static void add_type(Optimize_Info *info, int pos, Scheme_Object *pred) +static void add_type(Optimize_Info *info, Scheme_Object *var, Scheme_Object *pred) { Scheme_Hash_Tree *new_types = info->types; - if (optimize_is_mutated(info, pos)) + if (SCHEME_VAR(var)->mutated) return; /* Don't add the type if something is already there, this may happen when no_types. */ - if (do_optimize_get_predicate(info, pos, 1) - || optimize_is_local_type_valued(info, pos)) { + if (do_optimize_get_predicate(info, var, 1) + || SCHEME_VAR(var)->val_type) { return; } if (!new_types) new_types = scheme_make_hash_tree(0); - new_types = scheme_hash_tree_set(new_types, - scheme_make_integer(pos), - pred); + new_types = scheme_hash_tree_set(new_types, var, pred); info->types = new_types; } -static void merge_types(Optimize_Info *src_info, Optimize_Info *info, int delta) +static void merge_types(Optimize_Info *src_info, Optimize_Info *info, Scheme_Hash_Tree *skip_vars) { Scheme_Hash_Tree *types = src_info->types; - Scheme_Object *pos, *pred; + Scheme_Object *var, *pred; intptr_t i; if (!types) @@ -4268,9 +4210,9 @@ static void merge_types(Optimize_Info *src_info, Optimize_Info *info, int delta) i = scheme_hash_tree_next(types, -1); while (i != -1) { - scheme_hash_tree_index(types, i, &pos, &pred); - if (SCHEME_INT_VAL(pos)+delta >= 0) - add_type(info, SCHEME_INT_VAL(pos)+delta, pred); + scheme_hash_tree_index(types, i, &var, &pred); + if (!skip_vars || !scheme_hash_tree_get(skip_vars, var)) + add_type(info, var, pred); i = scheme_hash_tree_next(types, i); } } @@ -4280,7 +4222,7 @@ static void intersect_and_merge_types(Optimize_Info *t_info, Optimize_Info *f_in /* Add to base_info the intersection of the types of t_info and f_info */ { Scheme_Hash_Tree *t_types = t_info->types, *f_types = f_info->types; - Scheme_Object *pos, *t_pred, *f_pred; + Scheme_Object *var, *t_pred, *f_pred; intptr_t i; if (!t_types || !f_types) @@ -4294,10 +4236,10 @@ static void intersect_and_merge_types(Optimize_Info *t_info, Optimize_Info *f_in i = scheme_hash_tree_next(f_types, -1); while (i != -1) { - scheme_hash_tree_index(f_types, i, &pos, &f_pred); - t_pred = scheme_hash_tree_get(t_types, pos); + scheme_hash_tree_index(f_types, i, &var, &f_pred); + t_pred = scheme_hash_tree_get(t_types, var); if (t_pred && SAME_OBJ(t_pred, f_pred)) - add_type(base_info, SCHEME_INT_VAL(pos), f_pred); + add_type(base_info, var, f_pred); i = scheme_hash_tree_next(f_types, i); } } @@ -4333,35 +4275,35 @@ static void add_types_for_t_branch(Scheme_Object *t, Optimize_Info *info, int fu if (SAME_TYPE(SCHEME_TYPE(t), scheme_application2_type)) { Scheme_App2_Rec *app = (Scheme_App2_Rec *)t; if (SCHEME_PRIMP(app->rator) - && SAME_TYPE(SCHEME_TYPE(app->rand), scheme_local_type) - && !optimize_is_mutated(info, SCHEME_LOCAL_POS(app->rand)) + && SAME_TYPE(SCHEME_TYPE(app->rand), scheme_compiled_local_type) + && !SCHEME_VAR(app->rand)->mutated && relevant_predicate(app->rator)) { /* Looks like a predicate on a local variable. Record that the predicate succeeded, which may allow conversion of safe operations to unsafe operations. */ - add_type(info, SCHEME_LOCAL_POS(app->rand), app->rator); + add_type(info, app->rand, app->rator); } } else if (SAME_TYPE(SCHEME_TYPE(t), scheme_application3_type)) { Scheme_App3_Rec *app = (Scheme_App3_Rec *)t; Scheme_Object *pred1, *pred2; if (SAME_OBJ(app->rator, scheme_eq_prim)) { - if (SAME_TYPE(SCHEME_TYPE(app->rand1), scheme_local_type) - && !optimize_is_mutated(info, SCHEME_LOCAL_POS(app->rand1))) { - pred1 = optimize_get_predicate(info, SCHEME_LOCAL_POS(app->rand1)); + if (SAME_TYPE(SCHEME_TYPE(app->rand1), scheme_compiled_local_type) + && !SCHEME_VAR(app->rand1)->mutated) { + pred1 = optimize_get_predicate(info, app->rand1); if (!pred1) { - pred2 = expr_implies_predicate(app->rand2, info, 0, 5); + pred2 = expr_implies_predicate(app->rand2, info, NULL, 5); if (pred2) - add_type(info, SCHEME_LOCAL_POS(app->rand1), pred2); + add_type(info, app->rand1, pred2); } } - if (SAME_TYPE(SCHEME_TYPE(app->rand2), scheme_local_type) - && !optimize_is_mutated(info, SCHEME_LOCAL_POS(app->rand2))) { - pred2 = optimize_get_predicate(info, SCHEME_LOCAL_POS(app->rand2)); + if (SAME_TYPE(SCHEME_TYPE(app->rand2), scheme_compiled_local_type) + && !SCHEME_VAR(app->rand2)->mutated) { + pred2 = optimize_get_predicate(info, app->rand2); if (!pred2) { - pred1 = expr_implies_predicate(app->rand1, info, 0, 5); + pred1 = expr_implies_predicate(app->rand1, info, NULL, 5); if (pred1) - add_type(info, SCHEME_LOCAL_POS(app->rand2), pred1); + add_type(info, app->rand2, pred1); } } } @@ -4384,8 +4326,8 @@ static void add_types_for_f_branch(Scheme_Object *t, Optimize_Info *info, int fu if (fuel < 0) return; - if (SAME_TYPE(SCHEME_TYPE(t), scheme_local_type)) { - add_type(info, SCHEME_LOCAL_POS(t), scheme_not_prim); + if (SAME_TYPE(SCHEME_TYPE(t), scheme_compiled_local_type)) { + add_type(info, t, scheme_not_prim); } else if (SAME_TYPE(SCHEME_TYPE(t), scheme_branch_type)) { Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)t; @@ -4429,17 +4371,15 @@ static Scheme_Object *optimize_branch(Scheme_Object *o, Optimize_Info *info, int fb = b->fbranch; /* Convert (if expr ) to (if expr #f) */ - if (SAME_TYPE(SCHEME_TYPE(t), scheme_local_type) - && SAME_TYPE(SCHEME_TYPE(fb), scheme_local_type) - && (SCHEME_LOCAL_POS(t) == SCHEME_LOCAL_POS(fb))) { + if (SAME_TYPE(SCHEME_TYPE(t), scheme_compiled_local_type) + && SAME_OBJ(t, fb)) { fb = scheme_false; } if (context & OPT_CONTEXT_BOOLEAN) { /* For test position, convert (if expr) to (if #t expr) */ - if (SAME_TYPE(SCHEME_TYPE(t), scheme_local_type) - && SAME_TYPE(SCHEME_TYPE(tb), scheme_local_type) - && (SCHEME_LOCAL_POS(t) == SCHEME_LOCAL_POS(tb))) { + if (SAME_TYPE(SCHEME_TYPE(t), scheme_compiled_local_type) + && SAME_OBJ(t, tb)) { tb = scheme_true; } @@ -4460,10 +4400,9 @@ static Scheme_Object *optimize_branch(Scheme_Object *o, Optimize_Info *info, int /* Try to lift out `let`s and `begin`s around a test: */ { Scheme_Object *inside = NULL, *t2 = t; - int id_offset = 0; while (1) { - extract_tail_inside(&t2, &inside, &id_offset); + extract_tail_inside(&t2, &inside); /* Try optimize: (if (not x) y z) => (if x z y) */ if (SAME_TYPE(SCHEME_TYPE(t2), scheme_application2_type)) { @@ -4482,17 +4421,16 @@ static Scheme_Object *optimize_branch(Scheme_Object *o, Optimize_Info *info, int break; } - pred = expr_implies_predicate(t2, info, id_offset, 5); + pred = expr_implies_predicate(t2, info, NULL, 5); if (pred) { /* (if (let () (cons x y)) a b) => (if (begin (let () (begin x y #)) #t/#f) a b) */ Scheme_Object *test_val = SAME_OBJ(pred, scheme_not_prim) ? scheme_false : scheme_true; - t2 = optimize_ignored(t2, info, id_offset, 1, 0, 5); + t2 = optimize_ignored(t2, info, 1, 0, 5); t = replace_tail_inside(t2, inside, t); t2 = test_val; - id_offset = 0; - if (scheme_omittable_expr(t, 1, 5, 0, info, NULL, 0, 0, ID_OMIT)) { + if (scheme_omittable_expr(t, 1, 5, 0, info, NULL)) { t = test_val; inside = NULL; } else { @@ -4513,16 +4451,7 @@ static Scheme_Object *optimize_branch(Scheme_Object *o, Optimize_Info *info, int else xb = scheme_optimize_expr(tb, info, scheme_optimize_tail_context(context)); - if (id_offset){ - replace_tail_inside(scheme_void, inside, NULL); - /* t and xb are not 'inside' the let's, so we use id_offset = 0 */ - if (scheme_omittable_expr(t, 1, 5, 0, info, NULL, 0, 0, ID_OMIT)) - return xb; - else - return make_sequence_2(t, xb); - } else { - return replace_tail_inside(xb, inside, t); - } + return replace_tail_inside(xb, inside, t); } } @@ -4565,13 +4494,13 @@ static Scheme_Object *optimize_branch(Scheme_Object *o, Optimize_Info *info, int info->preserves_marks = then_info->preserves_marks; info->single_result = then_info->single_result; info->kclock = then_info->kclock; - merge_types(then_info, info, 0); + merge_types(then_info, info, NULL); info->escapes = 0; } else if (then_info->escapes) { info->preserves_marks = else_info->preserves_marks; info->single_result = else_info->single_result; - merge_types(else_info, info, 0); + merge_types(else_info, info, NULL); info->escapes = 0; } else { @@ -4613,16 +4542,15 @@ static Scheme_Object *optimize_branch(Scheme_Object *o, Optimize_Info *info, int nb = equivalent_exprs(tb, fb, then_info_init, else_info_init, context); if (nb) { info->size -= 1; /* could be more precise */ - return make_discarding_first_sequence(t, nb, info, 0); + return make_discarding_first_sequence(t, nb, info); } } /* Try optimize: (if x x #f) => x This pattern is included in the previous reduction, but this is still useful if x is mutable */ - if (SAME_TYPE(SCHEME_TYPE(t), scheme_local_type) - && SAME_TYPE(SCHEME_TYPE(tb), scheme_local_type) - && (SCHEME_LOCAL_POS(t) == SCHEME_LOCAL_POS(tb)) + if (SAME_TYPE(SCHEME_TYPE(t), scheme_compiled_local_type) + && SAME_OBJ(t, tb) && SCHEME_FALSEP(fb)) { info->size -= 2; return t; @@ -4663,8 +4591,8 @@ static Scheme_Object *optimize_branch(Scheme_Object *o, Optimize_Info *info, int static int omittable_key(Scheme_Object *k, Optimize_Info *info) { /* A key is not omittable if it might refer to a chaperoned/impersonated - continuation mark key, so that's why we pass NO_ID_OMIT: */ - return scheme_omittable_expr(k, 1, 20, 0, info, info, 0, 0, NO_ID_OMIT); + continuation mark key, so that's why we pass OMITTABLE_KEEP_VARS: */ + return scheme_omittable_expr(k, 1, 20, OMITTABLE_KEEP_VARS, info, info); } static Scheme_Object *optimize_wcm(Scheme_Object *o, Optimize_Info *info, int context) @@ -4690,7 +4618,7 @@ static Scheme_Object *optimize_wcm(Scheme_Object *o, Optimize_Info *info, int co if (info->escapes) { optimize_info_seq_done(info, &info_seq); info->size += 1; - return make_discarding_first_sequence(k, v, info, 0); + return make_discarding_first_sequence(k, v, info); } /* The presence of a key can be detected by other expressions, @@ -4711,8 +4639,8 @@ static Scheme_Object *optimize_wcm(Scheme_Object *o, Optimize_Info *info, int co optimize_info_seq_done(info, &info_seq); if (omittable_key(k, info) - && scheme_omittable_expr(b, -1, 20, 0, info, info, 0, 0, ID_OMIT)) - return make_discarding_first_sequence(v, b, info, 0); + && scheme_omittable_expr(b, -1, 20, 0, info, info)) + return make_discarding_first_sequence(v, b, info); /* info->single_result is already set */ info->preserves_marks = 0; @@ -4762,18 +4690,9 @@ set_optimize(Scheme_Object *data, Optimize_Info *info, int context) info->preserves_marks = 1; info->single_result = 1; - if (SAME_TYPE(SCHEME_TYPE(var), scheme_local_type)) { - int pos, delta; - - pos = SCHEME_LOCAL_POS(var); - + if (SAME_TYPE(SCHEME_TYPE(var), scheme_compiled_local_type)) { /* Register that we use this variable: */ - optimize_info_lookup(info, pos, NULL, NULL, 0, 0, NULL, NULL); - - /* Offset: */ - delta = optimize_info_get_shift(info, pos); - if (delta) - var = scheme_make_local(scheme_local_type, pos + delta, 0); + optimize_info_lookup(info, var, 0, NULL, 0, 0, NULL, NULL); } else { optimize_info_used_top(info); } @@ -4787,7 +4706,7 @@ set_optimize(Scheme_Object *data, Optimize_Info *info, int context) } static Scheme_Object * -set_clone(int dup_ok, Scheme_Object *data, Optimize_Info *info, int delta, int closure_depth) +set_clone(int single_use, Scheme_Object *data, Optimize_Info *info, Scheme_Hash_Tree *var_map) { Scheme_Set_Bang *sb = (Scheme_Set_Bang *)data, *naya; Scheme_Object *var, *val; @@ -4798,10 +4717,10 @@ set_clone(int dup_ok, Scheme_Object *data, Optimize_Info *info, int delta, int c var = naya->var; val = naya->val; - val = optimize_clone(dup_ok, val, info, delta, closure_depth); + val = optimize_clone(single_use, val, info, var_map, 0); if (!val) return NULL; - if (SAME_TYPE(SCHEME_TYPE(var), scheme_local_type)) { - var = optimize_clone(dup_ok, var, info, delta, closure_depth); + if (SAME_TYPE(SCHEME_TYPE(var), scheme_compiled_local_type)) { + var = optimize_clone(single_use, var, info, var_map, 0); if (!var) return NULL; } @@ -4811,20 +4730,6 @@ set_clone(int dup_ok, Scheme_Object *data, Optimize_Info *info, int delta, int c return (Scheme_Object *)naya; } -static Scheme_Object *set_shift(Scheme_Object *data, int delta, int after_depth) -{ - Scheme_Set_Bang *sb = (Scheme_Set_Bang *)data; - Scheme_Object *e; - - e = optimize_shift(sb->var, delta, after_depth); - sb->var = e; - - e = optimize_shift(sb->val, delta, after_depth); - sb->val = e; - - return (Scheme_Object *)sb; -} - static Scheme_Object * ref_optimize(Scheme_Object *data, Optimize_Info *info, int context) { @@ -4833,10 +4738,8 @@ ref_optimize(Scheme_Object *data, Optimize_Info *info, int context) optimize_info_used_top(info); v = SCHEME_PTR1_VAL(data); - if (SAME_TYPE(SCHEME_TYPE(v), scheme_local_type)) { - int is_mutated = 0; - optimize_info_mutated_lookup(info, SCHEME_LOCAL_POS(v), &is_mutated); - SCHEME_PTR1_VAL(data) = (is_mutated ? scheme_false : scheme_true); + if (SAME_TYPE(SCHEME_TYPE(v), scheme_compiled_local_type)) { + SCHEME_PTR1_VAL(data) = (SCHEME_VAR(v)->mutated ? scheme_false : scheme_true); } else if (SAME_TYPE(SCHEME_TYPE(v), scheme_compiled_toplevel_type)) { /* Knowing whether a top-level variable is fixed lets up optimize uses of `variable-reference-constant?` */ @@ -4870,31 +4773,17 @@ ref_optimize(Scheme_Object *data, Optimize_Info *info, int context) } static Scheme_Object * -ref_shift(Scheme_Object *data, int delta, int after_depth) -{ - Scheme_Object *v; - - v = optimize_shift(SCHEME_PTR1_VAL(data), delta, after_depth); - SCHEME_PTR1_VAL(data) = v; - - v = optimize_shift(SCHEME_PTR2_VAL(data), delta, after_depth); - SCHEME_PTR2_VAL(data) = v; - - return data; -} - -static Scheme_Object * -ref_clone(int dup_ok, Scheme_Object *data, Optimize_Info *info, int delta, int closure_depth) +ref_clone(int single_use, Scheme_Object *data, Optimize_Info *info, Scheme_Hash_Tree *var_map) { Scheme_Object *naya; Scheme_Object *a, *b; a = SCHEME_PTR1_VAL(data); - a = optimize_clone(dup_ok, a, info, delta, closure_depth); + a = optimize_clone(single_use, a, info, var_map, 0); if (!a) return NULL; b = SCHEME_PTR2_VAL(data); - b = optimize_clone(dup_ok, b, info, delta, closure_depth); + b = optimize_clone(single_use, b, info, var_map, 0); if (!b) return NULL; naya = scheme_alloc_object(); @@ -4930,7 +4819,7 @@ apply_values_optimize(Scheme_Object *data, Optimize_Info *info, int context) if (info->escapes) { info->size += 1; - return make_discarding_first_sequence(f, e, info, 0); + return make_discarding_first_sequence(f, e, info); } info->size += 1; @@ -4942,30 +4831,16 @@ apply_values_optimize(Scheme_Object *data, Optimize_Info *info, int context) } static Scheme_Object * -apply_values_shift(Scheme_Object *data, int delta, int after_depth) -{ - Scheme_Object *e; - - e = optimize_shift(SCHEME_PTR1_VAL(data), delta, after_depth); - SCHEME_PTR1_VAL(data) = e; - - e = optimize_shift(SCHEME_PTR2_VAL(data), delta, after_depth); - SCHEME_PTR2_VAL(data) = e; - - return data; -} - -static Scheme_Object * -apply_values_clone(int dup_ok, Scheme_Object *data, Optimize_Info *info, int delta, int closure_depth) +apply_values_clone(int single_use, Scheme_Object *data, Optimize_Info *info, Scheme_Hash_Tree *var_map) { Scheme_Object *f, *e; f = SCHEME_PTR1_VAL(data); e = SCHEME_PTR2_VAL(data); - f = optimize_clone(dup_ok, f, info, delta, closure_depth); + f = optimize_clone(single_use, f, info, var_map, 0); if (!f) return NULL; - e = optimize_clone(dup_ok, e, info, delta, closure_depth); + e = optimize_clone(single_use, e, info, var_map, 0); if (!e) return NULL; data = scheme_alloc_object(); @@ -4983,6 +4858,7 @@ with_immed_mark_optimize(Scheme_Object *data, Optimize_Info *info, int context) Scheme_Object *key, *val, *body; Optimize_Info_Sequence info_seq; Optimize_Info *body_info; + Scheme_Compiled_Local *var; optimize_info_seq_init(info, &info_seq); @@ -4997,62 +4873,54 @@ with_immed_mark_optimize(Scheme_Object *data, Optimize_Info *info, int context) optimize_info_seq_step(info, &info_seq); if (info->escapes) { optimize_info_seq_done(info, &info_seq); - return make_discarding_first_sequence(key, val, info, 0); + return make_discarding_first_sequence(key, val, info); } optimize_info_seq_done(info, &info_seq); - body_info = optimize_info_add_frame(info, 1, 1, 0); + body_info = optimize_info_add_frame(info, 1, 1, 0); + var = SCHEME_VAR(SCHEME_CAR(wcm->body)); + set_optimize_mode(var); + var->optimize.lambda_depth = body_info->lambda_depth; + var->optimize_used = 0; + var->optimize.init_kclock = info->kclock; - body = scheme_optimize_expr(wcm->body, body_info, 0); + body = scheme_optimize_expr(SCHEME_CDR(wcm->body), body_info, 0); optimize_info_done(body_info, NULL); wcm->key = key; wcm->val = val; - wcm->body = body; + SCHEME_CDR(wcm->body) = body; return data; } static Scheme_Object * -with_immed_mark_shift(Scheme_Object *data, int delta, int after_depth) -{ - Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)data; - Scheme_Object *e; - - e = optimize_shift(wcm->key, delta, after_depth); - wcm->key = e; - - e = optimize_shift(wcm->val, delta, after_depth); - wcm->val = e; - - e = optimize_shift(wcm->body, delta, after_depth+1); - wcm->body = e; - - return data; -} - -static Scheme_Object * -with_immed_mark_clone(int dup_ok, Scheme_Object *data, Optimize_Info *info, int delta, int closure_depth) +with_immed_mark_clone(int single_use, Scheme_Object *data, Optimize_Info *info, Scheme_Hash_Tree *var_map) { Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)data; Scheme_With_Continuation_Mark *wcm2; Scheme_Object *e; + Scheme_Compiled_Local *var; wcm2 = MALLOC_ONE_TAGGED(Scheme_With_Continuation_Mark); wcm2->so.type = scheme_with_immed_mark_type; - e = optimize_clone(dup_ok, wcm->key, info, delta, closure_depth); + e = optimize_clone(single_use, wcm->key, info, var_map, 0); if (!e) return NULL; wcm2->key = e; - e = optimize_clone(dup_ok, wcm->val, info, delta, closure_depth); + e = optimize_clone(single_use, wcm->val, info, var_map, 0); if (!e) return NULL; wcm2->val = e; - e = optimize_clone(dup_ok, wcm->body, info, delta, closure_depth+1); + var = clone_variable(SCHEME_VAR(SCHEME_CAR(wcm->body))); + var_map = scheme_hash_tree_set(var_map, SCHEME_CAR(wcm->body), (Scheme_Object *)var); + + e = optimize_clone(single_use, SCHEME_CDR(wcm->body), info, var_map, 0); if (!e) return NULL; + e = scheme_make_mutable_pair((Scheme_Object *)var, e); wcm2->body = e; return (Scheme_Object *)wcm2; @@ -5064,58 +4932,22 @@ case_lambda_optimize(Scheme_Object *expr, Optimize_Info *info, int context) Scheme_Object *le; int i; Scheme_Case_Lambda *seq = (Scheme_Case_Lambda *)expr; - mzshort **tus, *tu; - int *tu_lens, tup, tu_count = 0; - - if (info->transitive_use_pos) { - /* We'll need to merge transitive_use arrays */ - tup = info->transitive_use_pos - 1; - tus = (mzshort **)MALLOC_N(mzshort*, seq->count); - tu_lens = (int*)MALLOC_N_ATOMIC(int, seq->count); - } else { - tup = 0; - tus = NULL; - tu_lens = NULL; - } for (i = 0; i < seq->count; i++) { le = seq->array[i]; le = scheme_optimize_expr(le, info, 0); seq->array[i] = le; - - if (tus) { - tus[i] = info->transitive_use[tup]; - tu_lens[i] = info->transitive_use_len[tup]; - if (tus[i]) { - tu_count += tu_lens[i]; - } - info->transitive_use[tup] = NULL; - info->transitive_use_len[tup] = 0; - } } info->preserves_marks = 1; info->single_result = 1; info->size += 1; - if (tu_count) { - tu = MALLOC_N_ATOMIC(mzshort, tu_count); - tu_count = 0; - for (i = 0; i < seq->count; i++) { - if (tus[i]) { - memcpy(tu + tu_count, tus[i], tu_lens[i] * sizeof(mzshort)); - tu_count += tu_lens[i]; - } - } - info->transitive_use[tup] = tu; - info->transitive_use_len[tup] = tu_count; - } - return expr; } static Scheme_Object * -case_lambda_clone(int dup_ok, Scheme_Object *data, Optimize_Info *info, int delta, int closure_depth) +case_lambda_clone(int single_use, Scheme_Object *data, Optimize_Info *info, Scheme_Hash_Tree *var_map) { Scheme_Object *le; int i, sz; @@ -5128,7 +4960,7 @@ case_lambda_clone(int dup_ok, Scheme_Object *data, Optimize_Info *info, int delt for (i = 0; i < seq->count; i++) { le = seq->array[i]; - le = optimize_clone(dup_ok, le, info, delta, closure_depth); + le = optimize_clone(single_use, le, info, var_map, 0); if (!le) return NULL; seq2->array[i] = le; } @@ -5136,28 +4968,11 @@ case_lambda_clone(int dup_ok, Scheme_Object *data, Optimize_Info *info, int delt return (Scheme_Object *)seq2; } -static Scheme_Object * -case_lambda_shift(Scheme_Object *data, int delta, int after_depth) -{ - Scheme_Object *le; - int i; - Scheme_Case_Lambda *seq = (Scheme_Case_Lambda *)data; - - for (i = 0; i < seq->count; i++) { - le = seq->array[i]; - le = optimize_shift(le, delta, after_depth); - seq->array[i] = le; - } - - return data; -} - static Scheme_Object *begin0_optimize(Scheme_Object *obj, Optimize_Info *info, int context) { int i, count, drop = 0, prev_size, single_result = 0, preserves_marks = 0, kclock = 0, sclock = 0; Scheme_Sequence *s = (Scheme_Sequence *)obj; Scheme_Object *inside = NULL, *expr, *orig_first; - int id_offset = 0; Scheme_Object *le; Optimize_Info_Sequence info_seq; @@ -5183,7 +4998,7 @@ static Scheme_Object *begin0_optimize(Scheme_Object *obj, Optimize_Info *info, i s->array[0] = le; } else { /* Inlining and constant propagation can expose omittable expressions: */ - le = optimize_ignored(le, info, 0, -1, 1, 5); + le = optimize_ignored(le, info, -1, 1, 5); if (!le) { drop++; info->size = prev_size; @@ -5217,7 +5032,7 @@ static Scheme_Object *begin0_optimize(Scheme_Object *obj, Optimize_Info *info, i if (i != 0) { /* We will ignore the first expression too */ - le = optimize_ignored(s->array[0], info, 0, -1, 1, 5); + le = optimize_ignored(s->array[0], info, -1, 1, 5); if (!le) { drop++; info->size = prev_size; @@ -5241,7 +5056,7 @@ static Scheme_Object *begin0_optimize(Scheme_Object *obj, Optimize_Info *info, i s2->array[j++] = s->array[i]; } } - return flatten_sequence((Scheme_Object *)s2, info); + return flatten_sequence((Scheme_Object *)s2, info, context); } info->preserves_marks = 1; @@ -5254,17 +5069,10 @@ static Scheme_Object *begin0_optimize(Scheme_Object *obj, Optimize_Info *info, i expr = s->array[0]; orig_first = s->array[0]; - extract_tail_inside(&expr, &inside, &id_offset); - - if (id_offset) { - /* don't change the first expression if it needs to be shifted */ - inside = NULL; - expr = s->array[0]; - id_offset = 0; - } + extract_tail_inside(&expr, &inside); /* Try optimize (begin0 ...) => (begin ... ) */ - if (movable_expression(expr, info, 0, 0, kclock != info->kclock, + if (movable_expression(expr, info, 0, kclock != info->kclock, sclock != info->sclock, 0, 50)) { if ((s->count - drop) == 1) { /* drop the begin0 */ @@ -5311,7 +5119,7 @@ static Scheme_Object *begin0_optimize(Scheme_Object *obj, Optimize_Info *info, i } info->size += 1; - expr = flatten_sequence(expr, info); + expr = flatten_sequence(expr, info, context); return replace_tail_inside(expr, inside, orig_first); } @@ -5378,10 +5186,13 @@ static int is_liftable_prim(Scheme_Object *v, int or_escape) } } + if (SAME_OBJ(v, scheme_values_func)) + return 1; + return 0; } -int scheme_is_liftable(Scheme_Object *o, int bind_count, int fuel, int as_rator, int or_escape) +int scheme_is_liftable(Scheme_Object *o, Scheme_Hash_Tree *exclude_vars, int fuel, int as_rator, int or_escape) { Scheme_Type t = SCHEME_TYPE(o); @@ -5394,16 +5205,16 @@ int scheme_is_liftable(Scheme_Object *o, int bind_count, int fuel, int as_rator, return !as_rator; case scheme_compiled_toplevel_type: return 1; - case scheme_local_type: - if (SCHEME_LOCAL_POS(o) > bind_count) + case scheme_compiled_local_type: + if (!scheme_hash_tree_get(exclude_vars, o)) return 1; break; case scheme_branch_type: { Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)o; - if (scheme_is_liftable(b->test, bind_count, fuel - 1, 0, or_escape) - && scheme_is_liftable(b->tbranch, bind_count, fuel - 1, as_rator, or_escape) - && scheme_is_liftable(b->fbranch, bind_count, fuel - 1, as_rator, or_escape)) + if (scheme_is_liftable(b->test, exclude_vars, fuel - 1, 0, or_escape) + && scheme_is_liftable(b->tbranch, exclude_vars, fuel - 1, as_rator, or_escape) + && scheme_is_liftable(b->fbranch, exclude_vars, fuel - 1, as_rator, or_escape)) return 1; } break; @@ -5413,11 +5224,8 @@ int scheme_is_liftable(Scheme_Object *o, int bind_count, int fuel, int as_rator, int i; if (!is_liftable_prim(app->args[0], or_escape)) return 0; - if (0) /* not resolved, yet */ - if (bind_count >= 0) - bind_count += app->num_args; for (i = app->num_args + 1; i--; ) { - if (!scheme_is_liftable(app->args[i], bind_count, fuel - 1, 1, or_escape)) + if (!scheme_is_liftable(app->args[i], exclude_vars, fuel - 1, 1, or_escape)) return 0; } return 1; @@ -5428,11 +5236,8 @@ int scheme_is_liftable(Scheme_Object *o, int bind_count, int fuel, int as_rator, Scheme_App2_Rec *app = (Scheme_App2_Rec *)o; if (!is_liftable_prim(app->rator, or_escape)) return 0; - if (0) /* not resolved, yet */ - if (bind_count >= 0) - bind_count += 1; - if (scheme_is_liftable(app->rator, bind_count, fuel - 1, 1, or_escape) - && scheme_is_liftable(app->rand, bind_count, fuel - 1, 1, or_escape)) + if (scheme_is_liftable(app->rator, exclude_vars, fuel - 1, 1, or_escape) + && scheme_is_liftable(app->rand, exclude_vars, fuel - 1, 1, or_escape)) return 1; } break; @@ -5441,12 +5246,9 @@ int scheme_is_liftable(Scheme_Object *o, int bind_count, int fuel, int as_rator, Scheme_App3_Rec *app = (Scheme_App3_Rec *)o; if (!is_liftable_prim(app->rator, or_escape)) return 0; - if (0) /* not resolved, yet */ - if (bind_count >= 0) - bind_count += 2; - if (scheme_is_liftable(app->rator, bind_count, fuel - 1, 1, or_escape) - && scheme_is_liftable(app->rand1, bind_count, fuel - 1, 1, or_escape) - && scheme_is_liftable(app->rand2, bind_count, fuel - 1, 1, or_escape)) + if (scheme_is_liftable(app->rator, exclude_vars, fuel - 1, 1, or_escape) + && scheme_is_liftable(app->rand1, exclude_vars, fuel - 1, 1, or_escape) + && scheme_is_liftable(app->rand2, exclude_vars, fuel - 1, 1, or_escape)) return 1; } break; @@ -5454,18 +5256,15 @@ int scheme_is_liftable(Scheme_Object *o, int bind_count, int fuel, int as_rator, { Scheme_Let_Header *lh = (Scheme_Let_Header *)o; int i; - int post_bind = !(SCHEME_LET_FLAGS(lh) & (SCHEME_LET_RECURSIVE | SCHEME_LET_STAR)); - if (post_bind) { - o = lh->body; - for (i = lh->num_clauses; i--; ) { - if (!scheme_is_liftable(((Scheme_Compiled_Let_Value *)o)->value, bind_count, fuel - 1, as_rator, or_escape)) - return 0; - o = ((Scheme_Compiled_Let_Value *)o)->body; - } - if (scheme_is_liftable(o, bind_count + lh->count, fuel - 1, as_rator, or_escape)) - return 1; + o = lh->body; + for (i = lh->num_clauses; i--; ) { + if (!scheme_is_liftable(((Scheme_Compiled_Let_Value *)o)->value, exclude_vars, fuel - 1, as_rator, or_escape)) + return 0; + o = ((Scheme_Compiled_Let_Value *)o)->body; } + if (scheme_is_liftable(o, exclude_vars, fuel - 1, as_rator, or_escape)) + return 1; break; } default: @@ -5554,7 +5353,7 @@ int scheme_is_statically_proc(Scheme_Object *value, Optimize_Info *info) Scheme_Let_Header *lh = (Scheme_Let_Header *)value; if (lh->num_clauses == 1) { Scheme_Compiled_Let_Value *lv = (Scheme_Compiled_Let_Value *)lh->body; - if (scheme_omittable_expr(lv->value, lv->count, 20, 0, info, NULL, 0, 0, ID_OMIT)) { + if (scheme_omittable_expr(lv->value, lv->count, 20, 0, info, NULL)) { value = lv->body; info = NULL; } else @@ -5572,6 +5371,14 @@ Scheme_Object *scheme_make_noninline_proc(Scheme_Object *e) { Scheme_Object *ni; + while (SAME_TYPE(SCHEME_TYPE(e), scheme_compiled_let_void_type)) { + /* This must be (let ([x ]) ); see scheme_is_statically_proc() */ + Scheme_Let_Header *lh = (Scheme_Let_Header *)e; + Scheme_Compiled_Let_Value *lv = (Scheme_Compiled_Let_Value *)lh->body; + MZ_ASSERT(lh->num_clauses == 1); + e = lv->body; + } + ni = scheme_alloc_small_object(); ni->type = scheme_noninline_proc_type; SCHEME_PTR_VAL(ni) = e; @@ -5579,7 +5386,7 @@ Scheme_Object *scheme_make_noninline_proc(Scheme_Object *e) return ni; } -static int is_values_apply(Scheme_Object *e, int n, Optimize_Info *info, int depth, int fuel) +static int is_values_apply(Scheme_Object *e, int n, Optimize_Info *info, Scheme_Hash_Tree *except_vars, int fuel) { if (SAME_TYPE(SCHEME_TYPE(e), scheme_application_type)) { Scheme_App_Rec *app = (Scheme_App_Rec *)e; @@ -5593,42 +5400,11 @@ static int is_values_apply(Scheme_Object *e, int n, Optimize_Info *info, int dep return SAME_OBJ(scheme_values_func, app->rator); } else if (fuel && SAME_TYPE(SCHEME_TYPE(e), scheme_branch_type)) { Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)e; - if (SAME_TYPE(SCHEME_TYPE(b->test), scheme_local_type) - && scheme_omittable_expr(b->test, 1, -1, 0, info, info, depth, 0, NO_MUTABLE_ID_OMIT)) { - return (is_values_apply(b->tbranch, n, info, depth, 0) - && is_values_apply(b->fbranch, n, info, depth, 0)); - } - } - - return 0; -} - -static int can_reorder_values_arguments(Scheme_Object *e, Optimize_Info *info, int skip_depth) -{ - /* We can reorder the argument as long at at most one is non-omitable, - treating mutable variables as non-omitable for this purpose */ - - if (SAME_TYPE(SCHEME_TYPE(e), scheme_application_type)) { - Scheme_App_Rec *app = (Scheme_App_Rec *)e; - int i, count = 0; - for (i = app->num_args; i--; ) { - if (scheme_omittable_expr(app->args[i+1], 1, 5, 0, info, info, skip_depth, 0, NO_MUTABLE_ID_OMIT)) - count++; - } - return (count >= app->num_args - 1); - } else if (SAME_TYPE(SCHEME_TYPE(e), scheme_application2_type)) { - /* nothing to reorder */ - return 1; - } else if (SAME_TYPE(SCHEME_TYPE(e), scheme_application3_type)) { - Scheme_App3_Rec *app = (Scheme_App3_Rec *)e; - return (scheme_omittable_expr(app->rand1, 1, 5, 0, info, info, skip_depth, 0, NO_MUTABLE_ID_OMIT) - || scheme_omittable_expr(app->rand2, 1, 5, 0, info, info, skip_depth, 0, NO_MUTABLE_ID_OMIT)); - } else if (SAME_TYPE(SCHEME_TYPE(e), scheme_branch_type)) { - Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)e; - if (scheme_omittable_expr(b->tbranch, -1, 5, 0, info, info, skip_depth, 0, NO_MUTABLE_ID_OMIT)) { - return can_reorder_values_arguments(b->fbranch, info, skip_depth); - } else if (scheme_omittable_expr(b->fbranch, -1, 5, 0, info, info, skip_depth, 0, NO_MUTABLE_ID_OMIT)) { - return can_reorder_values_arguments(b->tbranch, info, skip_depth); + if (SAME_TYPE(SCHEME_TYPE(b->test), scheme_compiled_local_type) + && !scheme_hash_tree_get(except_vars, b->test) + && !SCHEME_VAR(b->test)->mutated) { + return (is_values_apply(b->tbranch, n, info, except_vars, 0) + && is_values_apply(b->fbranch, n, info, except_vars, 0)); } } @@ -5640,7 +5416,7 @@ static int no_mutable_bindings(Scheme_Compiled_Let_Value *pre_body) int i; for (i = pre_body->count; i--; ) { - if (pre_body->flags[i] & SCHEME_WAS_SET_BANGED) + if (pre_body->vars[i]->mutated) return 0; } @@ -5648,7 +5424,7 @@ static int no_mutable_bindings(Scheme_Compiled_Let_Value *pre_body) } static void update_rhs_value(Scheme_Compiled_Let_Value *naya, Scheme_Object *e, - Optimize_Info *info, Scheme_Object *tst) + Optimize_Info *info, Scheme_Compiled_Local *tst) { if (tst) { Scheme_Object *n; @@ -5657,12 +5433,12 @@ static void update_rhs_value(Scheme_Compiled_Let_Value *naya, Scheme_Object *e, if (!n) { Scheme_Branch_Rec *b; - /* In case `tst` was formerly a single-use variable, mark it as multi-use: */ - (void)optimize_reverse(info, SCHEME_LOCAL_POS(tst), 0, 1); + /* We're duplicating the test */ + increment_use_count(tst, 0); b = MALLOC_ONE_TAGGED(Scheme_Branch_Rec); b->so.type = scheme_branch_type; - b->test = tst; + b->test = (Scheme_Object *)tst; b->tbranch = naya->value; b->fbranch = e; @@ -5674,16 +5450,13 @@ static void update_rhs_value(Scheme_Compiled_Let_Value *naya, Scheme_Object *e, } static void unpack_values_application(Scheme_Object *e, Scheme_Compiled_Let_Value *naya, - int rev_bind_order, Optimize_Info *info, Scheme_Object *branch_test) + Optimize_Info *info, Scheme_Compiled_Local *branch_test) { if (SAME_TYPE(SCHEME_TYPE(e), scheme_application_type)) { Scheme_App_Rec *app = (Scheme_App_Rec *)e; int i; for (i = 0; i < app->num_args; i++) { - if (rev_bind_order) - update_rhs_value(naya, app->args[app->num_args - i], info, branch_test); - else - update_rhs_value(naya, app->args[i + 1], info, branch_test); + update_rhs_value(naya, app->args[i + 1], info, branch_test); naya = (Scheme_Compiled_Let_Value *)naya->body; } } else if (SAME_TYPE(SCHEME_TYPE(e), scheme_application2_type)) { @@ -5691,14 +5464,16 @@ static void unpack_values_application(Scheme_Object *e, Scheme_Compiled_Let_Valu update_rhs_value(naya, app->rand, info, branch_test); } else if (SAME_TYPE(SCHEME_TYPE(e), scheme_application3_type)) { Scheme_App3_Rec *app = (Scheme_App3_Rec *)e; - update_rhs_value(naya, rev_bind_order ? app->rand2 : app->rand1, info, branch_test); + update_rhs_value(naya, app->rand1, info, branch_test); naya = (Scheme_Compiled_Let_Value *)naya->body; - update_rhs_value(naya, rev_bind_order ? app->rand1 : app->rand2, info, branch_test); + update_rhs_value(naya, app->rand2, info, branch_test); } else if (SAME_TYPE(SCHEME_TYPE(e), scheme_branch_type)) { Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)e; - unpack_values_application(b->tbranch, naya, rev_bind_order, info, NULL); - unpack_values_application(b->fbranch, naya, rev_bind_order, info, b->test); + MZ_ASSERT(SAME_TYPE(SCHEME_TYPE(b->test), scheme_compiled_local_type)); + + unpack_values_application(b->tbranch, naya, info, NULL); + unpack_values_application(b->fbranch, naya, info, SCHEME_VAR(b->test)); } } @@ -5714,7 +5489,7 @@ static Scheme_Object *make_clones(Scheme_Compiled_Let_Value *retry_start, while (1) { value = clv->value; if (IS_COMPILED_PROC(value)) { - clone = optimize_clone(1, value, body_info, 0, 0); + clone = optimize_clone(1, value, body_info, empty_eq_hash_tree, 0); if (clone) { pr = scheme_make_raw_pair(scheme_make_raw_pair(value, clone), NULL); } else @@ -5843,14 +5618,14 @@ static int compiled_proc_body_size(Scheme_Object *o, int less_args) return 0; } -static int expr_size(Scheme_Object *o, Optimize_Info *info) +static int expr_size(Scheme_Object *o) { return compiled_proc_body_size(o, 0) + 1; } int scheme_might_invoke_call_cc(Scheme_Object *value) { - return !scheme_is_liftable(value, -1, 10, 0, 1); + return !scheme_is_liftable(value, empty_eq_hash_tree, 10, 0, 1); } #define ADVANCE_CLOCKS_INIT_FUEL 3 @@ -5927,7 +5702,7 @@ static int worth_lifting(Scheme_Object *v) lhs = SCHEME_TYPE(v); if ((lhs == scheme_compiled_unclosed_procedure_type) || (lhs == scheme_case_lambda_sequence_type) - || (lhs == scheme_local_type) + || (lhs == scheme_compiled_local_type) || (lhs == scheme_compiled_toplevel_type) || (lhs == scheme_compiled_quote_syntax_type) || (lhs > _scheme_compiled_values_types_)) @@ -5935,66 +5710,95 @@ static int worth_lifting(Scheme_Object *v) return 0; } +static void flip_transitive(Scheme_Hash_Table *ht, int on) +{ + Scheme_Compiled_Local *tvar; + int j; + Scheme_Object *to_remove = scheme_null; + + for (j = 0; j < ht->size; j++) { + if (ht->vals[j]) { + tvar = SCHEME_VAR(ht->keys[j]); + if (on) { + if (tvar->optimize_used) { + /* use of `tvar` is no longer dependent on anohter variable */ + to_remove = scheme_make_pair((Scheme_Object *)tvar, + to_remove); + } else + tvar->optimize_used = 1; + } else { + MZ_ASSERT(tvar->optimize_used); + tvar->optimize_used = 0; + } + } + } + + while (!SCHEME_NULLP(to_remove)) { + scheme_hash_set(ht, SCHEME_CAR(to_remove), NULL); + to_remove = SCHEME_CDR(to_remove); + } +} + +static void start_transitive_use_record(Optimize_Info *to_info, Optimize_Info *info, Scheme_Compiled_Local *var) +{ + if (var->optimize_used) + return; + + info->transitive_use_var = var; + var->optimize.transitive_uses_to = to_info; + + /* Restore use flags, if any, saved from before: */ + if (var->optimize.transitive_uses) + flip_transitive(var->optimize.transitive_uses, 1); +} + +static void end_transitive_use_record(Optimize_Info *info) +{ + Scheme_Compiled_Local *var = info->transitive_use_var; + + if (var != info->next->transitive_use_var) { + info->transitive_use_var = info->next->transitive_use_var; + + if (var->optimize.transitive_uses) + flip_transitive(var->optimize.transitive_uses, 0); + } +} + Scheme_Object * scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, int context) { - Optimize_Info *sub_info, *body_info, *rhs_info; + Optimize_Info *body_info, *rhs_info; Optimize_Info_Sequence info_seq; Scheme_Let_Header *head = (Scheme_Let_Header *)form; Scheme_Compiled_Let_Value *clv, *pre_body, *retry_start, *prev_body; Scheme_Object *body, *value, *ready_pairs = NULL, *rp_last = NULL, *ready_pairs_start; - Scheme_Once_Used *first_once_used = NULL, *last_once_used = NULL, *once_used; - int i, j, pos, is_rec, not_simply_let_star = 0, undiscourage, split_shift, skip_opts = 0; - int did_set_value, checked_once, skip_depth, unused_clauses, found_escapes; - int remove_last_one = 0, inline_fuel, rev_bind_order; - int post_bind = !(SCHEME_LET_FLAGS(head) & (SCHEME_LET_RECURSIVE | SCHEME_LET_STAR)); + Scheme_Once_Used *once_used; + Scheme_Hash_Tree *merge_skip_vars; + int i, j, is_rec, not_simply_let_star = 0, undiscourage, skip_opts = 0; + int did_set_value, found_escapes; + int remove_last_one = 0, inline_fuel; int pre_vclock, pre_aclock, pre_kclock, pre_sclock, increments_kclock = 0; int once_vclock, once_aclock, once_kclock, once_sclock, once_increments_kclock = 0; -# define pos_EARLIER(a, b) (rev_bind_order ? ((a) > (b)) : ((a) < (b))) - if (context & OPT_CONTEXT_BOOLEAN) { /* Special case: (let ([x M]) (if x x N)), where x is not in N, to (if M #t N), since we're in a test position. */ if (!(SCHEME_LET_FLAGS(head) & SCHEME_LET_RECURSIVE) && (head->count == 1) && (head->num_clauses == 1)) { clv = (Scheme_Compiled_Let_Value *)head->body; if (SAME_TYPE(SCHEME_TYPE(clv->body), scheme_branch_type) - && (((clv->flags[0] & SCHEME_USE_COUNT_MASK) >> SCHEME_USE_COUNT_SHIFT) - == 2)) { + && (clv->vars[0]->use_count == 2)) { Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)clv->body; - if (SAME_TYPE(SCHEME_TYPE(b->test), scheme_local_type) - && SAME_TYPE(SCHEME_TYPE(b->tbranch), scheme_local_type) - && !SCHEME_LOCAL_POS(b->test) - && !SCHEME_LOCAL_POS(b->tbranch)) { + if (SAME_OBJ(b->test, (Scheme_Object *)clv->vars[0]) + && SAME_OBJ(b->tbranch, (Scheme_Object *)clv->vars[0])) { Scheme_Branch_Rec *b3; b3 = MALLOC_ONE_TAGGED(Scheme_Branch_Rec); b3->so.type = scheme_branch_type; b3->test = clv->value; b3->tbranch = scheme_true; - if (post_bind) { - /* still need a `let' around N: */ - b3->fbranch = (Scheme_Object *)head; - clv->value = scheme_false; - clv->flags[0] = 0; /* variable now unused */ - clv->body = b->fbranch; - } else { - b3->fbranch = b->fbranch; - } + b3->fbranch = b->fbranch; - if (post_bind) - sub_info = info; - else - sub_info = optimize_info_add_frame(info, 1, 0, 0); - - form = scheme_optimize_expr((Scheme_Object *)b3, sub_info, context); - - if (!post_bind) { - info->single_result = sub_info->single_result; - info->preserves_marks = sub_info->preserves_marks; - optimize_info_done(sub_info, NULL); - merge_types(sub_info, info, -1); - } + form = scheme_optimize_expr((Scheme_Object *)b3, info, context); return form; } @@ -6007,21 +5811,10 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i tailness of E.) */ if (!(SCHEME_LET_FLAGS(head) & SCHEME_LET_RECURSIVE) && (head->count == 1) && (head->num_clauses == 1)) { clv = (Scheme_Compiled_Let_Value *)head->body; - if (SAME_TYPE(SCHEME_TYPE(clv->body), scheme_local_type) - && (((Scheme_Local *)clv->body)->position == 0)) { + if (SAME_OBJ((Scheme_Object *)clv->vars[0], clv->body)) { if (worth_lifting(clv->value)) { - if (post_bind) { - /* Just drop the let */ - return scheme_optimize_expr(clv->value, info, context); - } else { - sub_info = optimize_info_add_frame(info, 1, 0, 0); - body = scheme_optimize_expr(clv->value, sub_info, context); - info->single_result = sub_info->single_result; - info->preserves_marks = sub_info->preserves_marks; - optimize_info_done(sub_info, NULL); - merge_types(sub_info, info, -1); - return body; - } + /* Drop the let */ + return scheme_optimize_expr(clv->value, info, context); } } } @@ -6034,119 +5827,62 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i try_again = 0; /* (let ([x (let~ ([y M]) N)]) P) => (let~ ([y M]) (let ([x N]) P)) or (let ([x (begin M ... N)]) P) => (begin M ... (let ([x N]) P)) */ - if (post_bind) { - if (head->num_clauses == 1) { - clv = (Scheme_Compiled_Let_Value *)head->body; /* ([x ...]) */ - if (SAME_TYPE(SCHEME_TYPE(clv->value), scheme_compiled_let_void_type)) { - Scheme_Let_Header *lh = (Scheme_Let_Header *)clv->value; /* (let~ ([y ...]) ...) */ + if (head->num_clauses == 1) { + clv = (Scheme_Compiled_Let_Value *)head->body; /* ([x ...]) */ + if (SAME_TYPE(SCHEME_TYPE(clv->value), scheme_compiled_let_void_type)) { + Scheme_Let_Header *lh = (Scheme_Let_Header *)clv->value; /* (let~ ([y ...]) ...) */ - value = clv->body; /* = P */ - if (lh->count) - value = optimize_shift(value, lh->count, head->count); - if (value) { - clv->body = value; - - if (!lh->num_clauses) { - clv->value = lh->body; - lh->body = (Scheme_Object *)head; - } else { - body = lh->body; - for (i = lh->num_clauses - 1; i--; ) { - body = ((Scheme_Compiled_Let_Value *)body)->body; - } - clv->value = ((Scheme_Compiled_Let_Value *)body)->body; /* N */ - ((Scheme_Compiled_Let_Value *)body)->body = (Scheme_Object *)head; - } - - head = lh; - form = (Scheme_Object *)head; - is_rec = (SCHEME_LET_FLAGS(head) & SCHEME_LET_RECURSIVE); - post_bind = !(SCHEME_LET_FLAGS(head) & (SCHEME_LET_RECURSIVE | SCHEME_LET_STAR)); - try_again = 1; + if (!lh->num_clauses) { + clv->value = lh->body; + lh->body = (Scheme_Object *)head; + } else { + body = lh->body; + for (i = lh->num_clauses - 1; i--; ) { + body = ((Scheme_Compiled_Let_Value *)body)->body; } - } else if (SAME_TYPE(SCHEME_TYPE(clv->value), scheme_sequence_type)) { - Scheme_Sequence *seq = (Scheme_Sequence *)clv->value; /* (begin M ... N) */ - - clv->value = seq->array[seq->count - 1]; - seq->array[seq->count - 1] = (Scheme_Object *)head; - - return scheme_optimize_expr((Scheme_Object *)seq, info, context); + clv->value = ((Scheme_Compiled_Let_Value *)body)->body; /* N */ + ((Scheme_Compiled_Let_Value *)body)->body = (Scheme_Object *)head; } + + head = lh; + form = (Scheme_Object *)head; + is_rec = (SCHEME_LET_FLAGS(head) & SCHEME_LET_RECURSIVE); + try_again = !is_rec; + } else if (SAME_TYPE(SCHEME_TYPE(clv->value), scheme_sequence_type)) { + Scheme_Sequence *seq = (Scheme_Sequence *)clv->value; /* (begin M ... N) */ + + clv->value = seq->array[seq->count - 1]; + seq->array[seq->count - 1] = (Scheme_Object *)head; + + return scheme_optimize_expr((Scheme_Object *)seq, info, context); } } } while (try_again); } - split_shift = 0; - if (is_rec) { - /* Check whether we should break a prefix out into its own - letrec set. */ - body = head->body; - j = 0; - for (i = 0; i < head->num_clauses - 1; i++) { - pre_body = (Scheme_Compiled_Let_Value *)body; - if (SCHEME_CLV_FLAGS(pre_body) & SCHEME_CLV_NO_GROUP_LATER_USES) { - /* yes --- break group here */ - Scheme_Let_Header *h2; - - j += pre_body->count; - i++; - - h2 = MALLOC_ONE_TAGGED(Scheme_Let_Header); - h2->iso.so.type = scheme_compiled_let_void_type; - h2->count = head->count - j; - h2->num_clauses = head->num_clauses - i; - h2->body = pre_body->body; - SCHEME_LET_FLAGS(h2) = SCHEME_LET_RECURSIVE; - - head->count = j; - head->num_clauses = i; - - pre_body->body = (Scheme_Object *)h2; - - split_shift = h2->count; - - body = head->body; - for (j = 0; j < i; j++) { - pre_body = (Scheme_Compiled_Let_Value *)body; - pre_body->position -= split_shift; - body = pre_body->body; - } - - break; - } else { - j += pre_body->count; - body = pre_body->body; - } - } - } - - body_info = optimize_info_add_frame(info, head->count, head->count, - post_bind ? SCHEME_POST_BIND_FRAME : 0); - if (post_bind) - rhs_info = optimize_info_add_frame(info, 0, 0, 0); - else if (split_shift) - rhs_info = optimize_info_add_frame(body_info, split_shift, 0, 0); - else - rhs_info = body_info; + body_info = optimize_info_add_frame(info, head->count, head->count, 0); + rhs_info = body_info; + merge_skip_vars = scheme_make_hash_tree(0); body = head->body; for (i = head->num_clauses; i--; ) { pre_body = (Scheme_Compiled_Let_Value *)body; - pos = pre_body->position; for (j = pre_body->count; j--; ) { - if (pre_body->flags[j] & SCHEME_WAS_SET_BANGED) { - optimize_mutated(body_info, pos + j); - } else if (is_rec) { + merge_skip_vars = scheme_hash_tree_set(merge_skip_vars, (Scheme_Object *)pre_body->vars[j], scheme_true); + set_optimize_mode(pre_body->vars[j]); + pre_body->vars[j]->optimize.lambda_depth = body_info->lambda_depth; + pre_body->vars[j]->optimize_used = 0; + pre_body->vars[j]->optimize_outside_binding = 0; + if (!pre_body->vars[j]->mutated && is_rec) { /* Indicate that it's not yet ready, so it cannot be inlined: */ Scheme_Object *rp; - rp = scheme_make_raw_pair(scheme_false, NULL); + pre_body->vars[j]->optimize_unready = 1; + rp = scheme_make_raw_pair((Scheme_Object *)pre_body->vars[j], NULL); if (rp_last) SCHEME_CDR(rp_last) = rp; else ready_pairs = rp; rp_last = rp; - optimize_propagate(body_info, pos+j, rp_last, 0); } } body = pre_body->body; @@ -6161,12 +5897,13 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i pre_body = NULL; for (i = head->num_clauses; i--; ) { pre_body = (Scheme_Compiled_Let_Value *)body; - pos = pre_body->position; if ((pre_body->count == 1) && IS_COMPILED_PROC(pre_body->value) - && !(pre_body->flags[0] & SCHEME_WAS_SET_BANGED)) { - optimize_propagate(body_info, pos, estimate_closure_size(pre_body->value), 0); + && !pre_body->vars[0]->mutated) { + Scheme_Object *sz; + sz = estimate_closure_size(pre_body->value); + pre_body->vars[0]->optimize.known_val = sz; } body = pre_body->body; @@ -6175,27 +5912,6 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i } } - rev_bind_order = 0; - if (is_rec) - rev_bind_order = 1; - else if (head->num_clauses > 1) { - int pos; - body = head->body; - pre_body = (Scheme_Compiled_Let_Value *)body; - pos = pre_body->position; - body = pre_body->body; - for (i = head->num_clauses - 1; i--; ) { - pre_body = (Scheme_Compiled_Let_Value *)body; - if (pre_body->position < pos) { - rev_bind_order = 1; - break; - } else if (pre_body->position > pos) { - break; - } - body = pre_body->body; - } - } - optimize_info_seq_init(rhs_info, &info_seq); prev_body = NULL; @@ -6207,22 +5923,11 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i found_escapes = 0; for (i = head->num_clauses; i--; ) { pre_body = (Scheme_Compiled_Let_Value *)body; - pos = pre_body->position; if ((pre_body->count == 1) && IS_COMPILED_PROC(pre_body->value) - && !optimize_is_used(body_info, pos)) { - if (!body_info->transitive_use) { - mzshort **tu; - int *tu_len; - tu = (mzshort **)scheme_malloc(sizeof(mzshort *) * head->count); - tu_len = (int *)scheme_malloc_atomic(sizeof(int) * head->count); - memset(tu_len, 0, sizeof(int) * head->count); - body_info->transitive_use = tu; - body_info->transitive_use_len = tu_len; - } - body_info->transitive_use_pos = pos + 1; - } + && !pre_body->vars[0]->optimize_used) + start_transitive_use_record(body_info, rhs_info, pre_body->vars[0]); if (is_rec && OPT_DISCOURAGE_EARLY_INLINE && !rhs_info->letrec_not_twice && IS_COMPILED_PROC(pre_body->value)) { @@ -6301,12 +6006,12 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i --rhs_info->letrec_not_twice; } - body_info->transitive_use_pos = 0; + end_transitive_use_record(rhs_info); if (is_rec && !not_simply_let_star) { /* Keep track of whether we can simplify to let*: */ if (scheme_might_invoke_call_cc(value) - || optimize_any_uses(body_info, 0, pos+pre_body->count)) + || optimize_any_uses(body_info, pre_body, i+1)) not_simply_let_star = 1; } @@ -6315,25 +6020,14 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i The is_values_apply() and related functions also handle (if id (values e1 ...) (values e2 ...)) to effectively convert to (values (if id e1 e2) ...) and then split the values call, since - duplicating the id use and test is likely to pay off. - Beware that the transformation reorders the e sequence if - !rev_bind_order, so checks are needed to make sure that's ok. */ - skip_depth = (is_rec ? (pre_body->position + pre_body->count) : 0); + duplicating the id use and test is likely to pay off. */ if ((pre_body->count != 1) && (found_escapes - || (is_values_apply(value, pre_body->count, rhs_info, skip_depth, 1) - && ((!is_rec && no_mutable_bindings(pre_body) - && (rev_bind_order - /* When !rev_bind_order, the transformation reorders the arguments - to `values`, so check that it's ok: */ - || can_reorder_values_arguments(value, rhs_info, skip_depth))) - /* If the right-hand side is omittable, then there are - no side effects, so reordering is always ok. But if !rev_bind_order, - we pass NO_MUTABLE_ID_OMIT in case some other thread is mutating - an identifier in a way that could expose reordering: */ - || scheme_omittable_expr(value, pre_body->count, -1, 0, rhs_info, info, - skip_depth, 0, - rev_bind_order ? ID_OMIT : NO_MUTABLE_ID_OMIT))))) { + || (is_values_apply(value, pre_body->count, rhs_info, merge_skip_vars, 1) + && ((!is_rec && no_mutable_bindings(pre_body)) + /* If the right-hand side is omittable, then there are + no side effects, so mutation and recursiveness are ok */ + || scheme_omittable_expr(value, pre_body->count, -1, 0, rhs_info, info))))) { if (!pre_body->count && !i) { /* We want to drop the clause entirely, but doing it here messes up the loop for letrec. So wait and @@ -6342,47 +6036,27 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i } else { Scheme_Compiled_Let_Value *naya; Scheme_Object *rest = pre_body->body; - int *new_flags; - int cnt; + int j; - /* This conversion reorders the expressions if rev_bind_order. */ - if (pre_body->count) { - if (rev_bind_order) - cnt = 0; - else - cnt = pre_body->count - 1; - - while (1) { - naya = MALLOC_ONE_TAGGED(Scheme_Compiled_Let_Value); - naya->iso.so.type = scheme_compiled_let_value_type; - naya->body = rest; - naya->count = 1; - naya->position = pre_body->position + cnt; - new_flags = (int *)scheme_malloc_atomic(sizeof(int)); - new_flags[0] = pre_body->flags[cnt]; - naya->flags = new_flags; - rest = (Scheme_Object *)naya; - - if (rev_bind_order) { - cnt++; - if (cnt >= pre_body->count) - break; - } else { - if (!cnt) - break; - cnt--; - } - } + for (j = pre_body->count; j--; ) { + Scheme_Compiled_Local **new_vars; + naya = MALLOC_ONE_TAGGED(Scheme_Compiled_Let_Value); + naya->iso.so.type = scheme_compiled_let_value_type; + naya->body = rest; + naya->count = 1; + new_vars = MALLOC_N(Scheme_Compiled_Local *, 1); + new_vars[0] = pre_body->vars[j]; + naya->vars = new_vars; + rest = (Scheme_Object *)naya; } naya = (Scheme_Compiled_Let_Value *)rest; if (!found_escapes) { - unpack_values_application(value, naya, rev_bind_order, rhs_info, NULL); + unpack_values_application(value, naya, rhs_info, NULL); } else { Scheme_Compiled_Let_Value *naya2 = naya; - int i; - for (i = 0; i < pre_body->count; i++) { - if (!i) + for (j = 0; j < pre_body->count; j++) { + if (!j) naya2->value = value; else naya2->value = scheme_false; @@ -6403,7 +6077,6 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i pre_body = naya; body = (Scheme_Object *)naya; value = pre_body->value; - pos = pre_body->position; if (skip_opts) { /* Use "pre" clocks: */ @@ -6428,10 +6101,7 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i } } - checked_once = 0; - - if ((pre_body->count == 1) - && !(pre_body->flags[0] & SCHEME_WAS_SET_BANGED)) { + if ((pre_body->count == 1) && !pre_body->vars[0]->mutated) { int indirect = 0, indirect_binding = 0; while (indirect < 10) { @@ -6462,26 +6132,12 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i value = NULL; } - if (value && SAME_TYPE(SCHEME_TYPE(value), scheme_local_type)) { - /* Don't optimize reference to a local binding - that's not available yet, or that's mutable. */ - int vpos; - vpos = SCHEME_LOCAL_POS(value); - if (!post_bind && (vpos < head->count) && !pos_EARLIER(vpos, pos)) + if (value && SAME_TYPE(SCHEME_TYPE(value), scheme_compiled_local_type)) { + /* Don't optimize reference to a local that's mutable; also, + double-check that the value is ready, because we might be + nested in the RHS of a `letrec': */ + if (SCHEME_VAR(value)->mutated || SCHEME_VAR(value)->optimize_unready) value = NULL; - else { - /* Convert value back to a pre-optimized local coordinates. - Unless post_bind, this must be done with respect to - body_info, not rhs_info, because we attach the value to - body_info: */ - value = optimize_reverse(post_bind ? rhs_info : body_info, vpos, 1, 0); - - /* Double-check that the value is ready, because we might be - nested in the RHS of a `letrec': */ - if (value) - if (!optimize_info_is_ready(body_info, SCHEME_LOCAL_POS(value))) - value = NULL; - } } if (value) @@ -6493,68 +6149,47 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i if (is_rec) cnt = 2; else - cnt = ((pre_body->flags[0] & SCHEME_USE_COUNT_MASK) >> SCHEME_USE_COUNT_SHIFT); + cnt = pre_body->vars[0]->use_count; - optimize_propagate(body_info, pos, value, cnt == 1); + pre_body->vars[0]->optimize.known_val = value; did_set_value = 1; - checked_once = 1; } else if (value && !is_rec) { - int cnt, ct; + int cnt, ct, involves_k_cross; Scheme_Object *pred; - ct = scheme_expr_produces_local_type(value); - if (ct) - optimize_produces_local_type(body_info, pos, ct); + ct = scheme_expr_produces_local_type(value, &involves_k_cross); + if (ct) { + SCHEME_VAR(pre_body->vars[0])->val_type = ct; + if (involves_k_cross) { + /* Although this variable's uses do not necessarily cross + a continuation capture, the inference of its type + depends on that crossing, so we treat as having a crossing. + This is an accomodation to the bytecode format and + validator, which has no way to distinguish between + a known type and unboxing capability for that type. */ + SCHEME_VAR(pre_body->vars[0])->escapes_after_k_tick = 1; + } + } - if (SAME_TYPE(SCHEME_TYPE(value), scheme_local_type)) { + if (SAME_TYPE(SCHEME_TYPE(value), scheme_compiled_local_type)) { /* shouldn't get here, since scheme_compiled_propagate_ok() should have returned true, but just in case... local is in unoptimized coordinates */ pred = NULL; } else - pred = expr_implies_predicate(value, rhs_info, 0, 5); + pred = expr_implies_predicate(value, rhs_info, NULL, 5); if (pred) - add_type(body_info, pos, pred); + add_type(body_info, (Scheme_Object *)pre_body->vars[0], pred); if (!indirect) { - checked_once = 1; - cnt = ((pre_body->flags[0] & SCHEME_USE_COUNT_MASK) >> SCHEME_USE_COUNT_SHIFT); + cnt = pre_body->vars[0]->use_count; if (cnt == 1) { /* used only once; we may be able to shift the expression to the use site, instead of binding to a temporary */ - once_used = make_once_used(value, pos, + once_used = make_once_used(value, pre_body->vars[0], once_vclock, once_aclock, once_kclock, once_sclock, - once_increments_kclock, - NULL); - if (!last_once_used) - first_once_used = once_used; - else - last_once_used->next = once_used; - last_once_used = once_used; - optimize_propagate(body_info, pos, (Scheme_Object *)once_used, 1); - } - } - } - } - - if (!checked_once) { - /* Didn't handle once-used check in case of copy propagation, so check here. */ - int i, cnt; - for (i = pre_body->count; i--; ) { - if (!(pre_body->flags[i] & SCHEME_WAS_SET_BANGED)) { - cnt = ((pre_body->flags[i] & SCHEME_USE_COUNT_MASK) >> SCHEME_USE_COUNT_SHIFT); - if (cnt == 1) { - /* Need to register as once-used, in case of copy propagation */ - once_used = make_once_used(NULL, pos+i, - once_vclock, once_aclock, once_kclock, once_sclock, - once_increments_kclock, - NULL); - if (!last_once_used) - first_once_used = once_used; - else - last_once_used->next = once_used; - last_once_used = once_used; - optimize_propagate(body_info, pos+i, (Scheme_Object *)once_used, 1); + once_increments_kclock); + pre_body->vars[0]->optimize.known_val = (Scheme_Object *)once_used; } } } @@ -6570,7 +6205,7 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i && !body_info->letrec_not_twice && ((i < 1) || (!scheme_is_compiled_procedure(((Scheme_Compiled_Let_Value *)pre_body->body)->value, 1, 1) - && !scheme_is_liftable(((Scheme_Compiled_Let_Value *)pre_body->body)->value, head->count, 5, 1, 0)))) { + && !scheme_is_liftable(((Scheme_Compiled_Let_Value *)pre_body->body)->value, merge_skip_vars, 5, 1, 0)))) { Scheme_Object *prop_later = NULL; if (did_set_value) { @@ -6580,9 +6215,9 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i but then assume not for all if any turn out not (i.e., approximate fix point). */ int flags; Scheme_Object *clones, *cl, *cl_first; - /* Reset "ready" flags: */ + /* Reset "unready" flags: */ for (rp_last = ready_pairs_start; !SAME_OBJ(rp_last, ready_pairs); rp_last = SCHEME_CDR(rp_last)) { - SCHEME_CAR(rp_last) = scheme_false; + SCHEME_VAR(SCHEME_CAR(rp_last))->optimize_unready = 1; } /* Set-flags loop: */ clones = make_clones(retry_start, pre_body, rhs_info); @@ -6609,11 +6244,8 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i char use_psize; if ((clv->count == 1) - && rhs_info->transitive_use - && !optimize_is_used(body_info, clv->position)) { - body_info->transitive_use[clv->position] = NULL; - body_info->transitive_use_pos = clv->position + 1; - } + && !clv->vars[0]->optimize_used) + start_transitive_use_record(body_info, rhs_info, clv->vars[0]); cl = SCHEME_CDR(cl); self_value = SCHEME_CDR(cl_first); @@ -6643,7 +6275,7 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i clv->value = value; - if (!(clv->flags[0] & SCHEME_WAS_SET_BANGED)) { + if (!clv->vars[0]->mutated) { if (scheme_compiled_propagate_ok(value, rhs_info)) { /* Register re-optimized as the value for the binding, but maybe only if it didn't grow too much: */ @@ -6652,17 +6284,18 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i new_sz = compiled_proc_body_size(value, 0); else new_sz = 0; - if (new_sz <= sz) - optimize_propagate(body_info, clv->position, value, 0); + if (new_sz <= sz) { + clv->vars[0]->optimize.known_val = value; + } else if (!OPT_LIMIT_FUNCTION_RESIZE || (new_sz < 4 * sz)) - prop_later = scheme_make_raw_pair(scheme_make_pair(scheme_make_integer(clv->position), + prop_later = scheme_make_raw_pair(scheme_make_pair((Scheme_Object *)clv->vars[0], value), prop_later); } } - body_info->transitive_use_pos = 0; + end_transitive_use_record(rhs_info); } if (clv == pre_body) break; @@ -6671,8 +6304,8 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i for this binding are now ready: */ int i; for (i = clv->count; i--; ) { - if (!(clv->flags[i] & SCHEME_WAS_SET_BANGED)) { - SCHEME_CAR(ready_pairs_start) = scheme_true; + if (!clv->vars[i]->mutated) { + SCHEME_VAR(SCHEME_CAR(ready_pairs_start))->optimize_unready = 0; ready_pairs_start = SCHEME_CDR(ready_pairs_start); } } @@ -6694,10 +6327,7 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i while (prop_later) { value = SCHEME_CAR(prop_later); - optimize_propagate(body_info, - SCHEME_INT_VAL(SCHEME_CAR(value)), - SCHEME_CDR(value), - 0); + SCHEME_VAR(SCHEME_CAR(value))->optimize.known_val = SCHEME_CDR(value); prop_later = SCHEME_CDR(prop_later); } } @@ -6707,8 +6337,9 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i for this binding are now ready: */ int i; for (i = pre_body->count; i--; ) { - if (!(pre_body->flags[i] & SCHEME_WAS_SET_BANGED)) { - SCHEME_CAR(ready_pairs) = scheme_true; + pre_body->vars[i]->optimize.init_kclock = rhs_info->kclock; + if (!pre_body->vars[i]->mutated) { + SCHEME_VAR(SCHEME_CAR(ready_pairs))->optimize_unready = 0; ready_pairs = SCHEME_CDR(ready_pairs); } } @@ -6731,13 +6362,19 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i body = pre_body->body; } - optimize_info_seq_done(rhs_info, &info_seq); + if (!is_rec) { + /* All `let`-bound variables are now allocated: */ + body = head->body; + for (i = head->num_clauses; i--; ) { + pre_body = (Scheme_Compiled_Let_Value *)body; + for (j = pre_body->count; j--; ) { + pre_body->vars[j]->optimize.init_kclock = body_info->kclock; + } + body = pre_body->body; + } + } - if (post_bind) { - optimize_info_done(rhs_info, body_info); - merge_types(rhs_info, body_info, head->count); - } else if (split_shift) - optimize_info_done(rhs_info, body_info); + optimize_info_seq_done(body_info, &info_seq); if (!found_escapes) { body = scheme_optimize_expr(body, body_info, scheme_optimize_tail_context(context)); @@ -6760,157 +6397,154 @@ scheme_optimize_lets(Scheme_Object *form, Optimize_Info *info, int for_inline, i info->kclock = body_info->kclock; info->sclock = body_info->sclock; - /* Clear used flags where possible */ + /* Clear used flags where possible, clear once-used references, etc. */ body = head->body; - unused_clauses = 0; + prev_body = NULL; for (i = head->num_clauses; i--; ) { int used = 0, j; pre_body = (Scheme_Compiled_Let_Value *)body; - pos = pre_body->position; for (j = pre_body->count; j--; ) { - if (optimize_is_used(body_info, pos+j)) { + if (pre_body->vars[j]->optimize_used) { used = 1; break; } } - if (!used - && (scheme_omittable_expr(pre_body->value, pre_body->count, -1, 0, info, info, 0, 0, ID_OMIT) - || ((pre_body->count == 1) - && first_once_used - && (first_once_used->pos == pos) - && first_once_used->used))) { - for (j = pre_body->count; j--; ) { - if (pre_body->flags[j] & SCHEME_WAS_USED) { - pre_body->flags[j] -= SCHEME_WAS_USED; - } + /* once-used moved implies not optimize_used: */ + MZ_ASSERT(!(used + && (pre_body->count == 1) + && pre_body->vars[0]->optimize.known_val + && SAME_TYPE(scheme_once_used_type, SCHEME_TYPE(pre_body->vars[0]->optimize.known_val)) + && ((Scheme_Once_Used *)pre_body->vars[0]->optimize.known_val)->moved)); - if (first_once_used && (first_once_used->pos == (pos + j))) - first_once_used = first_once_used->next; + if (!used + && (scheme_omittable_expr(pre_body->value, pre_body->count, -1, 0, info, info) + || ((pre_body->count == 1) + && pre_body->vars[0]->optimize.known_val + && SAME_TYPE(scheme_once_used_type, SCHEME_TYPE(pre_body->vars[0]->optimize.known_val)) + && ((Scheme_Once_Used *)pre_body->vars[0]->optimize.known_val)->moved))) { + /* Drop the binding(s) */ + for (j = pre_body->count; j--; ) { + pre_body->vars[j]->mode = SCHEME_VAR_MODE_NONE; } - if (pre_body->count == 1) { - /* Drop expr and deduct from size to aid further inlining. */ + head->num_clauses -= 1; + head->count -= pre_body->count; + if (prev_body) + prev_body->body = pre_body->body; + else + head->body = pre_body->body; + /* Deduct from size to aid further inlining. */ + { int sz; - sz = expr_size(pre_body->value, info); - pre_body->value = scheme_false; - info->size -= sz; - unused_clauses++; + sz = expr_size(pre_body->value); + body_info->size -= sz; } } else { + if (!used && (pre_body->count == 1)) { + /* The whole binding is not omittable, but maybe the tail is omittable: */ + Scheme_Object *v2 = pre_body->value, *inside; + extract_tail_inside(&v2, &inside); + if (scheme_omittable_expr(v2, pre_body->count, -1, 0, info, info)) { + replace_tail_inside(scheme_false, inside, pre_body->value); + } + } + for (j = pre_body->count; j--; ) { int ct; - pre_body->flags[j] |= SCHEME_WAS_USED; - ct = optimize_is_local_type_arg(body_info, pos+j, 0); + pre_body->vars[j]->optimize_outside_binding = 1; + if (pre_body->vars[j]->optimize.known_val + && SAME_TYPE(scheme_once_used_type, SCHEME_TYPE(pre_body->vars[j]->optimize.known_val))) { + /* We're keeping this clause here, so don't allow movement of the once-used + value when peeking under bindings via extract_tail_inside(): */ + pre_body->vars[j]->optimize.known_val = NULL; + } + + ct = pre_body->vars[j]->arg_type; if (ct) { if (ALWAYS_PREFER_UNBOX_TYPE(ct) - || !optimize_escapes_after_k_tick(body_info, pos+j)) - pre_body->flags[j] |= (ct << SCHEME_WAS_TYPED_ARGUMENT_SHIFT); - } - - - if (first_once_used && (first_once_used->pos == (pos+j))) { - if (first_once_used->vclock < 0) { - /* single-use no longer true, due to copy propagation */ - pre_body->flags[j] |= SCHEME_USE_COUNT_MASK; - } - first_once_used = first_once_used->next; + || !pre_body->vars[j]->escapes_after_k_tick) + pre_body->vars[j]->arg_type = ct; } } info->size += 1; + prev_body = pre_body; } body = pre_body->body; } - if (unused_clauses && (head->num_clauses == unused_clauses)) { - /* It's worth removing the `let` wrapper and shifting the body to - enable further optimizations outside this expression, but we risk - quadratic work here, so use up shift fuel: */ - if (body_info->shift_fuel) { - optimize_info_done(body_info, NULL); - merge_types(body_info, info, -head->count); - info->shift_fuel--; - body = head->body; - for (j = head->num_clauses; j--; ) { - body = ((Scheme_Compiled_Let_Value *)body)->body; - } - return optimize_shift(body, -head->count, 0); - } - } - /* Optimized away all clauses? */ if (!head->num_clauses) { optimize_info_done(body_info, NULL); - merge_types(body_info, info, -head->count); - return head->body; + merge_types(body_info, info, merge_skip_vars); + return body; } if (is_rec && !not_simply_let_star) { /* We can simplify letrec to let* */ SCHEME_LET_FLAGS(head) -= SCHEME_LET_RECURSIVE; - SCHEME_LET_FLAGS(head) |= SCHEME_LET_STAR; is_rec = 0; } - { - int extract_depth = 0; + optimize_info_done(body_info, NULL); + merge_types(body_info, info, merge_skip_vars); - value = NULL; - - /* Check again for (let ([x ]) x). */ - if (!is_rec && (head->count == 1) && (head->num_clauses == 1)) { - clv = (Scheme_Compiled_Let_Value *)head->body; - if (SAME_TYPE(SCHEME_TYPE(clv->body), scheme_local_type) - && (((Scheme_Local *)clv->body)->position == 0)) { - if (worth_lifting(clv->value)) { - value = clv->value; - extract_depth = 1 + split_shift; - } - } - } - - /* Check for (let ([unused #f] ...) ) */ - if (!value) { - if (head->count == head->num_clauses) { - body = head->body; - for (i = head->num_clauses; i--; ) { - pre_body = (Scheme_Compiled_Let_Value *)body; - if ((pre_body->count != 1) - || !SCHEME_FALSEP(pre_body->value) - || (pre_body->flags[0] & SCHEME_WAS_USED)) - break; - body = pre_body->body; - } - if (i < 0) { - if (worth_lifting(body)) { - value = body; - extract_depth = head->count; - rhs_info = body_info; - post_bind = 0; - } - } - } - } - - if (value) { - value = optimize_clone(1, value, rhs_info, 0, 0); - - if (value) { - sub_info = optimize_info_add_frame(info, post_bind ? 0 : extract_depth, 0, 0); - sub_info->inline_fuel = 0; - value = scheme_optimize_expr(value, sub_info, context); - info->single_result = sub_info->single_result; - info->preserves_marks = sub_info->preserves_marks; - optimize_info_done(sub_info, NULL); - return value; - } + /* Check again for (let ([x ]) x). */ + if (!is_rec && (head->count == 1) && (head->num_clauses == 1)) { + clv = (Scheme_Compiled_Let_Value *)head->body; + if (SAME_OBJ(clv->body, (Scheme_Object *)clv->vars[0])) { + if (worth_lifting(clv->value)) + return clv->value; } } - optimize_info_done(body_info, NULL); - merge_types(body_info, info, -head->count); + if (!is_rec) { + /* One last pass to peel off unused bindings */ + Scheme_Object *prev = NULL, *rhs; + + body = head->body; + for (i = head->num_clauses; i--; ) { + pre_body = (Scheme_Compiled_Let_Value *)body; + if ((pre_body->count == 1) + && !pre_body->vars[0]->optimize_used) { + Scheme_Sequence *seq; + + pre_body->vars[0]->mode = SCHEME_VAR_MODE_NONE; + + seq = scheme_malloc_sequence(2); + seq->so.type = scheme_sequence_type; + seq->count = 2; + + rhs = pre_body->value; + if (!single_valued_noncm_expression(rhs, 5)) + rhs = ensure_single_value(rhs); + seq->array[0] = rhs; + + head->count--; + head->num_clauses--; + head->body = pre_body->body; + + if (head->num_clauses) + seq->array[1] = (Scheme_Object *)head; + else + seq->array[1] = head->body; + + if (prev) + (void)replace_tail_inside((Scheme_Object *)seq, prev, NULL); + else + form = (Scheme_Object *)seq; + prev = (Scheme_Object *)seq; + + body = pre_body->body; + } else + break; + } + + if (prev) + form = optimize_sequence(form, info, context, 0); + } return form; } @@ -6925,9 +6559,8 @@ optimize_closure_compilation(Scheme_Object *_data, Optimize_Info *info, int cont Scheme_Closure_Data *data; Scheme_Object *code, *ctx; Closure_Info *cl; - mzshort dcs, *dcm; - int i, cnt, init_vclock, init_aclock, init_kclock, init_sclock; - Scheme_Once_Used *first_once_used = NULL, *last_once_used = NULL; + int i, init_vclock, init_aclock, init_kclock, init_sclock; + Scheme_Hash_Table *ht; data = (Scheme_Closure_Data *)_data; @@ -6937,6 +6570,9 @@ optimize_closure_compilation(Scheme_Object *_data, Optimize_Info *info, int cont info = optimize_info_add_frame(info, data->num_params, data->num_params, SCHEME_LAMBDA_FRAME); + ht = scheme_make_hash_table(SCHEME_hash_ptr); + info->uses = ht; + init_vclock = info->vclock; init_aclock = info->aclock; init_kclock = info->kclock; @@ -6958,35 +6594,15 @@ optimize_closure_compilation(Scheme_Object *_data, Optimize_Info *info, int cont cl = (Closure_Info *)data->closure_map; for (i = 0; i < data->num_params; i++) { - if (cl->local_flags[i] & SCHEME_WAS_SET_BANGED) - optimize_mutated(info, i); - - cnt = ((cl->local_flags[i] & SCHEME_USE_COUNT_MASK) >> SCHEME_USE_COUNT_SHIFT); - if (cnt == 1) { - last_once_used = make_once_used(NULL, i, - info->vclock, info->aclock, info->kclock, info->sclock, 0, - last_once_used); - if (!first_once_used) first_once_used = last_once_used; - optimize_propagate(info, i, (Scheme_Object *)last_once_used, 1); - } + set_optimize_mode(cl->vars[i]); + cl->vars[i]->optimize.lambda_depth = info->lambda_depth; + cl->vars[i]->optimize_used = 0; + cl->vars[i]->optimize.init_kclock = info->kclock; } code = scheme_optimize_expr(data->code, info, 0); - for (i = 0; i < data->num_params; i++) { - int ct; - ct = optimize_is_local_type_arg(info, i, 1); - if (ct) - cl->local_flags[i] |= (ct << SCHEME_WAS_TYPED_ARGUMENT_SHIFT); - } - - while (first_once_used) { - if (first_once_used->vclock < 0) { - /* no longer used once, due to binding propagation */ - cl->local_flags[first_once_used->pos] |= SCHEME_USE_COUNT_MASK; - } - first_once_used = first_once_used->next; - } + propagate_used_variables(info); if (info->single_result) SCHEME_CLOSURE_DATA_FLAGS(data) |= CLOS_SINGLE_RESULT; @@ -7005,9 +6621,7 @@ optimize_closure_compilation(Scheme_Object *_data, Optimize_Info *info, int cont data->code = code; /* Remembers positions of used vars (and unsets usage for this level) */ - env_make_closure_map(info, &dcs, &dcm); - cl->base_closure_size = dcs; - cl->base_closure_map = dcm; + cl->base_closure = info->uses; if (env_uses_toplevel(info)) cl->has_tl = 1; else @@ -7025,7 +6639,7 @@ optimize_closure_compilation(Scheme_Object *_data, Optimize_Info *info, int cont info->size++; - data->closure_size = (cl->base_closure_size + data->closure_size = (cl->base_closure->count + (cl->has_tl ? 1 : 0)); optimize_info_done(info, NULL); @@ -7109,35 +6723,61 @@ static void merge_closure_local_type_map(Scheme_Closure_Data *data1, Scheme_Clos } } -static Scheme_Object *clone_closure_compilation(int dup_ok, Scheme_Object *_data, Optimize_Info *info, int delta, int closure_depth) +static Scheme_Compiled_Local *clone_variable(Scheme_Compiled_Local *var) +{ + Scheme_Compiled_Local *var2; + MZ_ASSERT(SAME_TYPE(var->so.type, scheme_compiled_local_type)); + var2 = MALLOC_ONE_TAGGED(Scheme_Compiled_Local); + memcpy(var2, var, sizeof(Scheme_Compiled_Local)); + return var2; +} + +static Scheme_Compiled_Local **clone_variable_array(Scheme_Compiled_Local **vars, + int sz, + Scheme_Hash_Tree **_var_map) +{ + Scheme_Compiled_Local **new_vars, *var; + Scheme_Hash_Tree *var_map = *_var_map; + int j; + + new_vars = MALLOC_N(Scheme_Compiled_Local*, sz); + for (j = sz; j--; ) { + var = clone_variable(vars[j]); + var->mode = SCHEME_VAR_MODE_NONE; + new_vars[j] = var; + var_map = scheme_hash_tree_set(var_map, (Scheme_Object *)vars[j], (Scheme_Object *)new_vars[j]); + } + + *_var_map = var_map; + return new_vars; +} + +static Scheme_Object *clone_closure_compilation(int single_use, Scheme_Object *_data, Optimize_Info *info, Scheme_Hash_Tree *var_map) { Scheme_Closure_Data *data, *data2; - Scheme_Object *body; + Scheme_Object *body, *var; + Scheme_Hash_Table *ht; Closure_Info *cl; - int *flags, sz; + Scheme_Compiled_Local **vars; + int sz; char *local_type_map; data = (Scheme_Closure_Data *)_data; - body = optimize_clone(dup_ok, data->code, info, delta, closure_depth + data->num_params); - if (!body) return NULL; - data2 = MALLOC_ONE_TAGGED(Scheme_Closure_Data); memcpy(data2, data, sizeof(Scheme_Closure_Data)); - data2->code = body; - cl = MALLOC_ONE_RT(Closure_Info); memcpy(cl, data->closure_map, sizeof(Closure_Info)); data2->closure_map = (mzshort *)cl; - /* We don't have to update base_closure_map, because - it will get re-computed as the closure is re-optimized. */ + vars = clone_variable_array(cl->vars, data2->num_params, &var_map); + cl->vars = vars; - sz = sizeof(int) * data2->num_params; - flags = (int *)scheme_malloc_atomic(sz); - memcpy(flags, cl->local_flags, sz); - cl->local_flags = flags; + body = optimize_clone(single_use, data->code, info, var_map, 0); + if (!body) return NULL; + + data2->code = body; if (cl->local_type_map) { sz = data2->num_params; @@ -7146,36 +6786,23 @@ static Scheme_Object *clone_closure_compilation(int dup_ok, Scheme_Object *_data cl->local_type_map = local_type_map; } - return (Scheme_Object *)data2; -} - -static Scheme_Object *shift_closure_compilation(Scheme_Object *_data, int delta, int after_depth) -{ - Scheme_Object *expr; - Scheme_Closure_Data *data = (Scheme_Closure_Data *)_data; - Closure_Info *cl; - int i, sz; - mzshort *naya; - - expr = optimize_shift(data->code, delta, after_depth + data->num_params); - data->code = expr; - - /* In case the result is not going to be re-optimized, we need - to update base_closure_map. */ - - cl = (Closure_Info *)data->closure_map; - sz = cl->base_closure_size; - naya = MALLOC_N_ATOMIC(mzshort, sz); - - for (i = 0; i < sz; i++) { - naya[i] = cl->base_closure_map[i]; - if (naya[i] >= after_depth) - naya[i] += delta; + if (cl->base_closure && var_map->count) { + int i; + ht = scheme_make_hash_table(SCHEME_hash_ptr); + for (i = 0; i < cl->base_closure->size; i++) { + if (cl->base_closure->vals[i]) { + var = scheme_hash_tree_get(var_map, cl->base_closure->keys[i]); + scheme_hash_set(ht, + (var + ? var + : cl->base_closure->keys[i]), + cl->base_closure->vals[i]); + } + } + cl->base_closure = ht; } - cl->base_closure_map = naya; - - return _data; + return (Scheme_Object *)data2; } static int closure_body_size(Scheme_Closure_Data *data, int check_assign, @@ -7189,7 +6816,7 @@ static int closure_body_size(Scheme_Closure_Data *data, int check_assign, if (check_assign) { /* Don't try to inline if any arguments are mutated: */ for (i = data->num_params; i--; ) { - if (cl->local_flags[i] & SCHEME_WAS_SET_BANGED) + if (cl->vars[i]->mutated) return -1; } } @@ -7209,11 +6836,6 @@ static int closure_has_top_level(Scheme_Closure_Data *data) return cl->has_tl; } -static int closure_argument_flags(Scheme_Closure_Data *data, int i) -{ - return ((Closure_Info *)data->closure_map)->local_flags[i]; -} - /*========================================================================*/ /* modules */ /*========================================================================*/ @@ -7251,7 +6873,7 @@ static Scheme_Object *is_cross_module_inline_candidiate(Scheme_Object *e, Optimi { if (IS_COMPILED_PROC(e)) { if (size_override || (compiled_proc_body_size(e, 1) < CROSS_MODULE_INLINE_SIZE)) - return optimize_clone(0, e, info, 0, 0); + return optimize_clone(0, e, info, empty_eq_hash_tree, 0); } return NULL; @@ -7265,7 +6887,7 @@ static int is_general_compiled_proc(Scheme_Object *e, Optimize_Info *info) if (seq->count > 0) { int i; for (i = seq->count - 1; i--; ) { - if (!scheme_omittable_expr(seq->array[i], -1, 20, 0, info, NULL, 0, 0, ID_OMIT)) + if (!scheme_omittable_expr(seq->array[i], -1, 20, 0, info, NULL)) return 0; } } @@ -7280,10 +6902,8 @@ static int is_general_compiled_proc(Scheme_Object *e, Optimize_Info *info) && (lh->num_clauses == 1) && SAME_TYPE(SCHEME_TYPE(lh->body), scheme_compiled_let_value_type)) { Scheme_Compiled_Let_Value *lv = (Scheme_Compiled_Let_Value *)lh->body; - if (IS_COMPILED_PROC(lv->value)) { - if (SAME_TYPE(SCHEME_TYPE(lv->body), scheme_local_type)) - return (SCHEME_LOCAL_POS(lv->body) == 0); - } + if (IS_COMPILED_PROC(lv->value)) + return SAME_OBJ(lv->body, (Scheme_Object *)lv->vars[0]); } } @@ -7315,14 +6935,14 @@ int split_define_values(Scheme_Object *e, int n, Scheme_Object *vars, Scheme_Obj macro to define the `x's */ Scheme_Let_Header *lh = (Scheme_Let_Header *)e; if ((lh->count == n) && (lh->num_clauses == n) - && !(SCHEME_LET_FLAGS(lh) & (SCHEME_LET_RECURSIVE | SCHEME_LET_STAR))) { + && !(SCHEME_LET_FLAGS(lh) & SCHEME_LET_RECURSIVE)) { Scheme_Object *body = lh->body; int i; for (i = 0; i < n; i++) { if (SAME_TYPE(SCHEME_TYPE(body), scheme_compiled_let_value_type)) { Scheme_Compiled_Let_Value *lv = (Scheme_Compiled_Let_Value *)body; if (lv->count == 1) { - if (!scheme_omittable_expr(lv->value, 1, 5, 0, NULL, NULL, n, 0, ID_OMIT)) + if (!scheme_omittable_expr(lv->value, 1, 5, 0, NULL, NULL)) return 0; body = lv->body; } else @@ -7332,13 +6952,11 @@ int split_define_values(Scheme_Object *e, int n, Scheme_Object *vars, Scheme_Obj } if ((n == 2) && SAME_TYPE(SCHEME_TYPE(body), scheme_application3_type)) { Scheme_App3_Rec *app = (Scheme_App3_Rec *)body; + Scheme_Compiled_Let_Value *lv = (Scheme_Compiled_Let_Value *)lh->body; if (SAME_OBJ(app->rator, scheme_values_func) - && SAME_TYPE(SCHEME_TYPE(app->rand1), scheme_local_type) - && (SCHEME_LOCAL_POS(app->rand1) == 0) - && SAME_TYPE(SCHEME_TYPE(app->rand2), scheme_local_type) - && (SCHEME_LOCAL_POS(app->rand2) == 1)) { + && SAME_OBJ(app->rand1, (Scheme_Object *)lv->vars[0]) + && SAME_OBJ(app->rand2, (Scheme_Object *)((Scheme_Compiled_Let_Value *)lv->body)->vars[0])) { if (vars) { - Scheme_Compiled_Let_Value *lv = (Scheme_Compiled_Let_Value *)lh->body; install_definition(vec, offset, SCHEME_CAR(vars), lv->value); vars = SCHEME_CDR(vars); lv = (Scheme_Compiled_Let_Value *)lv->body; @@ -7349,19 +6967,21 @@ int split_define_values(Scheme_Object *e, int n, Scheme_Object *vars, Scheme_Obj } else if (SAME_TYPE(SCHEME_TYPE(body), scheme_application_type) && ((Scheme_App_Rec *)body)->num_args == n) { Scheme_App_Rec *app = (Scheme_App_Rec *)body; + Scheme_Compiled_Let_Value *lv = (Scheme_Compiled_Let_Value *)lh->body; if (SAME_OBJ(app->args[0], scheme_values_func)) { for (i = 0; i < n; i++) { - if (!SAME_TYPE(SCHEME_TYPE(app->args[i+1]), scheme_local_type) - || SCHEME_LOCAL_POS(app->args[i+1]) != i) + if (!SAME_TYPE(SCHEME_TYPE(app->args[i+1]), scheme_compiled_local_type) + || !SAME_OBJ((Scheme_Object *)lv->vars[0], app->args[i+1])) return 0; + lv = (Scheme_Compiled_Let_Value *)lv->body; } if (vars) { body = lh->body; for (i = 0; i < n; i++) { - Scheme_Compiled_Let_Value *lv = (Scheme_Compiled_Let_Value *)body; - install_definition(vec, offset+i, SCHEME_CAR(vars), lv->value); + Scheme_Compiled_Let_Value *lv2 = (Scheme_Compiled_Let_Value *)body; + install_definition(vec, offset+i, SCHEME_CAR(vars), lv2->value); vars = SCHEME_CDR(vars); - body = lv->body; + body = lv2->body; } } return 1; @@ -7371,8 +6991,8 @@ int split_define_values(Scheme_Object *e, int n, Scheme_Object *vars, Scheme_Obj } else if ((n == 2) && SAME_TYPE(SCHEME_TYPE(e), scheme_application3_type)) { Scheme_App3_Rec *app = (Scheme_App3_Rec *)e; if (SAME_OBJ(app->rator, scheme_values_func) - && scheme_omittable_expr(app->rand1, 1, 5, 0, NULL, NULL, 0, 0, ID_OMIT) - && scheme_omittable_expr(app->rand2, 1, 5, 0, NULL, NULL, 0, 0, ID_OMIT)) { + && scheme_omittable_expr(app->rand1, 1, 5, 0, NULL, NULL) + && scheme_omittable_expr(app->rand2, 1, 5, 0, NULL, NULL)) { if (vars) { install_definition(vec, offset, SCHEME_CAR(vars), app->rand1); vars = SCHEME_CDR(vars); @@ -7386,7 +7006,7 @@ int split_define_values(Scheme_Object *e, int n, Scheme_Object *vars, Scheme_Obj if (SAME_OBJ(app->args[0], scheme_values_func)) { int i; for (i = 0; i < n; i++) { - if (!scheme_omittable_expr(app->args[i+1], 1, 5, 0, NULL, NULL, 0, 0, ID_OMIT)) + if (!scheme_omittable_expr(app->args[i+1], 1, 5, 0, NULL, NULL)) return 0; } if (vars) { @@ -7407,7 +7027,7 @@ module_optimize(Scheme_Object *data, Optimize_Info *info, int context) { Scheme_Module *m = (Scheme_Module *)data; Scheme_Object *e, *vars, *old_context; - int start_simltaneous = 0, i_m, cnt; + int start_simultaneous = 0, i_m, cnt; Scheme_Object *cl_first = NULL, *cl_last = NULL; Scheme_Hash_Table *consts = NULL, *fixed_table = NULL, *re_consts = NULL; Scheme_Hash_Table *originals = NULL; @@ -7567,7 +7187,7 @@ module_optimize(Scheme_Object *data, Optimize_Info *info, int context) information that's only available at optimization time: */ NULL, - info, 0, 0, ID_OMIT); + info); if (n == 1) { if (scheme_compiled_propagate_ok(e, info)) @@ -7600,7 +7220,7 @@ module_optimize(Scheme_Object *data, Optimize_Info *info, int context) } else if (sproc) { e2 = scheme_make_noninline_proc(e); } else if (IS_COMPILED_PROC(e)) { - e2 = optimize_clone(1, e, info, 0, 0); + e2 = optimize_clone(1, e, info, empty_eq_hash_tree, 0); if (e2) { Scheme_Object *pr; pr = scheme_make_raw_pair(scheme_make_raw_pair(e2, e), NULL); @@ -7668,7 +7288,7 @@ module_optimize(Scheme_Object *data, Optimize_Info *info, int context) } } } else { - cont = scheme_omittable_expr(e, -1, -1, 0, NULL, NULL, 0, 0, ID_OMIT); + cont = scheme_omittable_expr(e, -1, -1, 0, NULL, NULL); } if (i_m + 1 == cnt) cont = 0; @@ -7690,11 +7310,10 @@ module_optimize(Scheme_Object *data, Optimize_Info *info, int context) 0); while (1) { - /* Re-optimize this expression. We can optimize anything without - shift-cloning, since there are no local variables in scope. */ + /* Re-optimize this expression. */ int old_sz, new_sz; - e = SCHEME_VEC_ELS(m->bodies[0])[start_simltaneous]; + e = SCHEME_VEC_ELS(m->bodies[0])[start_simultaneous]; if (OPT_DELAY_GROUP_PROPAGATE || OPT_LIMIT_FUNCTION_RESIZE) { if (SAME_TYPE(SCHEME_TYPE(e), scheme_define_values_type)) { @@ -7708,13 +7327,13 @@ module_optimize(Scheme_Object *data, Optimize_Info *info, int context) optimize_info_seq_step(info, &info_seq); e = scheme_optimize_expr(e, info, 0); - SCHEME_VEC_ELS(m->bodies[0])[start_simltaneous] = e; + SCHEME_VEC_ELS(m->bodies[0])[start_simultaneous] = e; if (re_consts) { /* Install optimized closures into constant table --- unless, maybe, they grow too much: */ Scheme_Object *rpos; - rpos = scheme_hash_get(re_consts, scheme_make_integer(start_simltaneous)); + rpos = scheme_hash_get(re_consts, scheme_make_integer(start_simultaneous)); if (rpos) { Scheme_Object *old_e; @@ -7724,7 +7343,7 @@ module_optimize(Scheme_Object *data, Optimize_Info *info, int context) if (old_e && IS_COMPILED_PROC(old_e)) { if (!originals) originals = scheme_make_hash_table(SCHEME_hash_ptr); - scheme_hash_set(originals, scheme_make_integer(start_simltaneous), old_e); + scheme_hash_set(originals, scheme_make_integer(start_simultaneous), old_e); } if (!scheme_compiled_propagate_ok(e, info) @@ -7754,9 +7373,9 @@ module_optimize(Scheme_Object *data, Optimize_Info *info, int context) } } - if (start_simltaneous == i_m) + if (start_simultaneous == i_m) break; - start_simltaneous++; + start_simultaneous++; } flags = set_code_closure_flags(cl_first, 0, 0xFFFF, 0); @@ -7769,7 +7388,7 @@ module_optimize(Scheme_Object *data, Optimize_Info *info, int context) cl_last = cl_first = NULL; consts = NULL; re_consts = NULL; - start_simltaneous = i_m + 1; + start_simultaneous = i_m + 1; while (prop_later) { e = SCHEME_CAR(prop_later); @@ -7833,7 +7452,7 @@ module_optimize(Scheme_Object *data, Optimize_Info *info, int context) for (i_m = 0; i_m < cnt; i_m++) { /* Optimize this expression: */ e = SCHEME_VEC_ELS(m->bodies[0])[i_m]; - if (scheme_omittable_expr(e, -1, -1, 0, info, NULL, 0, 0, ID_OMIT)) { + if (scheme_omittable_expr(e, -1, -1, 0, info, NULL)) { can_omit++; } } @@ -7844,7 +7463,7 @@ module_optimize(Scheme_Object *data, Optimize_Info *info, int context) for (i_m = 0; i_m < cnt; i_m++) { /* Optimize this expression: */ e = SCHEME_VEC_ELS(m->bodies[0])[i_m]; - if (!scheme_omittable_expr(e, -1, -1, 0, info, NULL, 0, 0, ID_OMIT)) { + if (!scheme_omittable_expr(e, -1, -1, 0, info, NULL)) { SCHEME_VEC_ELS(vec)[j++] = e; } } @@ -7926,16 +7545,14 @@ Scheme_Object *scheme_optimize_expr(Scheme_Object *expr, Optimize_Info *info, in info->escapes = 0; switch (type) { - case scheme_local_type: + case scheme_compiled_local_type: { Scheme_Object *val; - int pos, delta, is_mutated = 0, single_use; + int is_mutated = 0; info->size += 1; - pos = SCHEME_LOCAL_POS(expr); - - val = optimize_info_lookup(info, pos, NULL, &single_use, + val = optimize_info_lookup(info, expr, 0, NULL, (context & OPT_CONTEXT_NO_SINGLE) ? 0 : 1, context, NULL, &is_mutated); @@ -7947,56 +7564,49 @@ Scheme_Object *scheme_optimize_expr(Scheme_Object *expr, Optimize_Info *info, in || !o->spans_k) && ((context & OPT_CONTEXT_SINGLED) || single_valued_noncm_expression(o->expr, 5))) - || movable_expression(o->expr, info, o->delta, o->cross_lambda, + || movable_expression(o->expr, info, + o->var->optimize.lambda_depth != info->lambda_depth, o->kclock != info->kclock, o->sclock != info->sclock, 0, 5)) { - val = optimize_clone(1, o->expr, info, o->delta, 0); - if (val) { - int save_fuel = info->inline_fuel, save_no_types = info->no_types; - int save_vclock, save_aclock, save_kclock, save_sclock; - info->size -= 1; - o->used = 1; - info->inline_fuel = 0; /* no more inlining; o->expr was already optimized */ - info->no_types = 1; /* cannot used inferred types, in case `val' inferred them */ - save_vclock = info->vclock; /* allowed to move => no change to clocks */ - save_aclock = info->aclock; - save_kclock = info->kclock; - save_sclock = info->sclock; + int save_fuel = info->inline_fuel, save_no_types = info->no_types; + int save_vclock, save_aclock, save_kclock, save_sclock; + info->size -= 1; + info->inline_fuel = 0; /* no more inlining; o->expr was already optimized */ + info->no_types = 1; /* cannot used inferred types, in case `val' inferred them */ + save_vclock = info->vclock; /* allowed to move => no change to clocks */ + save_aclock = info->aclock; + save_kclock = info->kclock; + save_sclock = info->sclock; - val = scheme_optimize_expr(val, info, context); + o->moved = 1; - if (info->maybe_values_argument) { - /* Although `val` could be counted as taking 0 time, we advance - the clock conservatively to be consistent with `values` - splitting. */ - advance_clocks_for_optimized(val, - &save_vclock, &save_aclock, &save_kclock, &save_sclock, - info, - ADVANCE_CLOCKS_INIT_FUEL); - } + val = scheme_optimize_expr(o->expr, info, context); - info->inline_fuel = save_fuel; - info->no_types = save_no_types; - info->vclock = save_vclock; - info->aclock = save_aclock; - info->kclock = save_kclock; - info->sclock = save_sclock; - return val; + if (info->maybe_values_argument) { + /* Although `val` could be counted as taking 0 time, we advance + the clock conservatively to be consistent with `values` + splitting. */ + advance_clocks_for_optimized(val, + &save_vclock, &save_aclock, &save_kclock, &save_sclock, + info, + ADVANCE_CLOCKS_INIT_FUEL); } + + info->inline_fuel = save_fuel; + info->no_types = save_no_types; + info->vclock = save_vclock; + info->aclock = save_aclock; + info->kclock = save_kclock; + info->sclock = save_sclock; + return val; } /* Can't move expression, so lookup again to mark as used and to perform any copy propagation that might apply. */ - val = optimize_info_lookup(info, pos, NULL, NULL, 0, context, NULL, NULL); + val = optimize_info_lookup(info, expr, 0, NULL, 0, context, NULL, NULL); if (val) return val; } else { - if (!single_use && SAME_TYPE(SCHEME_TYPE(val), scheme_local_type)) { - /* Since the replaced local was not single use, make sure the - replacement is also not marked as single use anymore */ - optimize_set_not_single_use(info, SCHEME_LOCAL_POS(val)); - } - if (SAME_TYPE(SCHEME_TYPE(val), scheme_compiled_toplevel_type) || (SCHEME_TYPE(val) > _scheme_compiled_values_types_)) { info->size -= 1; @@ -8008,15 +7618,10 @@ Scheme_Object *scheme_optimize_expr(Scheme_Object *expr, Optimize_Info *info, in info->vclock += 1; } - delta = optimize_info_get_shift(info, pos); - - val = collapse_local(pos + delta, info, context); + val = collapse_local(expr, info, context); if (val) return val; - if (delta) - expr = scheme_make_local(scheme_local_type, pos + delta, 0); - return expr; } case scheme_application_type: @@ -8027,7 +7632,7 @@ Scheme_Object *scheme_optimize_expr(Scheme_Object *expr, Optimize_Info *info, in return optimize_application3(expr, info, context); case scheme_sequence_type: case scheme_splice_sequence_type: - return optimize_sequence(expr, info, context); + return optimize_sequence(expr, info, context, 1); case scheme_branch_type: return optimize_branch(expr, info, context); case scheme_with_cont_mark_type: @@ -8133,25 +7738,35 @@ Scheme_Object *scheme_optimize_expr(Scheme_Object *expr, Optimize_Info *info, in } } -Scheme_Object *optimize_clone(int dup_ok, Scheme_Object *expr, Optimize_Info *info, int delta, int closure_depth) -/* Past closure_depth, need to reverse optimize to unoptimized with respect to info; - delta is the amount to skip in info to get to the frame that bound the code. - If dup_ok is 1, then the old copy will be dropped, so it's ok to "duplicate" - any constant. */ +static void increment_use_count(Scheme_Compiled_Local *var, int as_rator) +{ + if (var->use_count < SCHEME_USE_COUNT_INF) + var->use_count++; + if (!as_rator && (var->non_app_count < SCHEME_USE_COUNT_INF)) + var->non_app_count++; + + if (var->optimize.known_val + && SAME_TYPE(SCHEME_TYPE(var->optimize.known_val), scheme_once_used_type)) + var->optimize.known_val = NULL; +} + +Scheme_Object *optimize_clone(int single_use, Scheme_Object *expr, Optimize_Info *info, Scheme_Hash_Tree *var_map, int as_rator) +/* If single_use is 1, then the old copy will be dropped --- so it's ok to "duplicate" + any constant, and local-variable use counts should not be incremented. */ { int t; t = SCHEME_TYPE(expr); switch(t) { - case scheme_local_type: + case scheme_compiled_local_type: { - int pos = SCHEME_LOCAL_POS(expr); - if (pos >= closure_depth) { - expr = optimize_reverse(info, pos + delta - closure_depth, 0, !dup_ok); - if (closure_depth) - expr = scheme_make_local(scheme_local_type, SCHEME_LOCAL_POS(expr) + closure_depth, 0); - } + Scheme_Object *v; + v = scheme_hash_tree_get(var_map, expr); + if (v) + return v; + else if (!single_use) + increment_use_count(SCHEME_VAR(expr), as_rator); return expr; } case scheme_application2_type: @@ -8161,11 +7776,11 @@ Scheme_Object *optimize_clone(int dup_ok, Scheme_Object *expr, Optimize_Info *in app2 = MALLOC_ONE_TAGGED(Scheme_App2_Rec); app2->iso.so.type = scheme_application2_type; - expr = optimize_clone(dup_ok, app->rator, info, delta, closure_depth); + expr = optimize_clone(single_use, app->rator, info, var_map, 1); if (!expr) return NULL; app2->rator = expr; - expr = optimize_clone(dup_ok, app->rand, info, delta, closure_depth); + expr = optimize_clone(single_use, app->rand, info, var_map, 0); if (!expr) return NULL; app2->rand = expr; @@ -8181,7 +7796,7 @@ Scheme_Object *optimize_clone(int dup_ok, Scheme_Object *expr, Optimize_Info *in app2 = scheme_malloc_application(app->num_args + 1); for (i = app->num_args + 1; i--; ) { - expr = optimize_clone(dup_ok, app->args[i], info, delta, closure_depth); + expr = optimize_clone(single_use, app->args[i], info, var_map, !i); if (!expr) return NULL; app2->args[i] = expr; } @@ -8197,15 +7812,15 @@ Scheme_Object *optimize_clone(int dup_ok, Scheme_Object *expr, Optimize_Info *in app2 = MALLOC_ONE_TAGGED(Scheme_App3_Rec); app2->iso.so.type = scheme_application3_type; - expr = optimize_clone(dup_ok, app->rator, info, delta, closure_depth); + expr = optimize_clone(single_use, app->rator, info, var_map, 1); if (!expr) return NULL; app2->rator = expr; - expr = optimize_clone(dup_ok, app->rand1, info, delta, closure_depth); + expr = optimize_clone(single_use, app->rand1, info, var_map, 0); if (!expr) return NULL; app2->rand1 = expr; - expr = optimize_clone(dup_ok, app->rand2, info, delta, closure_depth); + expr = optimize_clone(single_use, app->rand2, info, var_map, 0); if (!expr) return NULL; app2->rand2 = expr; @@ -8218,8 +7833,8 @@ Scheme_Object *optimize_clone(int dup_ok, Scheme_Object *expr, Optimize_Info *in Scheme_Let_Header *head = (Scheme_Let_Header *)expr, *head2; Scheme_Object *body; Scheme_Compiled_Let_Value *lv, *lv2, *prev = NULL; - int i, *flags, sz; - int post_bind = !(SCHEME_LET_FLAGS(head) & (SCHEME_LET_RECURSIVE | SCHEME_LET_STAR)); + Scheme_Compiled_Local **vars; + int i; head2 = MALLOC_ONE_TAGGED(Scheme_Let_Header); head2->iso.so.type = scheme_compiled_let_void_type; @@ -8232,21 +7847,14 @@ Scheme_Object *optimize_clone(int dup_ok, Scheme_Object *expr, Optimize_Info *in for (i = head->num_clauses; i--; ) { lv = (Scheme_Compiled_Let_Value *)body; - sz = sizeof(int) * lv->count; - flags = (int *)scheme_malloc_atomic(sz); - memcpy(flags, lv->flags, sz); + vars = clone_variable_array(lv->vars, lv->count, &var_map); lv2 = MALLOC_ONE_TAGGED(Scheme_Compiled_Let_Value); SCHEME_CLV_FLAGS(lv2) |= (SCHEME_CLV_FLAGS(lv) & 0x1); lv2->iso.so.type = scheme_compiled_let_value_type; lv2->count = lv->count; - lv2->position = lv->position; - lv2->flags = flags; - - expr = optimize_clone(dup_ok, lv->value, info, delta, - closure_depth + (post_bind ? 0 : head->count)); - if (!expr) return NULL; - lv2->value = expr; + lv2->vars = vars; + lv2->value = lv->value; if (prev) prev->body = (Scheme_Object *)lv2; @@ -8261,7 +7869,18 @@ Scheme_Object *optimize_clone(int dup_ok, Scheme_Object *expr, Optimize_Info *in else head2->body = body; - expr = optimize_clone(dup_ok, body, info, delta, closure_depth + head->count); + body = head2->body; + for (i = head->num_clauses; i--; ) { + lv2 = (Scheme_Compiled_Let_Value *)body; + + expr = optimize_clone(single_use, lv2->value, info, var_map, 0); + if (!expr) return NULL; + lv2->value = expr; + + body = lv2->body; + } + + expr = optimize_clone(single_use, body, info, var_map, 0); if (!expr) return NULL; if (prev) @@ -8283,7 +7902,7 @@ Scheme_Object *optimize_clone(int dup_ok, Scheme_Object *expr, Optimize_Info *in seq2->count = seq->count; for (i = seq->count; i--; ) { - expr = optimize_clone(dup_ok, seq->array[i], info, delta, closure_depth); + expr = optimize_clone(single_use, seq->array[i], info, var_map, 0); if (!expr) return NULL; seq2->array[i] = expr; } @@ -8297,15 +7916,15 @@ Scheme_Object *optimize_clone(int dup_ok, Scheme_Object *expr, Optimize_Info *in b2 = MALLOC_ONE_TAGGED(Scheme_Branch_Rec); b2->so.type = scheme_branch_type; - expr = optimize_clone(dup_ok, b->test, info, delta, closure_depth); + expr = optimize_clone(single_use, b->test, info, var_map, 0); if (!expr) return NULL; b2->test = expr; - expr = optimize_clone(dup_ok, b->tbranch, info, delta, closure_depth); + expr = optimize_clone(single_use, b->tbranch, info, var_map, 0); if (!expr) return NULL; b2->tbranch = expr; - expr = optimize_clone(dup_ok, b->fbranch, info, delta, closure_depth); + expr = optimize_clone(single_use, b->fbranch, info, var_map, 0); if (!expr) return NULL; b2->fbranch = expr; @@ -8318,22 +7937,22 @@ Scheme_Object *optimize_clone(int dup_ok, Scheme_Object *expr, Optimize_Info *in wcm2 = MALLOC_ONE_TAGGED(Scheme_With_Continuation_Mark); wcm2->so.type = scheme_with_cont_mark_type; - expr = optimize_clone(dup_ok, wcm->key, info, delta, closure_depth); + expr = optimize_clone(single_use, wcm->key, info, var_map, 0); if (!expr) return NULL; wcm2->key = expr; - expr = optimize_clone(dup_ok, wcm->val, info, delta, closure_depth); + expr = optimize_clone(single_use, wcm->val, info, var_map, 0); if (!expr) return NULL; wcm2->val = expr; - expr = optimize_clone(dup_ok, wcm->body, info, delta, closure_depth); + expr = optimize_clone(single_use, wcm->body, info, var_map, 0); if (!expr) return NULL; wcm2->body = expr; return (Scheme_Object *)wcm2; } case scheme_compiled_unclosed_procedure_type: - return clone_closure_compilation(dup_ok, expr, info, delta, closure_depth); + return clone_closure_compilation(single_use, expr, info, var_map); case scheme_compiled_toplevel_type: case scheme_compiled_quote_syntax_type: return expr; @@ -8345,20 +7964,20 @@ Scheme_Object *optimize_clone(int dup_ok, Scheme_Object *expr, Optimize_Info *in case scheme_require_form_type: return NULL; case scheme_varref_form_type: - return ref_clone(dup_ok, expr, info, delta, closure_depth); + return ref_clone(single_use, expr, info, var_map); case scheme_set_bang_type: - return set_clone(dup_ok, expr, info, delta, closure_depth); + return set_clone(single_use, expr, info, var_map); case scheme_apply_values_type: - return apply_values_clone(dup_ok, expr, info, delta, closure_depth); + return apply_values_clone(single_use, expr, info, var_map); case scheme_with_immed_mark_type: - return with_immed_mark_clone(dup_ok, expr, info, delta, closure_depth); + return with_immed_mark_clone(single_use, expr, info, var_map); case scheme_case_lambda_sequence_type: - return case_lambda_clone(dup_ok, expr, info, delta, closure_depth); + return case_lambda_clone(single_use, expr, info, var_map); case scheme_module_type: return NULL; default: if (t > _scheme_compiled_values_types_) { - if (dup_ok || scheme_compiled_duplicate_ok(expr, 0)) + if (single_use || scheme_compiled_duplicate_ok(expr, 0)) return expr; } } @@ -8366,166 +7985,6 @@ Scheme_Object *optimize_clone(int dup_ok, Scheme_Object *expr, Optimize_Info *in return NULL; } -Scheme_Object *optimize_shift(Scheme_Object *expr, int delta, int after_depth) -/* Shift lexical addresses deeper by delta if already deeper than after_depth; - can mutate. */ -{ - int t; - - /* FIXME: need stack check */ - - t = SCHEME_TYPE(expr); - - switch(t) { - case scheme_local_type: - case scheme_local_unbox_type: - { - int pos = SCHEME_LOCAL_POS(expr); - if (pos >= after_depth) { - expr = scheme_make_local(t, SCHEME_LOCAL_POS(expr) + delta, 0); - } - return expr; - } - case scheme_application_type: - { - Scheme_App_Rec *app = (Scheme_App_Rec *)expr; - int i; - - for (i = app->num_args + 1; i--; ) { - expr = optimize_shift(app->args[i], delta, after_depth); - app->args[i] = expr; - } - - return (Scheme_Object *)app; - } - case scheme_application2_type: - { - Scheme_App2_Rec *app = (Scheme_App2_Rec *)expr; - - expr = optimize_shift(app->rator, delta, after_depth); - app->rator = expr; - - expr = optimize_shift(app->rand, delta, after_depth); - app->rand = expr; - - return (Scheme_Object *)app; - } - case scheme_application3_type: - { - Scheme_App3_Rec *app = (Scheme_App3_Rec *)expr; - - expr = optimize_shift(app->rator, delta, after_depth); - app->rator = expr; - - expr = optimize_shift(app->rand1, delta, after_depth); - app->rand1 = expr; - - expr = optimize_shift(app->rand2, delta, after_depth); - app->rand2 = expr; - - return (Scheme_Object *)app; - } - case scheme_compiled_let_void_type: - { - Scheme_Let_Header *head = (Scheme_Let_Header *)expr; - Scheme_Object *body; - Scheme_Compiled_Let_Value *lv = NULL; - int i; - int post_bind = !(SCHEME_LET_FLAGS(head) & (SCHEME_LET_RECURSIVE | SCHEME_LET_STAR)); - - /* Build let-value change: */ - body = head->body; - for (i = head->num_clauses; i--; ) { - lv = (Scheme_Compiled_Let_Value *)body; - - expr = optimize_shift(lv->value, delta, after_depth + (post_bind ? 0 : head->count)); - lv->value = expr; - - body = lv->body; - } - expr = optimize_shift(body, delta, after_depth + head->count); - - if (head->num_clauses) - lv->body = expr; - else - head->body = expr; - - return (Scheme_Object *)head; - } - case scheme_sequence_type: - case scheme_splice_sequence_type: - case scheme_begin0_sequence_type: - { - Scheme_Sequence *seq = (Scheme_Sequence *)expr; - int i; - - for (i = seq->count; i--; ) { - expr = optimize_shift(seq->array[i], delta, after_depth); - seq->array[i] = expr; - } - - return (Scheme_Object *)seq; - } - case scheme_branch_type: - { - Scheme_Branch_Rec *b = (Scheme_Branch_Rec *)expr; - - expr = optimize_shift(b->test, delta, after_depth); - b->test = expr; - - expr = optimize_shift(b->tbranch, delta, after_depth); - b->tbranch = expr; - - expr = optimize_shift(b->fbranch, delta, after_depth); - b->fbranch = expr; - - return (Scheme_Object *)b; - } - case scheme_with_cont_mark_type: - { - Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)expr; - - expr = optimize_shift(wcm->key, delta, after_depth); - wcm->key = expr; - - expr = optimize_shift(wcm->val, delta, after_depth); - wcm->val = expr; - - expr = optimize_shift(wcm->body, delta, after_depth); - wcm->body = expr; - - return (Scheme_Object *)wcm; - } - case scheme_compiled_unclosed_procedure_type: - return shift_closure_compilation(expr, delta, after_depth); - case scheme_compiled_toplevel_type: - case scheme_compiled_quote_syntax_type: - return expr; - case scheme_set_bang_type: - return set_shift(expr, delta, after_depth); - case scheme_varref_form_type: - return ref_shift(expr, delta, after_depth); - case scheme_apply_values_type: - return apply_values_shift(expr, delta, after_depth); - case scheme_with_immed_mark_type: - return with_immed_mark_shift(expr, delta, after_depth); - case scheme_case_lambda_sequence_type: - return case_lambda_shift(expr, delta, after_depth); - case scheme_boxenv_type: - case scheme_define_values_type: - case scheme_define_syntaxes_type: - case scheme_begin_for_syntax_type: - case scheme_require_form_type: - case scheme_module_type: - scheme_signal_error("optimize_shift: no shift available for %d", SCHEME_TYPE(expr)); - return NULL; - default: - return expr; - } - - return NULL; -} - /*========================================================================*/ /* compile-time env for optimization */ /*========================================================================*/ @@ -8539,7 +7998,6 @@ Optimize_Info *scheme_optimize_info_create(Comp_Prefix *cp, int get_logger) info->type = scheme_rt_optimize_info; #endif info->inline_fuel = 32; - info->shift_fuel = 16; info->flatten_fuel = 16; info->cp = cp; @@ -8555,17 +8013,12 @@ Optimize_Info *scheme_optimize_info_create(Comp_Prefix *cp, int get_logger) static void optimize_info_seq_init(Optimize_Info *info, Optimize_Info_Sequence *info_seq) { - info_seq->init_shift_fuel = info->shift_fuel; - info_seq->min_shift_fuel = info->shift_fuel; info_seq->init_flatten_fuel = info->flatten_fuel; info_seq->min_flatten_fuel = info->flatten_fuel; } static void optimize_info_seq_step(Optimize_Info *info, Optimize_Info_Sequence *info_seq) { - if (info->shift_fuel < info_seq->min_shift_fuel) - info_seq->min_shift_fuel = info->shift_fuel; - info->shift_fuel = info_seq->init_shift_fuel; if (info->flatten_fuel < info_seq->min_flatten_fuel) info_seq->min_flatten_fuel = info->flatten_fuel; info->flatten_fuel = info_seq->init_flatten_fuel; @@ -8573,8 +8026,6 @@ static void optimize_info_seq_step(Optimize_Info *info, Optimize_Info_Sequence * static void optimize_info_seq_done(Optimize_Info *info, Optimize_Info_Sequence *info_seq) { - if (info->shift_fuel > info_seq->min_shift_fuel) - info->shift_fuel = info_seq->min_shift_fuel; if (info->flatten_fuel > info_seq->min_flatten_fuel) info->flatten_fuel = info_seq->min_flatten_fuel; } @@ -8594,86 +8045,33 @@ void scheme_optimize_info_never_inline(Optimize_Info *oi) oi->inline_fuel = -1; } -static void register_transitive_use(Optimize_Info *info, int pos, int j); - -static void register_stat_dist(Optimize_Info *info, int i, int j) -{ - if (!info->stat_dists) { - int k, *ia; - char **ca; - ca = MALLOC_N(char*, info->new_frame); - info->stat_dists = ca; - ia = MALLOC_N_ATOMIC(int, info->new_frame); - info->sd_depths = ia; - for (k = info->new_frame; k--; ) { - info->sd_depths[k] = 0; - } - } - - if (i >= info->new_frame) - scheme_signal_error("internal error: bad stat-dist index"); - - if (info->sd_depths[i] <= j) { - char *naya, *a; - int k; - - naya = MALLOC_N_ATOMIC(char, (j + 1)); - for (k = j + 1; k--; ) { - naya[k] = 0; - } - a = info->stat_dists[i]; - for (k = info->sd_depths[i]; k--; ) { - naya[k] = a[k]; - } - - info->stat_dists[i] = naya; - info->sd_depths[i] = j + 1; - } - - if (info->transitive_use && info->transitive_use[i]) { - /* We're using a procedure that we weren't sure would be used. - Transitively mark everything that the procedure uses --- unless - a transitive accumulation is in effect, in which case we - don't follow this one now, leaving it to be triggered when - the one we're accumulating is triggered. */ - if (!info->transitive_use_pos) { - mzshort *map = info->transitive_use[i]; - int len = info->transitive_use_len[i]; - int k; - - info->transitive_use[i] = NULL; - - for (k = 0; k < len; k++) { - register_transitive_use(info, map[k], 0); - } - } - } - - info->stat_dists[i][j] = 1; -} +static void register_transitive(Scheme_Compiled_Local *var); +static void register_use_at(Scheme_Compiled_Local *var, Optimize_Info *info); static Scheme_Object *transitive_k(void) { Scheme_Thread *p = scheme_current_thread; - Optimize_Info *info = (Optimize_Info *)p->ku.k.p1; + Scheme_Compiled_Local *var = SCHEME_VAR(p->ku.k.p1); p->ku.k.p1 = NULL; - register_transitive_use(info, (int)p->ku.k.i1, (int)p->ku.k.i2); + register_transitive(var); return scheme_false; } -static void register_transitive_use(Optimize_Info *info, int pos, int j) +static void register_transitive(Scheme_Compiled_Local *var) { + Scheme_Hash_Table *ht; + Scheme_Compiled_Local *tvar; + int j; + #ifdef DO_STACK_CHECK # include "mzstkchk.h" { Scheme_Thread *p = scheme_current_thread; - p->ku.k.p1 = (void *)info; - p->ku.k.i1 = pos; - p->ku.k.i2 = j; + p->ku.k.p1 = (void *)var; scheme_handle_stack_overflow(transitive_k); @@ -8681,81 +8079,31 @@ static void register_transitive_use(Optimize_Info *info, int pos, int j) } #endif - while (info) { - if (info->flags & SCHEME_LAMBDA_FRAME) - j++; - if (pos < info->new_frame) - break; - pos -= info->new_frame; - info = info->next; - } + ht = var->optimize.transitive_uses; - if (info->sd_depths[pos] <= j) { - scheme_signal_error("bad transitive position depth: %d vs. %d", - info->sd_depths[pos], j); - } - - register_stat_dist(info, pos, j); -} - -static void env_make_closure_map(Optimize_Info *info, mzshort *_size, mzshort **_map) -{ - /* A closure map lists the captured variables for a closure; the - indices are resolved two new indices in the second phase of - compilation. */ - Optimize_Info *frame; - int i, j, pos = 0, lpos = 0, tu; - mzshort *map, size; - - /* Count vars used by this closure (skip args): */ - j = 1; - for (frame = info->next; frame; frame = frame->next) { - if (frame->flags & SCHEME_LAMBDA_FRAME) - j++; - - if (frame->stat_dists) { - for (i = 0; i < frame->new_frame; i++) { - if (frame->sd_depths[i] > j) { - if (frame->stat_dists[i][j]) { - pos++; - } - } - } + for (j = 0; j < ht->size; j++) { + if (ht->vals[j]) { + tvar = SCHEME_VAR(ht->keys[j]); + register_use_at(tvar, var->optimize.transitive_uses_to); } } +} - size = pos; - *_size = size; - map = MALLOC_N_ATOMIC(mzshort, size); - *_map = map; +static void propagate_used_variables(Optimize_Info *info) +{ + Scheme_Hash_Table *ht; + Scheme_Compiled_Local *tvar; + int j; - if (info->next && info->next->transitive_use_pos) { - info->next->transitive_use[info->next->transitive_use_pos - 1] = map; - info->next->transitive_use_len[info->next->transitive_use_pos - 1] = size; - tu = 1; - } else - tu = 0; - - /* Build map, unmarking locals and marking deeper in parent frame */ - j = 1; pos = 0; - for (frame = info->next; frame; frame = frame->next) { - if (frame->flags & SCHEME_LAMBDA_FRAME) - j++; - - if (frame->stat_dists) { - for (i = 0; i < frame->new_frame; i++) { - if (frame->sd_depths[i] > j) { - if (frame->stat_dists[i][j]) { - map[pos++] = lpos; - frame->stat_dists[i][j] = 0; /* This closure's done with these vars... */ - if (!tu) - frame->stat_dists[i][j - 1] = 1; /* ... but ensure previous keeps */ - } - } - lpos++; + if (info->next->uses) { + ht = info->uses; + for (j = 0; j < ht->size; j++) { + if (ht->vals[j]) { + tvar = SCHEME_VAR(ht->keys[j]); + if (tvar->optimize.lambda_depth < info->next->lambda_depth) + scheme_hash_set(info->next->uses, (Scheme_Object *)tvar, scheme_true); } - } else - lpos += frame->new_frame; + } } } @@ -8791,24 +8139,8 @@ static void optimize_info_used_top(Optimize_Info *info) } } -static void optimize_propagate(Optimize_Info *info, int pos, Scheme_Object *value, int single_use) -{ - /* A raw-pair `value' is an indicator for whether a letrec-bound - variable is ready. */ - Scheme_Object *p; - - p = scheme_make_vector(4, NULL); - SCHEME_VEC_ELS(p)[0] = info->consts; - SCHEME_VEC_ELS(p)[1] = scheme_make_integer(pos); - SCHEME_VEC_ELS(p)[2] = value; - SCHEME_VEC_ELS(p)[3] = (single_use ? scheme_true : scheme_false); - - info->consts = p; -} - -static Scheme_Once_Used *make_once_used(Scheme_Object *val, int pos, - int vclock, int aclock, int kclock, int sclock, int spans_k, - Scheme_Once_Used *prev) +static Scheme_Once_Used *make_once_used(Scheme_Object *val, Scheme_Compiled_Local *var, + int vclock, int aclock, int kclock, int sclock, int spans_k) { Scheme_Once_Used *o; @@ -8816,348 +8148,141 @@ static Scheme_Once_Used *make_once_used(Scheme_Object *val, int pos, o->so.type = scheme_once_used_type; o->expr = val; - o->pos = pos; + o->var = var; o->vclock = vclock; o->aclock = aclock; o->kclock = kclock; o->sclock = sclock; o->spans_k = spans_k; - if (prev) - prev->next = o; - return o; } -static void register_use(Optimize_Info *info, int pos, int flag) -/* pos must be in immediate frame */ +static int optimize_any_uses(Optimize_Info *info, Scheme_Compiled_Let_Value *at_clv, int n) { - if (!info->use) { - char *use; - use = (char *)scheme_malloc_atomic(info->new_frame); - memset(use, 0, info->new_frame); - info->use = use; - } - info->use[pos] |= flag; -} + int i, j; + Scheme_Compiled_Let_Value *clv = at_clv; -static void optimize_mutated(Optimize_Info *info, int pos) -/* pos must be in immediate frame */ -{ - register_use(info, pos, OPT_IS_MUTATED); -} - -static void optimize_produces_local_type(Optimize_Info *info, int pos, int ct) -/* pos must be in immediate frame */ -{ - register_use(info, pos, ct << OPT_LOCAL_TYPE_VAL_SHIFT); -} - -static Scheme_Object *optimize_reverse(Optimize_Info *info, int pos, int unless_mutated, int disrupt_single_use) -/* pos is in new-frame counts, and we want to produce an old-frame reference if - it's not mutated */ -{ - int delta = 0; - - while (1) { - if (pos < info->new_frame) - break; - pos -= info->new_frame; - delta += info->original_frame; - info = info->next; - } - - if (unless_mutated) - if (info->use && (info->use[pos] & OPT_IS_MUTATED)) - return NULL; - - if (disrupt_single_use) { - Scheme_Object *p, *n; - p = info->consts; - while (p) { - n = SCHEME_VEC_ELS(p)[1]; - if (SCHEME_INT_VAL(n) == pos) { - if (SCHEME_TRUEP(SCHEME_VEC_ELS(p)[3])) { - SCHEME_VEC_ELS(p)[3] = scheme_false; /* disable "single use" mark */ - } - n = SCHEME_VEC_ELS(p)[2]; - if (SAME_TYPE(SCHEME_TYPE(n), scheme_once_used_type)) { - ((Scheme_Once_Used *)n)->expr = NULL; - ((Scheme_Once_Used *)n)->vclock = -1; - } - break; - } - p = SCHEME_VEC_ELS(p)[0]; - } - } - - return scheme_make_local(scheme_local_type, pos + delta, 0); -} - -static int optimize_is_used(Optimize_Info *info, int pos) -/* pos must be in immediate frame */ -{ - int i; - - if (info->stat_dists) { - for (i = info->sd_depths[pos]; i--; ) { - if (info->stat_dists[pos][i]) - return 1; - } - } - - return 0; -} - -static int check_use(Optimize_Info *info, int pos, int mask, int shift) -/* pos is in new-frame counts */ -{ - while (info) { - if (pos < info->new_frame) - break; - pos -= info->new_frame; - info = info->next; - } - - if (info->use) - return (info->use[pos] >> shift) & mask; - - return 0; -} - -static int optimize_is_mutated(Optimize_Info *info, int pos) -/* pos is in new-frame counts */ -{ - return check_use(info, pos, OPT_IS_MUTATED, 0); -} - -static int optimize_escapes_after_k_tick(Optimize_Info *info, int pos) -/* pos is in new-frame counts */ -{ - return check_use(info, pos, OPT_ESCAPES_AFTER_K_TICK, 0); -} - -static int optimize_is_local_type_arg(Optimize_Info *info, int pos, int depth) -/* pos is in new-frame counts */ -{ - return check_use(info, pos, SCHEME_MAX_LOCAL_TYPE_MASK, OPT_LOCAL_TYPE_ARG_SHIFT); -} - -static int optimize_is_local_type_valued(Optimize_Info *info, int pos) -/* pos is in new-frame counts */ -{ - return check_use(info, pos, SCHEME_MAX_LOCAL_TYPE_MASK, OPT_LOCAL_TYPE_VAL_SHIFT); -} - -static void optimize_set_not_single_use(Optimize_Info *info, int pos) -/* pos is in new-frame counts */ -{ - Scheme_Object *p, *n; - - while (info) { - if (pos < info->new_frame) - break; - pos -= info->new_frame; - info = info->next; - } - - p = info->consts; - while (p) { - n = SCHEME_VEC_ELS(p)[1]; - if (SCHEME_INT_VAL(n) == pos) { - if (SCHEME_TRUEP(SCHEME_VEC_ELS(p)[3])) - SCHEME_VEC_ELS(p)[3] = scheme_false; - - break; - } - p = SCHEME_VEC_ELS(p)[0]; - } -} - -static int optimize_any_uses(Optimize_Info *info, int start_pos, int end_pos) -{ - int j, i; - - if (info->stat_dists) { - for (i = start_pos; i < end_pos; i++) { - for (j = info->sd_depths[i]; j--; ) { - if (info->stat_dists[i][j]) - return 1; - } - } - } - - if (info->transitive_use) { - for (i = info->new_frame; i--; ) { - if (info->transitive_use[i]) { - for (j = info->transitive_use_len[i]; j--; ) { - if ((info->transitive_use[i][j] >= start_pos) - && (info->transitive_use[i][j] < end_pos)) + while (n--) { + for (i = clv->count; i--; ) { + if (clv->vars[i]->optimize_used) + return 1; + for (j = at_clv->count; j--; ) { + if (at_clv->vars[j]->optimize.transitive_uses) { + if (scheme_hash_get(at_clv->vars[j]->optimize.transitive_uses, + (Scheme_Object *)clv->vars[i])) return 1; } } } + clv = (Scheme_Compiled_Let_Value *)clv->body; } return 0; } -static Scheme_Object *do_optimize_info_lookup(Optimize_Info *info, int pos, int j, int *closure_offset, int *single_use, - int *not_ready, int once_used_ok, int context, int *potential_size, - int disrupt_single_use, int *is_mutated, int just_test) +static void register_use_at(Scheme_Compiled_Local *var, Optimize_Info *info) { - Scheme_Object *p, *n; - int delta = 0, orig_j = j, kclock = info->kclock; + if (var->optimize.lambda_depth < info->lambda_depth) + scheme_hash_set(info->uses, (Scheme_Object *)var, scheme_true); - while (info) { - if (info->flags & SCHEME_LAMBDA_FRAME) - j++; - if (pos < info->original_frame) - break; - pos -= info->original_frame; - delta += info->new_frame; - info = info->next; + if (!var->optimize_used) { + var->optimize_used = 1; + + if (info->transitive_use_var + && (var->optimize.lambda_depth + <= info->transitive_use_var->optimize.transitive_uses_to->lambda_depth)) { + Scheme_Hash_Table *ht = info->transitive_use_var->optimize.transitive_uses; + + if (!ht) { + ht = scheme_make_hash_table(SCHEME_hash_ptr); + info->transitive_use_var->optimize.transitive_uses = ht; + } + scheme_hash_set(ht, (Scheme_Object *)var, scheme_true); + } + + if (var->optimize.transitive_uses) + register_transitive(var); } +} + +static Scheme_Object *optimize_info_lookup(Optimize_Info *info, Scheme_Object *var, int closure_ok, int *single_use, + int once_used_ok, int context, int *potential_size, int *is_mutated) +{ + Scheme_Object *n; + int kclock = info->kclock; + + MZ_ASSERT(SCHEME_VAR(var)->mode == SCHEME_VAR_MODE_OPTIMIZE); + MZ_ASSERT(SCHEME_VAR(var)->use_count); if (OPT_CONTEXT_TYPE(context)) - register_use(info, pos, OPT_CONTEXT_TYPE(context) << OPT_LOCAL_TYPE_ARG_SHIFT); - else if (!just_test && (kclock > info->init_kclock)) - register_use(info, pos, OPT_ESCAPES_AFTER_K_TICK); + SCHEME_VAR(var)->arg_type = OPT_CONTEXT_TYPE(context); + if (kclock > SCHEME_VAR(var)->optimize.init_kclock) + SCHEME_VAR(var)->escapes_after_k_tick = 1; - if (is_mutated) - if (info->use && (info->use[pos] & OPT_IS_MUTATED)) - *is_mutated = 1; + if (is_mutated && SCHEME_VAR(var)->mutated) + *is_mutated = 1; + if (single_use) + *single_use = ((SCHEME_VAR(var)->use_count == 1) + /* If we're outside the binding, then the binding + itself will remain as a used: */ + && !SCHEME_VAR(var)->optimize_outside_binding + /* To help avoid infinite unrolling, + don't count a self use as "single" use. */ + && !SCHEME_VAR(var)->optimize_unready); - if (just_test) return NULL; - - p = info->consts; - while (p) { - n = SCHEME_VEC_ELS(p)[1]; - if (SCHEME_INT_VAL(n) == pos) { - n = SCHEME_VEC_ELS(p)[2]; - if (info->flags & SCHEME_POST_BIND_FRAME) - delta += info->new_frame; - if (SCHEME_RPAIRP(n)) { - /* This was a letrec-bound identifier that may or may not be ready, - but which wasn't replaced with more information. */ - if (not_ready) - *not_ready = SCHEME_TRUEP(SCHEME_CAR(n)); - break; - } - if (SCHEME_BOXP(n)) { - /* A potential-size record: */ - if (potential_size) - *potential_size = (int)SCHEME_INT_VAL(SCHEME_BOX_VAL(n)); - break; - } - if (single_use) - *single_use = SCHEME_TRUEP(SCHEME_VEC_ELS(p)[3]); + n = SCHEME_VAR(var)->optimize.known_val; + if (n) { + if (SCHEME_BOXP(n)) { + /* A potential-size record: */ + if (potential_size) + *potential_size = (int)SCHEME_INT_VAL(SCHEME_BOX_VAL(n)); + } else { if (SAME_TYPE(SCHEME_TYPE(n), scheme_compiled_unclosed_procedure_type)) { if (context & OPT_CONTEXT_BOOLEAN) return scheme_true; - if (!closure_offset) - break; - else - *closure_offset = delta; + if (closure_ok) return n; } else if (SAME_TYPE(SCHEME_TYPE(n), scheme_case_lambda_sequence_type)) { if (context & OPT_CONTEXT_BOOLEAN) return scheme_true; - if (!closure_offset) - break; - else - *closure_offset = delta; + if (closure_ok) return n; } else if (SAME_TYPE(SCHEME_TYPE(n), scheme_compiled_toplevel_type)) { - /* Ok */ - } else if (closure_offset) { - /* Inlining can deal procedures and top-levels, but not other things. */ - return NULL; + return n; + } else if (closure_ok) { + /* Inlining can deal with procedures and top-levels, but not other things. */ } else if (SAME_TYPE(SCHEME_TYPE(n), scheme_once_used_type)) { - Scheme_Once_Used *o; - - if (disrupt_single_use) { - ((Scheme_Once_Used *)n)->expr = NULL; - ((Scheme_Once_Used *)n)->vclock = -1; + MZ_ASSERT(!((Scheme_Once_Used *)n)->moved); + MZ_ASSERT(!SCHEME_VAR(var)->optimize_outside_binding); + if (once_used_ok) { + /* In case this variable was tenatively used before: */ + SCHEME_VAR(var)->optimize_used = 0; + return n; } + } else if (SAME_TYPE(SCHEME_TYPE(n), scheme_compiled_local_type)) { + Scheme_Object *v2; + int cnt = SCHEME_VAR(var)->use_count; - if (!once_used_ok) - break; + v2 = optimize_info_lookup(info, n, 0, single_use, + once_used_ok && (cnt == 1), context, + potential_size, NULL); - o = (Scheme_Once_Used *)n; - if (!o->expr) break; /* disrupted or not available */ - - o->delta = delta; - o->info = info; - o->cross_lambda = (j != orig_j); - return (Scheme_Object *)o; - } else if (SAME_TYPE(SCHEME_TYPE(n), scheme_local_type)) { - int pos, cross_lambda = (j != orig_j); - - pos = SCHEME_LOCAL_POS(n); - if (info->flags & SCHEME_LAMBDA_FRAME) - j--; /* because it will get re-added on recur */ - else if (info->flags & SCHEME_POST_BIND_FRAME) - info = info->next; /* bindings are relative to next frame */ - - /* Marks local as used; we don't expect to get back - a value, because chaining would normally happen on the - propagate-call side. Chaining there also means that we - avoid stack overflow here. */ - if (single_use) { - if (!*single_use) - single_use = NULL; + if (v2) + return v2; + else { + if (cnt != 1) + increment_use_count(SCHEME_VAR(n), 0); + return n; } - - /* If the referenced variable is not single-use, then - the variable it is replaced by is no longer single-use */ - disrupt_single_use = !SCHEME_TRUEP(SCHEME_VEC_ELS(p)[3]); - - n = do_optimize_info_lookup(info, pos, j, NULL, single_use, NULL, - once_used_ok && !disrupt_single_use, context, - potential_size, disrupt_single_use, NULL, 0); - - if (!n) { - /* Return shifted reference to other local: */ - delta += optimize_info_get_shift(info, pos); - n = scheme_make_local(scheme_local_type, pos + delta, 0); - } else if (SAME_TYPE(SCHEME_TYPE(n), scheme_once_used_type)) { - /* Need to adjust delta: */ - delta += optimize_info_get_shift(info, pos); - ((Scheme_Once_Used *)n)->delta += delta; - if (cross_lambda) ((Scheme_Once_Used *)n)->cross_lambda = 1; - } - } - return n; + } else + return n; } - p = SCHEME_VEC_ELS(p)[0]; } - if (!closure_offset) - register_stat_dist(info, pos, j); + if (!closure_ok) + register_use_at(SCHEME_VAR(var), info); return NULL; } -static Scheme_Object *optimize_info_lookup(Optimize_Info *info, int pos, int *closure_offset, int *single_use, - int once_used_ok, int context, int *potential_size, int *is_mutated) -{ - return do_optimize_info_lookup(info, pos, 0, closure_offset, single_use, NULL, once_used_ok, context, - potential_size, 0, is_mutated, 0); -} - -static int optimize_info_is_ready(Optimize_Info *info, int pos) -{ - int closure_offset, single_use, ready = 1; - - do_optimize_info_lookup(info, pos, 0, &closure_offset, &single_use, &ready, 0, 0, NULL, 0, NULL, 0); - - return ready; -} - -static Scheme_Object *optimize_info_mutated_lookup(Optimize_Info *info, int pos, int *is_mutated) -{ - return do_optimize_info_lookup(info, pos, 0, NULL, NULL, NULL, 0, 0, NULL, 0, is_mutated, 1); -} - -Scheme_Object *do_optimize_get_predicate(Optimize_Info *info, int pos, int ignore_no_types) -/* pos is in new-frame counts */ +Scheme_Object *do_optimize_get_predicate(Optimize_Info *info, Scheme_Object *var, int ignore_no_types) { Scheme_Object *pred; @@ -9165,23 +8290,19 @@ Scheme_Object *do_optimize_get_predicate(Optimize_Info *info, int pos, int ignor while (info) { if (info->types) { - pred = scheme_hash_tree_get(info->types, scheme_make_integer(pos)); + pred = scheme_hash_tree_get(info->types, var); if (pred) return pred; } - pos -= info->new_frame; - if (pos < 0) - return NULL; info = info->next; } return NULL; } -Scheme_Object *optimize_get_predicate(Optimize_Info *info, int pos) -/* pos is in new-frame counts */ +Scheme_Object *optimize_get_predicate(Optimize_Info *info, Scheme_Object *var) { - return do_optimize_get_predicate(info, pos, 0); + return do_optimize_get_predicate(info, var, 0); } static Optimize_Info *optimize_info_add_frame(Optimize_Info *info, int orig, int current, int flags) @@ -9194,7 +8315,6 @@ static Optimize_Info *optimize_info_add_frame(Optimize_Info *info, int orig, int naya->original_frame = orig; naya->new_frame = current; naya->inline_fuel = info->inline_fuel; - naya->shift_fuel = info->shift_fuel; naya->flatten_fuel = info->flatten_fuel; naya->letrec_not_twice = info->letrec_not_twice; naya->enforce_const = info->enforce_const; @@ -9210,28 +8330,13 @@ static Optimize_Info *optimize_info_add_frame(Optimize_Info *info, int orig, int naya->use_psize = info->use_psize; naya->logger = info->logger; naya->no_types = info->no_types; + naya->lambda_depth = info->lambda_depth + ((flags & SCHEME_LAMBDA_FRAME) ? 1 : 0); + naya->uses = info->uses; + naya->transitive_use_var = info->transitive_use_var; return naya; } -static int optimize_info_get_shift(Optimize_Info *info, int pos) -{ - int delta = 0; - - while (info) { - if (pos < info->original_frame) - break; - pos -= info->original_frame; - delta += (info->new_frame - info->original_frame); - info = info->next; - } - - if (!info) - scheme_signal_error("error looking for local-variable offset"); - - return delta; -} - static void optimize_info_done(Optimize_Info *info, Optimize_Info *parent) { if (!parent) parent = info->next; @@ -9243,7 +8348,6 @@ static void optimize_info_done(Optimize_Info *info, Optimize_Info *parent) parent->sclock = info->sclock; parent->escapes = info->escapes; parent->psize += info->psize; - parent->shift_fuel = info->shift_fuel; parent->flatten_fuel = info->flatten_fuel; if (info->has_nonleaf) parent->has_nonleaf = 1; diff --git a/racket/src/racket/src/resolve.c b/racket/src/racket/src/resolve.c index 7c65eb3ac2..a1b003db0c 100644 --- a/racket/src/racket/src/resolve.c +++ b/racket/src/racket/src/resolve.c @@ -41,19 +41,17 @@ struct Resolve_Info { MZTAG_IF_REQUIRED char use_jit, in_module, in_proc, enforce_const, no_lift; - int size, oldsize, count, pos; + int current_depth; + int current_lex_depth; int max_let_depth; /* filled in by sub-expressions */ Resolve_Prefix *prefix; Scheme_Hash_Table *stx_map; /* compile offset => resolve offset; prunes prefix-recored stxes */ - mzshort toplevel_pos; /* -1 means consult `next' */ + mzshort toplevel_pos; void *tl_map; /* fixnum or bit array (as array of `int's) indicating which globals+lifts in prefix are used */ - mzshort *old_pos; - mzshort *new_pos; int stx_count; mzshort *old_stx_pos; /* NULL => consult next; new pos is index in array */ - int *flags; - Scheme_Object **lifted; /* maps bindings to lifts */ - Scheme_Object *lifts; /* accumulates lift info */ + Scheme_Hash_Tree *redirects; + Scheme_Object *lifts; struct Resolve_Info *next; }; @@ -63,13 +61,13 @@ static Scheme_Object * resolve_closure_compilation(Scheme_Object *_data, Resolve_Info *info, int can_lift, int convert, int just_compute_lift, Scheme_Object *precomputed_lift); -static Resolve_Info *resolve_info_extend(Resolve_Info *info, int size, int oldsize, int mapcount); -static void resolve_info_add_mapping(Resolve_Info *info, int oldp, int newp, int flags, Scheme_Object *lifted); -static void resolve_info_adjust_mapping(Resolve_Info *info, int oldp, int newp, int flags, Scheme_Object *lifted); -static int resolve_info_flags(Resolve_Info *info, int pos, Scheme_Object **lifted); -static int resolve_info_lookup(Resolve_Info *resolve, int pos, int *flags, Scheme_Object **lifted, int convert_shift); +static Resolve_Info *resolve_info_extend(Resolve_Info *info, int size, int lambda); +static void resolve_info_add_mapping(Resolve_Info *info, Scheme_Compiled_Local *var, Scheme_Object *v); +static int resolve_info_lookup(Resolve_Info *resolve, Scheme_Compiled_Local *var, Scheme_Object **lifted, + int convert_shift, int flags); +static Scheme_Object *resolve_info_lift_added(Resolve_Info *resolve, Scheme_Object *var, int convert_shift); static void resolve_info_set_toplevel_pos(Resolve_Info *info, int pos); -static void merge_resolve_tl_map(Resolve_Info *info, Resolve_Info *new_info); +static void merge_resolve(Resolve_Info *info, Resolve_Info *new_info); static Scheme_Object *resolve_generate_stub_lift(void); static int resolve_toplevel_pos(Resolve_Info *info); static int resolve_quote_syntax_offset(int i, Resolve_Info *info); @@ -77,16 +75,20 @@ static int resolve_quote_syntax_pos(Resolve_Info *info); static Scheme_Object *resolve_toplevel(Resolve_Info *info, Scheme_Object *expr, int keep_ready); static Scheme_Object *resolve_invent_toplevel(Resolve_Info *info); static Scheme_Object *resolve_invented_toplevel_to_defn(Resolve_Info *info, Scheme_Object *tl); +static Scheme_Object *shift_lifted_reference(Scheme_Object *tl, Resolve_Info *info, int delta); static Scheme_Object *shift_toplevel(Scheme_Object *expr, int delta); -static int resolving_in_procedure(Resolve_Info *info); -static int is_nonconstant_procedure(Scheme_Object *data, Resolve_Info *info, int skip); +static int is_nonconstant_procedure(Scheme_Object *data, Resolve_Info *info, Scheme_Hash_Tree *exclude_vars); static int resolve_is_inside_proc(Resolve_Info *info); +static int resolve_has_toplevel(Resolve_Info *info); static void set_tl_pos_used(Resolve_Info *info, int pos); #ifdef MZ_PRECISE_GC static void register_traversers(void); #endif +#define RESOLVE_UNUSED_OK 0x1 +#define RESOLVE_IGNORE_LIFTS 0x2 + void scheme_init_resolve() { #ifdef MZ_PRECISE_GC @@ -102,12 +104,11 @@ static Scheme_Object *check_converted_rator(Scheme_Object *rator, Resolve_Info * int orig_arg_cnt, int *_rdelta) { Scheme_Object *lifted; - int flags; - if (!SAME_TYPE(SCHEME_TYPE(rator), scheme_local_type)) + if (!SAME_TYPE(SCHEME_TYPE(rator), scheme_compiled_local_type)) return NULL; - (void)resolve_info_lookup(info, SCHEME_LOCAL_POS(rator), &flags, &lifted, orig_arg_cnt + 1); + (void)resolve_info_lookup(info, SCHEME_VAR(rator), &lifted, 0, 0); if (lifted && SCHEME_RPAIRP(lifted)) { Scheme_Object *vec, *arity; @@ -116,6 +117,12 @@ static Scheme_Object *check_converted_rator(Scheme_Object *rator, Resolve_Info * vec = SCHEME_CDR(lifted); *_rdelta = 0; + if (SAME_TYPE(SCHEME_TYPE(*new_rator), scheme_toplevel_type)) { + Scheme_Object *tl; + tl = shift_lifted_reference(*new_rator, info, orig_arg_cnt + SCHEME_VEC_SIZE(vec) - 1); + *new_rator = tl; + } + if (SCHEME_VEC_SIZE(vec) > 1) { /* Check that actual argument count matches expected. If it doesn't, we need to generate explicit code to report @@ -183,17 +190,13 @@ static Scheme_Object *resolve_application(Scheme_Object *o, Resolve_Info *orig_i if (additions) { /* Expand application with m arguments */ Scheme_App_Rec *app2; - Scheme_Object *loc; + Scheme_Object *arg; int m; m = SCHEME_VEC_SIZE(additions) - 1; app2 = scheme_malloc_application(n + m); for (i = 0; i < m; i++) { - loc = SCHEME_VEC_ELS(additions)[i+1]; - if (SCHEME_BOXP(loc)) - loc = SCHEME_BOX_VAL(loc); - else if (SCHEME_VECTORP(loc)) - loc = SCHEME_VEC_ELS(loc)[0]; - app2->args[i + 1] = loc; + arg = resolve_info_lift_added(orig_info, SCHEME_VEC_ELS(additions)[i+1], n - 1 + m); + app2->args[i + 1] = arg; } for (i = 1; i < n; i++) { app2->args[i + m] = app->args[i]; @@ -208,7 +211,7 @@ static Scheme_Object *resolve_application(Scheme_Object *o, Resolve_Info *orig_i devals = sizeof(Scheme_App_Rec) + ((n - mzFLEX_DELTA) * sizeof(Scheme_Object *)); - info = resolve_info_extend(orig_info, n - 1, 0, 0); + info = resolve_info_extend(orig_info, n - 1, 0); for (i = 0; i < n; i++) { Scheme_Object *le; @@ -220,10 +223,7 @@ static Scheme_Object *resolve_application(Scheme_Object *o, Resolve_Info *orig_i } } - info->max_let_depth += (n - 1); - if (orig_info->max_let_depth < info->max_let_depth) - orig_info->max_let_depth = info->max_let_depth; - merge_resolve_tl_map(orig_info, info); + merge_resolve(orig_info, info); for (i = 0; i < n; i++) { char et; @@ -256,7 +256,7 @@ static Scheme_Object *resolve_application2(Scheme_Object *o, Resolve_Info *orig_ { Resolve_Info *info; Scheme_App2_Rec *app; - Scheme_Object *le; + Scheme_Object *le, *arg; app = (Scheme_App2_Rec *)o; @@ -274,16 +274,11 @@ static Scheme_Object *resolve_application2(Scheme_Object *o, Resolve_Info *orig_ } else if (m > 1) { /* Expand application with m arguments */ Scheme_App_Rec *app2; - Scheme_Object *loc; int i; app2 = scheme_malloc_application(2 + m); for (i = 0; i < m; i++) { - loc = SCHEME_VEC_ELS(additions)[i+1]; - if (SCHEME_BOXP(loc)) - loc = SCHEME_BOX_VAL(loc); - else if (SCHEME_VECTORP(loc)) - loc = SCHEME_VEC_ELS(loc)[0]; - app2->args[i + 1] = loc; + arg = resolve_info_lift_added(orig_info, SCHEME_VEC_ELS(additions)[i+1], 1 + m); + app2->args[i + 1] = arg; } app2->args[0] = rator; app2->args[m+1] = app->rand; @@ -291,24 +286,19 @@ static Scheme_Object *resolve_application2(Scheme_Object *o, Resolve_Info *orig_ return resolve_application((Scheme_Object *)app2, orig_info, m + 1 + rdelta); } else { Scheme_App3_Rec *app2; - Scheme_Object *loc; app2 = MALLOC_ONE_TAGGED(Scheme_App3_Rec); app2->iso.so.type = scheme_application3_type; app2->rator = rator; - loc = SCHEME_VEC_ELS(additions)[1]; - if (SCHEME_BOXP(loc)) - loc = SCHEME_BOX_VAL(loc); - else if (SCHEME_VECTORP(loc)) - loc = SCHEME_VEC_ELS(loc)[0]; - app2->rand1 = loc; + arg = resolve_info_lift_added(orig_info, SCHEME_VEC_ELS(additions)[1], 1 + 1); + app2->rand1 = arg; app2->rand2 = app->rand; SCHEME_APPN_FLAGS(app2) |= APPN_FLAG_SFS_TAIL; - return resolve_application3((Scheme_Object *)app2, orig_info, 2 + rdelta); + return resolve_application3((Scheme_Object *)app2, orig_info, m + 1 + rdelta); } } } - info = resolve_info_extend(orig_info, 1, 0, 0); + info = resolve_info_extend(orig_info, 1, 0); if (!already_resolved_arg_count) { le = scheme_resolve_expr(app->rator, info); @@ -322,10 +312,7 @@ static Scheme_Object *resolve_application2(Scheme_Object *o, Resolve_Info *orig_ } else already_resolved_arg_count--; - info->max_let_depth += 1; - if (orig_info->max_let_depth < info->max_let_depth) - orig_info->max_let_depth = info->max_let_depth; - merge_resolve_tl_map(orig_info, info); + merge_resolve(orig_info, info); set_app2_eval_type(app); @@ -376,15 +363,11 @@ static Scheme_Object *resolve_application3(Scheme_Object *o, Resolve_Info *orig_ if (m) { /* Expand application with m arguments */ Scheme_App_Rec *app2; - Scheme_Object *loc; + Scheme_Object *arg; app2 = scheme_malloc_application(3 + m); for (i = 0; i < m; i++) { - loc = SCHEME_VEC_ELS(additions)[i+1]; - if (SCHEME_BOXP(loc)) - loc = SCHEME_BOX_VAL(loc); - else if (SCHEME_VECTORP(loc)) - loc = SCHEME_VEC_ELS(loc)[0]; - app2->args[i + 1] = loc; + arg = resolve_info_lift_added(orig_info, SCHEME_VEC_ELS(additions)[i+1], 2 + m); + app2->args[i + 1] = arg; } app2->args[0] = rator; app2->args[m+1] = app->rand1; @@ -398,7 +381,7 @@ static Scheme_Object *resolve_application3(Scheme_Object *o, Resolve_Info *orig_ } } - info = resolve_info_extend(orig_info, 2, 0, 0); + info = resolve_info_extend(orig_info, 2, 0); if (already_resolved_arg_count) { already_resolved_arg_count--; @@ -434,10 +417,7 @@ static Scheme_Object *resolve_application3(Scheme_Object *o, Resolve_Info *orig_ set_app3_eval_type(app); - info->max_let_depth += 2; - if (orig_info->max_let_depth < info->max_let_depth) - orig_info->max_let_depth = info->max_let_depth; - merge_resolve_tl_map(orig_info, info); + merge_resolve(orig_info, info); return (Scheme_Object *)app; } @@ -496,7 +476,7 @@ static Scheme_Object *look_for_letv_change(Scheme_Sequence *s) v = s->array[i]; if (SAME_TYPE(SCHEME_TYPE(v), scheme_let_value_type)) { Scheme_Let_Value *lv = (Scheme_Let_Value *)v; - if (scheme_omittable_expr(lv->body, 1, -1, 0, NULL, NULL, 0, 0, 0)) { + if (scheme_omittable_expr(lv->body, 1, -1, 0, NULL, NULL)) { int esize = s->count - (i + 1); int nsize = i + 1; Scheme_Object *nv, *ev; @@ -644,25 +624,24 @@ set_resolve(Scheme_Object *data, Resolve_Info *rslv) val = scheme_resolve_expr(val, rslv); - if (SAME_TYPE(SCHEME_TYPE(var), scheme_local_type)) { + if (SAME_TYPE(SCHEME_TYPE(var), scheme_compiled_local_type)) { Scheme_Let_Value *lv; Scheme_Object *cv; - int flags, li; + int li; + MZ_ASSERT(SCHEME_VAR(var)->mutated); + cv = scheme_compiled_void(); lv = MALLOC_ONE_TAGGED(Scheme_Let_Value); lv->iso.so.type = scheme_let_value_type; lv->body = cv; lv->count = 1; - li = resolve_info_lookup(rslv, SCHEME_LOCAL_POS(var), &flags, NULL, 0); + li = resolve_info_lookup(rslv, SCHEME_VAR(var), NULL, 0, 0); lv->position = li; - SCHEME_LET_VALUE_AUTOBOX(lv) = (flags & SCHEME_INFO_BOXED); + SCHEME_LET_VALUE_AUTOBOX(lv) = 1; lv->value = val; - if (!(flags & SCHEME_INFO_BOXED)) - scheme_signal_error("internal error: set!: set!ed local variable is not boxed"); - return (Scheme_Object *)lv; } @@ -688,7 +667,7 @@ ref_resolve(Scheme_Object *data, Resolve_Info *rslv) if (SCHEME_TRUEP(v)) SCHEME_VARREF_FLAGS(data) |= 0x1; /* => constant */ v = SCHEME_PTR2_VAL(data); - } else if (SAME_TYPE(SCHEME_TYPE(v), scheme_local_type)) { + } else if (SAME_TYPE(SCHEME_TYPE(v), scheme_compiled_local_type)) { v = scheme_resolve_expr(v, rslv); if (SAME_TYPE(SCHEME_TYPE(v), scheme_local_type)) SCHEME_VARREF_FLAGS(data) |= 0x1; /* because mutable would be unbox */ @@ -717,11 +696,19 @@ apply_values_resolve(Scheme_Object *data, Resolve_Info *rslv) return data; } +static void set_resolve_mode(Scheme_Compiled_Local *var) +{ + MZ_ASSERT(SAME_TYPE(var->so.type, scheme_compiled_local_type)); + memset(&var->resolve, 0, sizeof(var->resolve)); + var->mode = SCHEME_VAR_MODE_RESOLVE; +} + static Scheme_Object * with_immed_mark_resolve(Scheme_Object *data, Resolve_Info *orig_rslv) { Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)data; Scheme_Object *e; + Scheme_Compiled_Local *var; Resolve_Info *rslv = orig_rslv; e = scheme_resolve_expr(wcm->key, rslv); @@ -730,16 +717,17 @@ with_immed_mark_resolve(Scheme_Object *data, Resolve_Info *orig_rslv) e = scheme_resolve_expr(wcm->val, rslv); wcm->val = e; - rslv = resolve_info_extend(rslv, 1, 1, 1); - resolve_info_add_mapping(rslv, 0, 0, 0, NULL); + rslv = resolve_info_extend(rslv, 1, 0); + + var = SCHEME_VAR(SCHEME_CAR(wcm->body)); + set_resolve_mode(var); + var->resolve.co_depth = rslv->current_depth; + var->resolve.lex_depth = rslv->current_lex_depth; - e = scheme_resolve_expr(wcm->body, rslv); + e = scheme_resolve_expr(SCHEME_CDR(wcm->body), rslv); wcm->body = e; - rslv->max_let_depth += 1; - if (orig_rslv->max_let_depth < rslv->max_let_depth) - orig_rslv->max_let_depth = rslv->max_let_depth; - merge_resolve_tl_map(orig_rslv, rslv); + merge_resolve(orig_rslv, rslv); return data; } @@ -886,37 +874,13 @@ static int is_closed_reference(Scheme_Object *v) static Scheme_Object *scheme_resolve_generate_stub_closure() { Scheme_Closure *cl; - Scheme_Object **ca; + Scheme_Object *ca; cl = scheme_malloc_empty_closure(); - ca = MALLOC_N(Scheme_Object*, 4); - ca[0] = scheme_make_integer(0); - ca[1] = NULL; - ca[2] = scheme_make_integer(0); - ca[3] = NULL; + ca = scheme_make_vector(1, scheme_make_integer(0)); - return scheme_make_raw_pair((Scheme_Object *)cl, (Scheme_Object *)ca); -} - -static void shift_lift(Scheme_Object *lifted, int frame_size, int lifted_frame_size) -{ - int i, cnt, delta; - Scheme_Object **ca; - mzshort *map; - - if (!lifted) return; - if (!SCHEME_RPAIRP(lifted)) return; - - ca = (Scheme_Object **)SCHEME_CDR(lifted); - cnt = SCHEME_INT_VAL(ca[0]); - map = (mzshort *)ca[1]; - - delta = (frame_size - lifted_frame_size); - - for (i = 0; i < cnt; i++) { - map[i] += delta; - } + return scheme_make_raw_pair((Scheme_Object *)cl, ca); } static int get_convert_arg_count(Scheme_Object *lift) @@ -924,21 +888,21 @@ static int get_convert_arg_count(Scheme_Object *lift) if (!lift) return 0; else if (SCHEME_RPAIRP(lift)) { - Scheme_Object **ca; - ca = (Scheme_Object **)SCHEME_CDR(lift); - return SCHEME_INT_VAL(ca[0]); + lift = SCHEME_CDR(lift); + MZ_ASSERT(SCHEME_VECTORP(lift)); + return SCHEME_VEC_SIZE(lift) - 1; } else return 0; } -static mzshort* get_convert_arg_map(Scheme_Object *lift) +static Scheme_Object *get_convert_arg_map(Scheme_Object *lift) { if (!lift) return NULL; else if (SCHEME_RPAIRP(lift)) { - Scheme_Object **ca; - ca = (Scheme_Object **)SCHEME_CDR(lift); - return (mzshort *)ca[1]; + lift = SCHEME_CDR(lift); + MZ_ASSERT(SCHEME_VECTORP(lift)); + return lift; } else return NULL; } @@ -960,32 +924,32 @@ static Scheme_Object *drop_zero_value_return(Scheme_Object *expr) return NULL; } -#define NUM_SKIPS_FAST 5 +#define HAS_UNBOXABLE_TYPE(var) ((var)->val_type && (!(var)->escapes_after_k_tick || ALWAYS_PREFER_UNBOX_TYPE((var)->val_type))) Scheme_Object * scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) { - Resolve_Info *linfo, *val_linfo = NULL; + Resolve_Info *linfo; Scheme_Let_Header *head = (Scheme_Let_Header *)form; Scheme_Compiled_Let_Value *clv, *pre_body; Scheme_Let_Value *lv, *last = NULL; Scheme_Object *first = NULL, *body, *last_body = NULL, *last_seq = NULL; Scheme_Letrec *letrec; - mzshort *skips, skips_fast[NUM_SKIPS_FAST]; - char *local_types, local_types_fast[NUM_SKIPS_FAST]; - Scheme_Object **lifted, *lifted_fast[NUM_SKIPS_FAST], *boxes; - int i, pos, opos, rpos, recbox, num_rec_procs = 0, extra_alloc; + Scheme_Object *boxes; + int i, j, pos, rpos, recbox, num_rec_procs = 0, extra_alloc; int rec_proc_nonapply = 0; - int max_let_depth = 0; - int resolve_phase, num_skips; - Scheme_Object **lifted_recs; - int post_bind = !(SCHEME_LET_FLAGS(head) & (SCHEME_LET_RECURSIVE | SCHEME_LET_STAR)); + int resolve_phase, num_skips, lifted_recs; + Scheme_Hash_Tree *lift_exclude_vars; - /* Find body: */ + /* Find body and make a set of local bindings: */ body = head->body; pre_body = NULL; + lift_exclude_vars = scheme_make_hash_tree(0); for (i = head->num_clauses; i--; ) { pre_body = (Scheme_Compiled_Let_Value *)body; + for (j = 0; j < pre_body->count; j++) { + lift_exclude_vars = scheme_hash_tree_set(lift_exclude_vars, (Scheme_Object *)pre_body->vars[j], scheme_true); + } body = pre_body->body; } @@ -996,9 +960,11 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) for (i = head->num_clauses; i--; clv = (Scheme_Compiled_Let_Value *)clv->body) { int is_proc, is_lift; - if ((clv->count == 1) - && !(clv->flags[0] & SCHEME_WAS_USED)) { - /* skip */ + if ((clv->count == 1) + && !clv->vars[0]->optimize_used + && scheme_omittable_expr(clv->value, clv->count, -1, 0, NULL, NULL)) { + /* record omittable, so we don't have to keep checking: */ + clv->vars[0]->resolve_omittable = 1; } else { if (clv->count == 1) is_proc = scheme_is_compiled_procedure(clv->value, 1, 1); @@ -1010,7 +976,7 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) else if (SCHEME_CLV_FLAGS(clv) & SCHEME_CLV_NO_GROUP_USES) is_lift = 1; else - is_lift = scheme_is_liftable(clv->value, head->count, 5, 1, 0); + is_lift = scheme_is_liftable(clv->value, lift_exclude_vars, 5, 1, 0); if (!is_proc && !is_lift) { recbox = 1; @@ -1021,7 +987,7 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) int j; for (j = 0; j < clv->count; j++) { - if (clv->flags[j] & SCHEME_WAS_SET_BANGED) { + if (clv->vars[j]->mutated) { recbox = 1; break; } @@ -1029,9 +995,9 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) if (recbox) break; - if (is_nonconstant_procedure(clv->value, info, head->count)) { + if (is_nonconstant_procedure(clv->value, info, lift_exclude_vars)) { num_rec_procs++; - if (!(clv->flags[0] & SCHEME_WAS_ONLY_APPLIED)) + if (clv->vars[0]->non_app_count) rec_proc_nonapply = 1; } } @@ -1048,199 +1014,92 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) for (i = head->num_clauses; i--; clv = (Scheme_Compiled_Let_Value *)clv->body) { if (clv->count != 1) break; - if (clv->flags[0] & SCHEME_WAS_SET_BANGED) + if (clv->vars[0]->mutated) break; } if (i < 0) { /* Yes - build chain of Scheme_Let_Ones and we're done: */ - int skip_count = 0, frame_size, lifts_frame_size = 0; - int j, k, n, rev_bind_order = 0; - - if (head->num_clauses > 1) { - clv = (Scheme_Compiled_Let_Value *)head->body; - if (clv->position > ((Scheme_Compiled_Let_Value *)clv->body)->position) - rev_bind_order = 1; - } + int j, num_frames; j = head->num_clauses; - if (j <= NUM_SKIPS_FAST) { - skips = skips_fast; - lifted = lifted_fast; - local_types = local_types_fast; - } else { - skips = MALLOC_N_ATOMIC(mzshort, j); - lifted = MALLOC_N(Scheme_Object*, j); - local_types = MALLOC_N_ATOMIC(char, j); - } clv = (Scheme_Compiled_Let_Value *)head->body; for (i = 0; i < j; i++, clv = (Scheme_Compiled_Let_Value *)clv->body) { - int aty, pty; - - if (!(clv->flags[0] & SCHEME_WAS_USED)) - skips[i] = 1; - else - skips[i] = 0; - - aty = SCHEME_WAS_TYPED_ARGUMENT(clv->flags[0]); - pty = scheme_expr_produces_local_type(clv->value); - if (pty && ((pty == aty) || ALWAYS_PREFER_UNBOX_TYPE(pty))) - local_types[i] = pty; - else - local_types[i] = 0; - lifted[i] = NULL; + if (clv->vars[0]->optimize_used) { + int aty, pty, involes_k_cross; + aty = clv->vars[0]->arg_type; + pty = scheme_expr_produces_local_type(clv->value, &involes_k_cross); + if (pty && !involes_k_cross && ((pty == aty) || ALWAYS_PREFER_UNBOX_TYPE(pty))) + clv->vars[0]->val_type = pty; + else + clv->vars[0]->val_type = 0; + } } clv = (Scheme_Compiled_Let_Value *)head->body; + linfo = info; + num_frames = 0; for (i = 0; i < head->num_clauses; i++, clv = (Scheme_Compiled_Let_Value *)clv->body) { Scheme_Object *le; - if (!(clv->flags[0] & SCHEME_WAS_USED)) { - skip_count++; - } + if (!clv->vars[0]->optimize_used + && scheme_omittable_expr(clv->value, clv->count, -1, 0, NULL, NULL)) { + /* unused and omittable; skip */ + } else { + linfo = resolve_info_extend(linfo, 1, 0); + num_frames++; + set_resolve_mode(clv->vars[0]); + clv->vars[0]->resolve.co_depth = linfo->current_depth; + clv->vars[0]->resolve.lex_depth = linfo->current_lex_depth; - /* First `i+1' bindings now exist "at runtime", except those skipped. */ - /* The mapping is complicated because we now push in the order of - the variables, but it may have been compiled using the inverse order. */ - frame_size = i + 1 - skip_count; - if (lifts_frame_size != frame_size) { - /* We need to shift coordinates for any lifted[j] that is a - converted procedure. */ - for (j = i, k = 0; j >= 0; j--) { - shift_lift(lifted[j], frame_size, lifts_frame_size); - } - } - if (post_bind) { - linfo = resolve_info_extend(info, frame_size, 0, 0); - } else { - linfo = resolve_info_extend(info, frame_size, head->count, i + 1); - for (j = i, k = 0; j >= 0; j--) { - n = (rev_bind_order ? (head->count - j - 1) : j); - if (skips[j]) - resolve_info_add_mapping(linfo, n, -1, local_types[j] << SCHEME_INFO_TYPED_VAL_SHIFT, lifted[j]); - else - resolve_info_add_mapping(linfo, n, k++, local_types[j] << SCHEME_INFO_TYPED_VAL_SHIFT, lifted[j]); - } - } - lifts_frame_size = frame_size; - - if (skips[i]) { - le = scheme_void; - } else { - if ((clv->flags[0] & SCHEME_WAS_ONLY_APPLIED) + if (!info->no_lift + && !clv->vars[0]->non_app_count && SAME_TYPE(SCHEME_TYPE(clv->value), scheme_compiled_unclosed_procedure_type)) le = resolve_closure_compilation(clv->value, linfo, 1, 1, 0, NULL); else le = scheme_resolve_expr(clv->value, linfo); - } - if (max_let_depth < linfo->max_let_depth + frame_size) - max_let_depth = linfo->max_let_depth + frame_size; - merge_resolve_tl_map(info, linfo); + if (is_lifted_reference(le)) { + MZ_ASSERT(!info->no_lift); + clv->vars[0]->resolve.lifted = le; + /* Use of binding will be replaced by lift, so drop binding. */ + linfo = linfo->next; + --num_frames; + } else { + Scheme_Let_One *lo; + int et; - if (is_lifted_reference(le)) { - lifted[i] = le; - - /* At this point, it's ok to change our mind - about skipping, because compilation for previous - RHSs did not look at this one. */ - if (!skips[i]) { - skips[i] = 1; - skip_count++; + clv->vars[0]->resolve.lifted = NULL; + + lo = MALLOC_ONE_TAGGED(Scheme_Let_One); + lo->iso.so.type = scheme_let_one_type; + MZ_ASSERT(!SCHEME_RPAIRP(le)); + lo->value = le; + + et = scheme_get_eval_type(lo->value); + if (HAS_UNBOXABLE_TYPE(clv->vars[0])) + et |= (clv->vars[0]->val_type << LET_ONE_TYPE_SHIFT); + SCHEME_LET_EVAL_TYPE(lo) = et; + + if (last) + ((Scheme_Let_One *)last)->body = (Scheme_Object *)lo; + else + first = (Scheme_Object *)lo; + last = (Scheme_Let_Value *)lo; } } - - if (skips[i]) { - /* Unused binding, so drop it. */ - } else { - Scheme_Let_One *lo; - int et; - - lo = MALLOC_ONE_TAGGED(Scheme_Let_One); - lo->iso.so.type = scheme_let_one_type; - lo->value = le; - - et = scheme_get_eval_type(lo->value); - if (local_types[i]) - et |= (local_types[i] << LET_ONE_TYPE_SHIFT); - SCHEME_LET_EVAL_TYPE(lo) = et; - - if (last) - ((Scheme_Let_One *)last)->body = (Scheme_Object *)lo; - else - first = (Scheme_Object *)lo; - last = (Scheme_Let_Value *)lo; - } } - frame_size = head->count - skip_count; - linfo = resolve_info_extend(info, frame_size, head->count, head->count); - - if (lifts_frame_size != frame_size) { - for (i = head->count; i--; ) { - /* We need to shift coordinates for any lifted[j] that is a - converted procedure. */ - shift_lift(lifted[i], frame_size, lifts_frame_size); - } - } - - for (k = 0, i = head->count; i--; ) { - n = (rev_bind_order ? (head->count - i - 1) : i); - if ((skips[i] != 0) && (skips[i] != 1)) scheme_signal_error("trashed\n"); - if (skips[i]) - resolve_info_add_mapping(linfo, n, -1, local_types[i] << SCHEME_INFO_TYPED_VAL_SHIFT, lifted[i]); - else - resolve_info_add_mapping(linfo, n, k++, local_types[i] << SCHEME_INFO_TYPED_VAL_SHIFT, lifted[i]); - } - body = scheme_resolve_expr(body, linfo); if (last) ((Scheme_Let_One *)last)->body = body; - else { + else first = body; - } - if (max_let_depth < linfo->max_let_depth + frame_size) - max_let_depth = linfo->max_let_depth + frame_size; - - if (info->max_let_depth < max_let_depth) - info->max_let_depth = max_let_depth; - - merge_resolve_tl_map(info, linfo); - - /* Check for (let ([x ]) ( x)) at end, and change to - ( ). This transformation is more generally performed - at the optimization layer, the code here pre-dates the mode general - optimzation, and we keep it just in case. The simple case is easy here, - because the local-variable offsets in do not change (as long as - doesn't access the stack). */ - last_body = NULL; - body = first; - while (1) { - if (!SAME_TYPE(SCHEME_TYPE(body), scheme_let_one_type)) - break; - if (!SAME_TYPE(SCHEME_TYPE(((Scheme_Let_One *)body)->body), scheme_let_one_type)) - break; - last_body = body; - body = ((Scheme_Let_One *)body)->body; - } - if (SAME_TYPE(SCHEME_TYPE(body), scheme_let_one_type)) { - if (SAME_TYPE(SCHEME_TYPE(((Scheme_Let_One *)body)->body), scheme_application2_type)) { - Scheme_App2_Rec *app = (Scheme_App2_Rec *)((Scheme_Let_One *)body)->body; - if (SAME_TYPE(SCHEME_TYPE(app->rand), scheme_local_type) - && (SCHEME_LOCAL_POS(app->rand) == 1)) { - if (SCHEME_TYPE(app->rator) > _scheme_values_types_) { - /* Move to app, and drop let-one: */ - app->rand = ((Scheme_Let_One *)body)->value; - scheme_reset_app2_eval_type(app); - if (last_body) - ((Scheme_Let_One *)last_body)->body = (Scheme_Object *)app; - else - first = (Scheme_Object *)app; - } - } - } + for (i = 0; i < num_frames; i++) { + merge_resolve(linfo->next, linfo); + linfo = linfo->next; } return first; @@ -1248,28 +1107,26 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) /* Maybe some multi-binding lets, but all of them are unused and the RHSes are omittable? This can happen with auto-generated code. */ - int total = 0, j; + int j, any_used = 0; clv = (Scheme_Compiled_Let_Value *)head->body; for (i = head->num_clauses; i--; clv = (Scheme_Compiled_Let_Value *)clv->body) { - total += clv->count; for (j = clv->count; j--; ) { - if (clv->flags[j] & SCHEME_WAS_USED) + if (clv->vars[j]->optimize_used) { + any_used = 1; break; + } } - if (j >= 0) - break; - if (!scheme_omittable_expr(clv->value, clv->count, -1, 0, NULL, NULL, 0, 0, 0)) - break; + if (((clv->count == 1) || !any_used) + && scheme_omittable_expr(clv->value, clv->count, -1, 0, NULL, NULL)) { + if ((clv->count == 1) && !clv->vars[0]->optimize_used) + clv->vars[0]->resolve_omittable = 1; + } else + any_used = 1; } - if (i < 0) { + if (!any_used) { /* All unused and omittable */ - linfo = resolve_info_extend(info, 0, total, 0); - first = scheme_resolve_expr((Scheme_Object *)clv, linfo); - if (info->max_let_depth < linfo->max_let_depth) - info->max_let_depth = linfo->max_let_depth; - merge_resolve_tl_map(info, linfo); - return first; + return scheme_resolve_expr((Scheme_Object *)clv, info); } } } @@ -1277,8 +1134,9 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) num_skips = 0; clv = (Scheme_Compiled_Let_Value *)head->body; for (i = head->num_clauses; i--; clv = (Scheme_Compiled_Let_Value *)clv->body) { - if ((clv->count == 1) && !(clv->flags[0] & SCHEME_WAS_USED)) + if ((clv->count == 1) && clv->vars[0]->resolve_omittable) { num_skips++; + } } /* First assume that all letrec-bound procedures can be lifted to empty closures. @@ -1291,23 +1149,19 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) resolve_phase++) { /* Don't try plain lifting if we're not inside a proc: */ - if ((resolve_phase == 1) && !resolve_is_inside_proc(info)) + if ((resolve_phase == 1) && (!resolve_is_inside_proc(info) + || !resolve_has_toplevel(info))) resolve_phase = 2; if (resolve_phase < 2) { - linfo = resolve_info_extend(info, head->count - num_rec_procs - num_skips, head->count, head->count); - lifted_recs = MALLOC_N(Scheme_Object *, num_rec_procs); + linfo = resolve_info_extend(info, head->count - num_rec_procs - num_skips, 0); + lifted_recs = 1; } else { - linfo = resolve_info_extend(info, head->count - num_skips, head->count, head->count); - lifted_recs = NULL; + linfo = resolve_info_extend(info, head->count - num_skips, 0); + lifted_recs = 0; } - - if (post_bind) - val_linfo = resolve_info_extend(info, head->count - num_skips, 0, 0); - else - val_linfo = linfo; - /* Build mapping of compile-time indices to run-time indices, shuffling + /* Build mapping to run-time indices, shuffling letrecs to fall together in the shallowest part. Also determine and initialize lifts for recursive procedures. Generating lift information requires an iteration. */ @@ -1317,45 +1171,42 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) for (i = head->num_clauses; i--; clv = (Scheme_Compiled_Let_Value *)clv->body) { int j; - opos = clv->position; - - if ((clv->count == 1) && !(clv->flags[0] & SCHEME_WAS_USED)) { + if ((clv->count == 1) + && !clv->vars[0]->optimize_used + && clv->vars[0]->resolve_omittable) { /* skipped */ - resolve_info_add_mapping(linfo, opos, 0, 0, NULL); } else { for (j = 0; j < clv->count; j++) { - int p; Scheme_Object *lift; - if (num_rec_procs + set_resolve_mode(clv->vars[j]); + if (recbox) + clv->vars[j]->mutated = 1; + + if (num_rec_procs && (clv->count == 1) - && is_nonconstant_procedure(clv->value, info, head->count)) { - if (resolve_phase == 0) { + && is_nonconstant_procedure(clv->value, info, lift_exclude_vars)) { + MZ_ASSERT(!recbox); + if (resolve_phase == 0) lift = scheme_resolve_generate_stub_closure(); - lifted_recs[rpos] = lift; - p = 0; - } else if (resolve_phase == 1) { + else if (resolve_phase == 1) lift = resolve_generate_stub_lift(); - lifted_recs[rpos] = lift; - p = 0; - } else { + else lift = NULL; - p = rpos; - } + MZ_ASSERT(!info->no_lift || !lift); + clv->vars[0]->resolve.lifted = lift; + clv->vars[0]->resolve.co_depth = linfo->current_depth - rpos; + clv->vars[0]->resolve.lex_depth = linfo->current_lex_depth - rpos; rpos++; } else { - p = pos++; - lift = NULL; + clv->vars[j]->resolve.lifted = NULL; + clv->vars[j]->resolve.co_depth = linfo->current_depth - pos; + clv->vars[j]->resolve.lex_depth = linfo->current_lex_depth - pos; + /* Since Scheme_Let_Value doesn't record type info, we have + to drop any unboxing type info recorded for the variable: */ + clv->vars[j]->val_type = 0; + pos++; } - - resolve_info_add_mapping(linfo, opos, p, - ((recbox - || (clv->flags[j] & SCHEME_WAS_SET_BANGED)) - ? SCHEME_INFO_BOXED - : 0), - lift); - - opos++; } } } @@ -1369,46 +1220,45 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) int converted; do { clv = (Scheme_Compiled_Let_Value *)head->body; - rpos = 0; converted = 0; for (i = head->num_clauses; i--; clv = (Scheme_Compiled_Let_Value *)clv->body) { - opos = clv->position; - if ((clv->count == 1) && !(clv->flags[0] & SCHEME_WAS_USED)) { + if ((clv->count == 1) + && !clv->vars[0]->optimize_used + && clv->vars[0]->resolve_omittable) { /* skipped */ } else if ((clv->count == 1) - && is_nonconstant_procedure(clv->value, info, head->count)) { + && is_nonconstant_procedure(clv->value, info, lift_exclude_vars)) { Scheme_Object *lift, *old_lift; int old_convert_count; - mzshort *old_convert_map, *convert_map; + Scheme_Object *old_convert_map, *convert_map; - old_lift = lifted_recs[rpos]; + old_lift = clv->vars[0]->resolve.lifted; old_convert_count = get_convert_arg_count(old_lift); old_convert_map = get_convert_arg_map(old_lift); - lift = resolve_closure_compilation(clv->value, val_linfo, 1, 1, 1, + lift = resolve_closure_compilation(clv->value, linfo, 1, 1, 1, (resolve_phase ? NULL : old_lift)); - if (is_closed_reference(lift) - || (is_lifted_reference(lift) && resolve_phase)) { + if (!info->no_lift + && (is_closed_reference(lift) + || (is_lifted_reference(lift) && resolve_phase))) { if (!SAME_OBJ(old_lift, lift)) - resolve_info_adjust_mapping(linfo, opos, rpos, 0, lift); - lifted_recs[rpos] = lift; + clv->vars[0]->resolve.lifted = lift; if (get_convert_arg_count(lift) != old_convert_count) converted = 1; else if (old_convert_map) { int z; convert_map = get_convert_arg_map(lift); for (z = 0; z < old_convert_count; z++) { - if (old_convert_map[z] != convert_map[z]) + if (SCHEME_VEC_ELS(old_convert_map)[z+1] != SCHEME_VEC_ELS(convert_map)[z+1]) converted = 1; } } } else { - lifted_recs = NULL; + lifted_recs = 0; converted = 0; break; } - rpos++; } } } while (converted); @@ -1428,16 +1278,16 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) actual lift offsets before resolving procedure bodies. Also, we need to fix up the stub closures. */ clv = (Scheme_Compiled_Let_Value *)head->body; - rpos = 0; for (i = head->num_clauses; i--; clv = (Scheme_Compiled_Let_Value *)clv->body) { - opos = clv->position; - if ((clv->count == 1) && !(clv->flags[0] & SCHEME_WAS_USED)) { + if ((clv->count == 1) + && !clv->vars[0]->optimize_used + && clv->vars[0]->resolve_omittable) { /* skipped */ - } else if ((clv->count == 1) && is_nonconstant_procedure(clv->value, info, head->count)) { + } else if ((clv->count == 1) && is_nonconstant_procedure(clv->value, info, lift_exclude_vars)) { Scheme_Object *lift; - lift = lifted_recs[rpos]; + lift = clv->vars[0]->resolve.lifted; if (is_closed_reference(lift)) { - (void)resolve_closure_compilation(clv->value, val_linfo, 1, 1, 0, lift); + (void)resolve_closure_compilation(clv->value, linfo, 1, 1, 0, lift); /* lift is the final result; this result might be referenced in the body of closures already, or in not-yet-closed functions. If no one uses the result @@ -1445,12 +1295,10 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) GCed. */ clv->value = NULL; /* indicates that there's nothing more to do with the expr */ } else { - lift = resolve_closure_compilation(clv->value, val_linfo, 1, 1, 2, NULL); + lift = resolve_closure_compilation(clv->value, linfo, 1, 1, 2, NULL); /* need to resolve one more time for the body of the lifted function */ + clv->vars[0]->resolve.lifted = lift; } - resolve_info_adjust_mapping(linfo, opos, rpos, 0, lift); - lifted_recs[rpos] = lift; - rpos++; } } @@ -1460,7 +1308,7 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) } extra_alloc = 0; - + if (num_rec_procs) { if (!lifted_recs) { Scheme_Object **sa; @@ -1481,8 +1329,9 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) clv = (Scheme_Compiled_Let_Value *)head->body; rpos = 0; for (i = head->num_clauses; i--; clv = (Scheme_Compiled_Let_Value *)clv->body) { - opos = clv->position; - if ((clv->count == 1) && !(clv->flags[0] & SCHEME_WAS_USED)) { + if ((clv->count == 1) + && !clv->vars[0]->optimize_used + && clv->vars[0]->resolve_omittable) { /* skipped */ } else { int isproc; @@ -1490,26 +1339,25 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) if (!clv->value) isproc = 1; else if (clv->count == 1) - isproc = is_nonconstant_procedure(clv->value, info, post_bind ? 0 : head->count); + isproc = is_nonconstant_procedure(clv->value, info, lift_exclude_vars); else isproc = 0; if (num_rec_procs && isproc) { if (!lifted_recs) { - expr = resolve_closure_compilation(clv->value, val_linfo, 0, 0, 0, NULL); + expr = resolve_closure_compilation(clv->value, linfo, 0, 0, 0, NULL); if (!SAME_TYPE(SCHEME_TYPE(expr), scheme_unclosed_procedure_type)) { scheme_signal_error("internal error: unexpected empty closure"); } letrec->procs[rpos++] = expr; } else { - if (!is_closed_reference(lifted_recs[rpos])) { + if (!is_closed_reference(clv->vars[0]->resolve.lifted)) { /* Side-effect is to install lifted function: */ - (void)resolve_closure_compilation(clv->value, val_linfo, 1, 1, 0, lifted_recs[rpos]); + (void)resolve_closure_compilation(clv->value, linfo, 1, 1, 0, clv->vars[0]->resolve.lifted); } rpos++; } } else { int j; - Scheme_Object *one_lifted; if (!clv->count) expr = drop_zero_value_return(clv->value); @@ -1520,10 +1368,11 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) /* Change a `[() (begin expr (values))]' clause, which can be generated by internal-definition expansion, into a `begin' */ - expr = scheme_resolve_expr(expr, val_linfo); + expr = scheme_resolve_expr(expr, linfo); expr = scheme_make_sequence_compilation(scheme_make_pair(expr, scheme_make_pair(scheme_false, scheme_null)), + 0, 0); if (last) @@ -1538,7 +1387,7 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) last_body = NULL; last_seq = expr; } else { - expr = scheme_resolve_expr(clv->value, val_linfo); + expr = scheme_resolve_expr(clv->value, linfo); lv = MALLOC_ONE_TAGGED(Scheme_Let_Value); if (last) @@ -1557,7 +1406,7 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) lv->value = expr; if (clv->count) { int li; - li = resolve_info_lookup(linfo, clv->position, NULL, NULL, 0); + li = resolve_info_lookup(linfo, clv->vars[0], NULL, 0, RESOLVE_UNUSED_OK); lv->position = li; } else lv->position = 0; @@ -1565,11 +1414,10 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) SCHEME_LET_VALUE_AUTOBOX(lv) = recbox; for (j = lv->count; j--; ) { - if (!recbox - && (resolve_info_flags(linfo, opos + j, &one_lifted) & SCHEME_INFO_BOXED)) { + if (!recbox && clv->vars[j]->mutated) { GC_CAN_IGNORE Scheme_Object *pos; pos = scheme_make_integer(lv->position + j); - if (SCHEME_LET_FLAGS(head) & (SCHEME_LET_STAR | SCHEME_LET_RECURSIVE)) { + if (SCHEME_LET_FLAGS(head) & SCHEME_LET_RECURSIVE) { /* For let* or a let*-like letrec, we need to insert the boxes after each evaluation. */ Scheme_Object *boxenv; @@ -1600,7 +1448,7 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) } /* Resolve body: */ - body = scheme_resolve_expr(body, linfo); + body = scheme_resolve_expr((Scheme_Object *)clv, linfo); while (SCHEME_PAIRP(boxes)) { /* See bangboxenv... */ @@ -1667,15 +1515,8 @@ scheme_resolve_lets(Scheme_Object *form, Resolve_Info *info) } } - if (info->max_let_depth < linfo->max_let_depth + head->count - num_skips + extra_alloc) - info->max_let_depth = linfo->max_let_depth + head->count - num_skips + extra_alloc; - merge_resolve_tl_map(info, linfo); - if (val_linfo) { - if (info->max_let_depth < val_linfo->max_let_depth + head->count - num_skips + extra_alloc) - info->max_let_depth = val_linfo->max_let_depth + head->count - num_skips + extra_alloc; - merge_resolve_tl_map(info, val_linfo); - } - + merge_resolve(info, linfo); + return first; } @@ -1688,18 +1529,6 @@ XFORM_NONGCING int scheme_boxmap_size(int n) return ((CLOS_TYPE_BITS_PER_ARG * n) + (BITS_PER_MZSHORT - 1)) / BITS_PER_MZSHORT; } -static mzshort *allocate_boxmap(int n) -{ - mzshort *boxmap; - int size; - - size = scheme_boxmap_size(n); - boxmap = MALLOC_N_ATOMIC(mzshort, size); - memset(boxmap, 0, size * sizeof(mzshort)); - - return boxmap; -} - void scheme_boxmap_set(mzshort *boxmap, int j, int bit, int delta) /* assumes that existing bits are cleared */ { @@ -1707,15 +1536,6 @@ void scheme_boxmap_set(mzshort *boxmap, int j, int bit, int delta) boxmap[delta + (j / BITS_PER_MZSHORT)] |= ((mzshort)bit << (j & (BITS_PER_MZSHORT - 1))); } -static void boxmap_clear(mzshort *boxmap, int j, int delta) -{ - mzshort v; - j *= CLOS_TYPE_BITS_PER_ARG; - v = boxmap[delta + (j / BITS_PER_MZSHORT)]; - v ^= (v & ((mzshort)(((1 << CLOS_TYPE_BITS_PER_ARG) - 1) << (j & (BITS_PER_MZSHORT - 1))))); - boxmap[delta + (j / BITS_PER_MZSHORT)] = v; -} - int scheme_boxmap_get(mzshort *boxmap, int j, int delta) { j *= CLOS_TYPE_BITS_PER_ARG; @@ -1723,32 +1543,39 @@ int scheme_boxmap_get(mzshort *boxmap, int j, int delta) & ((1 << CLOS_TYPE_BITS_PER_ARG) - 1)); } -static int is_nonconstant_procedure(Scheme_Object *_data, Resolve_Info *info, int skip) +static int is_nonconstant_procedure(Scheme_Object *_data, Resolve_Info *info, Scheme_Hash_Tree *exclude_vars) { /* check whether `data' --- which is in a `letrec' --- can be converted to a constant independent of other bindings in the `letrec' */ Scheme_Closure_Data *data; Closure_Info *cl; Scheme_Object *lifted; - int i, sz; + int i; if (SAME_TYPE(SCHEME_TYPE(_data), scheme_compiled_unclosed_procedure_type)) { data = (Scheme_Closure_Data *)_data; - sz = data->closure_size; cl = (Closure_Info *)data->closure_map; if (cl->has_tl) return 1; - for (i = 0; i < sz; i++) { - if (cl->base_closure_map[i] < skip) - return 1; - resolve_info_lookup(info, cl->base_closure_map[i] - skip, NULL, &lifted, 0); - if (!lifted) - return 1; - if (SAME_TYPE(SCHEME_TYPE(lifted), scheme_toplevel_type) - || SAME_TYPE(SCHEME_TYPE(SCHEME_CAR(lifted)), scheme_toplevel_type)) - return 1; + for (i = 0; i < cl->base_closure->size; i++) { + if (cl->base_closure->vals[i]) { + Scheme_Compiled_Local *var = (Scheme_Compiled_Local *)cl->base_closure->keys[i]; + + if (scheme_hash_tree_get(exclude_vars, (Scheme_Object *)var)) + return 1; + + if (var->optimize_used) { + MZ_ASSERT(var->mode == SCHEME_VAR_MODE_RESOLVE); + resolve_info_lookup(info, var, &lifted, 0, 0); + if (!lifted) + return 1; + if (SAME_TYPE(SCHEME_TYPE(lifted), scheme_toplevel_type) + || SAME_TYPE(SCHEME_TYPE(SCHEME_CAR(lifted)), scheme_toplevel_type)) + return 1; + } + } } return 0; @@ -1763,17 +1590,14 @@ resolve_closure_compilation(Scheme_Object *_data, Resolve_Info *info, Scheme_Object *precomputed_lift) { Scheme_Closure_Data *data; - int i, closure_size, offset, np, num_params, expanded_already = 0, captured_typed; - int no_map_shift_needed; - int has_tl, convert_size, need_lift; - mzshort *oldpos, *closure_map, *new_closure_map; + int i, closure_size, new_params, num_params; + int need_type_map = 0; + int has_tl, need_lift, using_lifted = 0; + mzshort *closure_map; Closure_Info *cl; Resolve_Info *new_info; Scheme_Object *lifted, *result, *lifteds = NULL; Scheme_Hash_Table *captured = NULL; - mzshort *convert_boxes = NULL; /* local type for captured (i.e,. first captured is at 0) */ - mzshort *convert_map; /* includes local type for args and captured (i.e,. first captured - is at data->num_params) */ data = (Scheme_Closure_Data *)_data; cl = (Closure_Info *)data->closure_map; @@ -1781,7 +1605,7 @@ resolve_closure_compilation(Scheme_Object *_data, Resolve_Info *info, data->iso.so.type = scheme_unclosed_procedure_type; if (convert || can_lift) { - if (!convert && !resolving_in_procedure(info)) + if (!convert && !resolve_is_inside_proc(info)) can_lift = 0; /* no point in lifting when outside of a lambda or letrec */ if (!info->lifts) can_lift = 0; @@ -1800,381 +1624,241 @@ resolve_closure_compilation(Scheme_Object *_data, Resolve_Info *info, int at_least_one = 0; for (i = data->num_params; i--; ) { if (cl->local_type_map[i]) { - if (SCHEME_WAS_TYPED_ARGUMENT(cl->local_flags[i]) == cl->local_type_map[i]) + if ((cl->vars[i]->arg_type == cl->local_type_map[i]) + && (!cl->vars[i]->escapes_after_k_tick + || ALWAYS_PREFER_UNBOX_TYPE(cl->vars[i]->arg_type))) at_least_one = 1; else cl->local_type_map[i] = 0; } } - if (at_least_one) { - closure_size += scheme_boxmap_size(data->num_params + closure_size); - expanded_already = 1; - } else + if (at_least_one) + need_type_map = 1; + else cl->local_type_map = NULL; } - closure_map = (mzshort *)scheme_malloc_atomic(sizeof(mzshort) * closure_size); - if (cl->local_type_map) - memset(closure_map, 0, sizeof(mzshort) * closure_size); has_tl = cl->has_tl; + + /* Add original closure content to `captured`, pruning variables + that are lifted (so the closure might get smaller). The + `captured' table maps variables to new positions relative to the + current stack. */ + closure_size = 0; + captured = scheme_make_hash_table(SCHEME_hash_ptr); + for (i = 0; i < cl->base_closure->size; i++) { + if (cl->base_closure->vals[i]) { + Scheme_Compiled_Local *var = SCHEME_VAR(cl->base_closure->keys[i]); + int li; + + if ((var->mode == SCHEME_VAR_MODE_OPTIMIZE) + || !var->optimize_used) { + /* reference must have been optimized away; drop it + from the closure */ + } else { + li = resolve_info_lookup(info, var, &lifted, 0, 0); + if (lifted) { + /* Drop lifted binding from closure. */ + if (SAME_TYPE(SCHEME_TYPE(lifted), scheme_toplevel_type) + || SAME_TYPE(SCHEME_TYPE(SCHEME_CAR(lifted)), scheme_toplevel_type)) { + /* Former local variable is now a top-level variable. */ + has_tl = 1; + } + /* If the lifted binding is for a converted closure, + we may need to add more bindings to this closure. */ + if (SCHEME_RPAIRP(lifted)) { + lifteds = scheme_make_raw_pair(lifted, lifteds); + using_lifted = 1; + } + } else { + scheme_hash_set(captured, (Scheme_Object *)var, scheme_make_integer(closure_size)); + closure_size++; + /* Currently, we only need type (not boxing) information for closure content: */ + if (HAS_UNBOXABLE_TYPE(var)) + need_type_map = 1; + } + } + } + } + if (has_tl && !can_lift) convert = 0; - /* Locals in closure are first: */ - oldpos = cl->base_closure_map; - offset = 0; - for (i = 0; i < cl->base_closure_size; i++) { - int li, flags; - li = resolve_info_lookup(info, oldpos[i], &flags, &lifted, 0); - if (lifted) { - /* Drop lifted binding from closure. */ - if (SAME_TYPE(SCHEME_TYPE(lifted), scheme_toplevel_type) - || SAME_TYPE(SCHEME_TYPE(SCHEME_CAR(lifted)), scheme_toplevel_type)) { - has_tl = 1; - if (!can_lift) - convert = 0; - } - /* If the lifted binding is for a converted closure, - we may need to add more bindings to this closure. */ - if (SCHEME_RPAIRP(lifted)) { - lifteds = scheme_make_raw_pair(lifted, lifteds); - } - } else { - closure_map[offset] = li; - if (convert && (flags & (SCHEME_INFO_BOXED | SCHEME_INFO_TYPED_VAL_MASK))) { - /* The only problem with a boxed/local_type variable is that - it's more difficult to validate. We have to track - which arguments are boxes. And the resulting procedure - must be used only in application positions. */ - if (!convert_boxes) - convert_boxes = allocate_boxmap(cl->base_closure_size); - scheme_boxmap_set(convert_boxes, offset, - ((flags & SCHEME_INFO_BOXED) - ? CLOS_TYPE_BOXED - : CLOS_TYPE_TYPE_OFFSET + (flags >> SCHEME_INFO_TYPED_VAL_SHIFT)), - 0); - } else { - /* Currently, we only need local_type information as a closure type */ - if (flags & SCHEME_INFO_TYPED_VAL_MASK) { - if (!expanded_already) { - closure_size += scheme_boxmap_size(data->num_params + closure_size); - new_closure_map = (mzshort *)scheme_malloc_atomic(sizeof(mzshort) * closure_size); - memset(new_closure_map, 0, sizeof(mzshort) * closure_size); - memcpy(new_closure_map, closure_map, sizeof(mzshort) * data->closure_size); - closure_map = new_closure_map; - expanded_already = 1; - } - scheme_boxmap_set(closure_map, data->num_params + offset, - CLOS_TYPE_TYPE_OFFSET + (flags >> SCHEME_INFO_TYPED_VAL_SHIFT), - data->closure_size); - } - } - offset++; - } - } - - /* Add bindings introduced by closure conversion. The `captured' - table maps old positions to new positions. */ - captured_typed = 0; + /* Add variable references introduced by closure conversion. */ while (lifteds) { - int j, cnt, local_typed; - Scheme_Object *vec, *loc; - - if (!captured) { - captured = scheme_make_hash_table(SCHEME_hash_ptr); - for (i = 0; i < offset; i++) { - int cp, v; - cp = i; - if (convert_boxes) { - v = scheme_boxmap_get(convert_boxes, i, 0); - } else if (expanded_already) { - v = scheme_boxmap_get(closure_map, data->num_params + i, data->closure_size); - } else - v = 0; - if (v) - cp = -((cp << CLOS_TYPE_BITS_PER_ARG) + v); - scheme_hash_set(captured, scheme_make_integer(closure_map[i]), scheme_make_integer(cp)); - } - } + int j, cnt; + Scheme_Object *vec; lifted = SCHEME_CAR(lifteds); vec = SCHEME_CDR(lifted); cnt = SCHEME_VEC_SIZE(vec); --cnt; for (j = 0; j < cnt; j++) { - loc = SCHEME_VEC_ELS(vec)[j+1]; - if (SCHEME_BOXP(loc)) { - loc = SCHEME_BOX_VAL(loc); - local_typed = CLOS_TYPE_BOXED; - } else if (SCHEME_VECTORP(loc)) { - local_typed = SCHEME_INT_VAL(SCHEME_VEC_ELS(loc)[1]); - loc = SCHEME_VEC_ELS(loc)[0]; - } else { - local_typed = 0; - } - i = SCHEME_LOCAL_POS(loc); - if (!scheme_hash_get(captured, scheme_make_integer(i))) { + Scheme_Compiled_Local *var = (Scheme_Compiled_Local *)SCHEME_VEC_ELS(vec)[j+1]; + if (!scheme_hash_get(captured, (Scheme_Object *)var)) { /* Need to capture an extra binding: */ - int cp; - cp = captured->count; - if (local_typed) { - cp = -((cp << CLOS_TYPE_BITS_PER_ARG) + local_typed); - captured_typed = 1; - } - scheme_hash_set(captured, scheme_make_integer(i), scheme_make_integer(cp)); + scheme_hash_set(captured, (Scheme_Object *)var, scheme_make_integer(captured->count)); + if (HAS_UNBOXABLE_TYPE(var)) + need_type_map = 1; + closure_size++; } } lifteds = SCHEME_CDR(lifteds); } - if (captured && (captured->count > offset)) { - /* We need to extend the closure map. All the info - is in captured, so just build it from scratch. */ - int old_pos, j, new_size, need_flags; - new_size = (captured->count + (has_tl ? 1 : 0)); - if (cl->local_type_map || expanded_already || convert_boxes || captured_typed) { - need_flags = new_size; - new_size += scheme_boxmap_size(data->num_params + new_size); - expanded_already = 1; - } else - need_flags = 0; - closure_map = (mzshort *)scheme_malloc_atomic(sizeof(mzshort) * new_size); - if (need_flags) - memset(closure_map, 0, sizeof(mzshort) * new_size); - offset = captured->count; - convert_boxes = NULL; - for (j = captured->size; j--; ) { - if (captured->vals[j]) { - int cp; - cp = SCHEME_INT_VAL(captured->vals[j]); - old_pos = SCHEME_INT_VAL(captured->keys[j]); - if (cp < 0) { - /* Boxed or local_type */ - int bit; - cp = -cp; - bit = cp & ((1 << CLOS_TYPE_BITS_PER_ARG) - 1); - cp >>= CLOS_TYPE_BITS_PER_ARG; - if (!convert_boxes) - convert_boxes = allocate_boxmap(offset); - scheme_boxmap_set(convert_boxes, cp, bit, 0); - if (need_flags && (bit > CLOS_TYPE_TYPE_OFFSET)) - scheme_boxmap_set(closure_map, cp + data->num_params, bit, need_flags); - } - closure_map[cp] = old_pos; + /* To make compilation deterministic, sort the captured variables */ + if (closure_size) { + Scheme_Compiled_Local **c; + int j = 0; + c = MALLOC_N(Scheme_Compiled_Local*, closure_size); + for (i = 0; i < captured->size; i++) { + if (captured->vals[i]) { + c[j++] = SCHEME_VAR(captured->keys[i]); } } - no_map_shift_needed = 1; - } else - no_map_shift_needed = 0; - - if (convert - && (offset || !has_tl) /* either need args, or treat as convert because it's fully closed */ - ) { - /* Take over closure_map to be the convert map, instead. */ - convert_map = closure_map; - convert_size = offset; - - if (has_tl || convert_boxes || cl->local_type_map) { - int new_boxes_size; - int sz; - new_boxes_size = scheme_boxmap_size(convert_size + data->num_params + (has_tl ? 1 : 0)); - sz = ((has_tl ? sizeof(mzshort) : 0) + new_boxes_size * sizeof(mzshort)); - closure_map = (mzshort *)scheme_malloc_atomic(sz); - memset(closure_map, 0, sz); - if (convert_boxes) { - int bsz; - bsz = scheme_boxmap_size(convert_size); - memcpy(closure_map XFORM_OK_PLUS (has_tl ? 1 : 0), - convert_boxes, - bsz * sizeof(mzshort)); - } - } else - closure_map = NULL; - offset = 0; - } else { - convert = 0; - convert_map = NULL; - convert_size = 0; - convert_boxes = NULL; + scheme_sort_resolve_compiled_local_array(c, closure_size); + for (i = 0; i < closure_size; i++) { + scheme_hash_set(captured, (Scheme_Object *)c[i], scheme_make_integer(i)); + } } - /* Then the pointer to globals, if any: */ + if (convert && (closure_size || has_tl || using_lifted)) { + new_params = closure_size; + closure_size = 0; + } else { + new_params = 0; + convert = 0; + } + + /* Count the pointer to globals, if any: */ if (has_tl) { /* GLOBAL ASSUMPTION: jit.c assumes that the array of globals is the last item in the closure; grep for "GLOBAL ASSUMPTION" in jit.c and mzmark.c */ - int li; - li = resolve_toplevel_pos(info); - closure_map[offset] = li; - offset++; + closure_size++; } - if (!convert && !just_compute_lift && (offset < data->closure_size) - && expanded_already && !no_map_shift_needed) { - /* shift boxmap down, since we're dropping closure elements */ - int bsz; - bsz = scheme_boxmap_size(data->num_params + offset); - memmove(closure_map + offset, closure_map + data->closure_size, sizeof(mzshort) * bsz); - } + /* New arguments due to closure conversion will be added before + the original arguments: */ + num_params = data->num_params + new_params; - /* Reset closure_size, in case a lifted variable was removed: */ - closure_size = offset; - if (!just_compute_lift) { - data->closure_size = closure_size; - if (convert && convert_boxes) - SCHEME_CLOSURE_DATA_FLAGS(data) |= CLOS_HAS_TYPED_ARGS; - } - - /* Set up environment mapping, initialized for arguments: */ - - np = num_params = data->num_params; - if ((data->num_params == 1) + if ((num_params == 1) + && !new_params && (SCHEME_CLOSURE_DATA_FLAGS(data) & CLOS_HAS_REST) - && !(cl->local_flags[0] & SCHEME_WAS_USED) - && !convert) { - /* (lambda args E) where args is not in E => drop the argument */ - new_info = resolve_info_extend(info, 0, 1, cl->base_closure_size); + && !cl->vars[0]->optimize_used) { + /* We can claim 0 params plus CLOS_HAS_REST as an optimization */ num_params = 0; - if (!just_compute_lift) { - data->num_params = 0; - if (expanded_already) { - /* shift type map down: */ - for (i = 0; i < closure_size; i++) { - boxmap_clear(closure_map, i, closure_size); - scheme_boxmap_set(closure_map, i, scheme_boxmap_get(closure_map, i + 1, closure_size), closure_size); - } - SCHEME_CLOSURE_DATA_FLAGS(data) |= CLOS_HAS_TYPED_ARGS; - } - } - } else { - new_info = resolve_info_extend(info, data->num_params, data->num_params, - cl->base_closure_size + data->num_params); - for (i = 0; i < data->num_params; i++) { - resolve_info_add_mapping(new_info, i, i + closure_size + convert_size, - (((cl->local_flags[i] & SCHEME_WAS_SET_BANGED) - ? SCHEME_INFO_BOXED - : 0) - | ((convert && (cl->local_type_map && cl->local_type_map[i])) - ? (cl->local_type_map[i] << SCHEME_INFO_TYPED_VAL_SHIFT) - : 0)), - NULL); - if (convert && cl->local_type_map && cl->local_type_map[i] && !just_compute_lift) - scheme_boxmap_set(closure_map, i + convert_size, - cl->local_type_map[i] + CLOS_TYPE_TYPE_OFFSET, - closure_size); - } - if (expanded_already && !just_compute_lift) - SCHEME_CLOSURE_DATA_FLAGS(data) |= CLOS_HAS_TYPED_ARGS; } - /* Extend mapping to go from old locations on the stack (as if bodies were - evaluated immediately) to new locations (where closures - effectively shift and compact values on the stack). - - We don't have to include bindings added because an original - binding was lifted (i.e., the extra bindings in `captured'), - because they don't appear in the body. Instead, they are - introduced directly in resolved form through the `lifted' info. - That means, though, that we need to transform the `lifted' - mapping. */ - if (has_tl && convert) { - /* Skip handle for globals */ - offset = 1; - } else { - offset = 0; - } - for (i = 0; i < cl->base_closure_size; i++) { - int p = oldpos[i], flags; - - if (p < 0) - p -= np; - else - p += np; - - flags = resolve_info_flags(info, oldpos[i], &lifted); - - if (lifted && SCHEME_RPAIRP(lifted)) { - /* Convert from a vector of local references to an array of - positions. */ - Scheme_Object *vec, *loc, **ca; - mzshort *cmap, *boxmap = NULL; - int sz, j, cp; - - vec = SCHEME_CDR(lifted); - sz = SCHEME_VEC_SIZE(vec); - --sz; - cmap = MALLOC_N_ATOMIC(mzshort, sz); - for (j = 0; j < sz; j++) { - int is_boxed = 0, is_local_type = 0; - loc = SCHEME_VEC_ELS(vec)[j+1]; - if (SCHEME_BOXP(loc)) { - if (!boxmap) - boxmap = allocate_boxmap(sz); - scheme_boxmap_set(boxmap, j, CLOS_TYPE_BOXED, 0); - loc = SCHEME_BOX_VAL(loc); - is_boxed = 1; - } else if (SCHEME_VECTORP(loc)) { - if (!boxmap) - boxmap = allocate_boxmap(sz); - scheme_boxmap_set(boxmap, j, SCHEME_INT_VAL(SCHEME_VEC_ELS(loc)[1]), 0); - loc = SCHEME_VEC_ELS(loc)[0]; - is_local_type = 1; - } - loc = scheme_hash_get(captured, scheme_make_integer(SCHEME_LOCAL_POS(loc))); - cp = SCHEME_INT_VAL(loc); - if (cp < 0) { - int v; - cp = -cp; - v = cp & ((1 << CLOS_TYPE_BITS_PER_ARG) - 1); - cp >>= CLOS_TYPE_BITS_PER_ARG; - if (v == CLOS_TYPE_BOXED) { - if (convert && !is_boxed) - scheme_signal_error("internal error: lift mismatch (boxed)"); - } else { - if (convert && !is_local_type) - scheme_signal_error("internal error: lift mismatch (local type) %d", v); - } - } else { - if (convert && (is_boxed || is_local_type)) - scheme_signal_error("internal error: lift mismatch"); - } - cmap[j] = cp + (has_tl && convert ? 1 : 0); - } - - ca = MALLOC_N(Scheme_Object *, 4); - ca[0] = scheme_make_integer(sz); - ca[1] = (Scheme_Object *)cmap; - ca[2] = SCHEME_VEC_ELS(vec)[0]; - ca[3] = (Scheme_Object *)boxmap; - - lifted = scheme_make_raw_pair(SCHEME_CAR(lifted), (Scheme_Object *)ca); - } - - resolve_info_add_mapping(new_info, p, lifted ? 0 : offset++, flags, lifted); - } - if (has_tl) { - if (convert) - offset = 0; /* other closure elements converted to arguments */ - else - offset = closure_size - 1; - resolve_info_set_toplevel_pos(new_info, offset); - } - - if (!just_compute_lift) - data->closure_map = closure_map; - - new_info->in_proc = 1; - if (!just_compute_lift) { - Scheme_Object *code; - code = scheme_resolve_expr(data->code, new_info); - data->code = code; + if (convert && !need_type_map && new_params) { + /* As we turn closure content into arguments, we need mutation + info, so double-check whether a type map is needed after all. */ + for (i = 0; i < captured->size; i++) { + if (captured->vals[i]) { + Scheme_Compiled_Local *var = SCHEME_VAR(captured->keys[i]); + if (var->mutated) { + need_type_map = 1; + break; + } + } + } + } + + new_info = resolve_info_extend(info, num_params + closure_size, 1); + + data->closure_size = closure_size; + if (need_type_map) + SCHEME_CLOSURE_DATA_FLAGS(data) |= CLOS_HAS_TYPED_ARGS; + + MZ_ASSERT(need_type_map || !(SCHEME_CLOSURE_DATA_FLAGS(data) & CLOS_HAS_TYPED_ARGS)); + + /* Create the closure map, if needed */ + if (closure_size || need_type_map) { + int bmsz; + if (need_type_map) + bmsz = scheme_boxmap_size(closure_size + num_params); + else + bmsz = 0; + bmsz += closure_size; + closure_map = (mzshort *)scheme_malloc_atomic(sizeof(mzshort) * bmsz); + memset(closure_map + closure_size, 0, sizeof(mzshort) * (bmsz - closure_size)); + } else + closure_map = NULL; + + data->closure_map = closure_map; + data->num_params = num_params; + + /* Register original argument names and types */ + for (i = 0; i < num_params - new_params; i++) { + set_resolve_mode(cl->vars[i]); + cl->vars[i]->resolve.co_depth = new_info->current_depth - (i + new_params + closure_size); + cl->vars[i]->resolve.lex_depth = new_info->current_lex_depth - (i + new_params + closure_size); + if (convert) { + /* If we're lifting this function, then arguments can have unboxing + types, because the valdiator will be able to check all the + calls: */ + if (cl->local_type_map) + cl->vars[i]->val_type = cl->local_type_map[i]; + if (need_type_map) { + if (cl->local_type_map && cl->local_type_map[i]) + scheme_boxmap_set(closure_map, i + new_params, + cl->local_type_map[i] + CLOS_TYPE_TYPE_OFFSET, + closure_size); + } + } + } + + /* Register closure content (possibly as new params) */ + for (i = 0; i < captured->size; i++) { + if (captured->vals[i]) { + int pos = SCHEME_INT_VAL(captured->vals[i]); + Scheme_Compiled_Local *var = SCHEME_VAR(captured->keys[i]); + resolve_info_add_mapping(new_info, var, + scheme_make_integer(new_info->current_depth + - pos + - (convert + ? closure_size + : 0))); + MZ_ASSERT(need_type_map || (!HAS_UNBOXABLE_TYPE(var) && (!var->mutated || !convert))); + if (need_type_map) { + scheme_boxmap_set(closure_map, (pos + (convert ? 0 : num_params)), + ((HAS_UNBOXABLE_TYPE(var) + ? (var->val_type + CLOS_TYPE_TYPE_OFFSET) + : 0) + | (convert + ? (var->mutated ? CLOS_TYPE_BOXED : 0) + : 0)), + closure_size); + } + if (!convert) { + int li; + li = resolve_info_lookup(info, var, NULL, 0, 0); + closure_map[pos] = li; + } + } + } + + if (has_tl) { + /* array of globals is at the end: */ + resolve_info_set_toplevel_pos(new_info, closure_size - 1); + if (closure_map) { + int li; + li = resolve_toplevel_pos(info); + closure_map[closure_size-1] = li; + } + } else + resolve_info_set_toplevel_pos(new_info, -1); + + /* Resolve the closure body: */ + { + Scheme_Object *code; + code = scheme_resolve_expr(data->code, new_info); + data->code = code; + } data->max_let_depth = (new_info->max_let_depth - + num_params - + closure_size - + convert_size + SCHEME_TAIL_COPY_THRESHOLD); data->tl_map = new_info->tl_map; @@ -2185,9 +1869,9 @@ resolve_closure_compilation(Scheme_Object *_data, Resolve_Info *info, } /* Add code to box set!ed argument variables: */ - for (i = 0; i < num_params; i++) { - if (cl->local_flags[i] & SCHEME_WAS_SET_BANGED) { - int j = i + closure_size + convert_size; + for (i = 0; i < num_params - new_params; i++) { + if (cl->vars[i]->mutated) { + int j = i + closure_size + new_params; Scheme_Object *bcode; bcode = scheme_alloc_object(); @@ -2208,12 +1892,6 @@ resolve_closure_compilation(Scheme_Object *_data, Resolve_Info *info, } else need_lift = 0; - if (convert) { - num_params += convert_size; - if (!just_compute_lift) - data->num_params = num_params; - } - /* If the closure is empty, create the closure now */ if (!closure_size) { if (precomputed_lift) { @@ -2250,25 +1928,31 @@ resolve_closure_compilation(Scheme_Object *_data, Resolve_Info *info, closure_map[0] = 0; /* globals for closure creation will be at 0 after lifting */ result = tl; } - } else { - merge_resolve_tl_map(info, new_info); + } else if (!just_compute_lift) { + merge_resolve(info, new_info); } if (convert) { - Scheme_Object **ca, *arity; + /* Generate lift record, which is a vector containing + the original arity and then each variable captured in the closure + (or would be captured if there's no lift conversion). */ + Scheme_Object *ca, *arity; - if ((SCHEME_CLOSURE_DATA_FLAGS(data) & CLOS_HAS_REST)) { - arity = scheme_box(scheme_make_integer(num_params - convert_size - 1)); - } else { - arity = scheme_make_integer(num_params - convert_size); + if ((SCHEME_CLOSURE_DATA_FLAGS(data) & CLOS_HAS_REST)) + arity = scheme_box(scheme_make_integer(num_params - new_params - 1)); + else + arity = scheme_make_integer(num_params - new_params); + + ca = scheme_make_vector(1 + captured->count, scheme_false); + SCHEME_VEC_ELS(ca)[0] = arity; + + for (i = 0; i < captured->size; i++) { + if (captured->vals[i]) { + MZ_ASSERT(SAME_TYPE(scheme_compiled_local_type, SCHEME_TYPE(captured->keys[i]))); + SCHEME_VEC_ELS(ca)[1 + SCHEME_INT_VAL(captured->vals[i])] = captured->keys[i]; + } } - ca = MALLOC_N(Scheme_Object *, 4); - ca[0] = scheme_make_integer(convert_size); - ca[1] = (Scheme_Object *)convert_map; - ca[2] = arity; - ca[3] = (Scheme_Object *)convert_boxes; - if (precomputed_lift) { SCHEME_CAR(precomputed_lift) = result; SCHEME_CDR(precomputed_lift) = (Scheme_Object *)ca; @@ -2467,24 +2151,23 @@ Scheme_Object *scheme_resolve_expr(Scheme_Object *expr, Resolve_Info *info) #endif switch (type) { - case scheme_local_type: + case scheme_compiled_local_type: { - int pos, flags; + int pos; + Scheme_Compiled_Local *var = SCHEME_VAR(expr); Scheme_Object *lifted; - pos = resolve_info_lookup(info, SCHEME_LOCAL_POS(expr), &flags, &lifted, 0); + pos = resolve_info_lookup(info, var, &lifted, 0, 0); if (lifted) { /* Lexical reference replaced with top-level reference for a lifted value: */ - return lifted; + return shift_lifted_reference(lifted, info, 0); } else { - return scheme_make_local((flags & SCHEME_INFO_BOXED) + return scheme_make_local(var->mutated ? scheme_local_unbox_type : scheme_local_type, pos, - ((flags & SCHEME_INFO_TYPED_VAL_MASK) - ? (SCHEME_LOCAL_TYPE_OFFSET - + ((flags & SCHEME_INFO_TYPED_VAL_MASK) - >> SCHEME_INFO_TYPED_VAL_SHIFT)) + (HAS_UNBOXABLE_TYPE(var) + ? (SCHEME_LOCAL_TYPE_OFFSET + var->val_type) : 0)); } } @@ -2503,7 +2186,7 @@ Scheme_Object *scheme_resolve_expr(Scheme_Object *expr, Resolve_Info *info) case scheme_with_cont_mark_type: return resolve_wcm(expr, info); case scheme_compiled_unclosed_procedure_type: - return resolve_closure_compilation(expr, info, 1, 0, 0, NULL); + return resolve_closure_compilation(expr, info, !info->no_lift, 0, 0, NULL); case scheme_compiled_let_void_type: return scheme_resolve_lets(expr, info); case scheme_compiled_toplevel_type: @@ -2583,6 +2266,51 @@ Scheme_Object *scheme_resolve_list(Scheme_Object *expr, Resolve_Info *info) return first; } +static Scheme_Object *resolve_info_lift_added(Resolve_Info *resolve, Scheme_Object *v, int convert_shift) +{ + /* If a variable added as an argument for closure conversion is mutable, + we need to generate a non-unboxing reference to the variable: */ + Scheme_Compiled_Local *var; + int pos; + + if (!SAME_TYPE(SCHEME_TYPE(v), scheme_compiled_local_type)) { + /* must be an argument to a generated "bad arity" call */ + return v; + } + + var = SCHEME_VAR(v); + + pos = resolve_info_lookup(resolve, var, NULL, convert_shift, RESOLVE_IGNORE_LIFTS); + + return scheme_make_local(scheme_local_type, + pos, + ((!var->mutated && HAS_UNBOXABLE_TYPE(var)) + ? (SCHEME_LOCAL_TYPE_OFFSET + var->val_type) + : 0)); +} + +static Scheme_Object *shift_lifted_reference(Scheme_Object *tl, Resolve_Info *info, int delta) +{ + int pos = SCHEME_TOPLEVEL_POS(tl); + int depth; + + depth = resolve_toplevel_pos(info); + tl = scheme_make_toplevel(depth + delta, + pos, + 1, + SCHEME_TOPLEVEL_CONST); + + /* register if non-stub: */ + if (pos >= (info->prefix->num_toplevels + + info->prefix->num_stxes + + (info->prefix->num_stxes + ? 1 + : 0))) + set_tl_pos_used(info, pos); + + return tl; +} + /*========================================================================*/ /* compile-time env for resolve */ /*========================================================================*/ @@ -2688,9 +2416,10 @@ Resolve_Info *scheme_resolve_info_create(Resolve_Prefix *rp) naya->type = scheme_rt_resolve_info; #endif naya->prefix = rp; - naya->count = 0; + naya->current_depth = 1; /* initial slot for prefix */ + naya->max_let_depth = naya->current_depth; + naya->current_lex_depth = 0; naya->next = NULL; - naya->toplevel_pos = -1; ht = scheme_make_hash_table(SCHEME_hash_ptr); naya->stx_map = ht; @@ -2751,10 +2480,8 @@ int scheme_resolve_info_max_let_depth(Resolve_Info *ri) return ri->max_let_depth; } -static Resolve_Info *resolve_info_extend(Resolve_Info *info, int size, int oldsize, int mapc) - /* size = number of appended items in run-time frame */ - /* oldisze = number of appended items in original compile-time frame */ - /* mapc = mappings that will be installed */ +static Resolve_Info *resolve_info_extend(Resolve_Info *info, int size, int lambda) +/* size = number of appended items in run-time frame */ { Resolve_Info *naya; @@ -2764,34 +2491,21 @@ static Resolve_Info *resolve_info_extend(Resolve_Info *info, int size, int oldsi #endif naya->prefix = info->prefix; naya->stx_map = info->stx_map; - naya->next = info; + naya->next = (lambda ? NULL : info); naya->use_jit = info->use_jit; naya->enforce_const = info->enforce_const; - naya->size = size; - naya->oldsize = oldsize; - naya->count = mapc; - naya->pos = 0; - naya->toplevel_pos = -1; - naya->lifts = info->lifts; + naya->current_depth = (lambda ? 0 : info->current_depth) + size; + naya->current_lex_depth = info->current_lex_depth + size; + naya->toplevel_pos = (lambda + ? 0 + : ((info->toplevel_pos < 0) + ? -1 + : (info->toplevel_pos + size))); naya->no_lift = info->no_lift; - - if (mapc) { - int i, *ia; - mzshort *sa; - - sa = MALLOC_N_ATOMIC(mzshort, mapc); - naya->old_pos = sa; - sa = MALLOC_N_ATOMIC(mzshort, mapc); - naya->new_pos = sa; - ia = MALLOC_N_ATOMIC(int, mapc); - naya->flags = ia; - - for (i = mapc; i--; ) { - naya->old_pos[i] = 0; - naya->new_pos[i] = 0; - naya->flags[i] = 0; - } - } + naya->redirects = info->redirects; + naya->max_let_depth = naya->current_depth; + naya->in_proc = lambda || info->in_proc; + naya->lifts = info->lifts; return naya; } @@ -2884,8 +2598,12 @@ static void *merge_tl_map(void *tl_map, void *new_tl_map) } } -static void merge_resolve_tl_map(Resolve_Info *info, Resolve_Info *new_info) +static void merge_resolve(Resolve_Info *info, Resolve_Info *new_info) { + if (new_info->next /* NULL => lambda */ + && (new_info->max_let_depth > info->max_let_depth)) + info->max_let_depth = new_info->max_let_depth; + if (!new_info->tl_map) { /* nothing to do */ } else { @@ -2895,45 +2613,17 @@ static void merge_resolve_tl_map(Resolve_Info *info, Resolve_Info *new_info) } } -static void resolve_info_add_mapping(Resolve_Info *info, int oldp, int newp, int flags, Scheme_Object *lifted) +static void resolve_info_add_mapping(Resolve_Info *info, Scheme_Compiled_Local *var, Scheme_Object *v) { - if (info->pos == info->count) { - scheme_signal_error("internal error: add_mapping: " - "too many: %d", info->pos); + Scheme_Hash_Tree *ht; + + if (!info->redirects) { + ht = scheme_make_hash_tree(0); + info->redirects = ht; } - info->old_pos[info->pos] = oldp; - info->new_pos[info->pos] = newp; - info->flags[info->pos] = flags; - if (lifted) { - if (!info->lifted) { - Scheme_Object **lifteds; - lifteds = MALLOC_N(Scheme_Object*, info->count); - info->lifted = lifteds; - } - info->lifted[info->pos] = lifted; - } - - info->pos++; -} - -static void resolve_info_adjust_mapping(Resolve_Info *info, int oldp, int newp, int flags, Scheme_Object *lifted) -{ - int i; - - for (i = info->pos; i--; ) { - if (info->old_pos[i] == oldp) { - info->new_pos[i] = newp; - info->flags[i] = flags; - if (lifted) { - info->lifted[i] = lifted; - } - return; - } - } - - scheme_signal_error("internal error: adjust_mapping: " - "couldn't find: %d", oldp); + ht = scheme_hash_tree_set(info->redirects, (Scheme_Object *)var, v); + info->redirects = ht; } static void resolve_info_set_toplevel_pos(Resolve_Info *info, int pos) @@ -2941,124 +2631,38 @@ static void resolve_info_set_toplevel_pos(Resolve_Info *info, int pos) info->toplevel_pos = pos; } -static int do_resolve_info_lookup(Resolve_Info *info, int pos, int *flags, Scheme_Object **_lifted, int convert_shift) +static int resolve_info_lookup(Resolve_Info *info, Scheme_Compiled_Local *var, Scheme_Object **_lifted, + int convert_shift, int flags) { - Resolve_Info *orig_info = info; - int i, offset = 0, orig = pos; + Scheme_Object *v; + int depth; + + MZ_ASSERT(var->mode == SCHEME_VAR_MODE_RESOLVE); + MZ_ASSERT((flags & RESOLVE_UNUSED_OK) || (var->use_count > 0)); + MZ_ASSERT((flags & RESOLVE_UNUSED_OK) || var->optimize_used); + + if (var->resolve.lifted && !(flags & RESOLVE_IGNORE_LIFTS)) { + MZ_ASSERT(_lifted); + + v = var->resolve.lifted; + *_lifted = v; + + return -1; + } + + depth = var->resolve.co_depth; + if (info->redirects) { + v = scheme_hash_tree_get(info->redirects, (Scheme_Object *)var); + if (v) { + depth = SCHEME_INT_VAL(v); + MZ_ASSERT(var->val_type <= SCHEME_MAX_LOCAL_TYPE_MASK); + } + } if (_lifted) *_lifted = NULL; - while (info) { - for (i = info->pos; i--; ) { - int oldp = info->old_pos[i]; - if (pos == oldp) { - if (flags) - *flags = info->flags[i]; - if (info->lifted && (info->lifted[i])) { - int skip, shifted; - Scheme_Object *lifted, *tl, **ca; - - if (!_lifted) - scheme_signal_error("unexpected lifted binding"); - - lifted = info->lifted[i]; - - if (SCHEME_RPAIRP(lifted)) { - tl = SCHEME_CAR(lifted); - ca = (Scheme_Object **)SCHEME_CDR(lifted); - if (convert_shift) - shifted = (int)SCHEME_INT_VAL(ca[0]) + convert_shift - 1; - else - shifted = 0; - } else { - tl = lifted; - shifted = 0; - ca = NULL; - } - - if (SAME_TYPE(SCHEME_TYPE(tl), scheme_toplevel_type)) { - skip = resolve_toplevel_pos(orig_info); - tl = scheme_make_toplevel(skip + shifted, - SCHEME_TOPLEVEL_POS(tl), - 1, - SCHEME_TOPLEVEL_CONST); - - /* register if non-stub: */ - if (SCHEME_TOPLEVEL_POS(tl) >= (info->prefix->num_toplevels - + info->prefix->num_stxes - + (info->prefix->num_stxes - ? 1 - : 0))) - set_tl_pos_used(orig_info, SCHEME_TOPLEVEL_POS(tl)); - } - - if (SCHEME_RPAIRP(lifted)) { - int sz, i; - mzshort *posmap, *boxmap; - Scheme_Object *vec, *loc; - sz = (int)SCHEME_INT_VAL(ca[0]); - posmap = (mzshort *)ca[1]; - boxmap = (mzshort *)ca[3]; - vec = scheme_make_vector(sz + 1, NULL); - for (i = 0; i < sz; i++) { - int boxed = 0, local_typed = 0, flags = 0; - - if (boxmap) { - int lt; - lt = scheme_boxmap_get(boxmap, i, 0); - if (lt == CLOS_TYPE_BOXED) { - boxed = 1; - } else if (lt) { - local_typed = lt; - flags = ((lt - CLOS_TYPE_TYPE_OFFSET) + SCHEME_LOCAL_TYPE_OFFSET); - } - } - - loc = scheme_make_local(scheme_local_type, - posmap[i] + offset + shifted, - flags); - - if (boxed) - loc = scheme_box(loc); - else if (local_typed) { - loc = scheme_make_vector(2, loc); - SCHEME_VEC_ELS(loc)[1] = scheme_make_integer(local_typed); - } - - SCHEME_VEC_ELS(vec)[i+1] = loc; - } - SCHEME_VEC_ELS(vec)[0] = ca[2]; - lifted = scheme_make_raw_pair(tl, vec); - } else - lifted = tl; - - *_lifted = lifted; - - return 0; - } else { - pos = info->new_pos[i]; - if (pos < 0) - scheme_signal_error("internal error: skipped binding is used"); - return pos + offset; - } - } - } - - if (info->in_proc) { - scheme_signal_error("internal error: resolve_info_lookup: " - "searching past procedure"); - } - - pos -= info->oldsize; - offset += info->size; - info = info->next; - } - - scheme_signal_error("internal error: resolve_info_lookup: " - "variable %d not found", orig); - - return 0; + return info->current_depth - depth + convert_shift; } static Scheme_Object *resolve_generate_stub_lift() @@ -3066,48 +2670,20 @@ static Scheme_Object *resolve_generate_stub_lift() return scheme_make_toplevel(0, 0, 1, SCHEME_TOPLEVEL_CONST); } -static int resolve_info_flags(Resolve_Info *info, int pos, Scheme_Object **lifted) -{ - int flags; - - do_resolve_info_lookup(info, pos, &flags, lifted, 0); - - return flags; -} - -static int resolve_info_lookup(Resolve_Info *info, int pos, int *flags, Scheme_Object **lifted, int convert_shift) -{ - return do_resolve_info_lookup(info, pos, flags, lifted, convert_shift); -} - static int resolve_toplevel_pos(Resolve_Info *info) { - int pos = 0; - - while (info && (info->toplevel_pos < 0)) { - if (info->in_proc) { - scheme_signal_error("internal error: resolve_toplevel_pos: " - "searching past procedure"); - } - pos += info->size; - info = info->next; - } - - if (!info) - return pos; - else - return info->toplevel_pos + pos; + MZ_ASSERT(info->toplevel_pos >= 0); + return info->toplevel_pos; } static int resolve_is_inside_proc(Resolve_Info *info) { - while (info) { - if (info->in_proc) - return 1; - info = info->next; - } + return info->in_proc; +} - return 0; +static int resolve_has_toplevel(Resolve_Info *info) +{ + return info->toplevel_pos >= 0; } static int resolve_quote_syntax_offset(int i, Resolve_Info *info) @@ -3186,16 +2762,6 @@ static Scheme_Object *resolve_invented_toplevel_to_defn(Resolve_Info *info, Sche SCHEME_TOPLEVEL_CONST); } -static int resolving_in_procedure(Resolve_Info *info) -{ - while (info) { - if (info->in_proc) - return 1; - info = info->next; - } - return 0; -} - /*========================================================================*/ /* unresolve */ /*========================================================================*/ @@ -3217,8 +2783,7 @@ typedef struct Unresolve_Info { int stack_pos; /* stack in resolved coordinates */ int depth; /* stack in unresolved coordinates */ int stack_size; - int *flags; - mzshort *depths; + Scheme_Compiled_Local **vars; Scheme_Prefix *prefix; Scheme_Hash_Table *closures; /* handle cycles */ int has_non_leaf, has_tl, body_size; @@ -3228,7 +2793,6 @@ typedef struct Unresolve_Info { Comp_Prefix *comp_prefix; Scheme_Hash_Table *toplevels; Scheme_Object *definitions; - mzshort *ref_args; int lift_offset; Scheme_Hash_Table *ref_lifts; } Unresolve_Info; @@ -3240,7 +2804,7 @@ static Scheme_Sequence *unresolve_let_value(Scheme_Let_Value *lv, Unresolve_Info static Unresolve_Info *new_unresolve_info(Scheme_Prefix *prefix) { Unresolve_Info *ui; - int *f, *d, *r; + Scheme_Compiled_Local **vars; Scheme_Hash_Table *ht; ui = MALLOC_ONE_RT(Unresolve_Info); @@ -3248,12 +2812,8 @@ static Unresolve_Info *new_unresolve_info(Scheme_Prefix *prefix) ui->stack_pos = 0; ui->stack_size = 10; - f = (int *)scheme_malloc_atomic(sizeof(int) * ui->stack_size); - ui->flags = f; - d = (mzshort *)scheme_malloc_atomic(sizeof(mzshort) * ui->stack_size); - ui->depths = d; - r = (mzshort *)scheme_malloc_atomic(sizeof(mzshort) * ui->stack_size); - ui->ref_args = r; + vars = MALLOC_N(Scheme_Compiled_Local *, ui->stack_size); + ui->vars = vars; ui->inlining = 1; ht = scheme_make_hash_table(SCHEME_hash_ptr); @@ -3267,42 +2827,29 @@ static Unresolve_Info *new_unresolve_info(Scheme_Prefix *prefix) return ui; } -static int unresolve_stack_push(Unresolve_Info *ui, int n, int r_only, int rev) +static int unresolve_stack_push(Unresolve_Info *ui, int n, int make_vars) { - int pos, *f, i; - mzshort *d, *r; + int pos, i; + Scheme_Compiled_Local **vars, *var; pos = ui->stack_pos; if (pos + n > ui->stack_size) { - f = (int *)scheme_malloc_atomic(sizeof(int) * ((2 * ui->stack_size) + n)); - memcpy(f, ui->flags, sizeof(int) * pos); - - d = (mzshort *)scheme_malloc_atomic(sizeof(mzshort) * ((2 * ui->stack_size) + n)); - memcpy(d, ui->depths, sizeof(mzshort) * pos); + vars = MALLOC_N(Scheme_Compiled_Local *, ((2 * ui->stack_size) + n)); + memcpy(vars, ui->vars, sizeof(Scheme_Compiled_Local *) * pos); - r = (mzshort *)scheme_malloc_atomic(sizeof(mzshort) * ((2 * ui->stack_size) + n)); - memcpy(r, ui->ref_args, sizeof(mzshort) * pos); - - ui->flags = f; - ui->depths = d; - ui->ref_args = r; + ui->vars = vars; ui->stack_size = (2 * ui->stack_size) + n; } - memset(ui->flags + pos, 0, sizeof(int) * n); - memset(ui->ref_args + pos, 0, sizeof(int) * n); - if (!r_only) { - if (!rev) { - for (i = 0; i < n; i++) { - ui->depths[pos + i] = ui->depth++; - } - } else { - for (i = n; i--;) { - ui->depths[pos + i] = ui->depth++; - } + if (make_vars) { + for (i = 0; i < n; i++) { + var = MALLOC_ONE_TAGGED(Scheme_Compiled_Local); + var->so.type = scheme_compiled_local_type; + ui->vars[pos + i] = var; } - } + } else + memset(ui->vars + pos, 0, sizeof(Scheme_Compiled_Local *) * n); ui->stack_pos += n; @@ -3312,76 +2859,47 @@ static int unresolve_stack_push(Unresolve_Info *ui, int n, int r_only, int rev) return pos; } -static int *unresolve_stack_pop(Unresolve_Info *ui, int pos, int n) +static Scheme_Compiled_Local **unresolve_stack_extract(Unresolve_Info *ui, int pos, int n) { - int *f, i; + Scheme_Compiled_Local **vars; + int i; + if (!n) + return NULL; + + vars = MALLOC_N(Scheme_Compiled_Local *, n); + for (i = 0; i < n; i++) { + vars[i] = ui->vars[ui->stack_pos - pos - 1 - i]; + } + + return vars; +} + +static Scheme_Compiled_Local **unresolve_stack_pop(Unresolve_Info *ui, int pos, int n) +{ + Scheme_Compiled_Local **vars; + + MZ_ASSERT(!n || (ui->stack_pos == pos + n)); + + vars = unresolve_stack_extract(ui, 0, n); + ui->stack_pos = pos; - if (n) { - f = (int *)scheme_malloc_atomic(sizeof(int) * n); - for (i = 0; i < n; i++) { - f[i] = ui->flags[pos + (n - i - 1)]; - } - ui->depth -= n; - } else - f = NULL; - - LOG_UNRESOLVE(printf("pop %d(%d), d=%d, sp=%d, [%d, %d, %d, %d, %d]\n", n, pos, ui->depth, ui->stack_pos, - ui->depths[0], ui->depths[1], ui->depths[2], ui->depths[3], ui->depths[4])); - - return f; + return vars; } -XFORM_NONGCING static int combine_flags(int a, int b) +static Scheme_Compiled_Local *unresolve_lookup(Unresolve_Info *ui, int pos, int as_rator) { - int ac, bc; + Scheme_Compiled_Local *var = ui->vars[ui->stack_pos - pos - 1]; - /* We don't currently try to support SCHEME_WAS_APPLIED_EXCEPT_ONCE, - since that's to detect ((letrec ([f ....]) f) ....) patterns - that would have been converted away already for code to inline - across a module boundary. We do need to track SCHEME_WAS_ONLY_APPLIED, - so that the resolver can ultimately lift expressions. */ + if (var->use_count < SCHEME_USE_COUNT_INF) + var->use_count++; + if (!as_rator + && !var->is_ref_arg + && (var->non_app_count < SCHEME_USE_COUNT_INF)) + var->non_app_count++; - if ((b & SCHEME_WAS_ONLY_APPLIED) && !(a & SCHEME_WAS_ONLY_APPLIED)) { - bc = b; - b = a; - a = bc; - } - - if (a & SCHEME_WAS_ONLY_APPLIED) { - if ((b & SCHEME_WAS_USED) && !(b & SCHEME_WAS_ONLY_APPLIED)) - a -= SCHEME_WAS_ONLY_APPLIED; - } - - ac = (a & SCHEME_USE_COUNT_MASK) >> SCHEME_USE_COUNT_SHIFT; - bc = (b & SCHEME_USE_COUNT_MASK) >> SCHEME_USE_COUNT_SHIFT; - - ac += bc; - if (ac > SCHEME_USE_COUNT_INF) - ac = SCHEME_USE_COUNT_INF; - - a |= b; - a = (a - (a & SCHEME_USE_COUNT_MASK)) | (ac << SCHEME_USE_COUNT_SHIFT); - - return a; -} - -static int unresolve_set_flag(Unresolve_Info *ui, int pos, int flag) -{ - int old_flag, i = ui->stack_pos - pos - 1; - - if ((pos < 0) || (pos >= ui->stack_pos)) - scheme_signal_error("internal error: unresolve out of bounds"); - - old_flag = ui->flags[i]; - flag = combine_flags(flag | (1 << SCHEME_USE_COUNT_SHIFT), old_flag); - ui->flags[i] = flag; - - LOG_UNRESOLVE(printf("local %d -> %d (d=%d, sp=%d, i=%d, d[i]=%d)\n", - pos, ui->depth - ui->depths[i] - 1, ui->depth, ui->stack_pos, i, ui->depths[i])); - - return ui->depth - ui->depths[i] - 1; + return var; } static Scheme_Object *unresolve_closure_data_2(Scheme_Closure_Data *rdata, Unresolve_Info *ui) @@ -3389,7 +2907,8 @@ static Scheme_Object *unresolve_closure_data_2(Scheme_Closure_Data *rdata, Unres Scheme_Closure_Data *data; Scheme_Object *body; Closure_Info *cl; - int i, pos, data_pos, *flags, init_size, has_non_leaf, has_tl; + int i, pos, data_pos, init_size, has_non_leaf, has_tl; + Scheme_Compiled_Local **vars; scheme_delay_load_closure(rdata); @@ -3403,26 +2922,26 @@ static Scheme_Object *unresolve_closure_data_2(Scheme_Closure_Data *rdata, Unres data->num_params = rdata->num_params; data->name = rdata->name; - pos = unresolve_stack_push(ui, data->num_params, 0, 0); - - + pos = unresolve_stack_push(ui, data->num_params, 1); + vars = unresolve_stack_extract(ui, 0, data->num_params); + if (SCHEME_CLOSURE_DATA_FLAGS(rdata) & CLOS_HAS_TYPED_ARGS) { for (i = 0; i < data->num_params; i++) { LOG_UNRESOLVE(printf("ref_args[%d] = %d\n", ui->stack_pos - i - 1, scheme_boxmap_get(rdata->closure_map, i, rdata->closure_size))); - ui->ref_args[ui->stack_pos - i - 1] = - scheme_boxmap_get(rdata->closure_map, i, rdata->closure_size) == CLOS_TYPE_BOXED; + if (scheme_boxmap_get(rdata->closure_map, i, rdata->closure_size) == CLOS_TYPE_BOXED) { + vars[i]->mutated = 1; + vars[i]->is_ref_arg = 1; + } } } if (rdata->closure_size) { - data_pos = unresolve_stack_push(ui, rdata->closure_size, 1, 0); - /* remap closure slots: */ - /* TODO: remap ref-args? */ + data_pos = unresolve_stack_push(ui, rdata->closure_size, 0); for (i = rdata->closure_size; i--; ) { - int mp; - mp = ui->depths[pos - rdata->closure_map[i] - 1]; - ui->depths[ui->stack_pos - i - 1] = mp; + Scheme_Compiled_Local *mp; + mp = ui->vars[pos - rdata->closure_map[i] - 1]; + ui->vars[ui->stack_pos - i - 1] = mp; } } else data_pos = 0; @@ -3450,20 +2969,11 @@ static Scheme_Object *unresolve_closure_data_2(Scheme_Closure_Data *rdata, Unres cl->has_tl = ui->has_tl; ui->has_tl = ui->has_tl || has_tl; - if (rdata->closure_size) { - /* copy flags from unpacked closure to original slots */ - for (i = rdata->closure_size; i--; ) { - int a, b; - a = ui->flags[pos - rdata->closure_map[i] - 1]; - b = ui->flags[ui->stack_pos - i - 1]; - a = combine_flags(a, b); - ui->flags[pos - rdata->closure_map[i] - 1] = a; - } + if (rdata->closure_size) (void)unresolve_stack_pop(ui, data_pos, 0); - } - flags = unresolve_stack_pop(ui, pos, data->num_params); - cl->local_flags = flags; + (void)unresolve_stack_pop(ui, pos, 0); + cl->vars = vars; /* We don't need to set any more fields of cl, because optimize does that. */ @@ -3580,16 +3090,14 @@ static Scheme_Let_Header *make_let_header(int count) { lh->iso.so.type = scheme_compiled_let_void_type; lh->count = count; lh->num_clauses = 0; - SCHEME_LET_FLAGS(lh) = SCHEME_LET_STAR; return lh; } -static Scheme_Compiled_Let_Value *make_compiled_let_value(int position, int count) { +static Scheme_Compiled_Let_Value *make_compiled_let_value(int count) { Scheme_Compiled_Let_Value *clv; clv = MALLOC_ONE_TAGGED(Scheme_Compiled_Let_Value); clv->iso.so.type = scheme_compiled_let_value_type; clv->count = count; - clv->position = position; return clv; } @@ -3626,7 +3134,8 @@ static void attach_lv(Scheme_Let_Header *lh, static Scheme_Object *unresolve_let_void(Scheme_Object *e, Unresolve_Info *ui) { Scheme_Let_Void *lv = (Scheme_Let_Void *)e; - int i, pos, count, *flags; + int i, pos, count; + Scheme_Compiled_Local **vars; Scheme_Let_Header *lh; Scheme_Object *o; Unresolve_Let_Void_State *state; @@ -3634,9 +3143,9 @@ static Scheme_Object *unresolve_let_void(Scheme_Object *e, Unresolve_Info *ui) { state = scheme_malloc(sizeof(Unresolve_Let_Void_State)); count = lv->count; - pos = unresolve_stack_push(ui, count, 0, 0); + pos = unresolve_stack_push(ui, count, 1); lh = make_let_header(count); - + o = lv->body; attach_lv(lh, NULL, NULL, NULL, state); for (i = 0; i < count;) { @@ -3645,8 +3154,11 @@ static Scheme_Object *unresolve_let_void(Scheme_Object *e, Unresolve_Info *ui) { Scheme_Let_Value *lval = (Scheme_Let_Value *)o; Scheme_Compiled_Let_Value *clv; Scheme_Object *val; - clv = make_compiled_let_value(lval->position, lval->count); + clv = make_compiled_let_value(lval->count); lh->num_clauses++; + + vars = unresolve_stack_extract(ui, lval->position, lv->count); + clv->vars = vars; if (SCHEME_LET_VALUE_AUTOBOX(lval)) { SCHEME_LET_FLAGS(lh) = SCHEME_LET_RECURSIVE; @@ -3673,11 +3185,14 @@ static Scheme_Object *unresolve_let_void(Scheme_Object *e, Unresolve_Info *ui) { for (j = 0; j < lr->count; j++) { Scheme_Compiled_Let_Value *clv; Scheme_Object *val; - clv = make_compiled_let_value(j, 1); + Scheme_Compiled_Local **vars; + clv = make_compiled_let_value(1); lh->num_clauses++; + vars = unresolve_stack_extract(ui, j, 1); val = unresolve_expr_2(lr->procs[j], ui, 0); if (!val) return_NULL; clv->value = val; + clv->vars = vars; attach_lv(NULL, clv, NULL, NULL, state); i++; } @@ -3686,7 +3201,7 @@ static Scheme_Object *unresolve_let_void(Scheme_Object *e, Unresolve_Info *ui) { } case scheme_sequence_type: { Scheme_Sequence *seq = (Scheme_Sequence *)o; - int i; + int i; for (i = 0; i < seq->count - 1; i++) { if (!SAME_TYPE(SCHEME_TYPE(seq->array[i]), scheme_local_type)) { scheme_signal_error("internal error: unexpected form in sequence: %d", SCHEME_TYPE(o)); @@ -3705,27 +3220,7 @@ static Scheme_Object *unresolve_let_void(Scheme_Object *e, Unresolve_Info *ui) { if (!o) return_NULL; attach_lv(NULL, NULL, NULL, o, state); - flags = unresolve_stack_pop(ui, pos, lv->count); - - /* Set up flags */ - { - Scheme_Compiled_Let_Value *clv; - int count = 0, *clv_flags; - clv = (Scheme_Compiled_Let_Value *)(lh->body); - while (count < lv->count) { - if (SAME_TYPE(SCHEME_TYPE((Scheme_Object *)clv), scheme_sequence_type)) { - Scheme_Sequence *seq = (Scheme_Sequence *)clv; - clv = (Scheme_Compiled_Let_Value *)seq->array[seq->count - 1]; - } - clv_flags = (int *)scheme_malloc_atomic(sizeof(int) * clv->count); - for (i = 0; i < clv->count; i++) { - clv_flags[i] = flags[i + count]; - } - clv->flags = clv_flags; - count += clv->count; - clv = (Scheme_Compiled_Let_Value *)(clv->body); - } - } + (void)unresolve_stack_pop(ui, pos, 0); return (Scheme_Object *)lh; } @@ -4071,20 +3566,18 @@ Scheme_Object *unresolve_module(Scheme_Object *e, Unresolve_Info *ui) static Scheme_Sequence *unresolve_let_value(Scheme_Let_Value *lv, Unresolve_Info *ui, Scheme_Object* val, Scheme_Object *body) { Scheme_Set_Bang *sb; - Scheme_Object *var; + Scheme_Compiled_Local *var; Scheme_Sequence *seq; LOG_UNRESOLVE(printf("set! position: %d (stack pos %d)\n", lv->position, ui->stack_pos)); - if (ui->ref_args[ui->stack_pos - lv->position - 1]) { + + var = unresolve_lookup(ui, lv->position, 0); + + if (var->is_ref_arg) { Scheme_App2_Rec *app2; - var = scheme_make_local(scheme_local_type, - unresolve_set_flag(ui, - lv->position, - SCHEME_WAS_USED), - 0); app2 = MALLOC_ONE_TAGGED(Scheme_App2_Rec); app2->iso.so.type = scheme_application2_type; - app2->rator = var; + app2->rator = (Scheme_Object *)var; app2->rand = val; seq = scheme_malloc_sequence(2); seq->so.type = scheme_sequence_type; @@ -4093,16 +3586,12 @@ static Scheme_Sequence *unresolve_let_value(Scheme_Let_Value *lv, Unresolve_Info seq->array[1] = body; return seq; } - var = scheme_make_local(scheme_local_type, - unresolve_set_flag(ui, - lv->position, - (SCHEME_WAS_SET_BANGED | SCHEME_WAS_USED)), - 0); + var->mutated = 1; sb = MALLOC_ONE_TAGGED(Scheme_Set_Bang); sb->so.type = scheme_set_bang_type; - sb->var = var; + sb->var = (Scheme_Object *)var; sb->val = val; seq = scheme_malloc_sequence(2); @@ -4140,13 +3629,15 @@ Scheme_App_Rec *maybe_unresolve_app_refs(Scheme_App_Rec *app, Unresolve_Info *ui LOG_UNRESOLVE(printf("ui->stack_pos = %d, argpos = %d, i = %d\n", ui->stack_pos, SCHEME_LOCAL_POS(app->args[i + 1]), i)); if ((scheme_boxmap_get(data->closure_map, i, data->closure_size) == CLOS_TYPE_BOXED) && SAME_TYPE(SCHEME_TYPE(app->args[i + 1]), scheme_local_type) && - !ui->ref_args[ui->stack_pos - SCHEME_LOCAL_POS(app->args[i + 1]) - 1]) { + !ui->vars[ui->stack_pos - SCHEME_LOCAL_POS(app->args[i + 1]) - 1]->is_ref_arg) { Scheme_Case_Lambda *cl; Scheme_Closure_Data *d0, *d1; Scheme_Set_Bang *sb; Scheme_Object *local; - Scheme_Object *arg, *s; - int *flags; + Scheme_Object *s; + Scheme_Compiled_Local *arg; + int pos; + Scheme_Compiled_Local **vars; Closure_Info *ci; LOG_UNRESOLVE(printf("This will be a case-lambda: %d\n", i)); @@ -4160,16 +3651,13 @@ Scheme_App_Rec *maybe_unresolve_app_refs(Scheme_App_Rec *app, Unresolve_Info *ui s = scheme_gensym(s); cl->name = s; - arg = scheme_make_local(scheme_local_type, - unresolve_set_flag(ui, - SCHEME_LOCAL_POS(app->args[i + 1]), - (SCHEME_WAS_SET_BANGED | SCHEME_WAS_USED)), - 0); + arg = unresolve_lookup(ui, SCHEME_LOCAL_POS(app->args[i + 1]), 0); + arg->mutated = 1; d0 = MALLOC_ONE_TAGGED(Scheme_Closure_Data); d0->iso.so.type = scheme_compiled_unclosed_procedure_type; d0->num_params = 0; - d0->code = arg; + d0->code = (Scheme_Object *)arg; ci = MALLOC_ONE_RT(Closure_Info); SET_REQUIRED_TAG(ci->type = scheme_rt_closure_info); d0->closure_map = (mzshort *)ci; @@ -4178,6 +3666,8 @@ Scheme_App_Rec *maybe_unresolve_app_refs(Scheme_App_Rec *app, Unresolve_Info *ui d0->name = s; cl->array[0] = (Scheme_Object *)d0; + pos = unresolve_stack_push(ui, 1, 1); + vars = unresolve_stack_pop(ui, pos, 1); d1 = MALLOC_ONE_TAGGED(Scheme_Closure_Data); d1->iso.so.type = scheme_compiled_unclosed_procedure_type; @@ -4185,16 +3675,15 @@ Scheme_App_Rec *maybe_unresolve_app_refs(Scheme_App_Rec *app, Unresolve_Info *ui sb = MALLOC_ONE_TAGGED(Scheme_Set_Bang); sb->so.type = scheme_set_bang_type; - local = scheme_make_local(scheme_local_type, SCHEME_LOCAL_POS(arg) + 1, 0); - sb->var = local; + sb->var = (Scheme_Object *)arg; local = scheme_make_local(scheme_local_type, 0, 0); - sb->val = local; + sb->val = (Scheme_Object *)vars[0]; d1->code = (Scheme_Object *)sb; ci = MALLOC_ONE_RT(Closure_Info); SET_REQUIRED_TAG(ci->type = scheme_rt_closure_info); - flags = (int *)scheme_malloc_atomic(sizeof(int)); - flags[0] = SCHEME_WAS_USED; - ci->local_flags = flags; + ci->vars = vars; + vars[0]->use_count = 1; + vars[0]->non_app_count = 1; d1->closure_map = (mzshort *)ci; @@ -4240,31 +3729,19 @@ static Scheme_Object *unresolve_expr_2(Scheme_Object *e, Unresolve_Info *ui, int switch (SCHEME_TYPE(e)) { case scheme_local_type: - return scheme_make_local(scheme_local_type, - unresolve_set_flag(ui, - SCHEME_LOCAL_POS(e), - (SCHEME_WAS_USED - | (as_rator - ? SCHEME_WAS_ONLY_APPLIED - : 0))), - 0); + return (Scheme_Object *)unresolve_lookup(ui, SCHEME_LOCAL_POS(e), as_rator); case scheme_local_unbox_type: { - if (ui->ref_args[ui->stack_pos - SCHEME_LOCAL_POS(e) - 1]) { + Scheme_Compiled_Local *var; + var = unresolve_lookup(ui, SCHEME_LOCAL_POS(e), as_rator); + if (var->is_ref_arg) { Scheme_App_Rec *app; - Scheme_Object *rator; LOG_UNRESOLVE(printf("local unbox: %d (stack pos %d)\n", SCHEME_LOCAL_POS(e), ui->stack_pos)); app = scheme_malloc_application(1); - rator = scheme_make_local(scheme_local_type, - unresolve_set_flag(ui, SCHEME_LOCAL_POS(e), SCHEME_WAS_USED), - 0); - app->args[0] = rator; + app->args[0] = (Scheme_Object *)var; return (Scheme_Object *)app; } - return scheme_make_local(scheme_local_type, - unresolve_set_flag(ui, SCHEME_LOCAL_POS(e), - (SCHEME_WAS_SET_BANGED | SCHEME_WAS_USED)), - 0); + return (Scheme_Object *)var; } case scheme_sequence_type: case scheme_begin0_sequence_type: @@ -4294,7 +3771,7 @@ static Scheme_Object *unresolve_expr_2(Scheme_Object *e, Unresolve_Info *ui, int ui->body_size += app->num_args; check_nonleaf_rator(app->args[0], ui); - pos = unresolve_stack_push(ui, app->num_args, 1, 0); + pos = unresolve_stack_push(ui, app->num_args, 0); app2 = maybe_unresolve_app_refs(app, ui); if (app2) { @@ -4323,7 +3800,7 @@ static Scheme_Object *unresolve_expr_2(Scheme_Object *e, Unresolve_Info *ui, int ui->body_size += 1; check_nonleaf_rator(app->rator, ui); - pos = unresolve_stack_push(ui, 1, 1, 0); + pos = unresolve_stack_push(ui, 1, 0); rator = unresolve_expr_2(app->rator, ui, 0); if (!rator) return_NULL; @@ -4348,7 +3825,7 @@ static Scheme_Object *unresolve_expr_2(Scheme_Object *e, Unresolve_Info *ui, int ui->body_size += 2; check_nonleaf_rator(app->rator, ui); - pos = unresolve_stack_push(ui, 2, 1, 0); + pos = unresolve_stack_push(ui, 2, 0); rator = unresolve_expr_2(app->rator, ui, 0); if (!rator) return_NULL; @@ -4411,6 +3888,7 @@ static Scheme_Object *unresolve_expr_2(Scheme_Object *e, Unresolve_Info *ui, int { Scheme_With_Continuation_Mark *wcm = (Scheme_With_Continuation_Mark *)e, *wcm2; Scheme_Object *k, *v, *b; + Scheme_Compiled_Local **vars; int pos; k = unresolve_expr_2(wcm->key, ui, 0); @@ -4418,15 +3896,17 @@ static Scheme_Object *unresolve_expr_2(Scheme_Object *e, Unresolve_Info *ui, int v = unresolve_expr_2(wcm->val, ui, 0); if (!v) return_NULL; - pos = unresolve_stack_push(ui, 1, 0, 0); + pos = unresolve_stack_push(ui, 1, 1); + vars = unresolve_stack_extract(ui, 0, 1); b = unresolve_expr_2(wcm->body, ui, 0); if (!b) return_NULL; - (void)unresolve_stack_pop(ui, pos, 1); + (void)unresolve_stack_pop(ui, pos, 0); wcm2 = MALLOC_ONE_TAGGED(Scheme_With_Continuation_Mark); wcm2->so.type = scheme_with_immed_mark_type; wcm2->key = k; wcm2->val = v; + b = scheme_make_raw_pair((Scheme_Object *)vars[0], b); wcm2->body = b; return (Scheme_Object *)wcm2; @@ -4441,17 +3921,17 @@ static Scheme_Object *unresolve_expr_2(Scheme_Object *e, Unresolve_Info *ui, int Scheme_Object *rhs, *body; Scheme_Let_Header *lh; Scheme_Compiled_Let_Value *clv; - int *flags, pos; + Scheme_Compiled_Local **vars; + int pos; - pos = unresolve_stack_push(ui, 1, 1 /* => post-bind RHS */, 0); + pos = unresolve_stack_push(ui, 1, 1); rhs = unresolve_expr_2(lo->value, ui, 0); if (!rhs) return_NULL; - (void)unresolve_stack_pop(ui, pos, 0); - pos = unresolve_stack_push(ui, 1, 0, 0); body = unresolve_expr_2(lo->body, ui, 0); if (!body) return_NULL; - flags = unresolve_stack_pop(ui, pos, 1); + + vars = unresolve_stack_pop(ui, pos, 1); lh = MALLOC_ONE_TAGGED(Scheme_Let_Header); lh->iso.so.type = scheme_compiled_let_void_type; @@ -4461,9 +3941,8 @@ static Scheme_Object *unresolve_expr_2(Scheme_Object *e, Unresolve_Info *ui, int clv = MALLOC_ONE_TAGGED(Scheme_Compiled_Let_Value); clv->iso.so.type = scheme_compiled_let_value_type; clv->count = 1; - clv->position = 0; clv->value = rhs; - clv->flags = flags; + clv->vars = vars; clv->body = body; lh->body = (Scheme_Object *)clv; @@ -4633,7 +4112,8 @@ Scheme_Object *unresolve_closure_data(Scheme_Closure_Data *rdata, Unresolve_Info Scheme_Closure_Data *data; Scheme_Object *body; Closure_Info *cl; - int i, pos, data_pos, *flags, init_size, has_non_leaf; + int i, pos, data_pos, init_size, has_non_leaf; + Scheme_Compiled_Local **vars; scheme_delay_load_closure(rdata); @@ -4653,15 +4133,15 @@ Scheme_Object *unresolve_closure_data(Scheme_Closure_Data *rdata, Unresolve_Info data->num_params = rdata->num_params; data->name = rdata->name; - pos = unresolve_stack_push(ui, data->num_params, 0, 0); + pos = unresolve_stack_push(ui, data->num_params, 1); if (rdata->closure_size) { - data_pos = unresolve_stack_push(ui, rdata->closure_size, 1, 0); + data_pos = unresolve_stack_push(ui, rdata->closure_size, 0); /* remap closure slots: */ for (i = rdata->closure_size; i--; ) { - int mp; - mp = ui->depths[pos - rdata->closure_map[i] - 1]; - ui->depths[ui->stack_pos - i - 1] = mp; + Scheme_Compiled_Local *mp; + mp = ui->vars[pos - rdata->closure_map[i] - 1]; + ui->vars[ui->stack_pos - i - 1] = mp; } } else data_pos = 0; @@ -4684,20 +4164,11 @@ Scheme_Object *unresolve_closure_data(Scheme_Closure_Data *rdata, Unresolve_Info ui->has_non_leaf = has_non_leaf; - if (rdata->closure_size) { - /* copy flags from unpacked closure to original slots */ - for (i = rdata->closure_size; i--; ) { - int a, b; - a = ui->flags[pos - rdata->closure_map[i] - 1]; - b = ui->flags[ui->stack_pos - i - 1]; - a = combine_flags(a, b); - ui->flags[pos - rdata->closure_map[i] - 1] = a; - } + if (rdata->closure_size) (void)unresolve_stack_pop(ui, data_pos, 0); - } - flags = unresolve_stack_pop(ui, pos, data->num_params); - cl->local_flags = flags; + vars = unresolve_stack_pop(ui, pos, data->num_params); + cl->vars = vars; return (Scheme_Object *)data; } @@ -4782,19 +4253,9 @@ static Scheme_Object *unresolve_expr(Scheme_Object *e, Unresolve_Info *ui, int a switch (SCHEME_TYPE(e)) { case scheme_local_type: - return scheme_make_local(scheme_local_type, - unresolve_set_flag(ui, - SCHEME_LOCAL_POS(e), - (SCHEME_WAS_USED - | (as_rator - ? SCHEME_WAS_ONLY_APPLIED - : 0))), - 0); + return (Scheme_Object *)unresolve_lookup(ui, SCHEME_LOCAL_POS(e), as_rator); case scheme_local_unbox_type: - return scheme_make_local(scheme_local_type, - unresolve_set_flag(ui, SCHEME_LOCAL_POS(e), - (SCHEME_WAS_SET_BANGED | SCHEME_WAS_USED)), - 0); + return (Scheme_Object *)unresolve_lookup(ui, SCHEME_LOCAL_POS(e), as_rator); case scheme_sequence_type: { Scheme_Sequence *seq = (Scheme_Sequence *)e, *seq2; @@ -4821,7 +4282,7 @@ static Scheme_Object *unresolve_expr(Scheme_Object *e, Unresolve_Info *ui, int a ui->body_size += app->num_args; check_nonleaf_rator(app->args[0], ui); - pos = unresolve_stack_push(ui, app->num_args, 1, 0); + pos = unresolve_stack_push(ui, app->num_args, 0); app2 = scheme_malloc_application(app->num_args+1); @@ -4844,7 +4305,7 @@ static Scheme_Object *unresolve_expr(Scheme_Object *e, Unresolve_Info *ui, int a ui->body_size += 1; check_nonleaf_rator(app->rator, ui); - pos = unresolve_stack_push(ui, 1, 1, 0); + pos = unresolve_stack_push(ui, 1, 0); rator = unresolve_expr(app->rator, ui, 1); if (!rator) return_NULL; @@ -4869,7 +4330,7 @@ static Scheme_Object *unresolve_expr(Scheme_Object *e, Unresolve_Info *ui, int a ui->body_size += 2; check_nonleaf_rator(app->rator, ui); - pos = unresolve_stack_push(ui, 2, 1, 0); + pos = unresolve_stack_push(ui, 2, 0); rator = unresolve_expr(app->rator, ui, 1); if (!rator) return_NULL; @@ -4919,7 +4380,8 @@ static Scheme_Object *unresolve_expr(Scheme_Object *e, Unresolve_Info *ui, int a Scheme_Let_Header *lh; Scheme_Compiled_Let_Value *clv, *prev = NULL; Scheme_Object *rhs, *body; - int i, pos, *all_flags, *flags; + Scheme_Compiled_Local **vars; + int i, pos; lh = MALLOC_ONE_TAGGED(Scheme_Let_Header); lh->iso.so.type = scheme_compiled_let_void_type; @@ -4927,7 +4389,7 @@ static Scheme_Object *unresolve_expr(Scheme_Object *e, Unresolve_Info *ui, int a lh->num_clauses = lv->count; SCHEME_LET_FLAGS(lh) += SCHEME_LET_RECURSIVE; - pos = unresolve_stack_push(ui, lv->count, 0, 0); + pos = unresolve_stack_push(ui, lv->count, 1); for (i = lv->count; i--; ) { rhs = unresolve_expr(lr->procs[i], ui, 0); @@ -4936,9 +4398,11 @@ static Scheme_Object *unresolve_expr(Scheme_Object *e, Unresolve_Info *ui, int a clv = MALLOC_ONE_TAGGED(Scheme_Compiled_Let_Value); clv->iso.so.type = scheme_compiled_let_value_type; clv->count = 1; - clv->position = i; clv->value = rhs; + vars = unresolve_stack_extract(ui, i, 1); + clv->vars = vars; + if (prev) prev->body = (Scheme_Object *)clv; else @@ -4953,15 +4417,7 @@ static Scheme_Object *unresolve_expr(Scheme_Object *e, Unresolve_Info *ui, int a else lh->body = body; - all_flags = unresolve_stack_pop(ui, pos, lv->count); - - clv = (Scheme_Compiled_Let_Value *)lh->body; - for (i = lv->count; i--; ) { - flags = (int *)scheme_malloc_atomic(sizeof(int)); - flags[0] = all_flags[i]; - clv->flags = flags; - clv = (Scheme_Compiled_Let_Value *)clv->body; - } + (void)unresolve_stack_pop(ui, pos, 0); return (Scheme_Object *)lh; } @@ -4975,17 +4431,15 @@ static Scheme_Object *unresolve_expr(Scheme_Object *e, Unresolve_Info *ui, int a Scheme_Object *rhs, *body; Scheme_Let_Header *lh; Scheme_Compiled_Let_Value *clv; - int *flags, pos; + Scheme_Compiled_Local **vars; + int pos; + + pos = unresolve_stack_push(ui, 1, 1); - pos = unresolve_stack_push(ui, 1, 1 /* => post-bind RHS */, 0); rhs = unresolve_expr(lo->value, ui, 0); - if (!rhs) return_NULL; - (void)unresolve_stack_pop(ui, pos, 0); - - pos = unresolve_stack_push(ui, 1, 0, 0); body = unresolve_expr(lo->body, ui, 0); - if (!body) return_NULL; - flags = unresolve_stack_pop(ui, pos, 1); + + vars = unresolve_stack_pop(ui, pos, 1); lh = MALLOC_ONE_TAGGED(Scheme_Let_Header); lh->iso.so.type = scheme_compiled_let_void_type; @@ -4995,9 +4449,8 @@ static Scheme_Object *unresolve_expr(Scheme_Object *e, Unresolve_Info *ui, int a clv = MALLOC_ONE_TAGGED(Scheme_Compiled_Let_Value); clv->iso.so.type = scheme_compiled_let_value_type; clv->count = 1; - clv->position = 0; clv->value = rhs; - clv->flags = flags; + clv->vars = vars; clv->body = body; lh->body = (Scheme_Object *)clv; diff --git a/racket/src/racket/src/schpriv.h b/racket/src/racket/src/schpriv.h index fc08d6c35c..12d39aa482 100644 --- a/racket/src/racket/src/schpriv.h +++ b/racket/src/racket/src/schpriv.h @@ -1459,6 +1459,112 @@ Scheme_Object *scheme_top_introduce(Scheme_Object *form, Scheme_Env *genv); /* syntax run-time structures */ /*========================================================================*/ +/* A Scheme_Compiled_Local record represents a local variable, + both the binding and references to that binding. When inlining + of other transformations duplicate a variable, a new instance + is allocated to represent a separate variable. Different passes + in the comiler store different information about the variable. */ +typedef struct Scheme_Compiled_Local +{ + Scheme_Object so; + + /* The `mode` value is one of `SCHEME_VAR_MODE_NONE`, etc., + and it determines which of the union cases below (if any) + is active, corresponding to information for a particular + pass: */ + unsigned int mode : 3; + /* Number of time the variable was referenced as counted by + the initial compile phase; a `SCHEME_USE_COUNT_INF` + value corresponds to "more than we counted": */ + unsigned int use_count : 3; + /* Subset of `use_count` references that are in non-rator + positions: */ + unsigned int non_app_count : 3; + /* Records whether the variable is mutated; set in several + phases, and currently never unset: */ + unsigned int mutated : 1; + /* Records whether the optimizer discovered any uses; + if true, then `use_count` must be non-zero, but the + optimizer eliminate references and produce 0 here even + if `use_count` is non-zero: */ + unsigned int optimize_used : 1; + /* Set while compiling the right-hand side of a letrec + to indicate that current and later left-hand sides + are not yet initialized: */ + unsigned int optimize_unready : 1; + /* After optimizing a `let[rec]` form, we might still go into + the body (e.g., for funciton inlining), but mark the variable + as having a binding set up: */ + unsigned int optimize_outside_binding : 1; + /* Records an anlaysis during the resolve pass: */ + unsigned int resolve_omittable : 1; + /* The type desired by use positions for unboxing purposes; + set by the optimizer: */ + unsigned int arg_type : SCHEME_MAX_LOCAL_TYPE_BITS; + /* The type provided by the binding position, mainly for unboxing + purposes; set by the optimizer and potentially refined by the + resolve pass (especially for function arguments whose types are + set via local_type_map): */ + unsigned int val_type : SCHEME_MAX_LOCAL_TYPE_BITS; + /* Unboxing might be disabled because allocation of boxes would + be moved past a continuation: */ + unsigned int escapes_after_k_tick : 1; + /* During unresolve, indicates whether references should be + converted to calls: */ + unsigned int is_ref_arg : 1; + + Scheme_Object *name; + + /* `mode` determines which union is active: */ + union { + struct { + /* Maps the variable into the letrec-check pass's frames: */ + struct Letrec_Check_Frame *frame; + int frame_pos; + } letrec_check; + struct { + /* Constant- and copy-propagation information: */ + Scheme_Object *known_val; + /* Number of `lambda` wrappers, which is relevant for + accumulating closures, etc.: */ + int lambda_depth; + /* Vitual continuation-capture clock for the variable's + initialation, used to detect potential captures of + allocation: */ + int init_kclock; + /* Transitive uses record uses that become used if + the variable itself is used; which is relevant + for analyzing a letrec-bound function that might + not get called: */ + Scheme_Hash_Table *transitive_uses; + struct Optimize_Info *transitive_uses_to; + } optimize; + struct { + /* Records the position where the variable will be + on the runstack, counting down from the enclosing + procedure's starting point (i.e., backwards from the + run-time direction): */ + int co_depth; + /* Records a lexical depth for the purposes of sorting + variables (as needed to make compilation deterministic): */ + int lex_depth; + /* Information on closure-converstion of this + variable's binding: */ + Scheme_Object *lifted; + } resolve; + }; +} Scheme_Compiled_Local; + +#define SCHEME_VAR(v) ((Scheme_Compiled_Local *)v) + +#define SCHEME_USE_COUNT_INF 7 + +#define SCHEME_VAR_MODE_NONE 0 +#define SCHEME_VAR_MODE_COMPILE 1 +#define SCHEME_VAR_MODE_LETREC_CHECK 2 +#define SCHEME_VAR_MODE_OPTIMIZE 3 +#define SCHEME_VAR_MODE_RESOLVE 4 + typedef struct { Scheme_Inclhash_Object iso; /* keyex used for flags */ mzshort num_args; /* doesn't include rator, so arguments are at args[1]...args[num_args] */ @@ -1514,33 +1620,12 @@ typedef struct { additions to the top-level bindings table */ } Scheme_Compilation_Top; -/* A `let', `let*', or `letrec' form is compiled to the intermediate +/* A `let' or `letrec' form is compiled to the intermediate format (used during the optimization pass) as a Scheme_Let_Header with a chain of Scheme_Compiled_Let_Value records as its body, where there's one Scheme_Compiled_Let_Value for each binding - clause. A `let*' is normally expanded to nested `let's before - compilation, but the intermediate format also supports `let*', - which is useful mostly for converting a simple enough `letrec' form - into `let*. - - The body of the `let...' form is the body of the innermost - Scheme_Compiled_Let_Value record. Obviously, all N bindings of a - `let...' form are pushed onto the virtual stack for the body, but - the situation is more complex for the binding right-hand - sides. There are three cases: - - * Plain `let': no bindings are pushed, yet. (This is in contrast - to the convention for the final bytecode format, where space for - the binding is allocated before the right-hand side is - evaluated.) - - * `letrec': all bindings are pushed; the first clause is pushed - first, etc. - - * `let*' can be like `letrec', but also can have the bindings in - reverse order; that is, all bindings are pushed before any - right-hand side, but the last binding may be pushed first - instead of last. + clause. The body of the `let...' form is the body of the innermost + Scheme_Compiled_Let_Value record. */ typedef struct Scheme_Let_Header { @@ -1552,16 +1637,13 @@ typedef struct Scheme_Let_Header { #define SCHEME_LET_FLAGS(lh) MZ_OPT_HASH_KEY(&lh->iso) #define SCHEME_LET_RECURSIVE 0x1 -#define SCHEME_LET_STAR 0x2 typedef struct Scheme_Compiled_Let_Value { Scheme_Inclhash_Object iso; /* keyex used for set-starting */ mzshort count; - mzshort position; - int *flags; Scheme_Object *value; Scheme_Object *body; - Scheme_Object **names; /* NULL after letrec_check phase */ + Scheme_Compiled_Local **vars; } Scheme_Compiled_Let_Value; #define SCHEME_CLV_FLAGS(clv) MZ_OPT_HASH_KEY(&(clv)->iso) @@ -2688,8 +2770,9 @@ typedef struct Scheme_Comp_Env Scheme_Object **bindings; /* symbols */ Scheme_Object **vals; /* compile-time values */ Scheme_Object **shadower_deltas; + Scheme_Compiled_Local **vars; int *use; - int min_use, any_use; + int max_use, any_use; Scheme_Object *lifts; @@ -2765,10 +2848,9 @@ typedef struct Resolve_Info Resolve_Info; before a closure mapping is resolved. */ typedef struct { MZTAG_IF_REQUIRED - int *local_flags; /* for arguments from compile pass, flonum info updated in optimize pass */ - mzshort base_closure_size; /* doesn't include top-level (if any) */ - mzshort *base_closure_map; - char *local_type_map; /* NULL when has_tymap set => no local types */ + Scheme_Hash_Table *base_closure; + Scheme_Compiled_Local **vars; + char *local_type_map; /* determined by callers; NULL when has_tymap set => no local types */ char has_tl, has_tymap, has_nonleaf; int body_size, body_psize; } Closure_Info; @@ -3189,7 +3271,7 @@ Scheme_Logger *scheme_optimize_info_logger(Optimize_Info *); Scheme_Object *scheme_toplevel_to_flagged_toplevel(Scheme_Object *tl, int flags); -int scheme_expr_produces_local_type(Scheme_Object *expr); +int scheme_expr_produces_local_type(Scheme_Object *expr, int *_involves_k_cross); Scheme_Object *scheme_make_compiled_syntax(Scheme_Syntax *syntax, Scheme_Syntax_Expander *exp); @@ -3223,7 +3305,8 @@ void scheme_init_expand_recs(Scheme_Expand_Info *src, int drec, Scheme_Expand_Info *dest, int n); Scheme_Object *scheme_make_sequence_compilation(Scheme_Object *compiled_list, - int strip_values); + int strip_values, + int resolved); Scheme_App_Rec *scheme_malloc_application(int n); void scheme_finish_application(Scheme_App_Rec *app); @@ -3254,24 +3337,12 @@ Scheme_Object *scheme_build_closure_name(Scheme_Object *code, Scheme_Comp_Env *e #define SCHEME_SYNTAX(obj) SCHEME_PTR1_VAL(obj) #define SCHEME_SYNTAX_EXP(obj) SCHEME_PTR2_VAL(obj) -int *scheme_env_get_flags(Scheme_Comp_Env *frame, int start, int count); int scheme_env_check_reset_any_use(Scheme_Comp_Env *frame); -int scheme_env_min_use_below(Scheme_Comp_Env *frame, int pos); +int scheme_env_max_use_above(Scheme_Comp_Env *frame, int pos); void scheme_mark_all_use(Scheme_Comp_Env *frame); - -/* flags reported by scheme_env_get_flags */ -#define SCHEME_WAS_USED 0x1 -#define SCHEME_WAS_SET_BANGED 0x2 -#define SCHEME_WAS_ONLY_APPLIED 0x4 -#define SCHEME_WAS_APPLIED_EXCEPT_ONCE 0x8 - -#define SCHEME_USE_COUNT_MASK 0x70 -#define SCHEME_USE_COUNT_SHIFT 4 -#define SCHEME_USE_COUNT_INF (SCHEME_USE_COUNT_MASK >> SCHEME_USE_COUNT_SHIFT) - -#define SCHEME_WAS_TYPED_ARGUMENT_SHIFT 7 -#define SCHEME_WAS_TYPED_ARGUMENT_MASK (SCHEME_MAX_LOCAL_TYPE_MASK << SCHEME_WAS_TYPED_ARGUMENT_SHIFT) -#define SCHEME_WAS_TYPED_ARGUMENT(f) ((f & SCHEME_WAS_TYPED_ARGUMENT_MASK) >> SCHEME_WAS_TYPED_ARGUMENT_SHIFT) +void scheme_env_make_variables(Scheme_Comp_Env *frame); +void scheme_set_compilation_variables(Scheme_Comp_Env *frame, Scheme_Compiled_Local **vars, + int pos, int count); /* flags reported by scheme_resolve_info_flags */ #define SCHEME_INFO_BOXED 0x1 @@ -3349,14 +3420,14 @@ void scheme_prepare_env_stx_context(Scheme_Env *env); XFORM_NONGCING Scheme_Object *scheme_env_phase(Scheme_Env *env); Scheme_Env *scheme_find_env_at_phase(Scheme_Env *env, Scheme_Object *phase); -int scheme_used_app_only(Scheme_Comp_Env *env, int which); -int scheme_used_ever(Scheme_Comp_Env *env, int which); +int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int flags, + Optimize_Info *opt_info, Optimize_Info *warn_info); +#define OMITTABLE_RESOLVED 0x1 +#define OMITTABLE_KEEP_VARS 0x2 +#define OMITTABLE_KEEP_MUTABLE_VARS 0x4 -int scheme_omittable_expr(Scheme_Object *o, int vals, int fuel, int resolved, - Optimize_Info *opt_info, Optimize_Info *warn_info, - int min_id_depth, int id_offset, 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 or_escape); +int scheme_is_liftable(Scheme_Object *o, Scheme_Hash_Tree *exclude_vars, int fuel, int as_rator, int or_escape); int scheme_is_functional_nonfailing_primitive(Scheme_Object *rator, int num_args, int expected_vals); typedef struct { @@ -3393,8 +3464,6 @@ int scheme_closure_preserves_marks(Scheme_Object *p); int scheme_native_closure_preserves_marks(Scheme_Object *p); int scheme_native_closure_is_single_result(Scheme_Object *rator); -int scheme_is_env_variable_boxed(Scheme_Comp_Env *env, int which); - int scheme_get_eval_type(Scheme_Object *obj); Scheme_Object *scheme_make_application(Scheme_Object *v, Optimize_Info *info); @@ -4533,6 +4602,7 @@ void scheme_place_check_memory_use(); void scheme_clear_place_ifs_stack(); Scheme_Object **scheme_extract_sorted_keys(Scheme_Object *ht); +void scheme_sort_resolve_compiled_local_array(Scheme_Compiled_Local **a, intptr_t count); #ifdef MZ_USE_PLACES Scheme_Object *scheme_place_make_async_channel(); diff --git a/racket/src/racket/src/schvers.h b/racket/src/racket/src/schvers.h index 1b397112d8..884697452a 100644 --- a/racket/src/racket/src/schvers.h +++ b/racket/src/racket/src/schvers.h @@ -13,12 +13,12 @@ consistently.) */ -#define MZSCHEME_VERSION "6.4.0.7" +#define MZSCHEME_VERSION "6.4.0.8" #define MZSCHEME_VERSION_X 6 #define MZSCHEME_VERSION_Y 4 #define MZSCHEME_VERSION_Z 0 -#define MZSCHEME_VERSION_W 7 +#define MZSCHEME_VERSION_W 8 #define MZSCHEME_VERSION_MAJOR ((MZSCHEME_VERSION_X * 100) + MZSCHEME_VERSION_Y) #define MZSCHEME_VERSION_MINOR ((MZSCHEME_VERSION_Z * 1000) + MZSCHEME_VERSION_W) diff --git a/racket/src/racket/src/sfs.c b/racket/src/racket/src/sfs.c index 3cc0d7c3cb..cba3826d16 100644 --- a/racket/src/racket/src/sfs.c +++ b/racket/src/racket/src/sfs.c @@ -717,7 +717,7 @@ static Scheme_Object *sfs_let_one(Scheme_Object *o, SFS_Info *info) it might not because (1) it was introduced late by inlining, or (2) the rhs expression doesn't always produce a single value. */ - if (scheme_omittable_expr(rhs, 1, -1, 1, NULL, NULL, 0, 0, 0)) { + if (scheme_omittable_expr(rhs, 1, -1, OMITTABLE_RESOLVED, NULL, NULL)) { rhs = scheme_false; } else if ((ip < info->max_calls[pos]) && SAME_TYPE(SCHEME_TYPE(rhs), scheme_toplevel_type)) { diff --git a/racket/src/racket/src/stypes.h b/racket/src/racket/src/stypes.h index 96784c153c..8731df1029 100644 --- a/racket/src/racket/src/stypes.h +++ b/racket/src/racket/src/stypes.h @@ -36,270 +36,271 @@ enum { _scheme_values_types_, /* All following types are values */ /* intermediate compiled: */ - scheme_compiled_unclosed_procedure_type,/* 30 */ - scheme_compiled_let_value_type, /* 31 */ - scheme_compiled_let_void_type, /* 32 */ - scheme_compiled_toplevel_type, /* 33 */ - scheme_compiled_quote_syntax_type, /* 34 */ + scheme_compiled_local_type, /* 30 */ + scheme_compiled_unclosed_procedure_type,/* 31 */ + scheme_compiled_let_value_type, /* 32 */ + scheme_compiled_let_void_type, /* 33 */ + scheme_compiled_toplevel_type, /* 34 */ + scheme_compiled_quote_syntax_type, /* 35 */ scheme_quote_compilation_type, /* used while writing, only */ /* Registered in prefix table: */ - scheme_variable_type, /* 36 */ + scheme_variable_type, /* 37 */ scheme_module_variable_type, /* link replaces with scheme_variable_type */ - _scheme_compiled_values_types_, /* 38 */ + _scheme_compiled_values_types_, /* 39 */ /* procedure types */ - scheme_prim_type, /* 39 */ - scheme_closed_prim_type, /* 40 */ - scheme_closure_type, /* 41 */ - scheme_case_closure_type, /* 42 */ - scheme_cont_type, /* 43 */ - scheme_escaping_cont_type, /* 44 */ - scheme_proc_struct_type, /* 45 */ - scheme_native_closure_type, /* 46 */ - scheme_proc_chaperone_type, /* 47 */ + scheme_prim_type, /* 40 */ + scheme_closed_prim_type, /* 41 */ + scheme_closure_type, /* 42 */ + scheme_case_closure_type, /* 43 */ + scheme_cont_type, /* 44 */ + scheme_escaping_cont_type, /* 45 */ + scheme_proc_struct_type, /* 46 */ + scheme_native_closure_type, /* 47 */ + scheme_proc_chaperone_type, /* 48 */ - scheme_chaperone_type, /* 48 */ + scheme_chaperone_type, /* 49 */ /* structure type (plus one above for procs) */ - scheme_structure_type, /* 49 */ + scheme_structure_type, /* 50 */ /* number types (must be together) */ - scheme_integer_type, /* 50 */ - scheme_bignum_type, /* 51 */ - scheme_rational_type, /* 52 */ - scheme_float_type, /* 53 */ - scheme_double_type, /* 54 */ - scheme_complex_type, /* 55 */ + scheme_integer_type, /* 51 */ + scheme_bignum_type, /* 52 */ + scheme_rational_type, /* 53 */ + scheme_float_type, /* 54 */ + scheme_double_type, /* 55 */ + scheme_complex_type, /* 56 */ /* other eqv?-able values (must be with numbers) */ - scheme_char_type, /* 56 */ + scheme_char_type, /* 57 */ /* other values */ - scheme_long_double_type, /* 57 */ - scheme_char_string_type, /* 58 */ - scheme_byte_string_type, /* 59 */ - scheme_unix_path_type, /* 60 */ - scheme_windows_path_type, /* 61 */ - scheme_symbol_type, /* 62 */ - scheme_keyword_type, /* 63 */ - scheme_null_type, /* 64 */ - scheme_pair_type, /* 65 */ - scheme_mutable_pair_type, /* 66 */ - scheme_vector_type, /* 67 */ - scheme_inspector_type, /* 68 */ - scheme_input_port_type, /* 69 */ - scheme_output_port_type, /* 70 */ - scheme_eof_type, /* 71 */ - scheme_true_type, /* 72 */ - scheme_false_type, /* 73 */ - scheme_void_type, /* 74 */ - scheme_syntax_compiler_type, /* 75 */ - scheme_macro_type, /* 76 */ - scheme_box_type, /* 77 */ - scheme_thread_type, /* 78 */ - scheme_scope_type, /* 79 */ - scheme_stx_offset_type, /* 80 */ - scheme_cont_mark_set_type, /* 81 */ - scheme_sema_type, /* 82 */ - scheme_hash_table_type, /* 83 */ - scheme_hash_tree_type, /* 84 */ - scheme_eq_hash_tree_type, /* 85 */ - scheme_eqv_hash_tree_type, /* 86 */ - scheme_hash_tree_subtree_type, /* 87 */ - scheme_hash_tree_collision_type, /* 88 */ - scheme_hash_tree_indirection_type, /* 89 */ - scheme_cpointer_type, /* 90 */ - scheme_prefix_type, /* 91 */ - scheme_weak_box_type, /* 92 */ - scheme_ephemeron_type, /* 93 */ - scheme_struct_type_type, /* 94 */ - scheme_module_index_type, /* 95 */ - scheme_set_macro_type, /* 96 */ - scheme_listener_type, /* 97 */ - scheme_namespace_type, /* 98 */ - scheme_config_type, /* 99 */ - scheme_stx_type, /* 100 */ - scheme_will_executor_type, /* 101 */ - scheme_custodian_type, /* 102 */ - scheme_random_state_type, /* 103 */ - scheme_regexp_type, /* 104 */ - scheme_bucket_type, /* 105 */ - scheme_bucket_table_type, /* 106 */ - scheme_subprocess_type, /* 107 */ - scheme_compilation_top_type, /* 108 */ - scheme_wrap_chunk_type, /* 109 */ - scheme_eval_waiting_type, /* 110 */ - scheme_tail_call_waiting_type, /* 111 */ - scheme_undefined_type, /* 112 */ - scheme_struct_property_type, /* 113 */ - scheme_chaperone_property_type, /* 114 */ - scheme_multiple_values_type, /* 115 */ - scheme_placeholder_type, /* 116 */ - scheme_table_placeholder_type, /* 117 */ - scheme_scope_table_type, /* 118 */ - scheme_propagate_table_type, /* 119 */ - scheme_svector_type, /* 120 */ - scheme_resolve_prefix_type, /* 121 */ - scheme_security_guard_type, /* 122 */ - scheme_indent_type, /* 123 */ - scheme_udp_type, /* 124 */ - scheme_udp_evt_type, /* 125 */ - scheme_tcp_accept_evt_type, /* 126 */ - scheme_id_macro_type, /* 127 */ - scheme_evt_set_type, /* 128 */ - scheme_wrap_evt_type, /* 129 */ - scheme_handle_evt_type, /* 130 */ - scheme_replace_evt_type, /* 131 */ - scheme_active_replace_evt_type, /* 132 */ - scheme_nack_guard_evt_type, /* 133 */ - scheme_semaphore_repost_type, /* 134 */ - scheme_channel_type, /* 135 */ - scheme_channel_put_type, /* 136 */ - scheme_thread_resume_type, /* 137 */ - scheme_thread_suspend_type, /* 138 */ - scheme_thread_dead_type, /* 139 */ - scheme_poll_evt_type, /* 140 */ - scheme_nack_evt_type, /* 141 */ - scheme_module_registry_type, /* 142 */ - scheme_thread_set_type, /* 143 */ - scheme_string_converter_type, /* 144 */ - scheme_alarm_type, /* 145 */ - scheme_thread_recv_evt_type, /* 146 */ - scheme_thread_cell_type, /* 147 */ - scheme_channel_syncer_type, /* 148 */ - scheme_special_comment_type, /* 149 */ - scheme_write_evt_type, /* 150 */ - scheme_always_evt_type, /* 151 */ - scheme_never_evt_type, /* 152 */ - scheme_progress_evt_type, /* 153 */ - scheme_place_dead_type, /* 154 */ - scheme_already_comp_type, /* 155 */ - scheme_readtable_type, /* 156 */ - scheme_intdef_context_type, /* 157 */ - scheme_lexical_rib_type, /* 158 */ - scheme_thread_cell_values_type, /* 159 */ - scheme_global_ref_type, /* 160 */ - scheme_cont_mark_chain_type, /* 161 */ - scheme_raw_pair_type, /* 162 */ - scheme_prompt_type, /* 163 */ - scheme_prompt_tag_type, /* 164 */ - scheme_continuation_mark_key_type, /* 165 */ - scheme_expanded_syntax_type, /* 166 */ - scheme_delay_syntax_type, /* 167 */ - scheme_cust_box_type, /* 168 */ - scheme_resolved_module_path_type, /* 169 */ - scheme_module_phase_exports_type, /* 170 */ - scheme_logger_type, /* 171 */ - scheme_log_reader_type, /* 172 */ - scheme_marshal_share_type, /* 173 */ - scheme_rib_delimiter_type, /* 174 */ - scheme_noninline_proc_type, /* 175 */ - scheme_prune_context_type, /* 176 */ - scheme_future_type, /* 177 */ - scheme_flvector_type, /* 178 */ - scheme_extflvector_type, /* 179 */ - scheme_fxvector_type, /* 180 */ - scheme_place_type, /* 181 */ - scheme_place_object_type, /* 182 */ - scheme_place_async_channel_type, /* 183 */ - scheme_place_bi_channel_type, /* 184 */ - scheme_once_used_type, /* 185 */ - scheme_serialized_symbol_type, /* 186 */ - scheme_serialized_keyword_type, /* 187 */ - scheme_serialized_structure_type, /* 188 */ - scheme_fsemaphore_type, /* 189 */ - scheme_serialized_tcp_fd_type, /* 190 */ - scheme_serialized_file_fd_type, /* 191 */ - scheme_port_closed_evt_type, /* 192 */ - scheme_proc_shape_type, /* 193 */ - scheme_struct_proc_shape_type, /* 194 */ - scheme_phantom_bytes_type, /* 195 */ - scheme_environment_variables_type, /* 196 */ - scheme_filesystem_change_evt_type, /* 197 */ - scheme_ctype_type, /* 198 */ - scheme_plumber_type, /* 199 */ - scheme_plumber_handle_type, /* 200 */ + scheme_long_double_type, /* 58 */ + scheme_char_string_type, /* 59 */ + scheme_byte_string_type, /* 60 */ + scheme_unix_path_type, /* 61 */ + scheme_windows_path_type, /* 62 */ + scheme_symbol_type, /* 63 */ + scheme_keyword_type, /* 64 */ + scheme_null_type, /* 65 */ + scheme_pair_type, /* 66 */ + scheme_mutable_pair_type, /* 67 */ + scheme_vector_type, /* 68 */ + scheme_inspector_type, /* 69 */ + scheme_input_port_type, /* 70 */ + scheme_output_port_type, /* 71 */ + scheme_eof_type, /* 72 */ + scheme_true_type, /* 73 */ + scheme_false_type, /* 74 */ + scheme_void_type, /* 75 */ + scheme_syntax_compiler_type, /* 76 */ + scheme_macro_type, /* 77 */ + scheme_box_type, /* 78 */ + scheme_thread_type, /* 79 */ + scheme_scope_type, /* 80 */ + scheme_stx_offset_type, /* 81 */ + scheme_cont_mark_set_type, /* 82 */ + scheme_sema_type, /* 83 */ + scheme_hash_table_type, /* 84 */ + scheme_hash_tree_type, /* 85 */ + scheme_eq_hash_tree_type, /* 86 */ + scheme_eqv_hash_tree_type, /* 87 */ + scheme_hash_tree_subtree_type, /* 88 */ + scheme_hash_tree_collision_type, /* 89 */ + scheme_hash_tree_indirection_type, /* 90 */ + scheme_cpointer_type, /* 91 */ + scheme_prefix_type, /* 92 */ + scheme_weak_box_type, /* 93 */ + scheme_ephemeron_type, /* 94 */ + scheme_struct_type_type, /* 95 */ + scheme_module_index_type, /* 96 */ + scheme_set_macro_type, /* 97 */ + scheme_listener_type, /* 98 */ + scheme_namespace_type, /* 99 */ + scheme_config_type, /* 100 */ + scheme_stx_type, /* 101 */ + scheme_will_executor_type, /* 102 */ + scheme_custodian_type, /* 103 */ + scheme_random_state_type, /* 104 */ + scheme_regexp_type, /* 105 */ + scheme_bucket_type, /* 106 */ + scheme_bucket_table_type, /* 107 */ + scheme_subprocess_type, /* 108 */ + scheme_compilation_top_type, /* 109 */ + scheme_wrap_chunk_type, /* 110 */ + scheme_eval_waiting_type, /* 111 */ + scheme_tail_call_waiting_type, /* 112 */ + scheme_undefined_type, /* 113 */ + scheme_struct_property_type, /* 114 */ + scheme_chaperone_property_type, /* 115 */ + scheme_multiple_values_type, /* 116 */ + scheme_placeholder_type, /* 117 */ + scheme_table_placeholder_type, /* 118 */ + scheme_scope_table_type, /* 119 */ + scheme_propagate_table_type, /* 120 */ + scheme_svector_type, /* 121 */ + scheme_resolve_prefix_type, /* 122 */ + scheme_security_guard_type, /* 123 */ + scheme_indent_type, /* 124 */ + scheme_udp_type, /* 125 */ + scheme_udp_evt_type, /* 126 */ + scheme_tcp_accept_evt_type, /* 127 */ + scheme_id_macro_type, /* 128 */ + scheme_evt_set_type, /* 129 */ + scheme_wrap_evt_type, /* 130 */ + scheme_handle_evt_type, /* 131 */ + scheme_replace_evt_type, /* 132 */ + scheme_active_replace_evt_type, /* 133 */ + scheme_nack_guard_evt_type, /* 134 */ + scheme_semaphore_repost_type, /* 135 */ + scheme_channel_type, /* 136 */ + scheme_channel_put_type, /* 137 */ + scheme_thread_resume_type, /* 138 */ + scheme_thread_suspend_type, /* 139 */ + scheme_thread_dead_type, /* 140 */ + scheme_poll_evt_type, /* 141 */ + scheme_nack_evt_type, /* 142 */ + scheme_module_registry_type, /* 143 */ + scheme_thread_set_type, /* 144 */ + scheme_string_converter_type, /* 145 */ + scheme_alarm_type, /* 146 */ + scheme_thread_recv_evt_type, /* 147 */ + scheme_thread_cell_type, /* 148 */ + scheme_channel_syncer_type, /* 149 */ + scheme_special_comment_type, /* 150 */ + scheme_write_evt_type, /* 151 */ + scheme_always_evt_type, /* 152 */ + scheme_never_evt_type, /* 153 */ + scheme_progress_evt_type, /* 154 */ + scheme_place_dead_type, /* 155 */ + scheme_already_comp_type, /* 156 */ + scheme_readtable_type, /* 157 */ + scheme_intdef_context_type, /* 158 */ + scheme_lexical_rib_type, /* 159 */ + scheme_thread_cell_values_type, /* 160 */ + scheme_global_ref_type, /* 161 */ + scheme_cont_mark_chain_type, /* 162 */ + scheme_raw_pair_type, /* 163 */ + scheme_prompt_type, /* 164 */ + scheme_prompt_tag_type, /* 165 */ + scheme_continuation_mark_key_type, /* 166 */ + scheme_expanded_syntax_type, /* 167 */ + scheme_delay_syntax_type, /* 168 */ + scheme_cust_box_type, /* 169 */ + scheme_resolved_module_path_type, /* 170 */ + scheme_module_phase_exports_type, /* 171 */ + scheme_logger_type, /* 172 */ + scheme_log_reader_type, /* 173 */ + scheme_marshal_share_type, /* 174 */ + scheme_rib_delimiter_type, /* 175 */ + scheme_noninline_proc_type, /* 176 */ + scheme_prune_context_type, /* 177 */ + scheme_future_type, /* 178 */ + scheme_flvector_type, /* 179 */ + scheme_extflvector_type, /* 180 */ + scheme_fxvector_type, /* 181 */ + scheme_place_type, /* 182 */ + scheme_place_object_type, /* 183 */ + scheme_place_async_channel_type, /* 184 */ + scheme_place_bi_channel_type, /* 185 */ + scheme_once_used_type, /* 186 */ + scheme_serialized_symbol_type, /* 187 */ + scheme_serialized_keyword_type, /* 188 */ + scheme_serialized_structure_type, /* 189 */ + scheme_fsemaphore_type, /* 190 */ + scheme_serialized_tcp_fd_type, /* 191 */ + scheme_serialized_file_fd_type, /* 192 */ + scheme_port_closed_evt_type, /* 193 */ + scheme_proc_shape_type, /* 194 */ + scheme_struct_proc_shape_type, /* 195 */ + scheme_phantom_bytes_type, /* 196 */ + scheme_environment_variables_type, /* 197 */ + scheme_filesystem_change_evt_type, /* 198 */ + scheme_ctype_type, /* 199 */ + scheme_plumber_type, /* 200 */ + scheme_plumber_handle_type, /* 201 */ #ifdef MZTAG_REQUIRED - _scheme_last_normal_type_, /* 201 */ + _scheme_last_normal_type_, /* 202 */ - scheme_rt_weak_array, /* 202 */ + scheme_rt_weak_array, /* 203 */ - scheme_rt_comp_env, /* 203 */ - scheme_rt_constant_binding, /* 204 */ - scheme_rt_resolve_info, /* 205 */ - scheme_rt_unresolve_info, /* 206 */ - scheme_rt_optimize_info, /* 207 */ - scheme_rt_cont_mark, /* 208 */ - scheme_rt_saved_stack, /* 209 */ - scheme_rt_reply_item, /* 210 */ - scheme_rt_closure_info, /* 211 */ - scheme_rt_overflow, /* 212 */ - scheme_rt_overflow_jmp, /* 213 */ - scheme_rt_meta_cont, /* 214 */ - scheme_rt_dyn_wind_cell, /* 215 */ - scheme_rt_dyn_wind_info, /* 216 */ - scheme_rt_dyn_wind, /* 217 */ - scheme_rt_dup_check, /* 218 */ - scheme_rt_thread_memory, /* 219 */ - scheme_rt_input_file, /* 220 */ - scheme_rt_input_fd, /* 221 */ - scheme_rt_oskit_console_input, /* 222 */ - scheme_rt_tested_input_file, /* 223 */ - scheme_rt_tested_output_file, /* 224 */ - scheme_rt_indexed_string, /* 225 */ - scheme_rt_output_file, /* 226 */ - scheme_rt_load_handler_data, /* 227 */ - scheme_rt_pipe, /* 228 */ - scheme_rt_beos_process, /* 229 */ - scheme_rt_system_child, /* 230 */ - scheme_rt_tcp, /* 231 */ - scheme_rt_write_data, /* 232 */ - scheme_rt_tcp_select_info, /* 233 */ - scheme_rt_param_data, /* 234 */ - scheme_rt_will, /* 235 */ - scheme_rt_linker_name, /* 236 */ - scheme_rt_param_map, /* 237 */ - scheme_rt_finalization, /* 238 */ - scheme_rt_finalizations, /* 239 */ - scheme_rt_cpp_object, /* 240 */ - scheme_rt_cpp_array_object, /* 241 */ - scheme_rt_stack_object, /* 242 */ - scheme_rt_preallocated_object, /* 243 */ - scheme_thread_hop_type, /* 244 */ - scheme_rt_srcloc, /* 245 */ - scheme_rt_evt, /* 246 */ - scheme_rt_syncing, /* 247 */ - scheme_rt_comp_prefix, /* 248 */ - scheme_rt_user_input, /* 249 */ - scheme_rt_user_output, /* 250 */ - scheme_rt_compact_port, /* 251 */ - scheme_rt_read_special_dw, /* 252 */ - scheme_rt_regwork, /* 253 */ - scheme_rt_rx_lazy_string, /* 254 */ - scheme_rt_buf_holder, /* 255 */ - scheme_rt_parameterization, /* 256 */ - scheme_rt_print_params, /* 257 */ - scheme_rt_read_params, /* 258 */ - scheme_rt_native_code, /* 259 */ - scheme_rt_native_code_plus_case, /* 260 */ - scheme_rt_jitter_data, /* 261 */ - scheme_rt_module_exports, /* 262 */ - scheme_rt_delay_load_info, /* 263 */ - scheme_rt_marshal_info, /* 264 */ - scheme_rt_unmarshal_info, /* 265 */ - scheme_rt_runstack, /* 266 */ - scheme_rt_sfs_info, /* 267 */ - scheme_rt_validate_clearing, /* 268 */ - scheme_rt_lightweight_cont, /* 269 */ - scheme_rt_export_info, /* 270 */ - scheme_rt_cont_jmp, /* 271 */ - scheme_rt_letrec_check_frame, /* 272 */ + scheme_rt_comp_env, /* 204 */ + scheme_rt_constant_binding, /* 205 */ + scheme_rt_resolve_info, /* 206 */ + scheme_rt_unresolve_info, /* 207 */ + scheme_rt_optimize_info, /* 208 */ + scheme_rt_cont_mark, /* 209 */ + scheme_rt_saved_stack, /* 210 */ + scheme_rt_reply_item, /* 211 */ + scheme_rt_closure_info, /* 212 */ + scheme_rt_overflow, /* 213 */ + scheme_rt_overflow_jmp, /* 214 */ + scheme_rt_meta_cont, /* 215 */ + scheme_rt_dyn_wind_cell, /* 216 */ + scheme_rt_dyn_wind_info, /* 217 */ + scheme_rt_dyn_wind, /* 218 */ + scheme_rt_dup_check, /* 219 */ + scheme_rt_thread_memory, /* 220 */ + scheme_rt_input_file, /* 221 */ + scheme_rt_input_fd, /* 222 */ + scheme_rt_oskit_console_input, /* 223 */ + scheme_rt_tested_input_file, /* 224 */ + scheme_rt_tested_output_file, /* 225 */ + scheme_rt_indexed_string, /* 226 */ + scheme_rt_output_file, /* 227 */ + scheme_rt_load_handler_data, /* 228 */ + scheme_rt_pipe, /* 229 */ + scheme_rt_beos_process, /* 230 */ + scheme_rt_system_child, /* 231 */ + scheme_rt_tcp, /* 232 */ + scheme_rt_write_data, /* 233 */ + scheme_rt_tcp_select_info, /* 234 */ + scheme_rt_param_data, /* 235 */ + scheme_rt_will, /* 236 */ + scheme_rt_linker_name, /* 237 */ + scheme_rt_param_map, /* 238 */ + scheme_rt_finalization, /* 239 */ + scheme_rt_finalizations, /* 240 */ + scheme_rt_cpp_object, /* 241 */ + scheme_rt_cpp_array_object, /* 242 */ + scheme_rt_stack_object, /* 243 */ + scheme_rt_preallocated_object, /* 244 */ + scheme_thread_hop_type, /* 245 */ + scheme_rt_srcloc, /* 246 */ + scheme_rt_evt, /* 247 */ + scheme_rt_syncing, /* 248 */ + scheme_rt_comp_prefix, /* 249 */ + scheme_rt_user_input, /* 250 */ + scheme_rt_user_output, /* 251 */ + scheme_rt_compact_port, /* 252 */ + scheme_rt_read_special_dw, /* 253 */ + scheme_rt_regwork, /* 254 */ + scheme_rt_rx_lazy_string, /* 255 */ + scheme_rt_buf_holder, /* 256 */ + scheme_rt_parameterization, /* 257 */ + scheme_rt_print_params, /* 258 */ + scheme_rt_read_params, /* 259 */ + scheme_rt_native_code, /* 260 */ + scheme_rt_native_code_plus_case, /* 261 */ + scheme_rt_jitter_data, /* 262 */ + scheme_rt_module_exports, /* 263 */ + scheme_rt_delay_load_info, /* 264 */ + scheme_rt_marshal_info, /* 265 */ + scheme_rt_unmarshal_info, /* 266 */ + scheme_rt_runstack, /* 267 */ + scheme_rt_sfs_info, /* 268 */ + scheme_rt_validate_clearing, /* 269 */ + scheme_rt_lightweight_cont, /* 270 */ + scheme_rt_export_info, /* 271 */ + scheme_rt_cont_jmp, /* 272 */ + scheme_rt_letrec_check_frame, /* 273 */ #endif - scheme_deferred_expr_type, /* 273 */ + scheme_deferred_expr_type, /* 274 */ _scheme_last_type_ }; diff --git a/racket/src/racket/src/syntax.c b/racket/src/racket/src/syntax.c index 3af574b018..444267fe9d 100644 --- a/racket/src/racket/src/syntax.c +++ b/racket/src/racket/src/syntax.c @@ -47,10 +47,10 @@ ROSYM static Scheme_Object *fallbacks_symbol; READ_ONLY Scheme_Object *scheme_syntax_p_proc; -READ_ONLY Scheme_Hash_Tree *empty_hash_tree; -READ_ONLY Scheme_Scope_Table *empty_scope_table; -READ_ONLY Scheme_Scope_Table *empty_propagate_table; -READ_ONLY Scheme_Scope_Set *empty_scope_set; +READ_ONLY static Scheme_Hash_Tree *empty_hash_tree; +READ_ONLY static Scheme_Scope_Table *empty_scope_table; +READ_ONLY static Scheme_Scope_Table *empty_propagate_table; +READ_ONLY static Scheme_Scope_Set *empty_scope_set; ROSYM Scheme_Object *scheme_paren_shape_symbol; @@ -5858,6 +5858,18 @@ static void sort_number_array(Scheme_Object **a, intptr_t count) my_qsort(a, count, sizeof(Scheme_Object *), compare_nums); } +static int compare_vars_at_resolve(const void *_a, const void *_b) +{ + Scheme_Compiled_Local *a = *(Scheme_Compiled_Local **)_a; + Scheme_Compiled_Local *b = *(Scheme_Compiled_Local **)_b; + return a->resolve.lex_depth - b->resolve.lex_depth; +} + +void scheme_sort_resolve_compiled_local_array(Scheme_Compiled_Local **a, intptr_t count) +{ + my_qsort(a, count, sizeof(Scheme_Compiled_Local *), compare_vars_at_resolve); +} + static Scheme_Object *drop_export_registries(Scheme_Object *shifts) { Scheme_Object *l, *a, *vec, *p, *first = scheme_null, *last = NULL; diff --git a/racket/src/racket/src/type.c b/racket/src/racket/src/type.c index 27ac99a182..4d1d4ccd59 100644 --- a/racket/src/racket/src/type.c +++ b/racket/src/racket/src/type.c @@ -140,6 +140,7 @@ scheme_init_type () set_name(scheme_let_value_type, ""); set_name(scheme_let_void_type, ""); + set_name(scheme_compiled_local_type, ""); set_name(scheme_compiled_let_value_type, ""); set_name(scheme_compiled_let_void_type, ""); set_name(scheme_compiled_toplevel_type, ""); @@ -589,6 +590,7 @@ void scheme_register_traversers(void) GC_REG_TRAV(_scheme_values_types_, bad_trav); GC_REG_TRAV(scheme_compiled_unclosed_procedure_type, unclosed_proc); + GC_REG_TRAV(scheme_compiled_local_type, comp_local); GC_REG_TRAV(scheme_compiled_let_value_type, comp_let_value); GC_REG_TRAV(scheme_compiled_let_void_type, let_header); GC_REG_TRAV(scheme_compiled_toplevel_type, toplevel_obj); diff --git a/racket/src/racket/src/validate.c b/racket/src/racket/src/validate.c index 3654e62e0c..d914d5cd2d 100644 --- a/racket/src/racket/src/validate.c +++ b/racket/src/racket/src/validate.c @@ -169,9 +169,8 @@ void scheme_validate_code(Mz_CPort *port, Scheme_Object *code, if (num_toplevels || num_stxes || num_lifts) { stack[depth - 1] = VALID_TOPLEVELS; } - delta = depth - ((num_toplevels || num_stxes || num_lifts) ? 1 : 0); - + tls = MALLOC_N(mzshort*, num_lifts); if (code_vec) { @@ -1024,6 +1023,8 @@ static void validate_unclosed_procedure(Mz_CPort *port, Scheme_Object *expr, vld = VALID_BOX; typed_arg = 1; } else if (ct) { + if ((ct - CLOS_TYPE_TYPE_OFFSET) > SCHEME_MAX_LOCAL_TYPE) + scheme_ill_formed_code(port); vld = (VALID_TYPED + (ct - CLOS_TYPE_TYPE_OFFSET)); typed_arg = 1; } else @@ -1199,7 +1200,7 @@ static void no_typed(int need_local_type, Mz_CPort *port) static void check_typed(Scheme_Object *expr, int need_local_type, Mz_CPort *port) { if (need_local_type) { - if (scheme_expr_produces_local_type(expr) != need_local_type) + if (scheme_expr_produces_local_type(expr, NULL) != need_local_type) scheme_ill_formed_code(port); } } @@ -2052,6 +2053,10 @@ static int validate_expr(Mz_CPort *port, Scheme_Object *expr, result_ignored, vc, tailpos, procs); result = validate_join_const(result, expected_results); break; + case scheme_compiled_local_type: + { + scheme_ill_formed_code(port); + } default: /* All values are definitely ok, except pre-closed closures. Such a closure can refer back to itself, so we use a flag