mirror of
https://github.com/Mercury-Language/mercury.git
synced 2026-04-17 18:33:58 +00:00
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:
11
README.Java
11
README.Java
@@ -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.
|
||||
|
||||
|
||||
@@ -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();",
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
").
|
||||
|
||||
|
||||
@@ -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;
|
||||
").
|
||||
|
||||
%-----------------------------------------------------------------------------%
|
||||
|
||||
Reference in New Issue
Block a user