[m-rev.] for review: Java unreachable code removal Mk.2

Michael Wybrow mjwybrow at students.cs.mu.oz.au
Fri Feb 22 11:17:04 AEDT 2002


Fergus,

I've addressed all your review comments.
An interdiff follows, along with a full diff of this change.

Michael


Interdiff:

diff -u mlds_to_java.m mlds_to_java.m
--- mlds_to_java.m
+++ mlds_to_java.m
@@ -35,7 +35,7 @@
 %	     to avoid conflicting with `mercury.String'.
 %
 %	There is currently some code threaded through the output predicates
-%	(usually a variable called `JumpInfo') which keeps track of, and
+%	(usually a variable called `ExitMethods') which keeps track of, and
 %	removes unreachable code. Ideally this would be done as an MLDS->MLDS
 %	transformation, preferably in a seperate module. Unfortunately this
 %	is not possible due to the fact that the back-end generates `break'
@@ -1385,7 +1385,7 @@
 		indent_line(Context, Indent),
 		io__write_string("{\n"),
 		{ FuncInfo = func_info(Name, Signature) },
-		output_statement(Indent + 1, FuncInfo, Body, _JumpInfo),
+		output_statement(Indent + 1, FuncInfo, Body, _ExitMethods),
 		indent_line(Context, Indent),
 		io__write_string("}\n")	% end the function
 	).
@@ -1790,65 +1790,72 @@
 %
 
 	% These types are used by many of the output_stmt style predicates to
-	% pass back completetion information for previous statements.
+	% return information about the statement's control flow,
+	% i.e. about the different ways in which the statement can exit.
 	% In general we only output the current statement if the previous 
-	% statement could complete normally.
-	% We keep a set of jump types since some statements (like an
-	% if-then-else) could potentially break, and also complete. 
-:- type jump_info == set__set(jump_type).
+	% statement could complete normally (fall through).
+	% We keep a set of exit methods since some statements (like an
+	% if-then-else) could potentially break, and also fall through. 
+:- type exit_methods == set__set(exit_method).
 
-:- type jump_type
+:- type exit_method
 	--->	can_break
 	;	can_continue
 	;	can_return
 	;	can_throw
-	;	can_complete
+	;	can_fall_through	% Where the instruction can complete
+					% normally and execution can continue
+					% with the following statement.
 	.
 
 
 :- type func_info
 	--->	func_info(mlds__qualified_entity_name, mlds__func_params).
 
-:- pred output_statements(indent, func_info, list(mlds__statement), jump_info,
-		io__state, io__state).
+:- pred output_statements(indent, func_info, list(mlds__statement),
+		exit_methods, io__state, io__state).
 :- mode output_statements(in, in, in, out, di, uo) is det.
 
