diff --git a/collects/typed-scheme/optimizer/vector.rkt b/collects/typed-scheme/optimizer/vector.rkt index 11e7e937..32e65d3c 100644 --- a/collects/typed-scheme/optimizer/vector.rkt +++ b/collects/typed-scheme/optimizer/vector.rkt @@ -14,8 +14,8 @@ (define-syntax-class vector-op #:commit ;; we need the * versions of these unsafe operations to be chaperone-safe - (pattern (~literal vector-ref) #:with unsafe #'unsafe-vector-ref) - (pattern (~literal vector-set!) #:with unsafe #'unsafe-vector-set!)) + (pattern (~literal vector-ref) #:with unsafe #'unsafe-vector-ref #:with unsafe-no-impersonator #'unsafe-vector*-ref) + (pattern (~literal vector-set!) #:with unsafe #'unsafe-vector-set! #:with unsafe-no-impersonator #'unsafe-vector*-set!)) (define-syntax-class known-length-vector-expr #:commit @@ -64,17 +64,30 @@ (begin (log-optimization "vector" #'op) #`(op.unsafe v.opt #,((optimize) #'i) #,@(syntax-map (optimize) #'(new ...))))) + ;; we can do the bounds checking separately, to eliminate some of the checks (pattern (#%plain-app op:vector-op v:expr i:fixnum-expr new:expr ...) #:with opt (begin (log-optimization "vector access splitting" this-syntax) - #`(let ([new-i #,((optimize) #'i)] - [new-v #,((optimize) #'v)]) - (if #,(let ([one-sided #'(unsafe-fx< new-i (unsafe-vector*-length v))]) - (if (subtypeof? #'i -NonNegFixnum) - ;; we know it's nonnegative, one-sided check - one-sided - #`(and (unsafe-fx>= new-i 0) - #,one-sided))) - (op.unsafe new-v new-i #,@(syntax-map (optimize) #'(new ...))) - (op new-v new-i #,@(syntax-map (optimize) #'(new ...)))))))) + (let ([safe-fallback #`(op new-v new-i #,@(syntax-map (optimize) #'(new ...)))]) + #`(let ([new-i #,((optimize) #'i)] + [new-v #,((optimize) #'v)]) + ;; do the impersonator check up front, to avoid doing it twice (length and op) + (if (impersonator? new-v) + (if #,(let ([one-sided #'(unsafe-fx< new-i (unsafe-vector-length v))]) + (if (subtypeof? #'i -NonNegFixnum) + ;; we know it's nonnegative, one-sided check + one-sided + #`(and (unsafe-fx>= new-i 0) + #,one-sided))) + (op.unsafe new-v new-i #,@(syntax-map (optimize) #'(new ...))) + #,safe-fallback) + ;; not an impersonator, can use unsafe-vector* ops + (if #,(let ([one-sided #'(unsafe-fx< new-i (unsafe-vector*-length v))]) + (if (subtypeof? #'i -NonNegFixnum) + ;; we know it's nonnegative, one-sided check + one-sided + #`(and (unsafe-fx>= new-i 0) + #,one-sided))) + (op.unsafe-no-impersonator new-v new-i #,@(syntax-map (optimize) #'(new ...))) + #,safe-fallback)))))))