Make the Java backend not use native code to implement any standard library

Branches: main

Make the Java backend not use native code to implement any standard library
procedures.  The only such procedures were related to benchmarking and timing,
which aren't very important so I just make a best effort using methods that
the Java standard library provides.

library/benchmarking.m:
        Implement `benchmarking.report_stats' for Java as closely as possible
        without native code.  Add real time output.

        Add `benchmarking.ML_initialise' to remember the time when the
        program starts up.

compiler/mlds_to_java.m:
        Make the main wrapper call `benchmarking.ML_initialise' at startup.

library/time.m:
        Implement `time.clock', `time.times', `time.clocks_per_sec',
        `time.clk_tck' as closely as possible without native code.

library/Mmakefile:
        Comment out commands to build and install Native.so.

java/runtime/Native.c:
        Even though this is not used any more, update the function names for
        the "jmercury" package prefix.

README.Java:
        Update section on unimplemented procedures.
This commit is contained in:
Peter Wang
2009-08-14 06:34:03 +00:00
parent fe4c25c16f
commit 9fc47f5c91
6 changed files with 119 additions and 83 deletions

View File

@@ -127,7 +127,11 @@ A. The following implementation features are not supported:
benchmarking.report_stats/0:
benchmarking.report_full_memory_stats/0:
Memory usage statistics are not yet available, and cpu time
is obtained via native code as per time.m.
is not the same as in the C backends, as per time.m.
io.set_environment_var/4:
The Java APIs do not allow setting environment variables hence
this predicate simply throws an exception.
store.arg_ref/5:
store.new_arg_ref/5:
@@ -139,9 +143,8 @@ A. The following implementation features are not supported:
time.times/7:
time.clk_tck/0:
Because the current Java APIs do not provide any way of
implementing these procedures in pure Java, we have implemented
them using a native code library implemented in C and accessed
via JNI. This approach sacrifices some portability.
implementing these procedures exactly in pure Java, we have
approximated them with what is available.
This list is probably not complete.

View File

