1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-28 02:59:54 +00:00

Fix NaNboxing bug that cause flaky builds.

The macro janet_checktype(x, JANET_NUMBER) was incorrect when
x was NaN. This caused the initial unmarshalling dictionary to be missing
entries in certain cases.
This commit is contained in:
Calvin Rose 2020-09-06 14:58:30 -05:00
parent 321a758ab9
commit 24b8b0e382
6 changed files with 73 additions and 67 deletions

View File

@ -149,7 +149,7 @@ build/janet_boot: $(JANET_BOOT_OBJECTS)
# Now the reason we bootstrap in the first place # Now the reason we bootstrap in the first place
build/janet.c: build/janet_boot src/boot/boot.janet build/janet.c: build/janet_boot src/boot/boot.janet
build/janet_boot . JANET_PATH '$(JANET_PATH)' JANET_HEADERPATH '$(INCLUDEDIR)/janet' > $@ build/janet_boot . JANET_PATH '$(JANET_PATH)' > $@
cksum $@ cksum $@
######################## ########################

View File

@ -7,6 +7,8 @@
### ###
### ###
(def root-env "The root environment used to create environments with (make-env)" _env)
(def defn :macro (def defn :macro
"(defn name & more)\n\nDefine a function. Equivalent to (def name (fn name [args] ...))." "(defn name & more)\n\nDefine a function. Equivalent to (def name (fn name [args] ...))."
(fn defn [name & more] (fn defn [name & more]
@ -567,15 +569,6 @@
[head & body] [head & body]
(loop1 body head 0)) (loop1 body head 0))
(put _env 'loop1 nil)
(put _env 'check-indexed nil)
(put _env 'for-template nil)
(put _env 'for-var-template nil)
(put _env 'iterate-template nil)
(put _env 'each-template nil)
(put _env 'range-template nil)
(put _env 'loop-fiber-template nil)
(defmacro seq (defmacro seq
"Similar to loop, but accumulates the loop body into an array and returns that. "Similar to loop, but accumulates the loop body into an array and returns that.
See loop for details." See loop for details."
@ -594,6 +587,16 @@
[& body] [& body]
(tuple fiber/new (tuple 'fn '[] ;body) :yi)) (tuple fiber/new (tuple 'fn '[] ;body) :yi))
(defmacro- undef
"Remove binding from root-env"
[& syms]
~(do ,;(seq [s :in syms] ~(put root-env ',s nil))))
(undef _env)
(undef loop1 check-indexed for-template for-var-template iterate-template
each-template range-template loop-fiber-template)
(defn sum (defn sum
"Returns the sum of xs. If xs is empty, returns 0." "Returns the sum of xs. If xs is empty, returns 0."
[xs] [xs]
@ -749,7 +752,7 @@
[& xs] [& xs]
(compare-reduce >= xs)) (compare-reduce >= xs))
(put _env 'compare-reduce nil) (undef compare-reduce)
### ###
### ###
@ -785,8 +788,8 @@
[a &opt by] [a &opt by]
(sort-help a 0 (- (length a) 1) (or by <))) (sort-help a 0 (- (length a) 1) (or by <)))
(put _env 'sort-part nil) (undef sort-part)
(put _env 'sort-help nil) (undef sort-help)
(defn sort-by (defn sort-by
"Returns a new sorted array that compares elements by invoking "Returns a new sorted array that compares elements by invoking
@ -1140,8 +1143,8 @@
:tuple (tuple/slice (walk-ind f form)) :tuple (tuple/slice (walk-ind f form))
form)) form))
(put _env 'walk-ind nil) (undef walk-ind)
(put _env 'walk-dict nil) (undef walk-dict)
(defn postwalk (defn postwalk
"Do a post-order traversal of a data structure and call (f x) "Do a post-order traversal of a data structure and call (f x)
@ -1350,7 +1353,7 @@
[tab & colls] [tab & colls]
(loop [c :in colls (loop [c :in colls
key :keys c] key :keys c]
(set (tab key) (in c key))) (put tab key (in c key)))
tab) tab)
(defn merge (defn merge
@ -1361,7 +1364,7 @@
(def container @{}) (def container @{})
(loop [c :in colls (loop [c :in colls
key :keys c] key :keys c]
(set (container key) (in c key))) (put container key (in c key)))
container) container)
(defn keys (defn keys
@ -1615,9 +1618,9 @@
,(aux (+ 2 i)) ,(aux (+ 2 i))
,$res)))) 0))) ,$res)))) 0)))
(put _env 'sentinel nil) (undef sentinel)
(put _env 'match-1 nil) (undef match-1)
(put _env 'with-idemp nil) (undef with-idemp)
### ###
### ###
@ -1742,8 +1745,8 @@
[&opt sym] [&opt sym]
~(,doc* ',sym)) ~(,doc* ',sym))
(put _env 'env-walk nil) (undef env-walk)
(put _env 'print-index nil) (undef print-index)
### ###
### ###
@ -2032,7 +2035,7 @@
will inherit bindings from the parent environment, but new will inherit bindings from the parent environment, but new
bindings will not pollute the parent environment." bindings will not pollute the parent environment."
[&opt parent] [&opt parent]
(def parent (if parent parent _env)) (def parent (if parent parent root-env))
(def newenv (table/setproto @{} parent)) (def newenv (table/setproto @{} parent))
newenv) newenv)
@ -2248,10 +2251,11 @@
by make-image, such that (load-image bytes) is the same as (unmarshal bytes load-image-dict)." by make-image, such that (load-image bytes) is the same as (unmarshal bytes load-image-dict)."
@{}) @{})
(def comptime (defmacro comptime
"(comptime x)\n\n "(comptime x)\n\n
Evals x at compile time and returns the result. Similar to a top level unquote." Evals x at compile time and returns the result. Similar to a top level unquote."
:macro eval) [x]
(eval x))
(defn make-image (defn make-image
"Create an image from an environment returned by require. "Create an image from an environment returned by require.
@ -2305,7 +2309,7 @@
(module/add-paths ".jimage" :image) (module/add-paths ".jimage" :image)
# Version of fexists that works even with a reduced OS # Version of fexists that works even with a reduced OS
(if-let [has-stat (_env 'os/stat)] (if-let [has-stat (root-env 'os/stat)]
(let [stat (has-stat :value)] (let [stat (has-stat :value)]
(defglobal "fexists" (fn fexists [path] (= :file (stat path :mode))))) (defglobal "fexists" (fn fexists [path] (= :file (stat path :mode)))))
(defglobal "fexists" (defglobal "fexists"
@ -2352,10 +2356,10 @@
str-parts (interpose "\n " paths)] str-parts (interpose "\n " paths)]
[nil (string "could not find module " path ":\n " ;str-parts)]))) [nil (string "could not find module " path ":\n " ;str-parts)])))
(put _env 'fexists nil) (undef fexists)
(put _env 'mod-filter nil) (undef mod-filter)
(put _env 'check-. nil) (undef check-.)
(put _env 'not-check-. nil) (undef not-check-.)
(def module/cache (def module/cache
"Table mapping loaded module identifiers to their environments." "Table mapping loaded module identifiers to their environments."
@ -2463,7 +2467,7 @@
(def newv (table/setproto @{:private (not ep)} v)) (def newv (table/setproto @{:private (not ep)} v))
(put env (symbol prefix k) newv))) (put env (symbol prefix k) newv)))
(put _env 'require-1 nil) (undef require-1)
(defmacro import (defmacro import
"Import a module. First requires the module, and then merges its "Import a module. First requires the module, and then merges its
@ -2530,7 +2534,7 @@
(in (.slots frame-idx) (or nth 0))) (in (.slots frame-idx) (or nth 0)))
# Conditional compilation for disasm # Conditional compilation for disasm
(def disasm-alias (if-let [x (_env 'disasm)] (x :value))) (def disasm-alias (if-let [x (root-env 'disasm)] (x :value)))
(defn .disasm (defn .disasm
"Gets the assembly for the current function." "Gets the assembly for the current function."
@ -2592,13 +2596,9 @@
(debug/unfbreak fun i)) (debug/unfbreak fun i))
(print "Cleared " (length bytecode) " breakpoints in " fun)) (print "Cleared " (length bytecode) " breakpoints in " fun))
(unless (get _env 'disasm) (unless (get root-env 'disasm)
(put _env '.disasm nil) (undef .disasm .bytecode .breakall .clearall .ppasm))
(put _env '.bytecode nil) (undef disasm-alias)
(put _env '.breakall nil)
(put _env '.clearall nil)
(put _env '.ppasm nil))
(put _env 'disasm-alias nil)
(defn .source (defn .source
"Show the source code for the function being debugged." "Show the source code for the function being debugged."
@ -2652,9 +2652,9 @@
"An environment that contains dot prefixed functions for debugging." "An environment that contains dot prefixed functions for debugging."
@{}) @{})
(def- debugger-keys (filter (partial string/has-prefix? ".") (keys _env))) (def- debugger-keys (filter (partial string/has-prefix? ".") (keys root-env)))
(each k debugger-keys (put debugger-env k (_env k)) (put _env k nil)) (each k debugger-keys (put debugger-env k (root-env k)) (put root-env k nil))
(put _env 'debugger-keys nil) (undef debugger-keys)
### ###
### ###
@ -2750,7 +2750,7 @@
(each a args (import* (string a) :prefix "" :evaluator evaluator))) (each a args (import* (string a) :prefix "" :evaluator evaluator)))
# conditional compilation for reduced os # conditional compilation for reduced os
(def- getenv-alias (if-let [entry (in _env 'os/getenv)] (entry :value) (fn [&]))) (def- getenv-alias (if-let [entry (in root-env 'os/getenv)] (entry :value) (fn [&])))
(defn cli-main (defn cli-main
"Entrance for the Janet CLI tool. Call this functions with the command line "Entrance for the Janet CLI tool. Call this functions with the command line
@ -2885,12 +2885,7 @@
(setdyn :err-color (if *colorize* true)) (setdyn :err-color (if *colorize* true))
(repl getchunk nil env))) (repl getchunk nil env)))
(put _env 'no-side-effects nil) (undef no-side-effects is-safe-def safe-forms importers use-2 getenv-alias)
(put _env 'is-safe-def nil)
(put _env 'safe-forms nil)
(put _env 'importers nil)
(put _env 'use-2 nil)
(put _env 'getenv-alias nil)
### ###
### ###
@ -2898,12 +2893,13 @@
### ###
### ###
(def root-env "The root environment used to create environments with (make-env)" _env)
(do (do
(put _env 'boot/opts nil) (undef boot/opts undef)
(put _env '_env nil) (def load-dict (env-lookup root-env))
(def load-dict (env-lookup _env)) (put load-dict 'boot/config nil)
(put load-dict 'boot/args nil)
(each [k v] (pairs load-dict)
(if (number? v) (put load-dict k nil)))
(merge-into load-image-dict load-dict) (merge-into load-image-dict load-dict)
(merge-into make-image-dict (invert load-dict))) (merge-into make-image-dict (invert load-dict)))
@ -2924,25 +2920,29 @@
(put into k (x k)))) (put into k (x k))))
into) into)
(def env (fiber/getenv (fiber/current)))
# Modify env based on some options. # Modify env based on some options.
(loop [[k v] :pairs env (loop [[k v] :pairs root-env
:when (symbol? k)] :when (symbol? k)]
(def flat (proto-flatten @{} v)) (def flat (proto-flatten @{} v))
(when (boot/config :no-docstrings) (when (boot/config :no-docstrings)
(put flat :doc nil)) (put flat :doc nil))
(when (boot/config :no-sourcemaps) (when (boot/config :no-sourcemaps)
(put flat :source-map nil)) (put flat :source-map nil))
(put env k flat)) (put root-env k flat))
(put env 'boot/config nil) (put root-env 'boot/config nil)
(put env 'boot/args nil) (put root-env 'boot/args nil)
(def image (let [env-pairs (pairs (env-lookup env))
(def image (let [env-pairs (pairs (env-lookup root-env))
essential-pairs (filter (fn [[k v]] (or (cfunction? v) (abstract? v))) env-pairs) essential-pairs (filter (fn [[k v]] (or (cfunction? v) (abstract? v))) env-pairs)
lookup (table ;(mapcat identity essential-pairs)) lookup (table ;(mapcat identity essential-pairs))
reverse-lookup (invert lookup)] reverse-lookup (invert lookup)]
(marshal env reverse-lookup))) # Check no duplicate values
(def temp @{})
(eachp [k v] lookup
(if (in temp v) (errorf "duplicate value: %v" v))
(put temp v k))
(marshal root-env reverse-lookup)))
# Create amalgamation # Create amalgamation

View File

@ -23,6 +23,7 @@
#include <janet.h> #include <janet.h>
#include <assert.h> #include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <math.h>
#include "tests.h" #include "tests.h"
@ -44,6 +45,11 @@ int system_test() {
assert(janet_equals(janet_wrap_integer(INT32_MIN), janet_wrap_integer(INT32_MIN))); assert(janet_equals(janet_wrap_integer(INT32_MIN), janet_wrap_integer(INT32_MIN)));
assert(janet_equals(janet_wrap_number(1.4), janet_wrap_number(1.4))); assert(janet_equals(janet_wrap_number(1.4), janet_wrap_number(1.4)));
assert(janet_equals(janet_wrap_number(3.14159265), janet_wrap_number(3.14159265))); assert(janet_equals(janet_wrap_number(3.14159265), janet_wrap_number(3.14159265)));
#ifdef NAN
assert(janet_checktype(janet_wrap_number(NAN), JANET_NUMBER));
#else
assert(janet_checktype(janet_wrap_number(0.0 / 0.0), JANET_NUMBER));
#endif
assert(NULL != &janet_wrap_nil); assert(NULL != &janet_wrap_nil);

View File

@ -1218,7 +1218,7 @@ JanetTable *janet_core_env(JanetTable *replacements) {
} }
/* Load core cfunctions (and some built in janet assembly functions) */ /* Load core cfunctions (and some built in janet assembly functions) */
JanetTable *dict = janet_table(300); JanetTable *dict = janet_table(512);
janet_load_libs(dict); janet_load_libs(dict);
/* Add replacements */ /* Add replacements */

View File

@ -274,9 +274,9 @@ int32_t janet_hash(Janet x) {
if (sizeof(double) == sizeof(void *)) { if (sizeof(double) == sizeof(void *)) {
/* Assuming 8 byte pointer */ /* Assuming 8 byte pointer */
uint64_t i = janet_u64(x); uint64_t i = janet_u64(x);
uint32_t lo = (uint32_t) (i & 0xFFFFFFFF); uint32_t lo = (uint32_t)(i & 0xFFFFFFFF);
uint32_t hi = (uint32_t) (i >> 32); uint32_t hi = (uint32_t)(i >> 32);
hash = (int32_t) (hi ^ (lo >> 3)); hash = (int32_t)(hi ^ (lo >> 3));
} else { } else {
/* Assuming 4 byte pointer (or smaller) */ /* Assuming 4 byte pointer (or smaller) */
hash = (int32_t)((char *)janet_unwrap_pointer(x) - (char *)0); hash = (int32_t)((char *)janet_unwrap_pointer(x) - (char *)0);

View File

@ -579,7 +579,7 @@ JANET_API Janet janet_wrap_integer(int32_t x);
(((x).u64 & JANET_NANBOX_TAGBITS) == janet_nanbox_tag((type))) (((x).u64 & JANET_NANBOX_TAGBITS) == janet_nanbox_tag((type)))
#define janet_nanbox_isnumber(x) \ #define janet_nanbox_isnumber(x) \
(!isnan((x).number) || janet_nanbox_checkauxtype((x), JANET_NUMBER)) (!isnan((x).number) || ((((x).u64 >> 47) & 0xF) == JANET_NUMBER))
#define janet_checktype(x, t) \ #define janet_checktype(x, t) \
(((t) == JANET_NUMBER) \ (((t) == JANET_NUMBER) \