From 01eece18a7593f93f8360f7b188780bdb1db06f0 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Thu, 19 Dec 2013 12:22:05 -0700 Subject: [PATCH] dynamic-require: fast path for re-exported variables When `dynamic-require` is used to access an export that isn't a variable defined in the same module, `dynamic-require` falls back to `eval` in a fresh namespace, which can be expensive. The new fast path handles the case that a variable is re-exported. The new fast path is relevant to deserialization, which now uses a submodule that re-exports from an enclosing module. --- .../racket-test/tests/racket/module.rktl | 45 ++++++++++++++ racket/src/racket/src/module.c | 58 +++++++++++++++++-- 2 files changed, 98 insertions(+), 5 deletions(-) diff --git a/pkgs/racket-pkgs/racket-test/tests/racket/module.rktl b/pkgs/racket-pkgs/racket-test/tests/racket/module.rktl index 6e4011ffdc..5299557655 100644 --- a/pkgs/racket-pkgs/racket-test/tests/racket/module.rktl +++ b/pkgs/racket-pkgs/racket-test/tests/racket/module.rktl @@ -1004,6 +1004,51 @@ (begin-for-syntax (begin-for-syntax (define y 2)))) + +;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Check `dynamic-require` re-export fast path + +(for ([specs (list (list '(provide) + 'x) + (list '(provide x) + 'x) + (list '(provide (rename-out [x xx])) + 'x) + (list '(provide (rename-out [y x])) + 'x) + (list '(provide) + '(rename-out [y x]) + "y") + (list '(provide) + '(rename-out [z x]) + "x" + ;; slow: + "exp\nexp\nrun\nexp\nexp\n"))]) + (define ns (make-base-namespace)) + (define o (open-output-string)) + (parameterize ([current-output-port o]) + (eval `(module m racket/base + (require (for-syntax racket/base)) + (begin-for-syntax (displayln "exp")) + (define x "x") + (define y "y") + (define-syntax (z stx) #'x) + ,(car specs) + (module* sub #f + (displayln "run") + (provide ,(cadr specs)))) + ns)) + (define expected (if (null? (cddr specs)) "x" (caddr specs))) + (define expected-out (if ((length specs) . < . 4) + "exp\nexp\nrun\n" + (list-ref specs 3))) + (define (dynamic-require/o m x) + (parameterize ([current-output-port o]) + (dynamic-require m x))) + (parameterize ([current-namespace ns]) + (test expected dynamic-require/o '(submod 'm sub) 'x) + (test expected dynamic-require/o '(submod 'm sub) 'x)) + (test expected-out get-output-string o)) ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/racket/src/racket/src/module.c b/racket/src/racket/src/module.c index 36c1836c1d..1f75abe0e8 100644 --- a/racket/src/racket/src/module.c +++ b/racket/src/racket/src/module.c @@ -1205,8 +1205,57 @@ static Scheme_Object *_dynamic_require(int argc, Scheme_Object *argv[], break; } else { if (fail_with_error) { - if (!phase) { - /* Evaluate id in a fresh namespace */ + if (!phase + && srcm->me->rt->provide_srcs + && SCHEME_TRUEP(srcm->me->rt->provide_srcs[i])) { + /* Handle simple re-exporting */ + int j; + Scheme_Module *srcm2; + + srcmname = srcm->me->rt->provide_srcs[i]; + srcmname = scheme_modidx_shift(srcmname, srcm->me->src_modidx, srcm->self_modidx); + srcmname = scheme_module_resolve(srcmname, 1); + srcname = srcm->me->rt->provide_src_names[i]; + + srcm2 = module_load(srcmname, env, errname); + + for (j = srcm2->me->rt->num_var_provides; j--; ) { + if (SCHEME_FALSEP(srcm2->me->rt->provide_srcs[j]) + && SAME_OBJ(srcname, srcm2->me->rt->provide_src_names[j])) { + /* simple re-export applies: */ + srcm = srcm2; + count = srcm->me->rt->num_provides; + name = srcm2->me->rt->provides[j]; + i = j; + break; + } + } + if (j < 0) { + /* Try indirect: */ + Scheme_Module_Export_Info *exp_info = srcm2->exp_infos[0]; + for (j = exp_info->num_indirect_provides; j--; ) { + if (SAME_OBJ(srcname, exp_info->indirect_provides[j])) { + srcm = srcm2; + name = srcname; + count = srcm->me->rt->num_provides; + i = count; + position = j; + indirect_ok = 1; + break; + } + } + if (j < 0) { + /* simple re-exporting doesn't work */ + srcmname = NULL; + } + } + } + + if (srcmname) { + /* Simple re-exporting shortcut worked */ + break; + } else if (!phase) { + /* The long way: evaluate id in a fresh namespace */ Scheme_Object *a[3], *ns; Scheme_Config *config; Scheme_Cont_Frame_Data cframe; @@ -1243,7 +1292,7 @@ static Scheme_Object *_dynamic_require(int argc, Scheme_Object *argv[], NULL); } } - return NULL; + return NULL; } } } @@ -1265,8 +1314,7 @@ static Scheme_Object *_dynamic_require(int argc, Scheme_Object *argv[], if (i == count) { if (indirect_ok) { /* Try indirect provides: */ - Scheme_Module_Export_Info *exp_info = m->exp_infos[0]; - srcm = m; + Scheme_Module_Export_Info *exp_info = srcm->exp_infos[0]; count = exp_info->num_indirect_provides; if (position >= 0) { i = position;