@@ -1673,6 +1673,7 @@ write_main_driver(Indent, ClassName, !IO) :-
"jmercury.runtime.JavaInternal.progname = """ ++ ClassName ++ """;",
"jmercury.runtime.JavaInternal.args = args;",
"jmercury.runtime.JavaInternal.exit_status = 0;",
"benchmarking.ML_initialise();",
"try {",
" " ++ ClassName ++ ".main_2_p_0();",
" jmercury.runtime.JavaInternal.run_finalisers();",

View File

@@ -15,14 +15,14 @@
* Method: clock
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_mercury_runtime_Native_clock(JNIEnv *, jclass);
JNIEXPORT jint JNICALL Java_jmercury_runtime_Native_clock(JNIEnv *, jclass);
/*
* Class: Native
* Method: clocks_per_sec
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_mercury_runtime_Native_clocks_1per_1sec(
JNIEXPORT jint JNICALL Java_jmercury_runtime_Native_clocks_1per_1sec(
JNIEnv *, jclass);
/*
@@ -30,7 +30,7 @@ JNIEXPORT jint JNICALL Java_mercury_runtime_Native_clocks_1per_1sec(
* Method: times
* Signature: ()[I
*/
JNIEXPORT jintArray JNICALL Java_mercury_runtime_Native_times(
JNIEXPORT jintArray JNICALL Java_jmercury_runtime_Native_times(
JNIEnv *, jclass);
/*
@@ -38,14 +38,14 @@ JNIEXPORT jintArray JNICALL Java_mercury_runtime_Native_times(
* Method: clk_tck
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_mercury_runtime_Native_clk_1tck(JNIEnv *, jclass);
JNIEXPORT jint JNICALL Java_jmercury_runtime_Native_clk_1tck(JNIEnv *, jclass);
/*
* Class: Native
* Method: get_user_cpu_milliseconds
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_mercury_runtime_Native_get_1user_1cpu_1milliseconds(
JNIEXPORT jint JNICALL Java_jmercury_runtime_Native_get_1user_1cpu_1milliseconds(
JNIEnv *, jclass);
#include "mercury_imp.h"
@@ -63,17 +63,17 @@ JNIEXPORT jint JNICALL Java_mercury_runtime_Native_get_1user_1cpu_1milliseconds(
#endif
JNIEXPORT jint JNICALL
Java_mercury_runtime_Native_clock(JNIEnv *env, jclass obj) {
Java_jmercury_runtime_Native_clock(JNIEnv *env, jclass obj) {
return (MR_Integer) clock();
}
JNIEXPORT jint JNICALL
Java_mercury_runtime_Native_clocks_1per_1sec(JNIEnv *env, jclass obj) {
Java_jmercury_runtime_Native_clocks_1per_1sec(JNIEnv *env, jclass obj) {
return CLOCKS_PER_SEC;
}
JNIEXPORT jintArray JNICALL
Java_mercury_runtime_Native_times(JNIEnv *env, jclass obj) {
Java_jmercury_runtime_Native_times(JNIEnv *env, jclass obj) {
jint intarray[5];
jintArray result;
@@ -97,7 +97,7 @@ Java_mercury_runtime_Native_times(JNIEnv *env, jclass obj) {
return result;
}
JNIEXPORT jint JNICALL Java_mercury_runtime_Native_clk_1tck(
JNIEXPORT jint JNICALL Java_jmercury_runtime_Native_clk_1tck(
JNIEnv *env, jclass obj)
{
#if defined(MR_CLOCK_TICKS_PER_SECOND)
@@ -108,7 +108,7 @@ JNIEXPORT jint JNICALL Java_mercury_runtime_Native_clk_1tck(
}
JNIEXPORT jint JNICALL
Java_mercury_runtime_Native_get_1user_1cpu_1milliseconds(
Java_jmercury_runtime_Native_get_1user_1cpu_1milliseconds(
JNIEnv *env, jclass obj)
{
return MR_get_user_cpu_milliseconds();

View File

@@ -284,10 +284,11 @@ jars: classes
$(RM) $(STD_LIB_NAME).classes
$(JAR) $(JAR_CREATE_FLAGS) $(RT_LIB_NAME).jar jmercury/runtime/*.class
$(JAR) i $(RT_LIB_NAME).jar
-+cd jmercury/runtime && mmake $(NATIVE_SO)
-cp jmercury/runtime/$(NATIVE_SO) .
# -+cd jmercury/runtime && mmake $(NATIVE_SO)
# -cp jmercury/runtime/$(NATIVE_SO) .
# This shared object is needed to run some of the standard library methods.
# This shared object was used to implement some standard library methods,
# but currently not.
NATIVE_SO = Native.$(EXT_FOR_SHARED_LIB)
#-----------------------------------------------------------------------------#
@@ -536,7 +537,7 @@ ifneq (,$(findstring java,$(GRADE)))
install_library: jars
mkdir -p $(INSTALL_JAVA_LIBRARY_DIR)
cp $(JARS) $(INSTALL_JAVA_LIBRARY_DIR)
-cp $(NATIVE_SO) $(INSTALL_JAVA_LIBRARY_DIR)
# -cp $(NATIVE_SO) $(INSTALL_JAVA_LIBRARY_DIR)
else

View File

@@ -1,7 +1,7 @@
%---------------------------------------------------------------------------%
% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
%---------------------------------------------------------------------------%
% Copyright (C) 1994-2008 The University of Melbourne.
% Copyright (C) 1994-2009 The University of Melbourne.
% This file may only be copied under the terms of the GNU Library General
% Public License - see the file COPYING.LIB in the Mercury distribution.
%---------------------------------------------------------------------------%
@@ -27,6 +27,10 @@
% some memory and time usage statistics about the time period since
% the last call to report_stats to stderr.
%
% Note: in Java, this reports usage of the calling thread. You will get
% nonsensical results if the previous call to `report_stats' was from a
% different thread.
%
% Note: in Erlang, the benchmark_* procedures will change the apparent time
% of the last call to report_stats.
%
@@ -684,26 +688,45 @@ ML_memory_profile_compare_final(const void *i1, const void *i2)
:- pragma foreign_code("Java",
"
private static int time_at_start = 0;
private static int time_at_last_stat = 0;
private static int user_time_at_start = 0;
private static int user_time_at_last_stat = 0;
private static long real_time_at_start;
private static long real_time_at_last_stat;
static {
if (jmercury.runtime.Native.isAvailable()) {
time_at_start = jmercury.runtime.Native.get_user_cpu_milliseconds();
time_at_last_stat = time_at_start;
}
public static void
ML_initialise()
{
/*
** Class initialisation may be delayed so main() must explicitly initialise
** these variables at startup, otherwise the first call to `report_stats'
** will show the wrong elapsed time.
*/
real_time_at_start = System.currentTimeMillis();
real_time_at_last_stat = real_time_at_start;
}
private static void
ML_report_stats() {
int time_at_prev_stat = time_at_last_stat;
time_at_last_stat = get_user_cpu_milliseconds_1_p_0();
ML_report_stats()
{
int user_time_at_prev_stat = user_time_at_last_stat;
user_time_at_last_stat = ML_get_user_cpu_milliseconds();
System.err.print(""[Time: "" +
((time_at_last_stat - time_at_prev_stat) / 1000.0) +
"", "" +
((time_at_last_stat - time_at_start) / 1000.0)
);
long real_time_at_prev_stat = real_time_at_last_stat;
real_time_at_last_stat = System.currentTimeMillis();
System.err.print(
""[User time: +"" +
((user_time_at_last_stat - user_time_at_prev_stat) / 1000.0) +
""s, "" +
((user_time_at_last_stat - user_time_at_start) / 1000.0) +
""s"");
System.err.print(
"" Real time: +"" +
((real_time_at_last_stat - real_time_at_prev_stat) / 1000.0) +
""s, "" +
((real_time_at_last_stat - real_time_at_start) / 1000.0) +
""s"");
/*
** XXX At this point there should be a whole bunch of memory usage
@@ -715,7 +738,8 @@ ML_report_stats() {
}
private static void
ML_report_full_memory_stats() {
ML_report_full_memory_stats()
{
/*
** XXX The support for this predicate is even worse. Since we don't have
** access to memory usage statistics, all you get here is an apology.
@@ -849,6 +873,9 @@ repeat(N) :-
:- impure pred get_user_cpu_milliseconds(int::out) is det.
:- pragma foreign_export("Java", get_user_cpu_milliseconds(out),
"ML_get_user_cpu_milliseconds").
:- pragma foreign_proc("C",
get_user_cpu_milliseconds(Time::out),
[will_not_call_mercury],
@@ -870,14 +897,19 @@ repeat(N) :-
:- pragma foreign_proc("Java",
get_user_cpu_milliseconds(Time::out),
[will_not_call_mercury],
[will_not_call_mercury, may_not_duplicate],
"
if (jmercury.runtime.Native.isAvailable()) {
Time = jmercury.runtime.Native.get_user_cpu_milliseconds();
} else {
throw new java.lang.RuntimeException(
""get_user_cpu_milliseconds is not implemented in pure Java."" +
""Native dynamic link library is required."");
try {
java.lang.management.ThreadMXBean bean =
java.lang.management.ManagementFactory.getThreadMXBean();
long nsecs = bean.getCurrentThreadUserTime();
if (nsecs == -1) {
Time = -1;
} else {
Time = (int) (nsecs / 1000000L);
}
} catch (java.lang.UnsupportedOperationException e) {
Time = -1;
}
").

View File

@@ -4,7 +4,7 @@
% Originally written in 1999 by Tomas By <T.By@dcs.shef.ac.uk>
% "Feel free to use this code or parts of it any way you want."
%
% Some portions are Copyright (C) 1999-2007 The University of Melbourne.
% Some portions are Copyright (C) 1999-2007,2009 The University of Melbourne.
% This file may only be copied under the terms of the GNU Library General
% Public License - see the file COPYING.LIB in the Mercury distribution.
%-----------------------------------------------------------------------------%
@@ -88,6 +88,8 @@
% cannot be obtained, this procedure will throw a time_error exception.
% To obtain a time in seconds, divide Result by `time.clocks_per_sec'.
%
% On Java the elapsed time for the calling thread is returned.
%
:- pred time.clock(clock_t::out, io::di, io::uo) is det.
% time.clocks_per_sec:
@@ -124,7 +126,8 @@
% On non-POSIX systems that do not support this functionality,
% this procedure may simply always throw an exception.
%
% Currently on Win32 the child part of 'tms' is always zero.
% On Java the times for the calling thread are returned.
% On Win32 and Java the child part of 'tms' is always zero.
%
:- pred time.times(tms::out, clock_t::out, io::di, io::uo) is det.
@@ -279,13 +282,14 @@ time.clock(Result, !IO) :-
time.c_clock(Ret::out, _IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, tabled_for_io],
"
if (jmercury.runtime.Native.isAvailable()) {
Ret = jmercury.runtime.Native.clock();
java.lang.management.ThreadMXBean bean =
java.lang.management.ManagementFactory.getThreadMXBean();
long nsecs = bean.getCurrentThreadCpuTime();
if (nsecs == -1) {
Ret = -1;
} else {
throw new java.lang.RuntimeException(
""time.clock is not implemented "" +
""in pure Java. Native dynamic link "" +
""library is required."");
/* This must match the definition of clocks_per_sec. */
Ret = (int) (nsecs / 1000L);
}
").
@@ -310,14 +314,8 @@ time.clock(Result, !IO) :-
time.clocks_per_sec = (Ret::out),
[will_not_call_mercury, promise_pure, thread_safe],
"
if (jmercury.runtime.Native.isAvailable()) {
Ret = jmercury.runtime.Native.clocks_per_sec();
} else {
throw new java.lang.RuntimeException(
""time.clocks_per_sec is not implemented "" +
""in pure Java. Native dynamic link "" +
""library is required."");
}
/* Emulate the POSIX value. */
Ret = 1000000;
").
%-----------------------------------------------------------------------------%
@@ -390,27 +388,31 @@ time.times(Tms, Result, !IO) :-
:- pragma foreign_proc("Java",
time.c_times(Ret::out, Ut::out, St::out, CUt::out, CSt::out,
_IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, tabled_for_io],
[will_not_call_mercury, promise_pure, tabled_for_io, may_not_duplicate],
"
if (jmercury.runtime.Native.isAvailable()) {
int[] times = jmercury.runtime.Native.times();
if (times != null) {
Ret = times[0];
Ut = times[1];
St = times[2];
CUt = times[3];
CSt = times[4];
/* We can only keep the lower 31 bits of the timestamp. */
Ret = (int) (System.currentTimeMillis() & 0x7fffffff);
try {
java.lang.management.ThreadMXBean bean =
java.lang.management.ManagementFactory.getThreadMXBean();
long user_nsecs = bean.getCurrentThreadUserTime();
long cpu_nsecs = bean.getCurrentThreadCpuTime();
if (user_nsecs == -1 || cpu_nsecs == -1) {
Ut = -1;
St = -1;
} else {
throw new java.lang.RuntimeException(
""time_times failed to construct "" +
""integer array"");
/* These units must match the definition of clk_tck. */
Ut = (int) (user_nsecs / 1000000L);
St = (int) ((cpu_nsecs - user_nsecs) / 1000000L);
}
} else {
throw new java.lang.RuntimeException(
""time.times is not implemented "" +
""in pure Java. Native dynamic link "" +
""library is required."");
} catch (java.lang.UnsupportedOperationException e) {
Ut = -1;
St = -1;
}
CUt = 0;
CSt = 0;
").
%-----------------------------------------------------------------------------%
@@ -448,14 +450,11 @@ time.c_clk_tck = -1. % default is to throw an exception.
time.c_clk_tck = (Ret::out),
[will_not_call_mercury, promise_pure, thread_safe],
"
if (jmercury.runtime.Native.isAvailable()) {
Ret = jmercury.runtime.Native.clk_tck();
} else {
throw new java.lang.RuntimeException(
""time.clk_tck is not implemented "" +
""in pure Java. Native dynamic link "" +
""library is required."");
}
/*
** We use System.currentTimeMillis() to return elapsed time so say that
** there are 1000 clock ticks per second.
*/
Ret = 1000;
").
%-----------------------------------------------------------------------------%