[m-rev.] diff: workaround standard library initialization problems in the Java grade

Julien Fischer jfischer at opturion.com
Sun Mar 6 00:26:39 AEDT 2016


Workaround standard library initialization problems in the Java grades.

In the Java grade, the standard streams were not being entered into the stream
database and the I/O globals were not being initialized.  For executables,
generate a call to library.std_library_init/2 before main/2 is invoked.  There
is still a problem for Mercury libraries called from Java programs and for
predicates specified in `:- initialise' declarations.   For the latter, Mercury
requires that all standard library initialization be performed *before* any
user specified initialize predicates, but because we currently implement all of
this in Java using static initializers we can't guarantee that the order things
occur in.

The same issue affects the C# grade; I'll add a workaround for it separately.

library/io.m:
     In the predicate io.init_state/2, in the Java grade do not
     bother setting the current stream since for the standard text
     streams we do so as part of class initialization and

library/library.m:
     Export std_library_init/2 to Java.

compiler/mlds_to_java.m:
      Generate a call to library.std_library_init/2 before main/2 is called.
      XXX TODO we should roll the call that initializes the benchmarking module
      into the same.

tests/hard_coded/Mmakefile:
tests/hard_coded/stdlib_init.{m,exp}:
     Test that the stream database and globals in the io module are
     initialized before main/2 is called.

Julien.

diff --git a/compiler/mlds_to_java.m b/compiler/mlds_to_java.m
index 37da428..98c926b 100644
--- a/compiler/mlds_to_java.m
+++ b/compiler/mlds_to_java.m
@@ -2036,6 +2036,7 @@ write_main_driver(Indent, ClassName, !IO) :-
          "jmercury.runtime.JavaInternal.progname = """ ++ ClassName ++ """;",
          "jmercury.runtime.JavaInternal.args = args;",
          "jmercury.runtime.JavaInternal.exit_status = 0;",
+        "library.ML_std_library_init();",
          "benchmarking.ML_initialise();",
          "Runnable run_main = new Runnable() {",
          "    public void run() {",
diff --git a/library/io.m b/library/io.m
index 0bce404..c7a8116 100644
--- a/library/io.m
+++ b/library/io.m
@@ -1888,22 +1888,12 @@

  %---------------------------------------------------------------------------%
  %
-% Initialization
+% Initialization.
  %

  io.init_state(!IO) :-
      init_std_streams(!IO),
-    %
-    % In C grades the "current" streams are thread-local values, so can only be
-    % set after the MR_Context has been initialised for the initial thread.
-    %
-    io.set_input_stream(io.stdin_stream, _, !IO),
-    io.set_output_stream(io.stdout_stream, _, !IO),
-    io.stdin_binary_stream(StdinBinary, !IO),
-    io.stdout_binary_stream(StdoutBinary, !IO),
-    io.set_binary_input_stream(StdinBinary, _, !IO),
-    io.set_binary_output_stream(StdoutBinary, _, !IO),
-
+    init_current_streams(!IO),
      io.gc_init(type_of(StreamDb), type_of(Globals), !IO),
      map.init(StreamDb),
      type_to_univ("<globals>", Globals),
@@ -1947,6 +1937,30 @@ init_std_streams(!IO).
      'ML_erlang_global_server' ! {init_std_streams, StdStreams}
  ").

+:- pred init_current_streams(io::di, io::uo) is det.
+
+init_current_streams(!IO) :-
+    %
+    % In C grades the "current" streams are thread-local values, so can only be
+    % set after the MR_Context has been initialised for the initial thread.
+    %
+    io.set_input_stream(io.stdin_stream, _, !IO),
+    io.set_output_stream(io.stdout_stream, _, !IO),
+    io.stdin_binary_stream(StdinBinary, !IO),
+    io.stdout_binary_stream(StdoutBinary, !IO),
+    io.set_binary_input_stream(StdinBinary, _, !IO),
+    io.set_binary_output_stream(StdoutBinary, _, !IO).
+
+    % XXX Ditto for C#?
+    %
+:- pragma foreign_proc("Java",
+    init_current_streams(_IO0::di, _IO::uo),
+    [will_not_call_mercury, promise_pure],
+"
+    // Do nothing in the Java grade -- setting the current streams is handled
+    // during class initialization.
+").
+
      % Currently no finalization needed...
      % (Perhaps we should close all open Mercury files?
      % That will happen on process exit anyway, so currently we don't bother.)
diff --git a/library/library.m b/library/library.m
index 5b7fff9..b0e8585 100644
--- a/library/library.m
+++ b/library/library.m
@@ -352,6 +352,8 @@ mercury_std_library_module("version_store").

  :- pragma foreign_export("C", std_library_init(di, uo),
      "ML_std_library_init").
+:- pragma foreign_export("Java", std_library_init(di, uo),
+    "ML_std_library_init").
  :- pragma foreign_export("Erlang", std_library_init(di, uo),
      "ML_std_library_init").

diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index f092a21..9e55e2c3 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -274,6 +274,7 @@ ORDINARY_PROGS =	\
  	special_char \
  	stable_sort \
  	static_no_tag \
+	stdlib_init \
  	stream_format \
  	stream_ignore_ws \
  	stream_put_bug \
diff --git a/tests/hard_coded/stdlib_init.exp b/tests/hard_coded/stdlib_init.exp
index e69de29..ccaf39b 100644
--- a/tests/hard_coded/stdlib_init.exp
+++ b/tests/hard_coded/stdlib_init.exp
@@ -0,0 +1,5 @@
+"<globals>"
+mercury_op_table
+stream(0, input, preopen, stdin)
+stream(1, output, preopen, stdout)
+stream(1, output, preopen, stderr)
diff --git a/tests/hard_coded/stdlib_init.m b/tests/hard_coded/stdlib_init.m
index e69de29..02ee471 100644
--- a/tests/hard_coded/stdlib_init.m
+++ b/tests/hard_coded/stdlib_init.m
@@ -0,0 +1,22 @@
+% Test that the standard library is initialised before main/2 is called.
+
+:- module stdlib_init.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+main(!IO) :-
+    io.get_globals(Globals, !IO),
+    io.print_line(Globals, !IO),
+    io.get_op_table(OpsTable, !IO),
+    io.print_line(OpsTable, !IO),
+    io.stdin_stream(Stdin, !IO),
+    io.print_line(Stdin, !IO),
+    io.stdout_stream(Stdout, !IO),
+    io.print_line(Stdout, !IO),
+    io.stderr_stream(Stderr, !IO),
+    io.print_line(Stderr, !IO).



More information about the reviews mailing list