Skip to content

Commit fd6e195

Browse files
author
Thomas Kiley
authored
Merge pull request #1718 from cesaro/concurrency-team-small-fixes
Adding concurrency to Java
2 parents e6fe617 + 22afc5c commit fd6e195

File tree

12 files changed

+182
-52
lines changed

12 files changed

+182
-52
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ src/ansi-c/library/converter
117117
src/ansi-c/library/converter.exe
118118
src/util/irep_ids_convert
119119
src/util/irep_ids_convert.exe
120+
build/
120121

121122
*.pyc
122123

276 Bytes
Binary file not shown.
261 Bytes
Binary file not shown.
272 Bytes
Binary file not shown.
726 Bytes
Binary file not shown.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
public class static_init_order
2+
{
3+
// as per the Java Virtual Machine Specification,
4+
// section 5.5, p. 35 we expect the static initializer of
5+
// the parent class to be called before the static initializer
6+
// of the class in question.
7+
//
8+
// The following tests will verify the aforementioned behaviour.
9+
10+
public static void test1()
11+
{
12+
C object2 = new C();
13+
B object = new B();
14+
if(object2.x != 20)
15+
// order of init is: C.clint, B.clint, A.clint
16+
// This should not be reachable as expected order
17+
// should be: C.clint, A.clint, B.clint.
18+
assert(false);
19+
}
20+
21+
public static void test2()
22+
{
23+
C object2 = new C();
24+
B object = new B();
25+
// Assertion is expected to fail,
26+
// as the only way for object2.x
27+
// to be assigned a value of 10 is through
28+
// the following incorrect ordering of init calls:
29+
// C.clint, B.clint, A.clint
30+
assert(object2.x == 10);
31+
}
32+
}
33+
34+
class C
35+
{
36+
public static int x = 0;
37+
}
38+
39+
class A
40+
{
41+
static {
42+
C.x=10;
43+
}
44+
}
45+
46+
class B extends A
47+
{
48+
static {
49+
C.x=20;
50+
}
51+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
static_init_order.class
3+
--function static_init_order.test1 --trace
4+
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
^VERIFICATION SUCCESSFUL$
8+
--
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
static_init_order.class
3+
--function static_init_order.test2
4+
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
^VERIFICATION FAILED$
8+
--

src/ansi-c/expr2c.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2968,6 +2968,12 @@ std::string expr2ct::convert_code(
29682968
if(statement=="unlock")
29692969
return convert_code_unlock(src, indent);
29702970

2971+
if(statement==ID_atomic_begin)
2972+
return indent_str(indent)+"__CPROVER_atomic_begin();";
2973+
2974+
if(statement==ID_atomic_end)
2975+
return indent_str(indent)+"__CPROVER_atomic_end();";
2976+
29712977
if(statement==ID_function_call)
29722978
return convert_code_function_call(to_code_function_call(src), indent);
29732979

src/goto-programs/goto_convert.cpp

Lines changed: 64 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -344,23 +344,33 @@ void goto_convertt::convert_label(
344344

345345
goto_programt tmp;
346346

347-
// magic thread creation label?
347+
// magic thread creation label.
348+
// The "__CPROVER_ASYNC_" signals the start of a sequence of instructions
349+
// that can be executed in parallel, i.e, a new thread.
348350
if(has_prefix(id2string(label), "__CPROVER_ASYNC_"))
349351
{
350-
// this is like a START_THREAD
351-
codet tmp_code(ID_start_thread);
352-
tmp_code.copy_to_operands(code.op0());
353-
tmp_code.add_source_location()=code.source_location();
354-
convert(tmp_code, tmp);
352+
// the body of the thread is expected to be
353+
// in the operand.
354+
INVARIANT(code.op0().is_not_nil(),
355+
"op0 in magic thread creation label is null");
356+
357+
// replace the magic thread creation label with a
358+
// thread block (START_THREAD...END_THREAD).
359+
code_blockt thread_body;
360+
thread_body.add(to_code(code.op0()));
361+
thread_body.add_source_location()=code.source_location();
362+
generate_thread_block(thread_body, dest);
355363
}
356364
else
365+
{
357366
convert(to_code(code.op0()), tmp);
358367

359-
goto_programt::targett target=tmp.instructions.begin();
360-
dest.destructive_append(tmp);
368+
goto_programt::targett target=tmp.instructions.begin();
369+
dest.destructive_append(tmp);
361370

362-
targets.labels.insert({label, {target, targets.destructor_stack}});
363-
target->labels.push_front(label);
371+
targets.labels.insert({label, {target, targets.destructor_stack}});
372+
target->labels.push_front(label);
373+
}
364374
}
365375

366376
void goto_convertt::convert_gcc_local_label(
@@ -1539,39 +1549,14 @@ void goto_convertt::convert_start_thread(
15391549
const codet &code,
15401550
goto_programt &dest)
15411551
{
1542-
if(code.operands().size()!=1)
1543-
{
1544-
error().source_location=code.find_source_location();
1545-
error() << "start_thread expects one operand" << eom;
1546-
throw 0;
1547-
}
1548-
15491552
goto_programt::targett start_thread=
15501553
dest.add_instruction(START_THREAD);
1551-
15521554
start_thread->source_location=code.source_location();
1555+
start_thread->code=code;
15531556

1554-
{
1555-
// start_thread label;
1556-
// goto tmp;
1557-
// label: op0-code
1558-
// end_thread
1559-
// tmp: skip
1560-
1561-
goto_programt::targett goto_instruction=dest.add_instruction(GOTO);
1562-
goto_instruction->guard=true_exprt();
1563-
goto_instruction->source_location=code.source_location();
1564-
1565-
goto_programt tmp;
1566-
convert(to_code(code.op0()), tmp);
1567-
goto_programt::targett end_thread=tmp.add_instruction(END_THREAD);
1568-
end_thread->source_location=code.source_location();
1569-
1570-
start_thread->targets.push_back(tmp.instructions.begin());
1571-
dest.destructive_append(tmp);
1572-
goto_instruction->targets.push_back(dest.add_instruction(SKIP));
1573-
dest.instructions.back().source_location=code.source_location();
1574-
}
1557+
// remember it to do target later
1558+
targets.gotos.push_back(
1559+
std::make_pair(start_thread, targets.destructor_stack));
15751560
}
15761561

15771562
void goto_convertt::convert_end_thread(
@@ -2242,3 +2227,43 @@ void goto_convert(
22422227

22432228
::goto_convert(to_code(symbol.value), symbol_table, dest, message_handler);
22442229
}
2230+
2231+
/// Generates the necessary goto-instructions to represent a thread-block.
2232+
/// Specifically, the following instructions are generated:
2233+
///
2234+
/// A: START_THREAD : C
2235+
/// B: GOTO Z
2236+
/// C: SKIP
2237+
/// D: {THREAD BODY}
2238+
/// E: END_THREAD
2239+
/// Z: SKIP
2240+
///
2241+
/// \param thread_body: sequence of codet's that can be executed
2242+
/// in parallel.
2243+
/// \param [out] dest: resulting goto-instructions.
2244+
void goto_convertt::generate_thread_block(
2245+
const code_blockt &thread_body,
2246+
goto_programt &dest)
2247+
{
2248+
goto_programt preamble, body, postamble;
2249+
2250+
goto_programt::targett c=body.add_instruction();
2251+
c->make_skip();
2252+
convert(thread_body, body);
2253+
2254+
goto_programt::targett e=postamble.add_instruction(END_THREAD);
2255+
e->source_location=thread_body.source_location();
2256+
goto_programt::targett z=postamble.add_instruction();
2257+
z->make_skip();
2258+
2259+
goto_programt::targett a=preamble.add_instruction(START_THREAD);
2260+
a->source_location=thread_body.source_location();
2261+
a->targets.push_back(c);
2262+
goto_programt::targett b=preamble.add_instruction();
2263+
b->source_location=thread_body.source_location();
2264+
b->make_goto(z);
2265+
2266+
dest.destructive_append(preamble);
2267+
dest.destructive_append(body);
2268+
dest.destructive_append(postamble);
2269+
}

0 commit comments

Comments
 (0)