-output_statements(_, _, [], set__make_singleton_set(can_complete)) --> [].
-output_statements(Indent, FuncInfo, [Statement|Statements], JumpInfo) -->
-	output_statement(Indent, FuncInfo, Statement, StmtJumpInfo),
-	( { set__member(can_complete, StmtJumpInfo) } ->
-		output_statements(Indent, FuncInfo, Statements, StmtsJumpInfo),
-		{ JumpInfo0 = set__union(StmtJumpInfo, StmtsJumpInfo) },
-		( { set__member(can_complete, StmtsJumpInfo) } ->
-			{ JumpInfo = JumpInfo0 }
+output_statements(_, _, [], set__make_singleton_set(can_fall_through)) --> [].
+output_statements(Indent, FuncInfo, [Statement|Statements], ExitMethods) -->
+	output_statement(Indent, FuncInfo, Statement, StmtExitMethods),
+	( { set__member(can_fall_through, StmtExitMethods) } ->
+		output_statements(Indent, FuncInfo, Statements,
+				StmtsExitMethods),
+		{ ExitMethods0 = StmtExitMethods `set__union`
+				StmtsExitMethods },
+		( { set__member(can_fall_through, StmtsExitMethods) } ->
+			{ ExitMethods = ExitMethods0 }
 		;
 			% If the last statement could not complete normally
 			% the current block can no longer complete normally.
-			{ JumpInfo = set__delete(JumpInfo0, can_complete) }
+			{ ExitMethods = ExitMethods0 `set__delete`
+					can_fall_through }
 		)
 	;
 		% Don't output any more statements from the current list since
 		% the preceeding statement cannot complete.
-		{ JumpInfo = StmtJumpInfo }
+		{ ExitMethods = StmtExitMethods }
 	).
 
-:- pred output_statement(indent, func_info, mlds__statement, jump_info,
+:- pred output_statement(indent, func_info, mlds__statement, exit_methods,
 		io__state, io__state).
 :- mode output_statement(in, in, in, out, di, uo) is det.
 
 output_statement(Indent, FuncInfo, mlds__statement(Statement, Context),
-		JumpInfo) -->
+		ExitMethods) -->
 	output_context(Context),
-	output_stmt(Indent, FuncInfo, Statement, Context, JumpInfo).
+	output_stmt(Indent, FuncInfo, Statement, Context, ExitMethods).
 
-:- pred output_stmt(indent, func_info, mlds__stmt, mlds__context, jump_info,
+:- pred output_stmt(indent, func_info, mlds__stmt, mlds__context, exit_methods,
 		io__state, io__state).
 :- mode output_stmt(in, in, in, in, out, di, uo) is det.
 
 	%
 	% sequence
 	%
-output_stmt(Indent, FuncInfo, block(Defns, Statements), Context, JumpInfo) -->
+output_stmt(Indent, FuncInfo, block(Defns, Statements), Context,
+		ExitMethods) -->
 	indent_line(Indent),
 	io__write_string("{\n"),
 	( { Defns \= [] } ->
@@ -1860,14 +1867,14 @@
 	;
 		[]
 	),
-	output_statements(Indent + 1, FuncInfo, Statements, JumpInfo),
+	output_statements(Indent + 1, FuncInfo, Statements, ExitMethods),
 	indent_line(Context, Indent),
 	io__write_string("}\n").
 
 	%
 	% iteration
 	%
-output_stmt(Indent, FuncInfo, while(Cond, Statement, no), _, JumpInfo) -->
+output_stmt(Indent, FuncInfo, while(Cond, Statement, no), _, ExitMethods) -->
 	indent_line(Indent),
 	io__write_string("while ("),
 	output_rval(Cond),
@@ -1878,52 +1885,55 @@
 	( { Cond = const(false) } ->
 		indent_line(Indent),
 		io__write_string("{  /* Unreachable code */  }\n"),
-		{ JumpInfo = set__make_singleton_set(can_complete) }
+		{ ExitMethods = set__make_singleton_set(can_fall_through) }
 	;	
 		output_statement(Indent + 1, FuncInfo, Statement,
-				StmtJumpInfo),
-		{ JumpInfo = while_jump_info(Cond, StmtJumpInfo) }
+				StmtExitMethods),
+		{ ExitMethods = while_exit_methods(Cond, StmtExitMethods) }
 	).
 output_stmt(Indent, FuncInfo, while(Cond, Statement, yes), Context, 
-		JumpInfo) -->
+		ExitMethods) -->
 	indent_line(Indent),
 	io__write_string("do\n"),
-	output_statement(Indent + 1, FuncInfo, Statement, StmtJumpInfo),
+	output_statement(Indent + 1, FuncInfo, Statement, StmtExitMethods),
 	indent_line(Context, Indent),
 	io__write_string("while ("),
 	output_rval(Cond),
 	io__write_string(");\n"),
-	{ JumpInfo = while_jump_info(Cond, StmtJumpInfo) }.
+	{ ExitMethods = while_exit_methods(Cond, StmtExitMethods) }.
 
 
-	% Returns a set of jump_types that describes whether the while 
+	% Returns a set of exit_methods that describes whether the while 
 	% statement can complete normally.
-:- func while_jump_info(mlds__rval, jump_info) = jump_info.
-:- mode while_jump_info(in, in) = out is det.
+:- func while_exit_methods(mlds__rval, exit_methods) = exit_methods.
+:- mode while_exit_methods(in, in) = out is det.
 
-while_jump_info(Cond, BlockJumpInfo) = JumpInfo :-
+while_exit_methods(Cond, BlockExitMethods) = ExitMethods :-
 	% A while statement cannot complete normally if its condition
 	% expression is a constant expression with value true, and it
 	% doesn't contain a reachable break statement that exits the
 	% while statement.
 	(
+		% XXX This is not a sufficient way of testing for a Java 
+		%     "constant expression", though determining these
+		%     accurately is a little difficult to do here.
 		Cond = mlds__const(mlds__true),
-		not set__member(can_break, BlockJumpInfo)
+		not set__member(can_break, BlockExitMethods)
 	->
 		% Cannot complete normally
-		JumpInfo = set__init
+		ExitMethods0 = BlockExitMethods `set__delete` can_fall_through
 	;
-		JumpInfo0 = set__delete(BlockJumpInfo, can_continue),
-		JumpInfo1 = set__delete(JumpInfo0, can_break),
-		JumpInfo  = set__insert(JumpInfo1, can_complete)
-	).
+		ExitMethods0 = BlockExitMethods `set__insert` can_fall_through
+	),
+	ExitMethods = (ExitMethods0 `set__delete` can_continue)
+				    `set__delete` can_break.
 
 
 	%
 	% selection (if-then-else)
 	%
 output_stmt(Indent, FuncInfo, if_then_else(Cond, Then0, MaybeElse),
-		Context, JumpInfo) -->
+		Context, ExitMethods) -->
 	%
 	% we need to take care to avoid problems caused by the
 	% dangling else ambiguity
@@ -1955,19 +1965,20 @@
 	io__write_string("if ("),
 	output_rval(Cond),
 	io__write_string(")\n"),
-	output_statement(Indent + 1, FuncInfo, Then, ThenJumpInfo),
+	output_statement(Indent + 1, FuncInfo, Then, ThenExitMethods),
 	( { MaybeElse = yes(Else) } ->
 		indent_line(Context, Indent),
 		io__write_string("else\n"),
-		output_statement(Indent + 1, FuncInfo, Else, ElseJumpInfo),
+		output_statement(Indent + 1, FuncInfo, Else, ElseExitMethods),
 		% An if-then-else statement can complete normally iff the 
 		% then-statement can complete normally or the else-statement
 		% can complete normally.
-		{ JumpInfo = set__union(ThenJumpInfo, ElseJumpInfo) }
+		{ ExitMethods = ThenExitMethods `set__union` ElseExitMethods }
 	;
 		% An if-then statement can complete normally iff it is 
 		% reachable.
-		{ JumpInfo = set__make_singleton_set(can_complete) }
+		{ ExitMethods = ThenExitMethods `set__union` 
+				set__make_singleton_set(can_fall_through) }
 	).
 	
 	
@@ -1976,13 +1987,13 @@
 	% selection (switch)
 	%
 output_stmt(Indent, FuncInfo, switch(_Type, Val, _Range, Cases, Default),
-		Context, JumpInfo) -->
+		Context, ExitMethods) -->
 	indent_line(Context, Indent),
 	io__write_string("switch ("),
 	output_rval_maybe_with_enum(Val),
 	io__write_string(") {\n"),
 	output_switch_cases(Indent + 1, FuncInfo, Context, Cases, Default,
-			JumpInfo),
+			ExitMethods),
 	indent_line(Context, Indent),
 	io__write_string("}\n").
 
@@ -1990,32 +2001,32 @@
 	%
 	% transfer of control
 	% 
