Skip to content

Commit 235e2be

Browse files
committed
Impl updating files when rerun succeeded
1 parent de06648 commit 235e2be

File tree

6 files changed

+211
-99
lines changed

6 files changed

+211
-99
lines changed

src/App.re

Lines changed: 3 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,100 +1,12 @@
1-
open Goblint_lib;
2-
open Batteries;
3-
open Js_of_ocaml;
41
open Lwt.Infix;
5-
module Cabs2cil = GoblintCil.Cabs2cil;
6-
7-
exception InitFailed(string);
8-
9-
let init_cil = environment => {
10-
// Restore the environment hash table, which
11-
// syntacticsearch uses to map temporary variables created
12-
// by CIL to their original counterparts.
13-
Hashtbl.clear(Cabs2cil.environment);
14-
environment
15-
|> Hashtbl.enum
16-
|> Enum.iter(((k, v)) => Hashtbl.add(Cabs2cil.environment, k, v));
17-
};
18-
19-
// Each Goblint analysis module is assigned an ID, and this
20-
// ID depends on the module registration order, which might
21-
// differ from build to build. This function reorders the
22-
// analysis list to match the native version of Goblint.
23-
let renumber_goblint_analyses = registered_name => {
24-
let old_registered = Hashtbl.copy(MCP.registered);
25-
let old_registered_name = Hashtbl.copy(MCP.registered_name);
26-
Hashtbl.clear(MCP.registered);
27-
Hashtbl.clear(MCP.registered_name);
28-
Hashtbl.iter((name, id) => {
29-
let old_id = Hashtbl.find(old_registered_name, name);
30-
let spec = Hashtbl.find(old_registered, old_id);
31-
Hashtbl.replace(MCP.registered, id, spec);
32-
Hashtbl.replace(MCP.registered_name, name, id);
33-
}, registered_name);
34-
};
35-
36-
let init_goblint = (solver, spec, registered_name, config, cil) => {
37-
AfterConfig.run(); // This registers the "base" analysis
38-
39-
try(renumber_goblint_analyses(registered_name)) {
40-
| Not_found =>
41-
raise(InitFailed("Failed to renumber Goblint analyses"))
42-
};
43-
44-
Sys.chdir("/"); // Don't remove this
45-
46-
Sys_js.create_file(~name="/goblint/solver.marshalled", ~content=solver);
47-
Sys_js.create_file(~name="/goblint/config.json", ~content=config);
48-
Sys_js.create_file(~name="/goblint/spec_marshal", ~content=spec);
49-
50-
GobConfig.merge_file(Fpath.v("/goblint/config.json"));
51-
52-
GobConfig.set_bool("dbg.verbose", true);
53-
// TODO: Uncomment this to improve performance in future
54-
// GobConfig.set_bool("verify", false);
55-
56-
// For some reason, the standard Batteries output channels
57-
// appear to be closed by default and writing to them
58-
// raises [BatInnerIO.Output_closed]. This fixes it.
59-
let out = IO.output_channel(Stdlib.stdout);
60-
Messages.formatter := Format.formatter_of_output(out);
61-
62-
GobConfig.set_string("load_run", "goblint");
63-
64-
// These two will be set by config.json. Reset them.
65-
GobConfig.set_string("save_run", "");
66-
GobConfig.set_bool("gobview", false);
67-
68-
GobConfig.set_auto("trans.activated[+]", "'expeval'");
69-
70-
Cilfacade.init();
71-
Maingoblint.handle_extraspecials();
72-
Maingoblint.handle_flags();
73-
74-
// NOTE: Commenting this out since it breaks the node view. Semantic search
75-
// may depend on this code but it is currently broken because of unrelated
76-
// (and uknown) reasons anyway.
77-
// Cil.iterGlobals(cil, glob =>
78-
// switch (glob) {
79-
// | GFun(fd, _) =>
80-
// Cil.prepareCFG(fd);
81-
// Cil.computeCFGInfo(fd, true);
82-
// | _ => ()
83-
// }
84-
// );
85-
Cilfacade.current_file := cil;
86-
87-
let goblint = GvGoblint.unmarshal(spec, cil);
88-
89-
(goblint, cil);
90-
};
2+
open Init;
913

