From dfa5d4809223d15fb9ce2c172896b0e97bdfbb09 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Wed, 25 Oct 2017 17:35:20 -0600 Subject: [PATCH] unbreak JIT and check limits Repairs a problem with ce9894c8bf, where a large "inlined" vector allocation is not actually inlined, but other parts of the JIT assume that it will behave as inlined --- which implies that the runstack will be left unchanged after the call. Closes #1868 --- .../tests/racket/jitinline.rktl | 17 +++++++++++------ racket/src/racket/gc2/gc2.h | 7 ++++++- racket/src/racket/gc2/newgc.c | 2 ++ racket/src/racket/src/env.c | 5 ++++- racket/src/racket/src/jit.h | 3 +++ racket/src/racket/src/jitinline.c | 15 ++++++++++++--- racket/src/racket/src/jitstate.c | 16 ++++++++++++++++ racket/src/racket/src/schpriv.h | 7 ++++++- racket/src/racket/src/struct.c | 5 +---- 9 files changed, 61 insertions(+), 16 deletions(-) diff --git a/pkgs/racket-test-core/tests/racket/jitinline.rktl b/pkgs/racket-test-core/tests/racket/jitinline.rktl index 726002b5c5..fb2f12beed 100644 --- a/pkgs/racket-test-core/tests/racket/jitinline.rktl +++ b/pkgs/racket-test-core/tests/racket/jitinline.rktl @@ -934,12 +934,17 @@ ;; a vector allocation that is too large (parameterize ([current-namespace (make-base-namespace)]) - (let loop ([i 10]) - ((eval `(lambda (x) (vector x ,@(for/list ([j (in-range i)]) - j)))) - i) - (when (i . < . 100000) - (loop (floor (* i #e1.25)))))) + (for ([tail? '(#t #f)]) + (let loop ([i 10]) + ((eval `(lambda (f x) + ,(let ([e `(vector x ,@(for/list ([j (in-range i)]) + j))]) + (if tail? + e + `(f ,e))))) + values i) + (when (i . < . 10000) + (loop (floor (* i #e1.25))))))) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/racket/src/racket/gc2/gc2.h b/racket/src/racket/gc2/gc2.h index 9378872c79..10744593eb 100644 --- a/racket/src/racket/gc2/gc2.h +++ b/racket/src/racket/gc2/gc2.h @@ -298,6 +298,11 @@ GC2_EXTERN int GC_allocate_phantom_bytes(void *pb, intptr_t); Returns 0 if allocation should fail due to a memory limit, 1 otherwise. The representative `pb` determines who is charged. */ +GC2_EXTERN intptr_t GC_max_nursery_object_size(); +/* + Returns a lower bound on the maximum size allowed for allocation + in the nursery. */ + /***************************************************************************/ /* Memory tracing */ /***************************************************************************/ @@ -581,7 +586,7 @@ GC2_EXTERN intptr_t GC_is_place(); Otherwise returns 0; */ - GC2_EXTERN int GC_message_small_objects_size(void *msg_memory, intptr_t up_to); +GC2_EXTERN int GC_message_small_objects_size(void *msg_memory, intptr_t up_to); /* Determines whether the message qualifies as short and whether the total size of all objects allocated by the message allocator is less diff --git a/racket/src/racket/gc2/newgc.c b/racket/src/racket/gc2/newgc.c index 65f8fb47fa..a6cf9e2a49 100644 --- a/racket/src/racket/gc2/newgc.c +++ b/racket/src/racket/gc2/newgc.c @@ -1774,6 +1774,8 @@ intptr_t GC_alloc_alignment() intptr_t GC_malloc_stays_put_threshold() { return MAX_OBJECT_SIZE; } +intptr_t GC_max_nursery_object_size() { return MAX_OBJECT_SIZE - OBJHEAD_SIZE; } + /*****************************************************************************/ /* Nursery (a.k.a. generation 0) and generation 1/2 */ /*****************************************************************************/ diff --git a/racket/src/racket/src/env.c b/racket/src/racket/src/env.c index bf373213ad..ae9dc64df0 100644 --- a/racket/src/racket/src/env.c +++ b/racket/src/racket/src/env.c @@ -256,6 +256,9 @@ Scheme_Env *scheme_engine_instance_init() scheme_init_resolve(); scheme_init_sfs(); scheme_init_validate(); +#ifdef MZ_USE_JIT + scheme_init_jit(); +#endif scheme_init_process_globals(); @@ -492,7 +495,7 @@ static Scheme_Env *place_instance_init(void *stack_base, int initial_main_os_thr scheme_init_stack_check(); scheme_init_overflow(); - + scheme_init_thread_lwc(); scheme_init_compenv_places(); diff --git a/racket/src/racket/src/jit.h b/racket/src/racket/src/jit.h index 51f5cf0704..efce3eb7c5 100644 --- a/racket/src/racket/src/jit.h +++ b/racket/src/racket/src/jit.h @@ -266,6 +266,9 @@ typedef struct Apply_LWC_Args { typedef Scheme_Object *(*Continuation_Apply_Indirect)(Apply_LWC_Args *, intptr_t); typedef Scheme_Object *(*Continuation_Apply_Finish)(Apply_LWC_Args *args, void *stack, void *frame); +#define JIT_MAX_VECTOR_INLINE_SIZE 256 +#define JIT_MAX_STRUCT_FIELD_INLINE_COUNT 256 + #ifdef MZ_LONG_DOUBLE # define JIT_NUM_FL_KINDS 2 #else diff --git a/racket/src/racket/src/jitinline.c b/racket/src/racket/src/jitinline.c index d79ecf2407..cfa3980b6a 100644 --- a/racket/src/racket/src/jitinline.c +++ b/racket/src/racket/src/jitinline.c @@ -150,7 +150,7 @@ static int check_val_struct_prim(Scheme_Object *p, int arity) Scheme_Struct_Type *t; t = (Scheme_Struct_Type *)SCHEME_PRIM_CLOSURE_ELS(p)[0]; if ((arity == t->num_islots) - && (arity < 100)) { + && (arity < JIT_MAX_STRUCT_FIELD_INLINE_COUNT)) { return INLINE_STRUCT_PROC_CONSTR; } return 0; @@ -5288,9 +5288,18 @@ static int generate_vector_alloc(mz_jit_state *jitter, Scheme_Object *rator, c = 2; } else { c = app->num_args; - if (c > 256) { + if (c > JIT_MAX_VECTOR_INLINE_SIZE) { /* Too big for inline alloc */ - return scheme_generate_app(app, NULL, c, c, jitter, 0, 0, 0, 0); + i = scheme_generate_app(app, NULL, c, c, jitter, 0, 0, 0, 0); + CHECK_LIMIT(); + if (dest != JIT_R0) + jit_movr_p(dest, JIT_R0); + + /* since we're called in inline mode, need to manually pop: */ + jit_addi_l(JIT_RUNSTACK, JIT_RUNSTACK, WORDS_TO_BYTES(c)); + mz_runstack_popped(jitter, c); + + return i; } else if (c) scheme_generate_app(app, NULL, c, c, jitter, 0, 0, 0, 2); /* sync'd below */ } diff --git a/racket/src/racket/src/jitstate.c b/racket/src/racket/src/jitstate.c index 16916e910e..65c96cdcfb 100644 --- a/racket/src/racket/src/jitstate.c +++ b/racket/src/racket/src/jitstate.c @@ -29,6 +29,22 @@ /* Used by vector-set-performance-stats!: */ int scheme_jit_malloced; +void scheme_init_jit() +{ +#ifdef CAN_INLINE_ALLOC + intptr_t max_alloc; + max_alloc = GC_max_nursery_object_size(); + if ((sizeof(Scheme_Vector) + (JIT_MAX_VECTOR_INLINE_SIZE - mzFLEX_DELTA) * sizeof(Scheme_Object *)) > max_alloc) { + scheme_log_abort("Misconfigured: inlined vector size is greater than maximum allowed by GC"); + abort(); + } + if ((sizeof(Scheme_Structure) + ((JIT_MAX_STRUCT_FIELD_INLINE_COUNT - mzFLEX_DELTA) * sizeof(Scheme_Object *))) > max_alloc) { + scheme_log_abort("Misconfigured: inlined struct size is greater than maximum allowed by GC"); + abort(); + } +#endif +} + /*========================================================================*/ /* JIT buffer */ /*========================================================================*/ diff --git a/racket/src/racket/src/schpriv.h b/racket/src/racket/src/schpriv.h index 2649d52f8c..485f9bb49e 100644 --- a/racket/src/racket/src/schpriv.h +++ b/racket/src/racket/src/schpriv.h @@ -304,6 +304,9 @@ void scheme_init_finalization(void); void scheme_init_portable_case(void); void scheme_init_stack_check(void); void scheme_init_overflow(void); +#ifdef MZ_USE_JIT +void scheme_init_jit(void); +#endif #ifdef MZ_PRECISE_GC void scheme_register_traversers(void); void scheme_init_hash_key_procs(void); @@ -532,7 +535,6 @@ extern Scheme_Object *scheme_make_vector_proc; extern Scheme_Object *scheme_vector_immutable_proc; extern Scheme_Object *scheme_vector_ref_proc; extern Scheme_Object *scheme_vector_set_proc; -extern Scheme_Object *scheme_vector_cas_proc; extern Scheme_Object *scheme_list_to_vector_proc; extern Scheme_Object *scheme_unsafe_vector_length_proc; extern Scheme_Object *scheme_unsafe_struct_ref_proc; @@ -1075,6 +1077,9 @@ typedef struct Scheme_Structure Scheme_Object *slots[mzFLEX_ARRAY_DECL]; } Scheme_Structure; +#define MAX_STRUCT_FIELD_COUNT 32768 +#define MAX_STRUCT_FIELD_COUNT_STR "32768" + #ifdef MZ_USE_PLACES typedef struct Scheme_Serialized_Structure { diff --git a/racket/src/racket/src/struct.c b/racket/src/racket/src/struct.c index aecb666bc1..4e386e9051 100644 --- a/racket/src/racket/src/struct.c +++ b/racket/src/racket/src/struct.c @@ -2839,7 +2839,7 @@ static int parse_pos(const char *who, Scheme_Object *prim, Scheme_Object **args, if (!SCHEME_INTP(args[1]) || (SCHEME_INT_VAL(args[1]) < 0)) { if (SCHEME_BIGNUMP(args[1]) && SCHEME_BIGPOS(args[1])) { - pos = 32769; /* greater than max field count */ + pos = (MAX_STRUCT_FIELD_COUNT + 1); } else { if (!who) who = extract_field_proc_name(prim); @@ -3482,9 +3482,6 @@ static Scheme_Object *make_prefab_struct(int argc, Scheme_Object *argv[]) return scheme_make_prefab_struct_instance(stype, vec); } -#define MAX_STRUCT_FIELD_COUNT 32768 -#define MAX_STRUCT_FIELD_COUNT_STR "32768" - static Scheme_Object *prefab_key_struct_type(int argc, Scheme_Object *argv[]) { Scheme_Struct_Type *stype;