[m-rev.] for review: call javac only once per linked target (mmc --make)

Peter Wang novalazy at gmail.com
Tue May 5 12:11:02 AEST 2009


Branches: main

With mmc --make, invoke `javac' once only for a linked target, passing it all
the .java files which need compiling.  This is how the Java compiler is meant
to be used, and is much quicker.

compiler/make.program_target.m:
        As above.

        Clear cached timestamps of all `.class' files afterwards.

compiler/compile_target_code.m:
        Change `compile_java_file' to accept multiple Java files.

compiler/make.dependencies.m:
        Fix a bug. `.class' files should depend on the `.java' file only.

compiler/make.module_target.m:
compiler/mercury_compile.m:
        Conform to changes.

diff --git a/compiler/compile_target_code.m b/compiler/compile_target_code.m
index c07670a..f298c87 100644
--- a/compiler/compile_target_code.m
+++ b/compiler/compile_target_code.m
@@ -56,9 +56,9 @@
 :- pred assemble(io.output_stream::in, pic::in, module_name::in,
     bool::out, io::di, io::uo) is det.

-    % compile_java_file(ErrorStream, JavaFile, Succeeded)
+    % compile_java_files(ErrorStream, JavaFiles, Succeeded)
     %
-:- pred compile_java_file(io.output_stream::in, string::in, bool::out,
+:- pred compile_java_files(io.output_stream::in, list(string)::in, bool::out,
     io::di, io::uo) is det.

     % il_assemble(ErrorStream, ModuleName, HasMain, Succeeded)
@@ -865,11 +865,29 @@ gather_c_compiler_flags(PIC, AllCFlags, !IO) :-

 %-----------------------------------------------------------------------------%

-compile_java_file(ErrorStream, JavaFile, Succeeded, !IO) :-
+compile_java_files(ErrorStream, JavaFiles, Succeeded, !IO) :-
     globals.io_lookup_bool_option(verbose, Verbose, !IO),
-    maybe_write_string(Verbose, "% Compiling `", !IO),
-    maybe_write_string(Verbose, JavaFile, !IO),
-    maybe_write_string(Verbose, "':\n", !IO),
+    (
+        JavaFiles = [JavaFile | MoreFiles],
+        (
+            Verbose = yes,
+            io.write_string("% Compiling `", !IO),
+            io.write_string(JavaFile, !IO),
+            (
+                MoreFiles = [],
+                io.write_string("':\n", !IO)
+            ;
+                MoreFiles = [_ | _],
+                io.write_string("', etc.:\n", !IO)
+            )
+        ;
+            Verbose = no
+        )
+    ;
+        JavaFiles = [],
+        unexpected(this_file, "compile_java_files: empty list")
+    ),
+
     globals.io_lookup_string_option(java_compiler, JavaCompiler, !IO),
     globals.io_lookup_accumulating_option(java_flags, JavaFlagsList, !IO),
     join_string_list(JavaFlagsList, "", "", " ", JAVAFLAGS),
@@ -930,8 +948,9 @@ compile_java_file(ErrorStream, JavaFile, Succeeded, !IO) :-

     % Be careful with the order here!  Some options may override others.
     % Also be careful that each option is separated by spaces.
+    JoinedJavaFiles = string.join_list(" ", JavaFiles),
     string.append_list([JavaCompiler, " ", InclOpt, DirOpts,
-        Target_DebugOpt, JAVAFLAGS, " ", JavaFile], Command),
+        Target_DebugOpt, JAVAFLAGS, " ", JoinedJavaFiles], Command),
     invoke_system_command(ErrorStream, cmd_verbose_commands, Command,
         Succeeded, !IO).

diff --git a/compiler/make.dependencies.m b/compiler/make.dependencies.m
index 8e37b9f..6191138 100644
--- a/compiler/make.dependencies.m
+++ b/compiler/make.dependencies.m
@@ -391,8 +391,8 @@ target_dependencies(_, module_target_il_asm) =
     ]).
 target_dependencies(Globals, module_target_java_code) =
         compiled_code_dependencies(Globals).
-target_dependencies(Globals, module_target_java_class_code) =
-        compiled_code_dependencies(Globals).
+target_dependencies(_, module_target_java_class_code) =
+        module_target_java_code `of` self.
 target_dependencies(Globals, module_target_erlang_header) =
         target_dependencies(Globals, module_target_erlang_code).
 target_dependencies(Globals, module_target_erlang_code) =