924
let init = (solver, spec, config, meta, cil, analyses, warnings, stats, file_loc) => {
935
let cil =
946
switch (cil) {
957
| Ok(s) =>
968
let (c, e) = Marshal.from_string(s, 0);
97-
init_cil(e);
9+
Init.init_cil(e);
9810
c;
9911
| _ => raise(InitFailed("Failed to load CIL state"))
10012
};
@@ -172,6 +84,6 @@ let handle_error = exc => {
17284
| exc => handle_error(exc)
17385
}
17486
| _ => ()
175-
},
87+
}
17688
)
17789
);

src/Init.re

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
open Goblint_lib;
2+
open Batteries;
3+
open Js_of_ocaml;
4+
open Lwt.Infix;
5+
module Cabs2cil = GoblintCil.Cabs2cil;
6+
7+
exception InitFailed(string);
8+
9+
let init_cil = environment => {
10+
// Restore the environment hash table, which
11+
// syntacticsearch uses to map temporary variables created
12+
// by CIL to their original counterparts.
13+
Hashtbl.clear(Cabs2cil.environment);
14+
environment
15+
|> Hashtbl.enum
16+
|> Enum.iter(((k, v)) => Hashtbl.add(Cabs2cil.environment, k, v));
17+
};
18+
19+
// Each Goblint analysis module is assigned an ID, and this
20+
// ID depends on the module registration order, which might
21+
// differ from build to build. This function reorders the
22+
// analysis list to match the native version of Goblint.
23+
let renumber_goblint_analyses = registered_name => {
24+
let old_registered = Hashtbl.copy(MCP.registered);
25+
let old_registered_name = Hashtbl.copy(MCP.registered_name);
26+
Hashtbl.clear(MCP.registered);
27+
Hashtbl.clear(MCP.registered_name);
28+
Hashtbl.iter((name, id) => {
29+
let old_id = Hashtbl.find(old_registered_name, name);
30+
let spec = Hashtbl.find(old_registered, old_id);
31+
Hashtbl.replace(MCP.registered, id, spec);
32+
Hashtbl.replace(MCP.registered_name, name, id);
33+
}, registered_name);
34+
};
35+
36+
let init_goblint = (solver, spec, registered_name, config, cil) => {
37+
AfterConfig.run(); // This registers the "base" analysis
38+
39+
try(renumber_goblint_analyses(registered_name)) {
40+
| Not_found =>
41+
raise(InitFailed("Failed to renumber Goblint analyses"))
42+
};
43+
44+
Sys.chdir("/"); // Don't remove this
45+
46+
Sys_js.create_file(~name="/goblint/solver.marshalled", ~content=solver);
47+
Sys_js.create_file(~name="/goblint/config.json", ~content=config);
48+
Sys_js.create_file(~name="/goblint/spec_marshal", ~content=spec);
49+
50+
GobConfig.merge_file(Fpath.v("/goblint/config.json"));
51+
52+
GobConfig.set_bool("dbg.verbose", true);
53+
// TODO: Uncomment this to improve performance in future
54+
// GobConfig.set_bool("verify", false);
55+
56+
// For some reason, the standard Batteries output channels
57+
// appear to be closed by default and writing to them
58+
// raises [BatInnerIO.Output_closed]. This fixes it.
59+
let out = IO.output_channel(Stdlib.stdout);
60+
Messages.formatter := Format.formatter_of_output(out);
61+
62+
GobConfig.set_string("load_run", "goblint");
63+
64+
// These two will be set by config.json. Reset them.
65+
GobConfig.set_string("save_run", "");
66+
GobConfig.set_bool("gobview", false);
67+
68+
GobConfig.set_auto("trans.activated[+]", "'expeval'");
69+
70+
Cilfacade.init();
71+
Maingoblint.handle_extraspecials();
72+
Maingoblint.handle_flags();
73+
74+
// NOTE: Commenting this out since it breaks the node view. Semantic search
75+
// may depend on this code but it is currently broken because of unrelated
76+
// (and uknown) reasons anyway.
77+
// Cil.iterGlobals(cil, glob =>
78+
// switch (glob) {
79+
// | GFun(fd, _) =>
80+
// Cil.prepareCFG(fd);
81+
// Cil.computeCFGInfo(fd, true);
82+
// | _ => ()
83+
// }
84+
// );
85+
Cilfacade.current_file := cil;
86+
87+
let goblint = GvGoblint.unmarshal(spec, cil);
88+
89+
(goblint, cil);
90+
};
91+
92+
// function for reloading specific files when rerunning analysis
93+
let reload = (cil) => {
94+
[
95+
// files to be reloaded
96+
"./solver.marshalled",
97+
"./warnings.marshalled",
98+
"./stats.marshalled",
99+
100+
// required for solver, solver alone cannot update
101+
"./spec_marshal",
102+
"./analyses.marshalled",
103+
"./config.json",
104+
]
105+
|> List.map(HttpClient.get)
106+
|> Lwt.all
107+
>>= (l) => {
108+
Lwt.return(switch (l) {
109+
| [solver, warnings, stats, spec, analyses, config] => {
110+
111+
let goblintAndCil =
112+
switch (solver, spec, analyses, config) {
113+
| (Ok(s), Ok(spec), Ok(t), Ok(c)) => {
114+
let t = Marshal.from_string(t, 0);
115+
Some(init_goblint(s, spec, t, c, cil))
116+
}
117+
| _ => {
118+
Util.error_without_fail("Failed to load Goblint state");
119+
None
120+
}
121+
};
122+
print_endline("Initialized Goblint");
123+
124+
let warnings =
125+
switch (warnings) {
126+
| Ok(s) => Some(Marshal.from_string(s, 0))
127+
| _ => Util.error_without_fail("Failed to load the warning table"); None
128+
};
129+
print_endline("Restored the warning table");
130+
131+
let stats =
132+
switch (stats) {
133+
| Ok(s) => Some(Marshal.from_string(s, 0))
134+
| _ => Util.error_without_fail("Failed to load runtime stats"); None
135+
};
136+
137+
Some((goblintAndCil, warnings, stats))
138+
}
139+
| _ => None
140+
})
141+
}
142+
};