-output_stmt(_Indent, _FuncInfo, label(_LabelName), _Context, set__init) --> 
+output_stmt(_Indent, _FuncInfo, label(_LabelName), _Context, _ExitMethods) --> 
 	{ unexpected(this_file, 
 		"output_stmt: labels not supported in Java.") }.
 output_stmt(_Indent, _FuncInfo, goto(label(_LabelName)), _Context,
-		set__init) --> 
+		_ExitMethods) --> 
 	{ unexpected(this_file,
 		"output_stmt: gotos not supported in Java.") }.
-output_stmt(Indent, _FuncInfo, goto(break), _Context, JumpInfo) --> 
+output_stmt(Indent, _FuncInfo, goto(break), _Context, ExitMethods) --> 
 	indent_line(Indent),
 	io__write_string("break;\n"),
-	{ JumpInfo = set__make_singleton_set(can_break) }.
-output_stmt(Indent, _FuncInfo, goto(continue), _Context, JumpInfo) --> 
+	{ ExitMethods = set__make_singleton_set(can_break) }.
+output_stmt(Indent, _FuncInfo, goto(continue), _Context, ExitMethods) --> 
 	indent_line(Indent),
 	io__write_string("continue;\n"),
-	{ JumpInfo = set__make_singleton_set(can_continue) }.
+	{ ExitMethods = set__make_singleton_set(can_continue) }.
 output_stmt(_Indent, _FuncInfo, computed_goto(_Expr, _Labels), _Context,
-		set__init) --> 
+		_ExitMethods) --> 
 	{ unexpected(this_file, 
 		"output_stmt: computed gotos not supported in Java.") }.
 	
 	%
 	% function call/return
 	%
-output_stmt(Indent, CallerFuncInfo, Call, Context, JumpInfo) -->
+output_stmt(Indent, CallerFuncInfo, Call, Context, ExitMethods) -->
 	{ Call = call(Signature, FuncRval, MaybeObject, CallArgs,
-		Results, IsTailCall) },
+		Results, _IsTailCall) },
 	{ CallerFuncInfo = func_info(_Name, _Params) },
 	{ Signature = mlds__func_signature(ArgTypes, RetTypes) },
 	indent_line(Indent),
@@ -2126,15 +2137,19 @@
 	;
 		[]
 	),
-	( { IsTailCall = tail_call, Results = [] } ->
-		indent_line(Context, Indent + 1),
-		io__write_string("return;\n"),
-		{ JumpInfo = set__make_singleton_set(can_return) }
-	;
-		{ JumpInfo = set__make_singleton_set(can_complete) }
-	),
+	% XXX Is this needed? If present, it causes compiler errors for a
+	%     couple of files in the benchmarks directory.  -mjwybrow
+	%
+	% ( { IsTailCall = tail_call, Results = [] } ->
+	%	indent_line(Context, Indent + 1),
+	%	io__write_string("return;\n")
+	% ;
+	%	[]
+	% ),
+	%
 	indent_line(Indent),
-	io__write_string("}\n").
+	io__write_string("}\n"),
+	{ ExitMethods = set__make_singleton_set(can_fall_through) }.
 
 
 :- pred output_args_as_array(list(mlds__rval), list(mlds__type),
@@ -2166,7 +2181,7 @@
 	).
 
 
-output_stmt(Indent, FuncInfo, return(Results0), _Context, JumpInfo) -->
+output_stmt(Indent, FuncInfo, return(Results0), _Context, ExitMethods) -->
 	%
 	% XXX It's not right to just remove the dummy variables like this,
 	%     but currently they do not seem to be included in the ReturnTypes
@@ -2199,9 +2214,9 @@
 				output_boxed_rval(Type, Result))),
 		io__write_string("};\n")
 	),
-	{ JumpInfo = set__make_singleton_set(can_return) }.
+	{ ExitMethods = set__make_singleton_set(can_return) }.
 
-output_stmt(Indent, _FuncInfo, do_commit(Ref), _, JumpInfo) -->
+output_stmt(Indent, _FuncInfo, do_commit(Ref), _, ExitMethods) -->
 	indent_line(Indent),
 	output_rval(Ref),
 	io__write_string(" = new mercury.runtime.Commit();\n"),
@@ -2209,14 +2224,15 @@
 	io__write_string("throw "),
 	output_rval(Ref),
 	io__write_string(";\n"),
-	{ JumpInfo = set__make_singleton_set(can_throw) }.
+	{ ExitMethods = set__make_singleton_set(can_throw) }.
 
-output_stmt(Indent, FuncInfo, try_commit(_Ref, Stmt, Handler), _, JumpInfo) -->
+output_stmt(Indent, FuncInfo, try_commit(_Ref, Stmt, Handler), _,
+		ExitMethods) -->
 	indent_line(Indent),
 	io__write_string("try\n"),
 	indent_line(Indent),
 	io__write_string("{\n"),
-	output_statement(Indent + 1, FuncInfo, Stmt, TryJumpInfo0),
+	output_statement(Indent + 1, FuncInfo, Stmt, TryExitMethods0),
 	indent_line(Indent),
 	io__write_string("}\n"),
 	indent_line(Indent),
@@ -2224,11 +2240,11 @@
 	indent_line(Indent),
 	io__write_string("{\n"),
 	indent_line(Indent + 1),
-	output_statement(Indent + 1, FuncInfo, Handler, CatchJumpInfo),
+	output_statement(Indent + 1, FuncInfo, Handler, CatchExitMethods),
 	indent_line(Indent),
 	io__write_string("}\n"),
-	{ TryJumpInfo = set__delete(TryJumpInfo0, can_throw) },
-	{ JumpInfo = set__union(TryJumpInfo, CatchJumpInfo) }.
+	{ ExitMethods = (TryExitMethods0 `set__delete` can_throw)
+				         `set__union`  CatchExitMethods }.
 
 
 
@@ -2306,42 +2322,42 @@
 %
 
 :- pred output_switch_cases(indent, func_info, mlds__context,
-		list(mlds__switch_case), mlds__switch_default, jump_info,
+		list(mlds__switch_case), mlds__switch_default, exit_methods,
 		io__state, io__state).
 :- mode output_switch_cases(in, in, in, in, in, out, di, uo) is det.
 