diff --git a/compiler/make.module_target.m b/compiler/make.module_target.m
index 042d20f..3437a2a 100644
--- a/compiler/make.module_target.m
+++ b/compiler/make.module_target.m
@@ -509,7 +509,7 @@ build_object_code(ModuleName, target_java, _,
ErrorStream, _Imports, Succeeded,
         !IO) :-
     module_name_to_file_name(ModuleName, ".java", do_create_dirs, JavaFile,
         !IO),
-    compile_target_code.compile_java_file(ErrorStream, JavaFile,
+    compile_target_code.compile_java_files(ErrorStream, [JavaFile],
         Succeeded, !IO).
 build_object_code(ModuleName, target_il, _, ErrorStream, Imports, Succeeded,
         !IO) :-
@@ -539,7 +539,7 @@ compile_foreign_code_file(ErrorStream, _, _Imports,
         no_main, Succeeded, !IO).
 compile_foreign_code_file(ErrorStream, _, _Imports,
         foreign_code_file(lang_java, JavaFile, _ClassFile), Succeeded, !IO) :-
-    compile_target_code.compile_java_file(ErrorStream, JavaFile,
+    compile_target_code.compile_java_files(ErrorStream, [JavaFile],
         Succeeded, !IO).
 compile_foreign_code_file(ErrorStream, _, Imports,
         foreign_code_file(lang_csharp, CSharpFile, DLLFile),
diff --git a/compiler/make.program_target.m b/compiler/make.program_target.m
index 13842e3..7bf69cf 100644
--- a/compiler/make.program_target.m
+++ b/compiler/make.program_target.m
@@ -56,6 +56,7 @@
 :- import_module digraph.
 :- import_module dir.
 :- import_module getopt_io.
+:- import_module svmap.

 %-----------------------------------------------------------------------------%

@@ -204,20 +205,29 @@ make_linked_target_2(LinkedTargetFile, _,
Succeeded, !Info, !IO) :-
                 BuildDepsSucceeded0, !Info, !IO),
             (
                 BuildDepsSucceeded0 = yes,
-                foldl2_maybe_stop_at_error_maybe_parallel(KeepGoing,
-                    make_module_target, ObjTargets,
-                    BuildDepsSucceeded1, !Info, !IO)
+                maybe_make_java_files(MainModuleName,
+                    ObjectTargetType, ObjModules, BuildDepsSucceeded1,
+                    !Info, !IO)
             ;
                 BuildDepsSucceeded0 = no,
                 BuildDepsSucceeded1 = no
             ),
             (
                 BuildDepsSucceeded1 = yes,
+                foldl2_maybe_stop_at_error_maybe_parallel(KeepGoing,
+                    make_module_target, ObjTargets, BuildDepsSucceeded2,
+                    !Info, !IO)
+            ;
+                BuildDepsSucceeded1 = no,
+                BuildDepsSucceeded2 = no
+            ),
+            (
+                BuildDepsSucceeded2 = yes,
                 foldl2_maybe_stop_at_error(KeepGoing, make_module_target,
                     ForeignObjTargets,
                     BuildDepsSucceeded, !Info, !IO)
             ;
-                BuildDepsSucceeded1 = no,
+                BuildDepsSucceeded2 = no,
                 BuildDepsSucceeded = no
             )
         ),
@@ -626,6 +636,99 @@ linked_target_cleanup(MainModuleName, FileType,
OutputFileName,

 %-----------------------------------------------------------------------------%

+    % When compiling to Java we want to invoke `javac' just once, passing it a
+    % list of all out-of-date `.java' files.  This is a lot quicker than
+    % compiling each Java file individually.
+    %
+:- pred maybe_make_java_files(module_name::in, module_target_type::in,
+    list(module_name)::in, bool::out, make_info::in, make_info::out,
+    io::di, io::uo) is det.
+
+maybe_make_java_files(MainModuleName, ObjectTargetType, ObjModules, Succeeded,
+        !Info, !IO) :-
+    ( ObjectTargetType = module_target_java_class_code ->
+        out_of_date_java_modules(ObjModules, OutOfDateModules, !Info, !IO),
+        (
+            OutOfDateModules = [],
+            Succeeded = yes
+        ;
+            OutOfDateModules = [_ | _],
+            build_java_files(MainModuleName, OutOfDateModules, Succeeded,
+                !Info, !IO),
+            % javac might write more `.class' files than we anticipated (though
+            % it probably won't) so clear out all the timestamps which might be
+            % affected.
+            Timestamps0 = !.Info ^ file_timestamps,
+            map.foldl(delete_java_class_timestamps, Timestamps0,
+                map.init, Timestamps),
+            !Info ^ file_timestamps := Timestamps
+        )
+    ;
+        Succeeded = yes
+    ).
+
+:- pred out_of_date_java_modules(list(module_name)::in, list(module_name)::out,
+    make_info::in, make_info::out, io::di, io::uo) is det.
+
+out_of_date_java_modules(ObjModules, OutOfDateModules, !Info, !IO) :-
+    (
+        ObjModules = [],
+        OutOfDateModules = []
+    ;
+        ObjModules = [ModuleName | Rest],
+        out_of_date_java_modules(Rest, OutOfDateModules0, !Info, !IO),
+        JavaTarget = target_file(ModuleName, module_target_java_code),
+        ClassTarget = target_file(ModuleName, module_target_java_class_code),
+        get_target_timestamp(do_not_search, JavaTarget, MaybeJavaTimestamp,
+            !Info, !IO),
+        get_target_timestamp(do_not_search, ClassTarget, MaybeClassTimestamp,
+            !Info, !IO),
+        (
+            MaybeJavaTimestamp = ok(JavaTimestamp),
+            MaybeClassTimestamp = ok(ClassTimestamp),
+            ClassTimestamp @>= JavaTimestamp
+        ->
+            OutOfDateModules = OutOfDateModules0
+        ;
+            OutOfDateModules = [ModuleName | OutOfDateModules0]
+        )
+    ).
+
+:- pred build_java_files(module_name::in, list(module_name)::in, bool::out,
+    make_info::in, make_info::out, io::di, io::uo) is det.
+
+build_java_files(MainModuleName, ModuleNames, Succeeded, !Info, !IO) :-
+    verbose_msg(io.write_string("Making Java class files\n"), !IO),
+    ToJavaFile =
+        (pred(ModuleName::in, JavaFile::out, !.IO::di, !:IO::uo) is det :-
+            module_name_to_file_name(ModuleName, ".java", do_create_dirs,
+                JavaFile, !IO)
+        ),
+    list.map_foldl(ToJavaFile, ModuleNames, JavaFiles, !IO),
+    % We redirect errors to a file named after the main module.
+    build_with_output_redirect(MainModuleName,
+        build_java_files_2(JavaFiles), Succeeded, !Info, !IO).
+
+:- pred build_java_files_2(list(string)::in, io.output_stream::in, bool::out,
+    make_info::in, make_info::out, io::di, io::uo) is det.
+
+build_java_files_2(JavaFiles, ErrorStream, Succeeded, !Info, !IO) :-
+    call_in_forked_process(
+        compile_target_code.compile_java_files(ErrorStream, JavaFiles),
+        Succeeded, !IO).
+
+:- pred delete_java_class_timestamps(string::in, maybe_error(timestamp)::in,
+    file_timestamps::in, file_timestamps::out) is det.
+
+delete_java_class_timestamps(FileName, MaybeTimestamp, !Timestamps) :-
+    ( string.suffix(FileName, ".class") ->
+        true
+    ;
+        svmap.det_insert(FileName, MaybeTimestamp, !Timestamps)
+    ).
+
+%-----------------------------------------------------------------------------%
+
 make_misc_target(MainModuleName - TargetType, Succeeded, !Info, !IO) :-
     build_with_module_options(MainModuleName, [],
         make_misc_target_builder(MainModuleName - TargetType),
diff --git a/compiler/mercury_compile.m b/compiler/mercury_compile.m
index 489c454..8e1c736 100644
--- a/compiler/mercury_compile.m
+++ b/compiler/mercury_compile.m
@@ -1687,7 +1687,7 @@
mercury_compile_after_front_end(NestedSubModules, FindTimestampFiles,
                 io.output_stream(OutputStream, !IO),
                 module_name_to_file_name(ModuleName, ".java",
                     do_not_create_dirs, JavaFile, !IO),
-                compile_target_code.compile_java_file(OutputStream, JavaFile,
+                compile_target_code.compile_java_files(OutputStream,
[JavaFile],
                     Succeeded, !IO),
                 maybe_set_exit_status(Succeeded, !IO)
             ),
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list