diff options
author | Alain Frisch <alain@frisch.fr> | 2012-04-18 07:17:58 +0000 |
---|---|---|
committer | Alain Frisch <alain@frisch.fr> | 2012-04-18 07:17:58 +0000 |
commit | 061ed556888aed2c84267caca6a6ab832eb2da46 (patch) | |
tree | dd594255e06294b863e40a382af794adb60682aa | |
parent | 215e508e8bd53f7299ffd7d828794e2f4d4ba6f4 (diff) | |
parent | 3930c2fd79e43bd02e3bc79d6b047f3aeab0effe (diff) | |
download | ocaml-more_unboxing.tar.gz |
Sync with trunk.more_unboxing
git-svn-id: http://caml.inria.fr/svn/ocaml/branches/more_unboxing@12369 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
49 files changed, 462 insertions, 170 deletions
@@ -57,7 +57,7 @@ Standard library: with user-provided hash functions. - Marshal: marshalling of function values (flag Marshal.Closures) now also works for functions that come from dynamically-loaded modules (PR#5215) -- Random: +- Random: . More random initialization (Random.self_init()), using /dev/urandom when available (e.g. Linux, FreeBSD, MacOS X, Solaris) . Faster implementation of Random.float @@ -65,9 +65,14 @@ Standard library: - Set and Map: more efficient implementation of "filter" and "partition" - String: new function "map" (PR#3888) +Other libraries: +- Bigarray: added "release" functions that free memory and file mappings + just like GC finalization does eventually, but does it immediately. + Bug Fixes: - PR#1643: functions of the Lazy module whose named started with 'lazy_' have been deprecated, and new ones without the prefix added +- PR#3571: in Bigarrays, call msync() before unmapping to commit changes - PR#4549: Filename.dirname is not handling multiple / on Unix - PR#4688: (Windows) special floating-point values aren't converted to strings correctly @@ -88,8 +93,11 @@ Bug Fixes: - PR#5211: updated Genlex documentation to state that camlp4 is mandatory for 'parser' keyword and associated notation - PR#5238, PR#5277: Sys_error when getting error location +- PR#5295: OS threads: problem with caml_c_thread_unregister() - PR#5301: camlp4r and exception equal to another one with parameters - PR#5309: Queue.add is not thread/signal safe +- PR#5310: Ratio.create_ratio/create_normalized_ratio have misleading names +- PR#5311: better message for warning 23 - PR#5313: ocamlopt -g misses optimizations - PR#5316: objinfo now shows ccopts/ccobjs/force_link when applicable - PR#5322: type abbreviations expanding to a universal type variable @@ -112,6 +120,7 @@ Bug Fixes: - PR#5436: update object ids on unmarshaling - PR#5453: configure doesn't find X11 under Ubuntu/MultiarchSpec - PR#5461: Double linking of bytecode modules +- PR#5463: Bigarray.*.map_file fail if empty array is requested - PR#5469: private record type generated by functor loses abbreviation - PR#5475: Wrapper script for interpreted LablTk wrongly handles command line parameters @@ -124,7 +133,9 @@ Bug Fixes: - PR#5510: ocamldep has duplicate -ml{,i}-synonym options - PR#5511: in Bigarray.reshape, unwarranted limitation on new array dimensions. - PR#5513: Int64.div causes floating point exception (ocamlopt, x86) -- PR#5516: in Bigarray C stubs, use C99 / GCC flexible array types if possible +- PR#5516: in Bigarray C stubs, use C99 flexible array types if possible +- PR#5543: in Bigarray.map_file, try to avoid using lseek() when growing file +- PR#5538: combining -i and -annot in ocamlc - PR#5560: incompatible type for tuple pattern with -principal - problem with printing of string literals in camlp4 (reported on caml-list) - emacs mode: colorization of comments and strings now works correctly @@ -2891,5 +2902,3 @@ Caml Special Light 1.06: ------------------------ * First public release. - -$Id$ diff --git a/Makefile.nt b/Makefile.nt index b435f70b66..0b9e4e7c2f 100644 --- a/Makefile.nt +++ b/Makefile.nt @@ -28,6 +28,9 @@ CAMLDEP=boot/ocamlrun tools/ocamldep DEPFLAGS=$(INCLUDES) CAMLRUN=byterun/ocamlrun +CAMLP4OUT=$(CAMLP4:=out) +CAMLP4OPT=$(CAMLP4:=opt) + INCLUDES=-I utils -I parsing -I typing -I bytecomp -I asmcomp -I driver \ -I toplevel @@ -121,7 +124,8 @@ defaultentry: @echo "Please refer to the installation instructions in file README.win32." # Recompile the system using the bootstrap compiler -all: runtime ocamlc ocamllex ocamlyacc ocamltools library ocaml otherlibraries ocamldoc.byte ocamlbuild.byte $(CAMLP4OUT) $(DEBUGGER) +all: runtime ocamlc ocamllex ocamlyacc ocamltools library ocaml \ + otherlibraries ocamldoc.byte ocamlbuild.byte $(CAMLP4OUT) $(DEBUGGER) # The compilation of ocaml will fail if the runtime has changed. # Never mind, just do make bootstrap to reach fixpoint again. @@ -1,6 +1,4 @@ -4.01.0+dev0 (2012-03-12) +4.01.0+dev2_2012-04-17 # The version string is the first line of this file. # It must be in the format described in stdlib/sys.mli - -# $Id$ diff --git a/asmcomp/cmmgen.ml b/asmcomp/cmmgen.ml index fddf59862a..7d24f49700 100644 --- a/asmcomp/cmmgen.ml +++ b/asmcomp/cmmgen.ml @@ -78,7 +78,10 @@ let int_const n = (Nativeint.add (Nativeint.shift_left (Nativeint.of_int n) 1) 1n) let add_const c n = - if n = 0 then c else Cop(Caddi, [c; Cconst_int n]) + if n = 0 then c + else match c with + | Cconst_int x when no_overflow_add x n -> Cconst_int (x + n) + | c -> Cop(Caddi, [c; Cconst_int n]) let incr_int = function Cconst_int n when n < max_int -> Cconst_int(n+1) diff --git a/bytecomp/bytelink.ml b/bytecomp/bytelink.ml index 9bc5790c2e..4f93f0c2b5 100644 --- a/bytecomp/bytelink.ml +++ b/bytecomp/bytelink.ml @@ -466,6 +466,7 @@ let link_bytecode_as_c ppf tolink outfile = close_out outchan with x -> close_out outchan; + remove_file outfile; raise x end; if !Clflags.debug then diff --git a/byterun/compact.c b/byterun/compact.c index d409492877..c310bbebb6 100644 --- a/byterun/compact.c +++ b/byterun/compact.c @@ -144,7 +144,7 @@ static char *compact_allocate (mlsize_t size) return adr; } -void caml_compact_heap (void) +static void do_compaction (void) { char *ch, *chend; Assert (caml_gc_phase == Phase_idle); @@ -395,6 +395,60 @@ void caml_compact_heap (void) uintnat caml_percent_max; /* used in gc_ctrl.c and memory.c */ +void caml_compact_heap (void) +{ + uintnat target_size; + + do_compaction (); + /* Compaction may fail to shrink the heap to a reasonable size + because it deals in complete chunks: if a very large chunk + is at the beginning of the heap, everything gets moved to + it and it is not freed. + + In that case, we allocate a new chunk of the desired heap + size, chain it at the beginning of the heap (thus pretending + its address is smaller), and launch a second compaction. + This will move all data to this new chunk and free the + very large chunk. + + See PR#5389 + */ + /* We compute: + freewords = caml_fl_cur_size (exact) + heapsize = caml_heap_size (exact) + usedwords = heap_size - freewords + target_size = usedwords * (1 + caml_percent_free / 100) + + We recompact if target_size < heap_size / 2 + */ + target_size = (caml_stat_heap_size - Bsize_wsize (caml_fl_cur_size)) + * (100 + caml_percent_free) / 100; + target_size = caml_round_heap_chunk_size (target_size); + if (target_size < caml_stat_heap_size / 2){ + char *chunk; + + caml_gc_message (0x10, "Recompacting...\n", 0); + + /* round it up to a page size */ + chunk = caml_alloc_for_heap (target_size); + if (chunk == NULL) return; + caml_make_free_blocks ((value *) chunk, + Wsize_bsize (Chunk_size (chunk)), 0); + if (caml_page_table_add (In_heap, chunk, chunk + Chunk_size (chunk)) != 0){ + caml_free_for_heap (chunk); + return; + } + Chunk_next (chunk) = caml_heap_start; + caml_heap_start = chunk; + caml_stat_heap_size += Chunk_size (chunk); + if (caml_stat_heap_size > caml_stat_top_heap_size){ + caml_stat_top_heap_size = caml_stat_heap_size; + } + do_compaction (); + Assert (Chunk_next (caml_heap_start) == NULL); + } +} + void caml_compact_heap_maybe (void) { /* Estimated free words in the heap: @@ -408,7 +462,7 @@ void caml_compact_heap_maybe (void) float fw, fp; Assert (caml_gc_phase == Phase_idle); if (caml_percent_max >= 1000000) return; - if (caml_stat_major_collections < 3 || caml_stat_heap_chunks < 3) return; + if (caml_stat_major_collections < 3) return; fw = 3.0 * caml_fl_cur_size - 2.0 * caml_fl_size_at_phase_change; if (fw < 0) fw = caml_fl_cur_size; diff --git a/byterun/io.h b/byterun/io.h index 53d9bb9bf4..89a85380c7 100644 --- a/byterun/io.h +++ b/byterun/io.h @@ -22,7 +22,7 @@ #include "mlvalues.h" #ifndef IO_BUFFER_SIZE -#define IO_BUFFER_SIZE 4096 +#define IO_BUFFER_SIZE 65536 #endif #if defined(_WIN32) diff --git a/byterun/memory.c b/byterun/memory.c index b0801f130b..b99825d185 100644 --- a/byterun/memory.c +++ b/byterun/memory.c @@ -255,6 +255,8 @@ void caml_free_for_heap (char *mem) caller. All other blocks must have the color [caml_allocation_color(m)]. The caller must update [caml_allocated_words] if applicable. Return value: 0 if no error; -1 in case of error. + + See also: caml_compact_heap, which duplicates most of this function. */ int caml_add_to_heap (char *m) { diff --git a/camlp4/Camlp4Parsers/Camlp4OCamlParser.ml b/camlp4/Camlp4Parsers/Camlp4OCamlParser.ml index 3d841516e4..bbec29b966 100644 --- a/camlp4/Camlp4Parsers/Camlp4OCamlParser.ml +++ b/camlp4/Camlp4Parsers/Camlp4OCamlParser.ml @@ -158,6 +158,7 @@ module Make (Syntax : Sig.Camlp4Syntax) = struct DELETE_RULE Gram expr: SELF; ":="; SELF; dummy END; DELETE_RULE Gram expr: "~"; a_LIDENT; ":"; SELF END; DELETE_RULE Gram expr: "?"; a_LIDENT; ":"; SELF END; + DELETE_RULE Gram constructor_declarations: a_UIDENT; ":"; ctyp END; (* Some other DELETE_RULE are after the grammar *) value clear = Gram.Entry.clear; @@ -541,6 +542,15 @@ module Make (Syntax : Sig.Camlp4Syntax) = struct | t = ctyp LEVEL "ctyp1" -> t ] ] ; + constructor_declarations: + [ [ s = a_UIDENT; ":"; t = constructor_arg_list ; "->" ; ret = ctyp -> + <:ctyp< $uid:s$ : ($t$ -> $ret$) >> + | s = a_UIDENT; ":"; ret = constructor_arg_list -> + match Ast.list_of_ctyp ret [] with + [ [c] -> <:ctyp< $uid:s$ : $c$ >> + | _ -> raise (Stream.Error "invalid generalized constructor type") ] + ] ] + ; semi: [ [ ";;" -> () | -> () ] ] ; diff --git a/camlp4/Camlp4Parsers/Camlp4OCamlRevisedParser.ml b/camlp4/Camlp4Parsers/Camlp4OCamlRevisedParser.ml index c9744140d2..ed6dad0601 100644 --- a/camlp4/Camlp4Parsers/Camlp4OCamlRevisedParser.ml +++ b/camlp4/Camlp4Parsers/Camlp4OCamlRevisedParser.ml @@ -303,6 +303,15 @@ New syntax:\ value stopped_at _loc = Some (Loc.move_line 1 _loc) (* FIXME be more precise *); + value rec generalized_type_of_type = + fun + [ <:ctyp< $t1$ -> $t2$ >> -> + let (tl, rt) = generalized_type_of_type t2 in + ([t1 :: tl], rt) + | t -> + ([], t) ] + ; + value symbolchar = let list = ['$'; '!'; '%'; '&'; '*'; '+'; '-'; '.'; '/'; ':'; '<'; '='; '>'; '?'; @@ -1135,12 +1144,9 @@ New syntax:\ <:ctyp< $t1$ | $t2$ >> | s = a_UIDENT; "of"; t = constructor_arg_list -> <:ctyp< $uid:s$ of $t$ >> - | s = a_UIDENT; ":"; t = constructor_arg_list ; "->" ; ret = ctyp -> - <:ctyp< $uid:s$ : ($t$ -> $ret$) >> - | s = a_UIDENT; ":"; ret = constructor_arg_list -> - match Ast.list_of_ctyp ret [] with - [ [c] -> <:ctyp< $uid:s$ : $c$ >> - | _ -> raise (Stream.Error "invalid generalized constructor type") ] + | s = a_UIDENT; ":"; t = ctyp -> + let (tl, rt) = generalized_type_of_type t in + <:ctyp< $uid:s$ : ($Ast.tyAnd_of_list tl$ -> $rt$) >> | s = a_UIDENT -> <:ctyp< $uid:s$ >> ] ] diff --git a/camlp4/Camlp4Top/Top.ml b/camlp4/Camlp4Top/Top.ml index 1ff0ef8210..0e07eb21e6 100644 --- a/camlp4/Camlp4Top/Top.ml +++ b/camlp4/Camlp4Top/Top.ml @@ -60,45 +60,31 @@ value initialization = lazy begin else () end; -value lookup x xs = try Some (List.assq x xs) with [ Not_found -> None ]; - -value wrap parse_fun = - let token_streams = ref [] in - let cleanup lb = - try token_streams.val := List.remove_assq lb token_streams.val - with [ Not_found -> () ] - in - fun lb -> - let () = Lazy.force initialization in - let () = Register.iter_and_take_callbacks (fun (_, f) -> f ()) in - let token_stream = - match lookup lb token_streams.val with - [ None -> - let not_filtered_token_stream = Lexer.from_lexbuf lb in - let token_stream = Gram.filter (not_filtered not_filtered_token_stream) in - do { token_streams.val := [ (lb,token_stream) :: token_streams.val ]; token_stream } - | Some token_stream -> token_stream ] - in try - match token_stream with parser - [ [: `(EOI, _) :] -> raise End_of_file - | [: :] -> parse_fun token_stream ] - with - [ End_of_file | Sys.Break | (Loc.Exc_located _ (End_of_file | Sys.Break)) - as x -> (cleanup lb; raise x) - | x -> - let x = - match x with - [ Loc.Exc_located loc x -> do { +value wrap parse_fun lb = + let () = Lazy.force initialization in + let () = Register.iter_and_take_callbacks (fun (_, f) -> f ()) in + let not_filtered_token_stream = Lexer.from_lexbuf lb in + let token_stream = Gram.filter (not_filtered not_filtered_token_stream) in + try + match token_stream with parser + [ [: `(EOI, _) :] -> raise End_of_file + | [: :] -> parse_fun token_stream ] + with + [ End_of_file | Sys.Break | (Loc.Exc_located _ (End_of_file | Sys.Break)) + as x -> raise x + | x -> + let x = + match x with + [ Loc.Exc_located loc x -> do { Toploop.print_location Format.err_formatter (Loc.to_ocaml_location loc); x } - | x -> x ] - in - do { - cleanup lb; - Format.eprintf "@[<0>%a@]@." Camlp4.ErrorHandler.print x; - raise Exit - } ]; + | x -> x ] + in + do { + Format.eprintf "@[<0>%a@]@." Camlp4.ErrorHandler.print x; + raise Exit + } ]; value toplevel_phrase token_stream = match Gram.parse_tokens_after_filter Syntax.top_phrase token_stream with diff --git a/config/Makefile.mingw b/config/Makefile.mingw index 29d14f6e6c..ddbc628727 100644 --- a/config/Makefile.mingw +++ b/config/Makefile.mingw @@ -19,6 +19,9 @@ PREFIX=C:/ocamlmgw +### Remove this to disable compiling camlp4 +CAMLP4=camlp4 + ### Where to install the binaries BINDIR=$(PREFIX)/bin @@ -78,6 +81,7 @@ EXTRALIBS= NATDYNLINK=true CMXS=cmxs RUNTIMED=noruntimed +ASM_CFI_SUPPORTED=false ########## Configuration for the bytecode compiler @@ -1116,6 +1116,11 @@ if sh ./hasgot -i sys/types.h -i sys/mman.h && sh ./hasgot mmap munmap; then echo "#define HAS_MMAP" >> s.h fi +if sh ./hasgot pwrite; then + echo "pwrite() found" + echo "#define HAS_PWRITE" >> s.h +fi + nargs=none for i in 5 6; do if sh ./trycompile -DNUM_ARGS=${i} gethostbyname.c; then nargs=$i; break; fi diff --git a/debugger/program_loading.ml b/debugger/program_loading.ml index 6ef9d03e7c..bef9f80d17 100644 --- a/debugger/program_loading.ml +++ b/debugger/program_loading.ml @@ -50,10 +50,10 @@ let get_environment () = let env = Array.fold_right (fun elem acc -> - if have_name_in_config_env elem then - acc - else - elem :: acc) + if have_name_in_config_env elem then + acc + else + elem :: acc) env [] in Array.of_list (env @ !Debugger_config.environment) @@ -109,7 +109,7 @@ let generic_exec = "Win32" -> generic_exec_win | _ -> generic_exec_unix -(* Execute the program by calling the runtime explicitely *) +(* Execute the program by calling the runtime explicitly *) let exec_with_runtime = generic_exec (function () -> @@ -120,7 +120,7 @@ let exec_with_runtime = thinks each command line parameter is a file. So no good solution so far *) Printf.sprintf "%sset CAML_DEBUG_SOCKET=%s && %s %s %s" - (get_win32_environment ()) + (get_win32_environment ()) !socket_name runtime_program !program_name @@ -140,7 +140,7 @@ let exec_direct = "Win32" -> (* See the comment above *) Printf.sprintf "%sset CAML_DEBUG_SOCKET=%s && %s %s" - (get_win32_environment ()) + (get_win32_environment ()) !socket_name !program_name !arguments diff --git a/ocamlbuild/command.ml b/ocamlbuild/command.ml index 131cd8586c..1ce80c9743 100644 --- a/ocamlbuild/command.ml +++ b/ocamlbuild/command.ml @@ -91,9 +91,15 @@ let atomize_paths l = S(List.map (fun x -> P x) l) let env_path = lazy begin let path_var = Sys.getenv "PATH" in + let parse_path = + if Sys.os_type = "Win32" then + Lexers.parse_environment_path_w + else + Lexers.parse_environment_path + in let paths = try - Lexers.parse_environment_path (Lexing.from_string path_var) + parse_path (Lexing.from_string path_var) with Lexers.Error msg -> raise (Lexers.Error ("$PATH: " ^ msg)) in let norm_current_dir_name path = @@ -119,21 +125,33 @@ let virtual_solver virtual_command = failwith (Printf.sprintf "the solver for the virtual command %S \ has failed finding a valid command" virtual_command) +(* On Windows, we need to also check for the ".exe" version of the file. *) +let file_or_exe_exists file = + sys_file_exists file || Sys.os_type = "Win32" && sys_file_exists (file ^ ".exe") -(* FIXME windows *) let search_in_path cmd = + (* Try to find [cmd] in path [path]. *) + let try_path path = + (* Don't know why we're trying to be subtle here... *) + if path = Filename.current_dir_name then file_or_exe_exists cmd + else file_or_exe_exists (filename_concat path cmd) + in if Filename.is_implicit cmd then - let path = List.find begin fun path -> - if path = Filename.current_dir_name then sys_file_exists cmd - else sys_file_exists (filename_concat path cmd) - end !*env_path in + let path = List.find try_path !*env_path in + (* We're not trying to append ".exe" here because all windows shells are + * capable of understanding the command without the ".exe" suffix. *) filename_concat path cmd - else cmd + else + cmd (*** string_of_command_spec{,_with_calls *) let rec string_of_command_spec_with_calls call_with_tags call_with_target resolve_virtuals spec = let self = string_of_command_spec_with_calls call_with_tags call_with_target resolve_virtuals in let b = Buffer.create 256 in + (* The best way to prevent bash from switching to its windows-style + * quote-handling is to prepend an empty string before the command name. *) + if Sys.os_type = "Win32" then + Buffer.add_string b "''"; let first = ref true in let put_space () = if !first then diff --git a/ocamlbuild/command.mli b/ocamlbuild/command.mli index 0cdc602c8a..f54b8e8ac1 100644 --- a/ocamlbuild/command.mli +++ b/ocamlbuild/command.mli @@ -44,3 +44,5 @@ val deps_of_tags : Tags.t -> pathname list val dep : Tags.elt list -> pathname list -> unit val pdep : Tags.elt list -> Tags.elt -> (string -> pathname list) -> unit + +val file_or_exe_exists: string -> bool diff --git a/ocamlbuild/lexers.mli b/ocamlbuild/lexers.mli index 2f37edca64..bc5de4cfb1 100644 --- a/ocamlbuild/lexers.mli +++ b/ocamlbuild/lexers.mli @@ -32,6 +32,8 @@ val trim_blanks : Lexing.lexbuf -> string Example: ":aaa:bbb:::ccc:" -> [""; "aaa"; "bbb"; ""; ""; "ccc"; ""] *) val parse_environment_path : Lexing.lexbuf -> string list +(* Same one, for Windows (PATH is ;-separated) *) +val parse_environment_path_w : Lexing.lexbuf -> string list val conf_lines : string option -> int -> string -> Lexing.lexbuf -> conf val path_scheme : bool -> Lexing.lexbuf -> diff --git a/ocamlbuild/lexers.mll b/ocamlbuild/lexers.mll index 7b191b0d97..2206f862c0 100644 --- a/ocamlbuild/lexers.mll +++ b/ocamlbuild/lexers.mll @@ -81,6 +81,15 @@ and comma_or_blank_sep_strings_aux = parse | space* eof { [] } | _ { raise (Error "Expecting (comma|blank)-separated strings (2)") } +and parse_environment_path_w = parse + | ([^ ';']* as word) { word :: parse_environment_path_aux_w lexbuf } + | ';' ([^ ';']* as word) { "" :: word :: parse_environment_path_aux_w lexbuf } + | eof { [] } +and parse_environment_path_aux_w = parse + | ';' ([^ ';']* as word) { word :: parse_environment_path_aux_w lexbuf } + | eof { [] } + | _ { raise (Error "Impossible: expecting colon-separated strings") } + and parse_environment_path = parse | ([^ ':']* as word) { word :: parse_environment_path_aux lexbuf } | ':' ([^ ':']* as word) { "" :: word :: parse_environment_path_aux lexbuf } diff --git a/ocamlbuild/my_std.ml b/ocamlbuild/my_std.ml index 78286b53c8..3ba8550242 100644 --- a/ocamlbuild/my_std.ml +++ b/ocamlbuild/my_std.ml @@ -249,18 +249,17 @@ let sys_command = | "Win32" -> fun cmd -> if cmd = "" then 0 else let cmd = "bash -c "^Filename.quote cmd in - (* FIXME fix Filename.quote for windows *) - let cmd = String.subst "\"&\"\"&\"" "&&" cmd in Sys.command cmd | _ -> fun cmd -> if cmd = "" then 0 else Sys.command cmd (* FIXME warning fix and use Filename.concat *) let filename_concat x y = if x = Filename.current_dir_name || x = "" then y else - if x.[String.length x - 1] = '/' then + if Sys.os_type = "Win32" && (x.[String.length x - 1] = '\\') || x.[String.length x - 1] = '/' then if y = "" then x else x ^ y - else x ^ "/" ^ y + else + x ^ "/" ^ y (* let reslash = match Sys.os_type with diff --git a/ocamlbuild/options.ml b/ocamlbuild/options.ml index b0ca59d27a..d17e0dc136 100644 --- a/ocamlbuild/options.ml +++ b/ocamlbuild/options.ml @@ -50,8 +50,8 @@ let mk_virtual_solvers = if sys_file_exists !dir then let long = filename_concat !dir cmd in let long_opt = long ^ ".opt" in - if sys_file_exists long_opt then A long_opt - else if sys_file_exists long then A long + if file_or_exe_exists long_opt then A long_opt + else if file_or_exe_exists long then A long else try let _ = search_in_path opt in a_opt with Not_found -> a_cmd else diff --git a/ocamlbuild/shell.ml b/ocamlbuild/shell.ml index c76d154583..3fbeb81aa7 100644 --- a/ocamlbuild/shell.ml +++ b/ocamlbuild/shell.ml @@ -23,7 +23,12 @@ let is_simple_filename s = | _ -> false in loop 0 let quote_filename_if_needed s = - if is_simple_filename s then s else Filename.quote s + if is_simple_filename s then s + (* We should probably be using [Filename.unix_quote] except that function + * isn't exported. Users on Windows will have to live with not being able to + * install OCaml into c:\o'caml. Too bad. *) + else if Sys.os_type = "Win32" then Printf.sprintf "'%s'" s + else Filename.quote s let chdir dir = reset_filesys_cache (); Sys.chdir dir diff --git a/ocamlbuild/shell.mli b/ocamlbuild/shell.mli index d393c7b3e7..2d867b032d 100644 --- a/ocamlbuild/shell.mli +++ b/ocamlbuild/shell.mli @@ -9,10 +9,14 @@ (* *) (***********************************************************************) - (* Original author: Nicolas Pouillard *) + val is_simple_filename : string -> bool + val quote_filename_if_needed : string -> string +(** This will quote using Unix conventions, even on Windows, because commands are + * always run through bash -c on Windows. *) + val chdir : string -> unit val rm : string -> unit val rm_f : string -> unit diff --git a/otherlibs/bigarray/bigarray.h b/otherlibs/bigarray/bigarray.h index 8625b0d9fe..f6552107a6 100644 --- a/otherlibs/bigarray/bigarray.h +++ b/otherlibs/bigarray/bigarray.h @@ -73,8 +73,8 @@ struct caml_ba_array { intnat num_dims; /* Number of dimensions */ intnat flags; /* Kind of element array + memory layout + allocation status */ struct caml_ba_proxy * proxy; /* The proxy for sub-arrays, or NULL */ - /* PR#5516: use C99's / gcc's flexible array types if possible */ -#if (__STDC_VERSION__ >= 199901L) || defined(__GNUC__) + /* PR#5516: use C99's flexible array types if possible */ +#if (__STDC_VERSION__ >= 199901L) intnat dim[] /*[num_dims]*/; /* Size in each dimension */ #else intnat dim[1] /*[num_dims]*/; /* Size in each dimension */ diff --git a/otherlibs/bigarray/bigarray.ml b/otherlibs/bigarray/bigarray.ml index 1d3dbcf971..b9f22b1828 100644 --- a/otherlibs/bigarray/bigarray.ml +++ b/otherlibs/bigarray/bigarray.ml @@ -99,6 +99,8 @@ module Genarray = struct = "caml_ba_map_file_bytecode" "caml_ba_map_file" let map_file fd ?(pos = 0L) kind layout shared dims = map_internal fd kind layout shared dims pos + external release: ('a, 'b, 'c) t -> unit + = "caml_ba_release" end module Array1 = struct @@ -122,6 +124,8 @@ module Array1 = struct ba let map_file fd ?pos kind layout shared dim = Genarray.map_file fd ?pos kind layout shared [|dim|] + external release: ('a, 'b, 'c) t -> unit + = "caml_ba_release" end module Array2 = struct @@ -161,6 +165,8 @@ module Array2 = struct ba let map_file fd ?pos kind layout shared dim1 dim2 = Genarray.map_file fd ?pos kind layout shared [|dim1;dim2|] + external release: ('a, 'b, 'c) t -> unit + = "caml_ba_release" end module Array3 = struct @@ -210,6 +216,8 @@ module Array3 = struct ba let map_file fd ?pos kind layout shared dim1 dim2 dim3 = Genarray.map_file fd ?pos kind layout shared [|dim1;dim2;dim3|] + external release: ('a, 'b, 'c) t -> unit + = "caml_ba_release" end external genarray_of_array1: ('a, 'b, 'c) Array1.t -> ('a, 'b, 'c) Genarray.t diff --git a/otherlibs/bigarray/bigarray.mli b/otherlibs/bigarray/bigarray.mli index 8b260bf790..73c27b5750 100644 --- a/otherlibs/bigarray/bigarray.mli +++ b/otherlibs/bigarray/bigarray.mli @@ -426,7 +426,27 @@ module Genarray : or a SIGBUS signal may be raised. This happens, for instance, if the file is shrinked. *) - end + val release: ('a, 'b, 'c) t -> unit + (** Release the resources associated with the given big array, + then set all of its dimensions to 0, causing subsequent accesses + to the big array to fail. This releasing of resources is performed + automatically by the garbage collector when the big array is no longer + referenced by the program. However, memory behavior of the program + can be improved by releasing the resources explicitly via + [Genarray.release] as soon as the big array is no longer useful. + + If the big array was created with [Genarray.create], the memory + space occupied by its data is freed. If the big array was + created with [Genarray.map_file], updates performed on the array + are flushed to the file (if the mapping is shared), then the + mapping is removed, freeing the corresponding virtual memory + space. If several views on the big array data were created + using [Genarray.sub_*] or [Genarray.slice_*], data release occurs + when the last not-yet-released view is released. Multiple calls + to [Genarray.release] on the same big array are safe: the second + and subsequent calls have no effect. *) + +end (** {6 One-dimensional arrays} *) @@ -496,16 +516,20 @@ module Array1 : sig (** Memory mapping of a file as a one-dimensional big array. See {!Bigarray.Genarray.map_file} for more details. *) + val release: ('a, 'b, 'c) t -> unit + (** Explicit release of the resources associated with the big array. + See {!Bigarray.Genarray.release} for more details. *) + external unsafe_get: ('a, 'b, 'c) t -> int -> 'a = "%caml_ba_unsafe_ref_1" (** Like {!Bigarray.Array1.get}, but bounds checking is not always performed. Use with caution and only when the program logic guarantees that - the access is within bounds. *) + the access is within bounds and the big array has not been released. *) external unsafe_set: ('a, 'b, 'c) t -> int -> 'a -> unit = "%caml_ba_unsafe_set_1" (** Like {!Bigarray.Array1.set}, but bounds checking is not always performed. Use with caution and only when the program logic guarantees that - the access is within bounds. *) + the access is within bounds and the big array has not been released. *) end @@ -601,15 +625,21 @@ module Array2 : (** Memory mapping of a file as a two-dimensional big array. See {!Bigarray.Genarray.map_file} for more details. *) + val release: ('a, 'b, 'c) t -> unit + (** Explicit release of the resources associated with the big array. + See {!Bigarray.Genarray.release} for more details. *) + external unsafe_get: ('a, 'b, 'c) t -> int -> int -> 'a = "%caml_ba_unsafe_ref_2" - (** Like {!Bigarray.Array2.get}, but bounds checking is not always - performed. *) + (** Like {!Bigarray.Array2.get}, but bounds checking is not always performed. + Use with caution and only when the program logic guarantees that + the access is within bounds and the big array has not been released. *) external unsafe_set: ('a, 'b, 'c) t -> int -> int -> 'a -> unit = "%caml_ba_unsafe_set_2" - (** Like {!Bigarray.Array2.set}, but bounds checking is not always - performed. *) + (** Like {!Bigarray.Array2.set}, but bounds checking is not always performed. + Use with caution and only when the program logic guarantees that + the access is within bounds and the big array has not been released. *) end @@ -729,15 +759,21 @@ module Array3 : (** Memory mapping of a file as a three-dimensional big array. See {!Bigarray.Genarray.map_file} for more details. *) + val release: ('a, 'b, 'c) t -> unit + (** Explicit release of the resources associated with the big array. + See {!Bigarray.Genarray.release} for more details. *) + external unsafe_get: ('a, 'b, 'c) t -> int -> int -> int -> 'a = "%caml_ba_unsafe_ref_3" - (** Like {!Bigarray.Array3.get}, but bounds checking is not always - performed. *) + (** Like {!Bigarray.Array3.get}, but bounds checking is not always performed. + Use with caution and only when the program logic guarantees that + the access is within bounds and the big array has not been released. *) external unsafe_set: ('a, 'b, 'c) t -> int -> int -> int -> 'a -> unit = "%caml_ba_unsafe_set_3" - (** Like {!Bigarray.Array3.set}, but bounds checking is not always - performed. *) + (** Like {!Bigarray.Array3.set}, but bounds checking is not always performed. + Use with caution and only when the program logic guarantees that + the access is within bounds and the big array has not been released. *) end diff --git a/otherlibs/bigarray/bigarray_stubs.c b/otherlibs/bigarray/bigarray_stubs.c index 8afdc0df6e..4021b74aee 100644 --- a/otherlibs/bigarray/bigarray_stubs.c +++ b/otherlibs/bigarray/bigarray_stubs.c @@ -160,8 +160,8 @@ caml_ba_alloc(int flags, int num_dims, void * data, intnat * dim) if (data == NULL && size != 0) caml_raise_out_of_memory(); flags |= CAML_BA_MANAGED; } - /* PR#5516: use C99's / gcc's flexible array types if possible */ -#if (__STDC_VERSION__ >= 199901L) || defined(__GNUC__) + /* PR#5516: use C99's flexible array types if possible */ +#if (__STDC_VERSION__ >= 199901L) asize = sizeof(struct caml_ba_array) + num_dims * sizeof(intnat); #else asize = sizeof(struct caml_ba_array) + (num_dims - 1) * sizeof(intnat); @@ -496,18 +496,19 @@ CAMLprim value caml_ba_layout(value vb) return Val_int(Caml_ba_array_val(vb)->flags & CAML_BA_LAYOUT_MASK); } -/* Finalization of a big array */ +/* Finalization / release of a big array */ static void caml_ba_finalize(value v) { struct caml_ba_array * b = Caml_ba_array_val(v); + intnat i; switch (b->flags & CAML_BA_MANAGED_MASK) { case CAML_BA_EXTERNAL: break; case CAML_BA_MANAGED: if (b->proxy == NULL) { - free(b->data); + free(b->data); /* no op if b->data = NULL */ } else { if (-- b->proxy->refcount == 0) { free(b->proxy->data); @@ -526,6 +527,17 @@ static void caml_ba_finalize(value v) } break; } + /* Make sure that subsequent accesses to the bigarray fail (empty bounds) + and that subsequent calls to caml_ba_finalize do nothing. */ + for (i = 0; i < b->num_dims; i++) b->dim[i] = 0; + b->data = NULL; + b->proxy = NULL; +} + +CAMLprim value caml_ba_release(value v) +{ + caml_ba_finalize(v); + return Val_unit; } /* Comparison of two big arrays */ diff --git a/otherlibs/bigarray/mmap_unix.c b/otherlibs/bigarray/mmap_unix.c index 8e71664ab0..30294cc4bb 100644 --- a/otherlibs/bigarray/mmap_unix.c +++ b/otherlibs/bigarray/mmap_unix.c @@ -25,12 +25,14 @@ extern int caml_ba_element_size[]; /* from bigarray_stubs.c */ +#include <errno.h> #ifdef HAS_UNISTD #include <unistd.h> #endif #ifdef HAS_MMAP #include <sys/types.h> #include <sys/mman.h> +#include <sys/stat.h> #endif #if defined(HAS_MMAP) @@ -39,15 +41,61 @@ extern int caml_ba_element_size[]; /* from bigarray_stubs.c */ #define MAP_FAILED ((void *) -1) #endif +/* [caml_grow_file] function contributed by Gerd Stolpmann (PR#5543). */ + +static int caml_grow_file(int fd, file_offset size) +{ + char c; + int p; + + /* First use pwrite for growing - it is a conservative method, as it + can never happen that we shrink by accident + */ +#ifdef HAS_PWRITE + c = 0; + p = pwrite(fd, &c, 1, size - 1); +#else + + /* Emulate pwrite with lseek. This should only be necessary on ancient + systems nowadays + */ + file_offset currpos; + currpos = lseek(fd, 0, SEEK_CUR); + if (currpos != -1) { + p = lseek(fd, size - 1, SEEK_SET); + if (p != -1) { + c = 0; + p = write(fd, &c, 1); + if (p != -1) + p = lseek(fd, currpos, SEEK_SET); + } + } + else p=-1; +#endif +#ifdef HAS_TRUNCATE + if (p == -1 && errno == ESPIPE) { + /* Plan B. Check if at least ftruncate is possible. There are + some non-seekable descriptor types that do not support pwrite + but ftruncate, like shared memory. We never get into this case + for real files, so there is no danger of truncating persistent + data by accident + */ + p = ftruncate(fd, size); + } +#endif + return p; +} + + CAMLprim value caml_ba_map_file(value vfd, value vkind, value vlayout, value vshared, value vdim, value vstart) { int fd, flags, major_dim, shared; intnat num_dims, i; intnat dim[CAML_BA_MAX_NUM_DIMS]; - file_offset currpos, startpos, file_size, data_size; + file_offset startpos, file_size, data_size; + struct stat st; uintnat array_size, page, delta; - char c; void * addr; fd = Int_val(vfd); @@ -65,18 +113,15 @@ CAMLprim value caml_ba_map_file(value vfd, value vkind, value vlayout, if (dim[i] < 0) caml_invalid_argument("Bigarray.create: negative dimension"); } - /* Determine file size */ + /* Determine file size. We avoid lseek here because it is fragile, + and because some mappable file types do not support it + */ caml_enter_blocking_section(); - currpos = lseek(fd, 0, SEEK_CUR); - if (currpos == -1) { - caml_leave_blocking_section(); - caml_sys_error(NO_ARG); - } - file_size = lseek(fd, 0, SEEK_END); - if (file_size == -1) { + if (fstat(fd, &st) == -1) { caml_leave_blocking_section(); caml_sys_error(NO_ARG); } + file_size = st.st_size; /* Determine array size in bytes (or size of array without the major dimension if that dimension wasn't specified) */ array_size = caml_ba_element_size[flags & CAML_BA_KIND_MASK]; @@ -99,26 +144,22 @@ CAMLprim value caml_ba_map_file(value vfd, value vkind, value vlayout, } else { /* Check that file is large enough, and grow it otherwise */ if (file_size < startpos + array_size) { - if (lseek(fd, startpos + array_size - 1, SEEK_SET) == -1) { - caml_leave_blocking_section(); - caml_sys_error(NO_ARG); - } - c = 0; - if (write(fd, &c, 1) != 1) { + if (caml_grow_file(fd, startpos + array_size) == -1) { /* PR#5543 */ caml_leave_blocking_section(); caml_sys_error(NO_ARG); } } } - /* Restore original file position */ - lseek(fd, currpos, SEEK_SET); /* Determine offset so that the mapping starts at the given file pos */ page = getpagesize(); - delta = (uintnat) (startpos % page); + delta = (uintnat) startpos % page; /* Do the mmap */ shared = Bool_val(vshared) ? MAP_SHARED : MAP_PRIVATE; - addr = mmap(NULL, array_size + delta, PROT_READ | PROT_WRITE, - shared, fd, startpos - delta); + if (array_size > 0) + addr = mmap(NULL, array_size + delta, PROT_READ | PROT_WRITE, + shared, fd, startpos - delta); + else + addr = NULL; /* PR#5463 - mmap fails on empty region */ caml_leave_blocking_section(); if (addr == (void *) MAP_FAILED) caml_sys_error(NO_ARG); addr = (void *) ((uintnat) addr + delta); @@ -128,8 +169,8 @@ CAMLprim value caml_ba_map_file(value vfd, value vkind, value vlayout, #else -value caml_ba_map_file(value vfd, value vkind, value vlayout, - value vshared, value vdim, value vpos) +CAMLprim value caml_ba_map_file(value vfd, value vkind, value vlayout, + value vshared, value vdim, value vpos) { caml_invalid_argument("Bigarray.map_file: not supported"); return Val_unit; @@ -148,6 +189,12 @@ void caml_ba_unmap_file(void * addr, uintnat len) #if defined(HAS_MMAP) uintnat page = getpagesize(); uintnat delta = (uintnat) addr % page; - munmap((void *)((uintnat)addr - delta), len + delta); + if (len == 0) return; /* PR#5463 */ + addr = (void *)((uintnat)addr - delta); + len = len + delta; +#if defined(_POSIX_SYNCHRONIZED_IO) + msync(addr, len, MS_ASYNC); /* PR#3571 */ +#endif + munmap(addr, len); #endif } diff --git a/otherlibs/num/ratio.mli b/otherlibs/num/ratio.mli index 60c0f66dba..408aea9b48 100644 --- a/otherlibs/num/ratio.mli +++ b/otherlibs/num/ratio.mli @@ -13,7 +13,10 @@ (* $Id$ *) -(* Module [Ratio]: operations on rational numbers *) +(** Operation on rational numbers. + + This module is used to support the implementation of {!Num} and + should not be called directly. *) open Nat open Big_int @@ -25,6 +28,8 @@ open Big_int type ratio +(**/**) + val null_denominator : ratio -> bool val numerator_ratio : ratio -> big_int val denominator_ratio : ratio -> big_int @@ -32,8 +37,9 @@ val sign_ratio : ratio -> int val normalize_ratio : ratio -> ratio val cautious_normalize_ratio : ratio -> ratio val cautious_normalize_ratio_when_printing : ratio -> ratio -val create_ratio : big_int -> big_int -> ratio +val create_ratio : big_int -> big_int -> ratio (* assumes nothing *) val create_normalized_ratio : big_int -> big_int -> ratio + (* assumes normalized argument *) val is_normalized_ratio : ratio -> bool val report_sign_ratio : ratio -> big_int -> big_int val abs_ratio : ratio -> ratio diff --git a/otherlibs/systhreads/st_stubs.c b/otherlibs/systhreads/st_stubs.c index ba10205eb1..9b2493a16e 100644 --- a/otherlibs/systhreads/st_stubs.c +++ b/otherlibs/systhreads/st_stubs.c @@ -344,7 +344,10 @@ static value caml_thread_new_descriptor(value clos) static void caml_thread_remove_info(caml_thread_t th) { - if (th->next == th) all_threads = NULL; /* last OCaml thread exiting */ + if (th->next == th) + all_threads = NULL; /* last OCaml thread exiting */ + else if (all_threads == th) + all_threads = th->next; /* PR#5295 */ th->next->prev = th->prev; th->prev->next = th->next; #ifndef NATIVE_CODE diff --git a/parsing/location.ml b/parsing/location.ml index 02b135fae0..561a9060c4 100644 --- a/parsing/location.ml +++ b/parsing/location.ml @@ -223,8 +223,8 @@ let print_filename ppf file = let reset () = num_loc_lines := 0 -let (msg_file, msg_line, msg_chars, msg_to, msg_colon, msg_head) = - ("File \"", "\", line ", ", characters ", "-", ":", "") +let (msg_file, msg_line, msg_chars, msg_to, msg_colon) = + ("File \"", "\", line ", ", characters ", "-", ":") (* return file, line, char from the given position *) let get_pos_info pos = @@ -236,7 +236,7 @@ let print_loc ppf loc = let endchar = loc.loc_end.pos_cnum - loc.loc_start.pos_cnum + startchar in if file = "//toplevel//" then begin if highlight_locations ppf loc none then () else - fprintf ppf "Characters %i-%i:@." + fprintf ppf "Characters %i-%i" loc.loc_start.pos_cnum loc.loc_end.pos_cnum end else begin fprintf ppf "%s%a%s%i" msg_file print_filename file msg_line line; @@ -248,7 +248,8 @@ let print_loc ppf loc = let print ppf loc = if loc.loc_start.pos_fname = "//toplevel//" && highlight_locations ppf loc none then () - else fprintf ppf "%a%s@.%s" print_loc loc msg_colon msg_head + else fprintf ppf "%a%s@." print_loc loc msg_colon +;; let print_error ppf loc = print ppf loc; diff --git a/parsing/location.mli b/parsing/location.mli index 1f12366fd0..2b1a5a8fa5 100644 --- a/parsing/location.mli +++ b/parsing/location.mli @@ -63,6 +63,6 @@ val print_filename: formatter -> string -> unit val show_filename: string -> string (** In -absname mode, return the absolute path for this filename. Otherwise, returns the filename unchanged. *) - + val absname: bool ref diff --git a/parsing/parser.mly b/parsing/parser.mly index cb4d102509..a5065b5cfd 100644 --- a/parsing/parser.mly +++ b/parsing/parser.mly @@ -52,7 +52,7 @@ let mkpatvar name pos = (* Ghost expressions and patterns: - expressions and patterns that do not appear explicitely in the + expressions and patterns that do not appear explicitly in the source file they have the loc_ghost flag set to true. Then the profiler will not try to instrument them and the -stypes option will not try to display their type. diff --git a/stdlib/gc.mli b/stdlib/gc.mli index 71b8ffa783..45d882f25a 100644 --- a/stdlib/gc.mli +++ b/stdlib/gc.mli @@ -158,7 +158,7 @@ external quick_stat : unit -> stat = "caml_gc_quick_stat" external counters : unit -> float * float * float = "caml_gc_counters" (** Return [(minor_words, promoted_words, major_words)]. This function - is as fast at [quick_stat]. *) + is as fast as [quick_stat]. *) external get : unit -> control = "caml_gc_get" (** Return the current values of the GC parameters in a [control] record. *) diff --git a/stdlib/printf.ml b/stdlib/printf.ml index c55c64d367..567949064a 100644 --- a/stdlib/printf.ml +++ b/stdlib/printf.ml @@ -638,12 +638,19 @@ let mkprintf to_s get_out outc outs flush k fmt = kapr kpr fmt ;; +(************************************************************** + + Defining [fprintf] and various flavors of [fprintf]. + + **************************************************************) + let kfprintf k oc = mkprintf false (fun _ -> oc) output_char output_string flush k ;; -let ifprintf _ = kapr (fun _ -> Obj.magic ignore);; +let ikfprintf k oc = kapr (fun _ _ -> Obj.magic (k oc));; let fprintf oc = kfprintf ignore oc;; +let ifprintf oc = ikfprintf ignore oc;; let printf fmt = fprintf stdout fmt;; let eprintf fmt = fprintf stderr fmt;; @@ -671,7 +678,12 @@ let ksprintf k = let sprintf fmt = ksprintf (fun s -> s) fmt;; -(* Obsolete and deprecated. *) +(************************************************************** + + Deprecated stuff. + + **************************************************************) + let kprintf = ksprintf;; (* For OCaml system internal use only: needed to implement modules [Format] diff --git a/stdlib/printf.mli b/stdlib/printf.mli index 6fcb45ebac..f7dca62d61 100644 --- a/stdlib/printf.mli +++ b/stdlib/printf.mli @@ -82,7 +82,8 @@ val fprintf : out_channel -> ('a, out_channel, unit) format -> 'a - [!]: take no argument and flush the output. - [%]: take no argument and output one [%] character. - [\@]: take no argument and output one [\@] character. - - [,]: take no argument and do nothing. + - [,]: take no argument and output nothing: a no-op delimiter for + conversion specifications. The optional [flags] are: - [-]: left-justify the output (default is right justification). @@ -115,12 +116,6 @@ val printf : ('a, out_channel, unit) format -> 'a val eprintf : ('a, out_channel, unit) format -> 'a (** Same as {!Printf.fprintf}, but output on [stderr]. *) -val ifprintf : 'a -> ('b, 'a, unit) format -> 'b -(** Same as {!Printf.fprintf}, but does not print anything. - Useful to ignore some material when conditionally printing. - @since 3.10.0 -*) - val sprintf : ('a, unit, string) format -> 'a (** Same as {!Printf.fprintf}, but instead of printing on an output channel, return a string containing the result of formatting the arguments. *) @@ -130,6 +125,12 @@ val bprintf : Buffer.t -> ('a, Buffer.t, unit) format -> 'a append the formatted arguments to the given extensible buffer (see module {!Buffer}). *) +val ifprintf : 'a -> ('b, 'a, unit) format -> 'b +(** Same as {!Printf.fprintf}, but does not print anything. + Useful to ignore some material when conditionally printing. + @since 3.10.0 +*) + (** Formatted output functions with continuations. *) val kfprintf : (out_channel -> 'a) -> out_channel -> @@ -139,6 +140,14 @@ val kfprintf : (out_channel -> 'a) -> out_channel -> @since 3.09.0 *) +val ikfprintf : (out_channel -> 'a) -> out_channel -> + ('b, out_channel, unit, 'a) format4 -> 'b +;; +(** Same as [kfprintf] above, but does not print anything. + Useful to ignore some material when conditionally printing. + @since 4.0 +*) + val ksprintf : (string -> 'a) -> ('b, unit, string, 'a) format4 -> 'b;; (** Same as [sprintf] above, but instead of returning the string, passes it to the first argument. diff --git a/stdlib/random.ml b/stdlib/random.ml index 50b5708220..800c629706 100644 --- a/stdlib/random.ml +++ b/stdlib/random.ml @@ -53,7 +53,7 @@ module State = struct let j = i mod 55 in let k = i mod l in accu := combine !accu seed.(k); - s.st.(j) <- s.st.(j) lxor extract !accu; + s.st.(j) <- (s.st.(j) lxor extract !accu) land 0x3FFFFFFF; (* PR#5575 *) done; s.idx <- 0; ;; @@ -78,8 +78,9 @@ module State = struct let curval = s.st.(s.idx) in let newval = s.st.((s.idx + 24) mod 55) + (curval lxor ((curval lsr 25) land 0x1F)) in - s.st.(s.idx) <- newval; - newval land 0x3FFFFFFF (* land is needed for 64-bit arch *) + let newval30 = newval land 0x3FFFFFFF in (* PR#5575 *) + s.st.(s.idx) <- newval30; + newval30 ;; let rec intaux s n = diff --git a/stdlib/random.mli b/stdlib/random.mli index 9c66c3a86e..d8ea01e621 100644 --- a/stdlib/random.mli +++ b/stdlib/random.mli @@ -67,7 +67,7 @@ val bool : unit -> bool (** {6 Advanced functions} *) (** The functions from module [State] manipulate the current state - of the random generator explicitely. + of the random generator explicitly. This allows using one or several deterministic PRNGs, even in a multi-threaded program, without interference from other parts of the program. diff --git a/stdlib/scanf.ml b/stdlib/scanf.ml index 37740765d5..cac4a136a4 100644 --- a/stdlib/scanf.ml +++ b/stdlib/scanf.ml @@ -483,7 +483,7 @@ let compatible_format_type fmt1 fmt2 = Tformat.summarize_format_type (string_to_format fmt2);; (* Checking that [c] is indeed in the input, then skips it. - In this case, the character c has been explicitely specified in the + In this case, the character c has been explicitly specified in the format as being mandatory in the input; hence we should fail with End_of_file in case of end_of_input. (Remember that Scan_failure is raised only when (we can prove by evidence) that the input does not match the diff --git a/testsuite/tests/basic-more/testrandom.ml b/testsuite/tests/basic-more/testrandom.ml index 150d408898..af0e3a2f41 100644 --- a/testsuite/tests/basic-more/testrandom.ml +++ b/testsuite/tests/basic-more/testrandom.ml @@ -1,13 +1,12 @@ open Random -let _ = +let _ = for i = 0 to 20 do - print_float (float 1000.); print_char ' ' + print_int (int 1000); print_char ' ' done; print_newline (); print_newline (); for i = 0 to 20 do - print_int (int 1000); print_char ' ' + print_float (float 1000.); print_char ' ' done let _ = exit 0 - diff --git a/testsuite/tests/basic-more/testrandom.reference b/testsuite/tests/basic-more/testrandom.reference index f063674d90..366e682c15 100644 --- a/testsuite/tests/basic-more/testrandom.reference +++ b/testsuite/tests/basic-more/testrandom.reference @@ -1,4 +1,4 @@ -270.251355065 597.822945853 287.052171181 625.315015859 241.029649126 559.742196387 932.074421229 756.637587326 360.006556146 987.177314953 190.217751234 758.516786217 59.8488223602 328.350439075 172.627051105 944.543207513 629.424106752 868.196647048 174.382120878 78.1259713643 34.3270777955 +344 685 182 641 439 500 104 20 921 370 217 885 949 678 615 412 401 606 428 869 289 -683 782 740 270 835 136 791 168 324 222 156 835 328 636 233 153 671 69 95 357 92 +122.128067547 461.324792129 360.006556146 768.75882284 396.500946942 190.217751234 567.660068681 403.59226778 59.8488223602 363.816246826 764.705761642 172.627051105 481.861849093 399.173195422 629.424106752 391.547032203 676.701133948 174.382120878 994.425675487 585.00027757 34.3270777955 All tests succeeded. diff --git a/testsuite/tests/lib-bigarray/bigarrays.ml b/testsuite/tests/lib-bigarray/bigarrays.ml index 85901400eb..28ed9af6f4 100644 --- a/testsuite/tests/lib-bigarray/bigarrays.ml +++ b/testsuite/tests/lib-bigarray/bigarrays.ml @@ -384,6 +384,12 @@ let _ = test 12 true (test_blit_fill complex64 [Complex.zero; Complex.one; Complex.i] Complex.i 1 1); + testing_function "release"; + let a = from_list int [1;2;3;4;5] in + test 1 (Array1.dim a) 5; + Array1.release a; + test 2 (Array1.dim a) 0; + (* Bi-dimensional arrays *) print_newline(); @@ -533,6 +539,14 @@ let _ = test 7 (Array2.slice_right a 2) (from_list_fortran int [1002;2002;3002;4002;5002]); test 8 (Array2.slice_right a 3) (from_list_fortran int [1003;2003;3003;4003;5003]); + testing_function "release"; + let a = (make_array2 int c_layout 0 4 6 id) in + test 1 (Array2.dim1 a) 4; + test 2 (Array2.dim2 a) 6; + Array2.release a; + test 3 (Array2.dim1 a) 0; + test 4 (Array2.dim2 a) 0; + (* Tri-dimensional arrays *) print_newline(); @@ -654,6 +668,16 @@ let _ = test 6 (Array3.slice_right_1 a 1 2) (from_list_fortran int [112;212;312]); test 7 (Array3.slice_right_1 a 3 1) (from_list_fortran int [131;231;331]); + testing_function "release"; + let a = (make_array3 int c_layout 0 4 5 6 id) in + test 1 (Array3.dim1 a) 4; + test 2 (Array3.dim2 a) 5; + test 3 (Array3.dim3 a) 6; + Array3.release a; + test 4 (Array3.dim1 a) 0; + test 5 (Array3.dim2 a) 0; + test 6 (Array3.dim3 a) 0; + (* Reshaping *) print_newline(); testing_function "------ Reshaping --------"; @@ -717,6 +741,7 @@ let _ = let a = Array1.map_file fd float64 c_layout true 10000 in Unix.close fd; for i = 0 to 9999 do a.{i} <- float i done; + Array1.release a; let fd = Unix.openfile mapped_file [Unix.O_RDONLY] 0 in let b = Array2.map_file fd float64 fortran_layout false 100 (-1) in Unix.close fd; @@ -727,7 +752,8 @@ let _ = done done; test 1 !ok true; - b.{50,50} <- (-1.0); + b.{50,50} <- (-1.0); (* private mapping -> no effect on file *) + Array2.release b; let fd = Unix.openfile mapped_file [Unix.O_RDONLY] 0 in let c = Array2.map_file fd float64 c_layout false (-1) 100 in Unix.close fd; @@ -738,6 +764,7 @@ let _ = done done; test 2 !ok true; + Array2.release c; let fd = Unix.openfile mapped_file [Unix.O_RDONLY] 0 in let c = Array2.map_file fd ~pos:800L float64 c_layout false (-1) 100 in Unix.close fd; @@ -748,6 +775,7 @@ let _ = done done; test 3 !ok true; + Array2.release c; let fd = Unix.openfile mapped_file [Unix.O_RDONLY] 0 in let c = Array2.map_file fd ~pos:79200L float64 c_layout false (-1) 100 in Unix.close fd; @@ -755,12 +783,13 @@ let _ = for j = 0 to 99 do if c.{0,j} <> float (100 * 99 + j) then ok := false done; - test 4 !ok true + test 4 !ok true; + Array2.release c; + test 5 (Array2.dim1 c) 0; + test 5 (Array2.dim2 c) 0 end; - (* Force garbage collection of the mapped bigarrays above, otherwise - Win32 doesn't let us erase the file. Notice the begin...end above - so that the VM doesn't keep stack references to the mapped bigarrays. *) - Gc.full_major(); + (* Win32 doesn't let us erase the file if any mapping on the file is + still active. Normally, they have all been released explicitly. *) Sys.remove mapped_file; () diff --git a/testsuite/tests/lib-bigarray/bigarrays.reference b/testsuite/tests/lib-bigarray/bigarrays.reference index bdc7beae23..def96fe4c5 100644 --- a/testsuite/tests/lib-bigarray/bigarrays.reference +++ b/testsuite/tests/lib-bigarray/bigarrays.reference @@ -17,6 +17,8 @@ sub 1... 2... 3... 4... 5... 6... 7... 8... 9... blit, fill 1... 2... 3... 4... 5... 6... 7... 8... 9... 10... 11... 12... +release + 1... 2... ------ Array2 -------- @@ -32,6 +34,8 @@ sub 1... 2... slice 1... 2... 3... 4... 5... 6... 7... 8... +release + 1... 2... 3... 4... ------ Array3 -------- @@ -45,6 +49,8 @@ dim 1... 2... 3... 4... 5... 6... slice1 1... 2... 3... 4... 5... 6... 7... +release + 1... 2... 3... 4... 5... 6... ------ Reshaping -------- @@ -58,4 +64,4 @@ reshape_2 output_value/input_value 1... 2... 3... 4... 5... 6... 7... 8... 9... 10... 11... 12... 13... 14... map_file - 1... 2... 3... 4... + 1... 2... 3... 4... 5... 5... diff --git a/testsuite/tests/tool-ocamldoc/odoc_test.ml b/testsuite/tests/tool-ocamldoc/odoc_test.ml index 1339f10a59..b5cc55626b 100644 --- a/testsuite/tests/tool-ocamldoc/odoc_test.ml +++ b/testsuite/tests/tool-ocamldoc/odoc_test.ml @@ -114,4 +114,4 @@ let _ = method generate = inst#generate end end in - Odoc_args.set_generator (Odoc_gen.Other (module My_generator : Odoc_gen.Base)) + Odoc_args.set_generator (Odoc_gen.Base (module My_generator : Odoc_gen.Base)) diff --git a/typing/env.ml b/typing/env.ml index 33a19152f8..53afa5a9e4 100644 --- a/typing/env.ml +++ b/typing/env.ml @@ -865,12 +865,13 @@ and store_type id path info env = if not (Hashtbl.mem used_constructors k) then let used = ref false in Hashtbl.add used_constructors k (fun () -> used := true); - !add_delayed_check_forward - (fun () -> - if not !used then - Location.prerr_warning loc (Warnings.Unused_constructor c) - ) - ) + if not (ty = "" || ty.[0] = '_') + then !add_delayed_check_forward + (fun () -> + if not !used then + Location.prerr_warning loc (Warnings.Unused_constructor c) + ) + ) constructors end; { env with diff --git a/typing/includecore.ml b/typing/includecore.ml index 23c715f4df..972102af88 100644 --- a/typing/includecore.ml +++ b/typing/includecore.ml @@ -200,13 +200,12 @@ let rec compare_records env decl1 decl2 n labels1 labels2 = then compare_records env decl1 decl2 (n+1) rem1 rem2 else [Field_type lab1] -let type_declarations env id decl1 decl2 = +let type_declarations env name decl1 id decl2 = if decl1.type_arity <> decl2.type_arity then [Arity] else if not (private_flags decl1 decl2) then [Privacy] else let err = match (decl1.type_kind, decl2.type_kind) with (_, Type_abstract) -> [] | (Type_variant cstrs1, Type_variant cstrs2) -> - let name = Ident.name id in if decl1.type_private = Private || decl2.type_private = Public then List.iter (fun (c, _, _) -> Env.mark_constructor_used name decl1 c) diff --git a/typing/includecore.mli b/typing/includecore.mli index 66bd04c310..17515a8e20 100644 --- a/typing/includecore.mli +++ b/typing/includecore.mli @@ -36,8 +36,8 @@ type type_mismatch = val value_descriptions: Env.t -> value_description -> value_description -> module_coercion val type_declarations: - Env.t -> Ident.t -> - type_declaration -> type_declaration -> type_mismatch list + Env.t -> string -> + type_declaration -> Ident.t -> type_declaration -> type_mismatch list val exception_declarations: Env.t -> exception_declaration -> exception_declaration -> bool (* diff --git a/typing/includemod.ml b/typing/includemod.ml index 4cc2904087..f1e87f55ac 100644 --- a/typing/includemod.ml +++ b/typing/includemod.ml @@ -63,7 +63,7 @@ let value_descriptions env cxt subst id vd1 vd2 = let type_declarations env cxt subst id decl1 decl2 = Env.mark_type_used (Ident.name id) decl1; let decl2 = Subst.type_declaration subst decl2 in - let err = Includecore.type_declarations env id decl1 decl2 in + let err = Includecore.type_declarations env (Ident.name id) decl1 id decl2 in if err <> [] then raise(Error[cxt, Type_declarations(id, decl1, decl2, err)]) (* Inclusion between exception declarations *) diff --git a/typing/typedecl.ml b/typing/typedecl.ml index 3f483c8df0..307d5041b5 100644 --- a/typing/typedecl.ml +++ b/typing/typedecl.ml @@ -359,8 +359,10 @@ let check_abbrev env (_, sdecl) (id, decl) = else if not (Ctype.equal env false args decl.type_params) then [Includecore.Constraint] else - Includecore.type_declarations env id + Includecore.type_declarations env + (Path.last path) decl' + id (Subst.type_declaration (Subst.add_type id path Subst.identity) decl) in diff --git a/utils/warnings.ml b/utils/warnings.ml index e6ea56e9a8..4745598b07 100644 --- a/utils/warnings.ml +++ b/utils/warnings.ml @@ -235,7 +235,7 @@ let message = function Here is an example of a value that is not matched:\n" ^ s | Non_closed_record_pattern s -> "the following labels are not bound in this record pattern:\n" ^ s ^ - "\nEither bind these labels explicitly or add `; _' to the pattern." + "\nEither bind these labels explicitly or add '; _' to the pattern." | Statement_type -> "this expression should have type unit." | Unused_match -> "this match case is unused." @@ -262,8 +262,8 @@ let message = function "this statement never returns (or has an unsound type.)" | Camlp4 s -> s | Useless_record_with -> - "this record is defined by a `with' expression,\n\ - but no fields are borrowed from the original." + "all the fields are explicitly listed in this record:\n\ + the 'with' clause is useless." | Bad_module_name (modname) -> "bad source file name: \"" ^ modname ^ "\" is not a valid module name." | All_clauses_guarded -> |