-output_switch_cases(Indent, FuncInfo, Context, [], Default, JumpInfo) -->
-	output_switch_default(Indent, FuncInfo, Context, Default, JumpInfo).
+output_switch_cases(Indent, FuncInfo, Context, [], Default, ExitMethods) -->
+	output_switch_default(Indent, FuncInfo, Context, Default, ExitMethods).
 output_switch_cases(Indent, FuncInfo, Context, [Case|Cases], Default,
-		JumpInfo) -->
-	output_switch_case(Indent, FuncInfo, Context, Case, CaseJumpInfo0),
+		ExitMethods) -->
+	output_switch_case(Indent, FuncInfo, Context, Case, CaseExitMethods0),
 	output_switch_cases(Indent, FuncInfo, Context, Cases, Default, 
-			CasesJumpInfo),
-	( { set__member(can_break, CaseJumpInfo0) } ->
-		{ CaseJumpInfo1 = set__delete(CaseJumpInfo0, can_break) },
-		{ CaseJumpInfo = set__insert(CaseJumpInfo1, can_complete) }
+			CasesExitMethods),
+	( { set__member(can_break, CaseExitMethods0) } ->
+		{ CaseExitMethods = (CaseExitMethods0 `set__delete` can_break)
+				`set__insert` can_fall_through }
 	;
-		{ CaseJumpInfo = CaseJumpInfo0 }
+		{ CaseExitMethods = CaseExitMethods0 }
 	),
-	{ JumpInfo = set__union(CaseJumpInfo, CasesJumpInfo) }.
+	{ ExitMethods = CaseExitMethods `set__union` CasesExitMethods }.
 
 
 :- pred output_switch_case(indent, func_info, mlds__context,
-		mlds__switch_case, jump_info, io__state, io__state).
+		mlds__switch_case, exit_methods, io__state, io__state).
 :- mode output_switch_case(in, in, in, in, out, di, uo) is det.
 
-output_switch_case(Indent, FuncInfo, Context, Case, JumpInfo) -->
+output_switch_case(Indent, FuncInfo, Context, Case, ExitMethods) -->
 	{ Case = (Conds - Statement) },
 	list__foldl(output_case_cond(Indent, Context), Conds),
-	output_statement(Indent + 1, FuncInfo, Statement, StmtJumpInfo),
-	( { set__member(can_complete, StmtJumpInfo) } ->
+	output_statement(Indent + 1, FuncInfo, Statement, StmtExitMethods),
+	( { set__member(can_fall_through, StmtExitMethods) } ->
 		indent_line(Context, Indent + 1),
 		io__write_string("break;\n"),
-		{ JumpInfo0 = set__delete(StmtJumpInfo, can_complete) },
-		{ JumpInfo = set__insert(JumpInfo0, can_break) }
+		{ ExitMethods = (StmtExitMethods `set__insert` can_break)
+				`set__delete` can_fall_through }
 	;
 		% Don't output `break' since it would be unreachable.
-		{ JumpInfo = StmtJumpInfo }
+		{ ExitMethods = StmtExitMethods }
 	).
 
 :- pred output_case_cond(indent, mlds__context, mlds__case_match_cond, 
@@ -2358,26 +2374,24 @@
 		"output_case_cond: cannot match ranges in Java cases") }.
 
 :- pred output_switch_default(indent, func_info, mlds__context,
-		mlds__switch_default, jump_info, io__state, io__state).
+		mlds__switch_default, exit_methods, io__state, io__state).
 :- mode output_switch_default(in, in, in, in, out, di, uo) is det.
 
 output_switch_default(_Indent, _FuncInfo, _Context, default_do_nothing,
-		JumpInfo) -->
-	{ JumpInfo = set__make_singleton_set(can_complete) }.
+		ExitMethods) -->
+	{ ExitMethods = set__make_singleton_set(can_fall_through) }.
 output_switch_default(Indent, FuncInfo, Context, default_case(Statement),
-		JumpInfo) -->
+		ExitMethods) -->
 	indent_line(Context, Indent),
 	io__write_string("default:\n"),
-	output_statement(Indent + 1, FuncInfo, Statement, JumpInfo).
+	output_statement(Indent + 1, FuncInfo, Statement, ExitMethods).
 output_switch_default(Indent, _FuncInfo, Context, default_is_unreachable,
-		JumpInfo) -->
+		ExitMethods) -->
 	indent_line(Context, Indent),
 	io__write_string("default: /*NOTREACHED*/\n"), 
 	indent_line(Context, Indent + 1),
 	io__write_string("throw new mercury.runtime.UnreachableDefault();\n"),
-	% This exception will never be caught so statements following it are
-	% unreachable.
-	{ JumpInfo = set__make_singleton_set(can_throw) }.
+	{ ExitMethods = set__make_singleton_set(can_throw) }.
 
 %-----------------------------------------------------------------------------%
 
@@ -2391,9 +2405,10 @@
 	%
 	% atomic statements
 	%
-output_stmt(Indent, FuncInfo, atomic(AtomicStatement), Context, JumpInfo) -->
+output_stmt(Indent, FuncInfo, atomic(AtomicStatement), Context,
+		ExitMethods) -->
 	output_atomic_stmt(Indent, FuncInfo, AtomicStatement, Context),
-	{ JumpInfo = set__make_singleton_set(can_complete) }.
+	{ ExitMethods = set__make_singleton_set(can_fall_through) }.
 
 :- pred output_atomic_stmt(indent, func_info,
 		mlds__atomic_statement, mlds__context, io__state, io__state).




And the full diff:



Index: handle_options.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/handle_options.m,v
retrieving revision 1.131
diff -u -r1.131 handle_options.m
--- handle_options.m	19 Feb 2002 06:21:44 -0000	1.131
+++ handle_options.m	19 Feb 2002 23:34:20 -0000
@@ -357,11 +357,6 @@
 	%	  pointers.
 	%   - store nondet environments on the heap
 	%         Because Java has no way of allocating structs on the stack.
