Make the optimizer recognize and track `make-struct-property-type`
values, and use that information to recognize `make-struct-type`
calls that will defnitely succeed because a property that hs no
guard is given a value in the list of properties.
Combined with the change to require-keyword expansion, this
change allows the optimizer to inline `f` in
(define (g y)
(f #:x y))
(define (f #:x x)
(list x))
because the `make-struct-type` that appears between `g` and `f`
is determined to have no side-effect that would prevent `f` from
having its expected value.
When a module defines and exports an identifier at two phases,
and when another module imports both of them at the same phase,
an error was not reported as it should have been.
Some expressions are omittable only when the arguments have certain types.
In this case the application is marked with APPN_FLAG_OMITTABLE instead of relaying on the flags of the primitive.
The optimizer can't use this flag to move the expression inside a lamba or across a potential continuation capture, unlike other omittable expressions. They can be moved
only in more restricted conditions.
For example, in this program
#lang racket/base
(define n 10000)
(define m 10000)
(time
(define xs (build-list n (lambda (x) 0)))
(length xs)
(define ws (list->vector xs)) ; <-- omittable
(for ([i (in-range m)])
(vector-ref ws 0))) ; <-- ws is used once
If the optimizer moves the expression in the definition of ws inside the recursive
lambda that is created by the for, then the code is equivalent to:
#lang racket/base
(define n 10000)
(define m 10000)
(time
(define xs (build-list n (lambda (x) 0)))
(length xs)
(for ([i (in-range m)])
(vector-ref (list->vector xs) 0))) ; <-- moved here
And the new code is O(n*m) instead of O(n+m). This example is a minimized version
of the function kde from the plot package, where n=m and the bug changed the run
time from linear to quadratic.
The application of some procedures are omittables when the arguments have
certain properties. Check the arity of the procedure before marking the application as omittable.
The only case that appears to be relevant is the expression (-).
The relevant predicates are almost disjoint. The superposition
is solved with predicate_implies and predicate_implies_not.
This is also valid considering the equivalence classes modulo
eqv? and equal?. So if the optimizer knows that two expressions
X and Y have different relevant types, then it can reduce
(equal? X Y) ==> (begin X Y #f).
Allow a `struct` form to be recognized when it provides
a number as the 8th argument to `make-struct-type`. In
particular, that change allows the construction of
optional-keyword functions to be recognized as a
purely functional operation.
Also, allow the optimizer to use information about imports
when deciding whether a module-level form is functional.
It's ok to use that information, because the validator has
it, too.
This combination of changes allows something like
(define (f #:optional [x #f])
(later))
(define (later) ....)
to compile to a reference to `later` wihout a check.
Due to an obvious problem in the setup, the letrec-check pass wasn't
running an intended dead-code pruning pass. Correcting the problem
cuases one test in "optimize.rktl" to change, because the letrec-check
pass can see more in one case than thanother.
(Problem discovered by accidentally fixing the setup in a Racket
branch based on "linklets".)
Along with the `PLT_COMPILED_FILE_CHECK` environment variable, allows
the timestamp check to be disabled when deciding whether to use a
compiled bytecode file.
In accomodating this change, `raco make` and `raco setup` in all modes
check whether the SHA1 hash of a module source matches the one
recorded in its ".dep" file, even if the timestamp on the bytecode
file is newer. (If the compile-file check mode is 'exists, the
timestamp is completely ignored.)
After refactoring the test for the inferred types of some procedures that
use vector?/bytes?/string?/list? it was easier to spot the missing information.
Note that in the documentation, some arguments like the position in
(vector-ref <vector> <position>)
are documented as exact-nonnegative-integer? but due to the implementation
details they are actually in a subset of fixnum?s.
When `read` parses a literal hash table, it inserts an placeholder
just in case it's needed for cycles. The `unsafe-immutable-hash-...`
operations in some cases did not detect and remove the placeholder.
Closes#1376
Merge to v6.6
The namespace returned by `variable-reference->namespace` (or
`namespace-anchor->namespace`) may be used via `eval` to define new
bindings, so enable top-level binding support for the namespace.
for example, make the optimizer convert something like
(struct a (x))
(lambda (v) (if (a? v) (a-x v) #f))
to
(struct a (x))
(lambda (v) (if (a? v) (unsafe-struct-ref v 0) #f))
The optimizer change in e887fa56d1 recognized struct declarations that
involved only whitelisted properties to guarantee that constructor
properties are preserved --- while `prop:chaperone-unsafe-undefined`
can affect the constructor, and other properties might imply that one.
But the optimizer's transformer aren't actually invalidated by
`prop:chaperone-unsafe-undefined`; the JIT's assumptions are affected,
but that's handled in a different way. So, remove the whitelist and
allow any property list.
The optimizer tries to reduce the `if` assuming that the result will be used.
In case it later detects that the result will be ignored, it can try to
apply some additional reductions to the branches and to the whole expression.
This function exposes the fast subset operation that is built in for
immutable hash tables (and used by the set-of-scopes implementation).
Also, make the space optimization implicit for `eq?`-based hash tables
that contain only #t values (instead of explicit and only available
internally). It turns out to be easy and efficient to make the
representation automatic, because the HAMT implementation can support
a mixture of nodes with some containing explicit values and some
containing implicit #t values.
When the properties argument for `make-struct-type` is non-empty,
then we cant; guarantee that `make-struct-type` succeeds, but
if it does, then we can still know that the result is a structure
type and (as long as `prop:chaperone-unsafe-undefined` is not
involved) the properties don't affect the constructor, predicate,
selector, or mutators.
This fixes an immediate problem, but the macro expander should have
complained about an unbound `maybe` at phase 2. (A new implementation
of the macro expander detected the unbound `maybe`.)
When an array value is provided, make sure that it's an array
with at least the expected length (or longer) and same element
layout. That's weaker than checking that the array elements have
the right type, because an `eq?` check at the ctype layer seems
too strong, and the ctype API doesn't provide enough information
for a more flexible equality.
A phase shift was mising on `begin-for-syntax`es introduced by
`syntax-local-lift-module-end-declaration`, which is in turn
used to implement` module+`, so `module+` didn't work under
two or more `begin-for-syntaxes`.
Closes#1312
Syntax objects generally make sense as properties in other syntax
objects, but they require special care when marshaling to bytecode
(as syntax objects do in general). To make that special handling
possible and reliable, constrain the shape of allowed values.
The name `path-extension` created a conflict for an existing
registered package, so it should not have been added to
`racket/path`.
Also, `path-get-extension` was intended to work on a path
that is syntactically a directory, so fix and test that.
Change the one expansion mode as far as I can tell) that disables
lifts so that lifts are now allowed, which means that
`(syntax-transforming?)` implies `(syntax-transforming--with-lifts?)`.
The old documentation incorrectly characterized when lifts
were allowed. Ryan noticed the documentation problem, and that
observation led to this simplication.
A `#:name` identifier picks the name that is bound to static
information about a structure type. An `#:extra-name` identifier
specifies an additional name to be bound to the information.
This pair of options is analogous to `#:constructor-name`
and `#:extra-constructor-name`.
Based on Jen Axel's suggestion and implementation.
Closes#1309
Provide a cleaned-up set up path-extension functions. In contrast
to `path-{add,replace}-suffix` and `filename-extension`, a dot
at the beginning of a path element is not treated as an extension
separator. Also, `path-extension` returns an extension including
its separator, which is more consistent with other extension
functions.
The new `path-has-extension?` function replaces many uses of
regexp matching in the base collections.
Closes#1307
Reduce (unbox (box x)) => x
Extend the reductions for cXr to the unsafe versions, for
example reduce (unsafe-car (cons x y)) => x
Check and save types in unsafe operations