src/Main.re

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,65 @@
11
open Batteries;
2+
open Lwt.Infix;
23

34
[@react.component]
45
let make = (~cil, ~goblint, ~warnings, ~meta, ~stats, ~file_loc) => {
6+
let (analysisState, setAnalysisState) = React.useState(_ => Option.some(ParameterView.Executed));
7+
8+
// reloadable components of goblint due to rerunning analyses
9+
let (cil_, setCil_) = React.useState(_ => cil);
10+
let (goblint_, setGoblint_) = React.useState(_ => goblint);
11+
let (warnings_, setWarnings_) = React.useState(_ => warnings);
12+
let (stats_, setStats_) = React.useState(_ => stats);
13+
14+
React.useEffect1(() => {
15+
switch (analysisState) {
16+
| Some(s) => {
17+
if (ParameterView.is_successful(s)) {
18+
// reload files
19+
let reload = () => {
20+
Init.reload(cil_) >>=
21+
(result) => {
22+
switch (result) {
23+
| Some((goblintAndCil, warnings, stats)) => {
24+
let _ = switch (goblintAndCil) {
25+
| Some((goblint', cil')) => {
26+
setGoblint_(_ => goblint')
27+
setCil_(_ => cil');
28+
};
29+
| None => Util.error_without_fail("Could not reload goblint and cil for rerun")
30+
};
31+
32+
switch (warnings) {
33+
| Some(w) => setWarnings_(_ => w);
34+
| None => Util.error_without_fail("Could not reload warnings for rerun")
35+
};
36+
37+
switch (stats) {
38+
| Some(s) => setStats_(_ => s);
39+
| None => Util.error_without_fail("Could not reload stats for rerun")
40+
};
41+
};
42+
| None => Util.error_without_fail("Could not reload metrics for rerun")
43+
}
44+
45+
setAnalysisState(_ => None);
46+
Lwt.return();
47+
}
48+
};
49+
50+
ignore(reload());
51+
}
52+
}
53+
| None => setAnalysisState(_ => None);
54+
};
55+
56+
None
57+
}, [|analysisState|]);
58+
559
let (state, dispatch) =
660
React.useReducer(
761
Reducer.reducer,
8-
State.make(~cil, ~goblint, ~warnings, ~meta, ~stats, ~file_loc, ()),
62+
State.make(~cil=cil_, ~goblint=goblint_, ~warnings=warnings_, ~meta, ~stats=stats_, ~file_loc, ()),
963
);
1064

1165
let fetch_file =
@@ -81,12 +135,12 @@ let make = (~cil, ~goblint, ~warnings, ~meta, ~stats, ~file_loc) => {
81135
| None => <div className="content d-flex flex-column h-75 overflow-auto p-4" />
82136
| Some(f) => <Content state display=f dispatch />
83137
}}
84-
<Panel state dispatch goblint_path inputValue setInputValue disableRun setDisableRun inputState setInputState sortDesc setSortDesc history setHistory />
138+
<Panel state dispatch goblint_path inputValue setInputValue disableRun setDisableRun inputState setInputState sortDesc setSortDesc history setHistory setAnalysisState />
85139
</div>
86140
<div className="col-3 border-start overflow-auto py-2 h-100">
87141
<SidebarRight
88142
active={state.selected_sidebar_right}
89-
goblint
143+
goblint={goblint_}
90144
inspect={state.inspect}
91145
dispatch
92146
/>

src/Util.ml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
open Js_of_ocaml
22
let log s = Firebug.console##log (Js.string s)
3-
let error s = Firebug.console##error (Js.string s); failwith(s)
3+
let error_without_fail s = Firebug.console##error (Js.string s)
4+
let error s = error_without_fail(s); failwith(s)
45
let warning s = Firebug.console##warn (Js.string s)

src/ui/panel/Panel.re

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ let make_nav_pills = (current, dispatch) => {
3131
};
3232

3333
[@react.component]
34-
let make = (~state, ~dispatch, ~goblint_path, ~inputValue, ~setInputValue, ~disableRun, ~setDisableRun, ~inputState, ~setInputState, ~sortDesc, ~setSortDesc, ~history, ~setHistory) => {
34+
let make = (~state, ~dispatch, ~goblint_path, ~inputValue, ~setInputValue, ~disableRun, ~setDisableRun, ~inputState, ~setInputState, ~sortDesc, ~setSortDesc, ~history, ~setHistory, ~setAnalysisState) => {
3535

3636
let locations = (state.goblint)#dead_locations;
3737

@@ -41,7 +41,7 @@ let make = (~state, ~dispatch, ~goblint_path, ~inputValue, ~setInputValue, ~disa
4141
| Some(Warnings) => <WarningView warnings={state.warnings} dispatch />
4242
| Some(DeadCode) => <DeadCodeView locations dispatch />
4343
| Some(Statistics) => <GvStatisticsView stats={state.stats} />
44-
| Some(Parameters) => <ParameterView goblint_path inputValue setInputValue disableRun setDisableRun inputState setInputState sortDesc setSortDesc history setHistory />
44+
| Some(Parameters) => <ParameterView goblint_path inputValue setInputValue disableRun setDisableRun inputState setInputState sortDesc setSortDesc history setHistory setAnalysisState/>
4545
| _ => React.null
4646
};
4747

src/ui/panel/ParameterView.re

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ let headers = [
5959
] |> Header.of_list;
6060

6161
[@react.component]
62-
let make = (~goblint_path, ~inputValue, ~setInputValue, ~disableRun, ~setDisableRun, ~inputState, ~setInputState, ~sortDesc, ~setSortDesc, ~history, ~setHistory) => {
62+
let make = (~goblint_path, ~inputValue, ~setInputValue, ~disableRun, ~setDisableRun, ~inputState, ~setInputState, ~sortDesc, ~setSortDesc, ~history, ~setHistory, ~setAnalysisState) => {
6363
// Linked to cancelation, see reasons below in on_cancel() for why it is commented out
6464
//let (disableCancel, setDisableCancel) = React.useState(_ => true);
6565

@@ -165,13 +165,15 @@ let make = (~goblint_path, ~inputValue, ~setInputValue, ~disableRun, ~setDisable
165165

166166
if (inputState == Ok && !is_malformed && !disableRun) {
167167
let time = Time.get_local_time();
168-
let element = (parameter_list, time, Executing, "");
168+
let init_state = Executing;
169+
let element = (parameter_list, time, init_state, "");
169170

170171
let new_history = List.cons(element, history);
171172

172173
setHistory(_ => new_history);
173174
//setDisableCancel(_ => false);
174175
setDisableRun(_ => true);
176+
setAnalysisState(_ => Some(init_state));
175177

176178
let modify_history = (result: paramState, response_msg: string): unit => {
177179
let pickedElem = new_history |> List.hd;
@@ -182,6 +184,7 @@ let make = (~goblint_path, ~inputValue, ~setInputValue, ~disableRun, ~setDisable
182184
setHistory(_ => new_history);
183185
//setDisableCancel(_ => true);
184186
setDisableRun(_ => false);
187+
setAnalysisState(_ => Some(result));
185188
}
186189
}
187190

0 commit comments

Comments
 (0)