-	%   - not optimizing tailcalls
-	%         XXX Optimized tailcalls currently cause compilation errors
-	%             in the Java back-end because javac is unwilling to
-	%             compile unreachable code they generate.
-	%	      For this reason they have been disabled.
 	%   - no static ground terms
 	%         XXX Previously static ground terms used to not work with
 	%             --high-level-data.  But this has been (mostly?) fixed now.
@@ -377,7 +372,6 @@
 		globals__io_set_option(gcc_nested_functions, bool(no)),
 		globals__io_set_option(nondet_copy_out, bool(yes)),
 		globals__io_set_option(det_copy_out, bool(yes)),
-		globals__io_set_option(optimize_tailcalls, bool(no)),
 		globals__io_set_option(num_tag_bits, int(0)),
 		globals__io_set_option(static_ground_terms, bool(no)),
 		globals__io_set_option(put_nondet_env_on_heap, bool(yes))
Index: mlds_to_java.m
===================================================================
RCS file: /home/mercury1/repository/mercury/compiler/mlds_to_java.m,v
retrieving revision 1.23
diff -u -r1.23 mlds_to_java.m
--- mlds_to_java.m	15 Feb 2002 08:17:15 -0000	1.23
+++ mlds_to_java.m	22 Feb 2002 00:03:33 -0000
@@ -19,12 +19,12 @@
 %	higher order functions
 %	multidet and nondet predicates
 %	test tests/benchmarks/*.m
+%	generate optimized tailcalls
 % TODO: 
 %	General code cleanup
 %	handle static ground terms
 %	RTTI (requires static ground terms)
 %	generate names of classes etc. correctly (mostly same as IL backend)
-%	generate optimized tailcalls
 %
 %	handle foreign code written in Java
 %	handle foreign code written in C 
@@ -33,6 +33,15 @@
 %       To avoid namespace conflicts all Java names must be fully qualified.
 %	e.g. The classname `String' must be qualified as `java.lang.String'
 %	     to avoid conflicting with `mercury.String'.
+%
+%	There is currently some code threaded through the output predicates
+%	(usually a variable called `ExitMethods') which keeps track of, and
+%	removes unreachable code. Ideally this would be done as an MLDS->MLDS
+%	transformation, preferably in a seperate module. Unfortunately this
+%	is not possible due to the fact that the back-end generates `break'
+%	statements for cases in switches as they are output, meaning that we
+%	can't remove them in a pass over the MLDS. 
+%
 %-----------------------------------------------------------------------------%
 
 :- module mlds_to_java.
@@ -67,7 +76,7 @@
 :- import_module builtin_ops.
 :- import_module prog_data, prog_out, type_util, error_util.
 
-:- import_module bool, int, string, library, list.
+:- import_module bool, int, string, library, list, set.
 :- import_module assoc_list, term, std_util, require.
 
 %-----------------------------------------------------------------------------%
@@ -339,16 +348,16 @@
 	{ find_pointer_addressed_methods(Defns0, [], CodeAddrs0) },
 	{ CodeAddrs = list__sort_and_remove_dups(CodeAddrs0) },
 	%
-	% Output transformed MLDS as Java source.  
-	%
-	output_src_start(Indent, ModuleName, Imports, Defns1), 
-	%
 	% Create wrappers in MLDS for all pointer addressed methods.
 	% 
 	{ generate_code_addr_wrappers(Indent + 1, CodeAddrs, [], 
 			WrapperDefns) },
-	{ Defns1 = WrapperDefns ++ Defns0 }, 
-	{ list__filter(defn_is_rtti_data, Defns1, _RttiDefns, NonRttiDefns) },
+	{ Defns = WrapperDefns ++ Defns0 }, 
+	%
+	% Output transformed MLDS as Java source.  
+	%
+	output_src_start(Indent, ModuleName, Imports, Defns), 
+	{ list__filter(defn_is_rtti_data, Defns, _RttiDefns, NonRttiDefns) },
 	% XXX Need to output RTTI data at this point.
 	{ CtorData = none },  % Not a constructor.
 	output_defns(Indent + 1, MLDS_ModuleName, CtorData, NonRttiDefns),
@@ -1376,7 +1385,7 @@
 		indent_line(Context, Indent),
 		io__write_string("{\n"),
 		{ FuncInfo = func_info(Name, Signature) },
-		output_statement(Indent + 1, FuncInfo, Body),
+		output_statement(Indent + 1, FuncInfo, Body, _ExitMethods),
 		indent_line(Context, Indent),
 		io__write_string("}\n")	% end the function
 	).
@@ -1780,33 +1789,73 @@
 % Code to output statements
 %
 
+	% These types are used by many of the output_stmt style predicates to
+	% return information about the statement's control flow,
+	% i.e. about the different ways in which the statement can exit.
+	% In general we only output the current statement if the previous 
+	% statement could complete normally (fall through).
+	% We keep a set of exit methods since some statements (like an
+	% if-then-else) could potentially break, and also fall through. 
+:- type exit_methods == set__set(exit_method).
+
+:- type exit_method
+	--->	can_break
+	;	can_continue
+	;	can_return
+	;	can_throw
+	;	can_fall_through	% Where the instruction can complete
+					% normally and execution can continue
+					% with the following statement.
+	.
+
+
 :- type func_info
 	--->	func_info(mlds__qualified_entity_name, mlds__func_params).
 
 :- pred output_statements(indent, func_info, list(mlds__statement),
-		io__state, io__state).
-:- mode output_statements(in, in, in, di, uo) is det.
+		exit_methods, io__state, io__state).
+:- mode output_statements(in, in, in, out, di, uo) is det.
 
-output_statements(Indent, FuncInfo, Statements) -->
-	list__foldl(output_statement(Indent, FuncInfo),
-			Statements).
+output_statements(_, _, [], set__make_singleton_set(can_fall_through)) --> [].
+output_statements(Indent, FuncInfo, [Statement|Statements], ExitMethods) -->
+	output_statement(Indent, FuncInfo, Statement, StmtExitMethods),
+	( { set__member(can_fall_through, StmtExitMethods) } ->
+		output_statements(Indent, FuncInfo, Statements,
+				StmtsExitMethods),
+		{ ExitMethods0 = StmtExitMethods `set__union`
+				StmtsExitMethods },
+		( { set__member(can_fall_through, StmtsExitMethods) } ->
+			{ ExitMethods = ExitMethods0 }
+		;
+			% If the last statement could not complete normally
+			% the current block can no longer complete normally.
+			{ ExitMethods = ExitMethods0 `set__delete`
+					can_fall_through }
+		)
+	;
+		% Don't output any more statements from the current list since
+		% the preceeding statement cannot complete.
+		{ ExitMethods = StmtExitMethods }
+	).
 
-:- pred output_statement(indent, func_info, mlds__statement,
+:- pred output_statement(indent, func_info, mlds__statement, exit_methods,
 		io__state, io__state).
-:- mode output_statement(in, in, in, di, uo) is det.
+:- mode output_statement(in, in, in, out, di, uo) is det.
 
-output_statement(Indent, FuncInfo, mlds__statement(Statement, Context)) -->
+output_statement(Indent, FuncInfo, mlds__statement(Statement, Context),
+		ExitMethods) -->
 	output_context(Context),
-	output_stmt(Indent, FuncInfo, Statement, Context).
+	output_stmt(Indent, FuncInfo, Statement, Context, ExitMethods).
 
-:- pred output_stmt(indent, func_info, mlds__stmt, mlds__context,
+:- pred output_stmt(indent, func_info, mlds__stmt, mlds__context, exit_methods,
 		io__state, io__state).
-:- mode output_stmt(in, in, in, in, di, uo) is det.
+:- mode output_stmt(in, in, in, in, out, di, uo) is det.
 
 	%
 	% sequence
 	%
-output_stmt(Indent, FuncInfo, block(Defns, Statements), Context) -->
+output_stmt(Indent, FuncInfo, block(Defns, Statements), Context,
+		ExitMethods) -->
 	indent_line(Indent),
 	io__write_string("{\n"),
 	( { Defns \= [] } ->
@@ -1818,33 +1867,73 @@
 	;
 		[]
 	),
-	output_statements(Indent + 1, FuncInfo, Statements),
+	output_statements(Indent + 1, FuncInfo, Statements, ExitMethods),
 	indent_line(Context, Indent),
 	io__write_string("}\n").
 
 	%
 	% iteration
 	%
-output_stmt(Indent, FuncInfo, while(Cond, Statement, no), _) -->
+output_stmt(Indent, FuncInfo, while(Cond, Statement, no), _, ExitMethods) -->
 	indent_line(Indent),
 	io__write_string("while ("),
 	output_rval(Cond),
 	io__write_string(")\n"),
-	output_statement(Indent + 1, FuncInfo, Statement).
-output_stmt(Indent, FuncInfo, while(Cond, Statement, yes), Context) -->
+	% The contained statement is reachable iff the while statement is 
+	% reachable and the condition expression is not a constant expression
+	% whose value is false.
+	( { Cond = const(false) } ->
+		indent_line(Indent),
+		io__write_string("{  /* Unreachable code */  }\n"),
+		{ ExitMethods = set__make_singleton_set(can_fall_through) }
+	;	
+		output_statement(Indent + 1, FuncInfo, Statement,
+				StmtExitMethods),
+		{ ExitMethods = while_exit_methods(Cond, StmtExitMethods) }
+	).
+output_stmt(Indent, FuncInfo, while(Cond, Statement, yes), Context, 
+		ExitMethods) -->
 	indent_line(Indent),
 	io__write_string("do\n"),
-	output_statement(Indent + 1, FuncInfo, Statement),
+	output_statement(Indent + 1, FuncInfo, Statement, StmtExitMethods),
 	indent_line(Context, Indent),
 	io__write_string("while ("),
 	output_rval(Cond),
-	io__write_string(");\n").
+	io__write_string(");\n"),
+	{ ExitMethods = while_exit_methods(Cond, StmtExitMethods) }.
+
+
+	% Returns a set of exit_methods that describes whether the while 
+	% statement can complete normally.
+:- func while_exit_methods(mlds__rval, exit_methods) = exit_methods.
+:- mode while_exit_methods(in, in) = out is det.
+
+while_exit_methods(Cond, BlockExitMethods) = ExitMethods :-
+	% A while statement cannot complete normally if its condition
+	% expression is a constant expression with value true, and it
+	% doesn't contain a reachable break statement that exits the
+	% while statement.
+	(
+		% XXX This is not a sufficient way of testing for a Java 
+		%     "constant expression", though determining these
+		%     accurately is a little difficult to do here.
+		Cond = mlds__const(mlds__true),
+		not set__member(can_break, BlockExitMethods)
+	->
+		% Cannot complete normally
+		ExitMethods0 = BlockExitMethods `set__delete` can_fall_through
+	;
+		ExitMethods0 = BlockExitMethods `set__insert` can_fall_through
+	),
+	ExitMethods = (ExitMethods0 `set__delete` can_continue)
+				    `set__delete` can_break.
+
 
 	%
 	% selection (if-then-else)
 	%
 output_stmt(Indent, FuncInfo, if_then_else(Cond, Then0, MaybeElse),
-		Context) -->
+		Context, ExitMethods) -->
 	%
 	% we need to take care to avoid problems caused by the
 	% dangling else ambiguity
@@ -1876,53 +1965,66 @@
 	io__write_string("if ("),
 	output_rval(Cond),
 	io__write_string(")\n"),
-	output_statement(Indent + 1, FuncInfo, Then),
+	output_statement(Indent + 1, FuncInfo, Then, ThenExitMethods),
 	( { MaybeElse = yes(Else) } ->
 		indent_line(Context, Indent),
 		io__write_string("else\n"),
-		output_statement(Indent + 1, FuncInfo, Else)
-	;
-		[]
+		output_statement(Indent + 1, FuncInfo, Else, ElseExitMethods),
+		% An if-then-else statement can complete normally iff the 
+		% then-statement can complete normally or the else-statement
+		% can complete normally.
+		{ ExitMethods = ThenExitMethods `set__union` ElseExitMethods }
+	;
+		% An if-then statement can complete normally iff it is 
+		% reachable.
+		{ ExitMethods = ThenExitMethods `set__union` 
+				set__make_singleton_set(can_fall_through) }
 	).
-
+	
+	
 
 	%
 	% selection (switch)
 	%
 output_stmt(Indent, FuncInfo, switch(_Type, Val, _Range, Cases, Default),
-		Context) -->
+		Context, ExitMethods) -->
 	indent_line(Context, Indent),
 	io__write_string("switch ("),
 	output_rval_maybe_with_enum(Val),
 	io__write_string(") {\n"),
-	list__foldl(output_switch_case(Indent + 1, FuncInfo, Context), Cases),
-	output_switch_default(Indent + 1, FuncInfo, Context, Default),
+	output_switch_cases(Indent + 1, FuncInfo, Context, Cases, Default,
+			ExitMethods),
 	indent_line(Context, Indent),
 	io__write_string("}\n").
-	
+
+
 	%
 	% transfer of control
 	% 
-output_stmt(_Indent, _FuncInfo, label(_LabelName), _Context) --> 
+output_stmt(_Indent, _FuncInfo, label(_LabelName), _Context, _ExitMethods) --> 
 	{ unexpected(this_file, 
 		"output_stmt: labels not supported in Java.") }.
-output_stmt(_Indent, _FuncInfo, goto(label(_LabelName)), _Context) --> 
+output_stmt(_Indent, _FuncInfo, goto(label(_LabelName)), _Context,
+		_ExitMethods) --> 
 	{ unexpected(this_file,
 		"output_stmt: gotos not supported in Java.") }.
-output_stmt(Indent, _FuncInfo, goto(break), _Context) --> 
+output_stmt(Indent, _FuncInfo, goto(break), _Context, ExitMethods) --> 
 	indent_line(Indent),
-	io__write_string("break;\n").
-output_stmt(Indent, _FuncInfo, goto(continue), _Context) --> 
-	indent_line(Indent),
-	io__write_string("continue;\n").
-output_stmt(_Indent, _FuncInfo, computed_goto(_Expr, _Labels), _Context) --> 
+	io__write_string("break;\n"),
+	{ ExitMethods = set__make_singleton_set(can_break) }.
+output_stmt(Indent, _FuncInfo, goto(continue), _Context, ExitMethods) --> 
+	indent_line(Indent),
+	io__write_string("continue;\n"),
+	{ ExitMethods = set__make_singleton_set(can_continue) }.
+output_stmt(_Indent, _FuncInfo, computed_goto(_Expr, _Labels), _Context,
+		_ExitMethods) --> 
 	{ unexpected(this_file, 
 		"output_stmt: computed gotos not supported in Java.") }.
 	
 	%
 	% function call/return
 	%
-output_stmt(Indent, CallerFuncInfo, Call, Context) -->
+output_stmt(Indent, CallerFuncInfo, Call, Context, ExitMethods) -->
 	{ Call = call(Signature, FuncRval, MaybeObject, CallArgs,
 		Results, _IsTailCall) },
 	{ CallerFuncInfo = func_info(_Name, _Params) },
@@ -2046,7 +2148,8 @@
 	% ),
 	%
 	indent_line(Indent),
-	io__write_string("}\n").
+	io__write_string("}\n"),
+	{ ExitMethods = set__make_singleton_set(can_fall_through) }.
 
 
 :- pred output_args_as_array(list(mlds__rval), list(mlds__type),
@@ -2078,7 +2181,7 @@
 	).
 
 
-output_stmt(Indent, FuncInfo, return(Results0), _Context) -->
+output_stmt(Indent, FuncInfo, return(Results0), _Context, ExitMethods) -->
 	%
 	% XXX It's not right to just remove the dummy variables like this,
 	%     but currently they do not seem to be included in the ReturnTypes
@@ -2093,7 +2196,8 @@
 	% 
 	{ Results = remove_dummy_vars(Results0) },
 	( { Results = [] } ->
-		[]
+		indent_line(Indent),
+		io__write_string("return;\n")
 	; { Results = [Rval] } ->
 		indent_line(Indent),
 		io__write_string("return "),
@@ -2109,23 +2213,26 @@
 			(pred((Type - Result)::in, di, uo) is det -->
 				output_boxed_rval(Type, Result))),
 		io__write_string("};\n")
-	).
+	),
+	{ ExitMethods = set__make_singleton_set(can_return) }.
 
-output_stmt(Indent, _FuncInfo, do_commit(Ref), _) -->
+output_stmt(Indent, _FuncInfo, do_commit(Ref), _, ExitMethods) -->
 	indent_line(Indent),
 	output_rval(Ref),
 	io__write_string(" = new mercury.runtime.Commit();\n"),
 	indent_line(Indent),
 	io__write_string("throw "),
 	output_rval(Ref),
-	io__write_string(";\n").
+	io__write_string(";\n"),
+	{ ExitMethods = set__make_singleton_set(can_throw) }.
 
-output_stmt(Indent, FuncInfo, try_commit(_Ref, Stmt, Handler), _) -->
+output_stmt(Indent, FuncInfo, try_commit(_Ref, Stmt, Handler), _,
+		ExitMethods) -->
 	indent_line(Indent),
 	io__write_string("try\n"),
 	indent_line(Indent),
 	io__write_string("{\n"),
-	output_statement(Indent + 1, FuncInfo, Stmt),
+	output_statement(Indent + 1, FuncInfo, Stmt, TryExitMethods0),
 	indent_line(Indent),
 	io__write_string("}\n"),
 	indent_line(Indent),
@@ -2133,9 +2240,11 @@
 	indent_line(Indent),
 	io__write_string("{\n"),
 	indent_line(Indent + 1),
-	output_statement(Indent + 1, FuncInfo, Handler),
+	output_statement(Indent + 1, FuncInfo, Handler, CatchExitMethods),
 	indent_line(Indent),
-	io__write_string("}\n").
+	io__write_string("}\n"),
+	{ ExitMethods = (TryExitMethods0 `set__delete` can_throw)
+				         `set__union`  CatchExitMethods }.
 
 
 
@@ -2212,16 +2321,44 @@
 % Extra code for outputting switch statements
 %
 
+:- pred output_switch_cases(indent, func_info, mlds__context,
+		list(mlds__switch_case), mlds__switch_default, exit_methods,
+		io__state, io__state).
+:- mode output_switch_cases(in, in, in, in, in, out, di, uo) is det.
+
+output_switch_cases(Indent, FuncInfo, Context, [], Default, ExitMethods) -->
+	output_switch_default(Indent, FuncInfo, Context, Default, ExitMethods).
+output_switch_cases(Indent, FuncInfo, Context, [Case|Cases], Default,
+		ExitMethods) -->
+	output_switch_case(Indent, FuncInfo, Context, Case, CaseExitMethods0),
+	output_switch_cases(Indent, FuncInfo, Context, Cases, Default, 
+			CasesExitMethods),
+	( { set__member(can_break, CaseExitMethods0) } ->
+		{ CaseExitMethods = (CaseExitMethods0 `set__delete` can_break)
+				`set__insert` can_fall_through }
+	;
+		{ CaseExitMethods = CaseExitMethods0 }
+	),
+	{ ExitMethods = CaseExitMethods `set__union` CasesExitMethods }.
+
+
 :- pred output_switch_case(indent, func_info, mlds__context,
-		mlds__switch_case, io__state, io__state).
-:- mode output_switch_case(in, in, in, in, di, uo) is det.
+		mlds__switch_case, exit_methods, io__state, io__state).
+:- mode output_switch_case(in, in, in, in, out, di, uo) is det.
 
-output_switch_case(Indent, FuncInfo, Context, Case) -->
+output_switch_case(Indent, FuncInfo, Context, Case, ExitMethods) -->
 	{ Case = (Conds - Statement) },
 	list__foldl(output_case_cond(Indent, Context), Conds),
-	output_statement(Indent + 1, FuncInfo, Statement),
-	indent_line(Context, Indent + 1),
-	io__write_string("break;\n").
+	output_statement(Indent + 1, FuncInfo, Statement, StmtExitMethods),
+	( { set__member(can_fall_through, StmtExitMethods) } ->
+		indent_line(Context, Indent + 1),
+		io__write_string("break;\n"),
+		{ ExitMethods = (StmtExitMethods `set__insert` can_break)
+				`set__delete` can_fall_through }
+	;
+		% Don't output `break' since it would be unreachable.
+		{ ExitMethods = StmtExitMethods }
+	).
 
 :- pred output_case_cond(indent, mlds__context, mlds__case_match_cond, 
 		io__state, io__state).
@@ -2237,20 +2374,24 @@
 		"output_case_cond: cannot match ranges in Java cases") }.
 
 :- pred output_switch_default(indent, func_info, mlds__context,
-		mlds__switch_default, io__state, io__state).
-:- mode output_switch_default(in, in, in, in, di, uo) is det.
+		mlds__switch_default, exit_methods, io__state, io__state).
+:- mode output_switch_default(in, in, in, in, out, di, uo) is det.
 
-output_switch_default(_Indent, _FuncInfo, _Context, default_do_nothing) --> 
-	[].
-output_switch_default(Indent, FuncInfo, Context, default_case(Statement)) -->
+output_switch_default(_Indent, _FuncInfo, _Context, default_do_nothing,
+		ExitMethods) -->
+	{ ExitMethods = set__make_singleton_set(can_fall_through) }.
+output_switch_default(Indent, FuncInfo, Context, default_case(Statement),
+		ExitMethods) -->
 	indent_line(Context, Indent),
 	io__write_string("default:\n"),
-	output_statement(Indent + 1, FuncInfo, Statement).
-output_switch_default(Indent, _FuncInfo, Context, default_is_unreachable) -->
+	output_statement(Indent + 1, FuncInfo, Statement, ExitMethods).
+output_switch_default(Indent, _FuncInfo, Context, default_is_unreachable,
+		ExitMethods) -->
 	indent_line(Context, Indent),
 	io__write_string("default: /*NOTREACHED*/\n"), 
 	indent_line(Context, Indent + 1),
-	io__write_string("throw new mercury.runtime.UnreachableDefault();\n").
+	io__write_string("throw new mercury.runtime.UnreachableDefault();\n"),
+	{ ExitMethods = set__make_singleton_set(can_throw) }.
 
 %-----------------------------------------------------------------------------%
 
@@ -2264,8 +2405,10 @@
 	%
 	% atomic statements
 	%
-output_stmt(Indent, FuncInfo, atomic(AtomicStatement), Context) -->
-	output_atomic_stmt(Indent, FuncInfo, AtomicStatement, Context).
+output_stmt(Indent, FuncInfo, atomic(AtomicStatement), Context,
+		ExitMethods) -->
+	output_atomic_stmt(Indent, FuncInfo, AtomicStatement, Context),
+	{ ExitMethods = set__make_singleton_set(can_fall_through) }.
 
 :- pred output_atomic_stmt(indent, func_info,
 		mlds__atomic_statement, mlds__context, io__state, io__state).

--------------------------------------------------------------------------
mercury-reviews mailing list
post:  mercury-reviews at cs.mu.oz.au
administrative address: owner-mercury-reviews at cs.mu.oz.au
unsubscribe: Address: mercury-reviews-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-reviews-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the reviews mailing list