]> git.lizzy.rs Git - rust.git/blob - src/test/codegen/coverage-experiments/src/coverage_injection_test2.rs
explained lang_item function body (count_code_region)
[rust.git] / src / test / codegen / coverage-experiments / src / coverage_injection_test2.rs
1 /*                       */ use std::io::Error;
2 /*                       */ use std::io::ErrorKind;
3 /*                       */
4 /*                       */ /// Align Rust counter increment with with:
5 /*                       */ /// [‘llvm.instrprof.increment’ Intrinsic](https://llvm.org/docs/LangRef.html#llvm-instrprof-increment-intrinsic)
6 /*                       */ ///
7 /*                       */ /// declare void @llvm.instrprof.increment(i8* <name>, i64 <hash>, i32 <num-counters>, i32 <index>)
8 /*                       */ ///
9 /*                       */ /// The first argument is a pointer to a global variable containing the name of the entity
10 /*                       */ /// being instrumented. This should generally be the (mangled) function name for a set of
11 /*                       */ /// counters.
12 /*                       */ ///
13 /*                       */ /// The second argument is a hash value that can be used by the consumer of the profile data
14 /*                       */ /// to detect changes to the instrumented source, and the third is the number of counters
15 /*                       */ /// associated with name. It is an error if hash or num-counters differ between two
16 /*                       */ /// instances of instrprof.increment that refer to the same name.
17 /*                       */ ///
18 /*                       */ /// The last argument refers to which of the counters for name should be incremented. It
19 /*                       */ /// should be a value between 0 and num-counters.
20 /*                       */ ///
21 /*                       */ /// # Arguments
22 /*                       */ ///
23 /*                       */ /// `mangled_fn_name` - &'static ref to computed and injected static str, using:
24 /*                       */ ///
25 /*                       */ ///     ```
26 /*                       */ ///     fn rustc_symbol_mangling::compute_symbol_name(
27 /*                       */ ///         tcx: TyCtxt<'tcx>,
28 /*                       */ ///         instance: Instance<'tcx>,
29 /*                       */ ///         compute_instantiating_crate: impl FnOnce() -> CrateNum,
30 /*                       */ ///     ) -> String
31 /*                       */ ///     ```
32 /*                       */ ///
33 /*                       */ /// `source_version_hash` - Compute hash based that only changes if there are "significant"
34 /*                       */ /// to control-flow inside the function.
35 /*                       */ ///
36 /*                       */ /// `num_counters` - The total number of counter calls [MAX(counter_index) + 1] within the
37 /*                       */ /// function.
38 /*                       */ ///
39 /*                       */ /// `counter_index` - zero-based counter index scoped by the function. (Ordering of
40 /*                       */ /// counters, relative to the source code location, is apparently not expected.)
41 /*                       */ ///
42 /*                       */ /// # Notes
43 /*                       */ ///
44 /*                       */ /// * The mangled_fn_name may not be computable until generics are monomorphized (see
45 /*                       */ ///   parameters required by rustc_symbol_mangling::compute_symbol_name).
46 /*                       */ /// * The version hash may be computable from AST analysis, and may not benefit from further
47 /*                       */ ///   lowering.
48 /*                       */ /// * num_counters depends on having already identified all counter insertion locations.
49 /*                       */ /// * counter_index can be computed at time of counter insertion (incrementally).
50 /*                       */ /// * Numeric parameters are signed to match the llvm increment intrinsic parameter types.
51 /*                       */ fn __lower_incr_cov(_mangled_fn_name: &'static str, _fn_version_hash: i64, _num_counters: i32, _counter_index: i32) {
52 /*                       */ }
53 /*                       */
54 /*                       */ /// A coverage counter implementation that will work as both an intermediate coverage
55 /*                       */ /// counting and reporting implementation at the AST-level only--for debugging and
56 /*                       */ /// development--but also serves as a "marker" to be replaced by calls to LLVM
57 /*                       */ /// intrinsic coverage counter APIs during the lowering process.
58 /*                       */ ///
59 /*                       */ /// Calls to this function will be injected automatically into the AST. When LLVM intrinsics
60 /*                       */ /// are enabled, the counter function calls that were injected into the AST serve as
61 /*                       */ /// placeholders, to be replaced by an alternative, such as:
62 /*                       */ ///
63 /*                       */ ///     * direct invocation of the `llvm.instrprof.increment()` intrinsic; or
64 /*                       */ ///     * the `__lower_incr_cov()` function, defined above, that would invoke the
65 /*                       */ ///       `llvm.instrprof.increment()` intrinsic; or
66 /*                       */ ///     * a similar expression wrapper, with the additional parameters (as defined above
67 /*                       */ ///       for `__lower_incr_cov()`, that invokes `llvm.instrprof.increment()` and returns the
68 /*                       */ ///       result of the wrapped expression)
69 /*                       */ ///
70 /*                       */ /// The first two options would require replacing the inlined wrapper call with something
71 /*                       */ /// like:
72 /*                       */ ///
73 /*                       */ /// ```
74 /*                       */ /// { let result = {expr}; __inlined_incr_cov(context, counter); result }
75 /*                       */ /// ```
76 /*                       */ ///
77 /*                       */ /// But if the lowering process is already unwrapping the inlined call to `__incr_cov()`, then
78 /*                       */ /// it may be a perfect opportunity to replace the function with one of these more
79 /*                       */ /// direct methods.
80 /*                       */ ///
81 /*                       */ #[inline(always)]
82 /*                       */ pub fn __incr_cov(region_loc: &str) {
83 /*                       */     // Either call the intermediate non-llvm coverage counter API or
84 /*                       */     // replace the call to this function with the expanded `__lower_incr_cov()` call.
85 /*                       */
86 /*                       */     // let _lock = increment_counter(counter);
87 /*                       */     println!("{}", region_loc);
88 /*                       */ }
89 /*                       */
90 /*                       */ /// Write a report identifying each incremented counter and the number of times each counter
91 /*                       */ /// was incremented.
92 /*                       */ fn __report() {
93 /*                       */     println!("WRITE REPORT!");
94 /*                       */ }
95 /*                       */
96 /*                       */ macro_rules! from {
97 /*                       */     ($from:expr) => { &format!("from: {}\n  to: {}:{}:{}", $from, file!(), line!(), column!()) };
98 /*                       */ }
99 /*                       */
100 /*                       */ #[derive(Debug)]
101 /*                       */ enum TestEnum {
102 /*                       */     Red,
103 /*                       */     Green,
104 /*                       */     Blue,
105 /*                       */ }
106 /*                       */
107 /*                       */ struct TestStruct {
108 /*                       */     field: i32,
109 /*                       */ }
110 /*                       */
111 /*                       */ // IMPORTANT! IS WRAPPING main() ENOUGH? OR DO I ALSO NEED TO WRAP THREAD FUNCTIONS, ASSUMING
112 /*                       */ // THEY ARE STILL RUNNING WITH MAIN EXITS? (IF THEY CAN). NOT SURE HOW RUST HANDLES THAT.
113 /*                       */
114 /*                       */ // I SUSPECT USING THREAD_LOCAL COUNTERS MAY NOT ACTUALLY BE AN OPTIMIZATION OVER MUTEX LOCKS,
115 /*                       */ // BUT MAYBE I SHOULD ASK.
116 /*                       */
117 /*                       */ impl TestStruct {
118 /*    -                  */     fn new() -> Self {
119 /*    ┃                  */         let __result = Self::new_with_value(31415); // function-scoped counter index = 0
120 /*    ┃                  */         __incr_cov(from!("fn new()"));
121 /*    ┃                  */         __result
122 /*    -                  */     }
123 /*                       */
124 /*    -                  */     fn new_with_value(field: i32) -> Self {
125 /*    ┃                  */         let __result = Self {
126 /*    ┃                  */             field,
127 /*    ┃                  */         };
128 /*    ┃                  */         __incr_cov(from!("fn new_with_value()")); // function-scoped counter index = 0
129 /*    ┃                  */         __result
130 /*    -                  */     }
131 /*                       */
132 /*                       */     fn call_closure<F>(&self, closure: F) -> bool
133 /*                       */     where
134 /*                       */         F: FnOnce(
135 /*                       */             i32,
136 /*                       */         ) -> bool,
137 /*    -                  */     {
138 /*    ┃                  */         let __result = closure(123);
139 /*    ┃                  */         __incr_cov(from!("fn call_closure()")); // function-scoped counter index = 0
140 /*    ┃                  */         __result
141 /*    -                  */     }
142 /*                       */
143 /*    -                  */     fn various(&self) -> Result<(),Error> {
144 /*    ┃                  */         use TestEnum::*;
145 /*    ┃                  */         let mut color = Red;
146 /*    ┃                  */         let _ = color;
147 /*    ┃                  */         color = Blue;
148 /*    ┃                  */         let _ = color;
149 /*    ┃                  */         color = Green;
150 /*    ┃                  */         match { let __result = color; __incr_cov(from!("fn various")); __result } { // function-scoped counter index = 0
151 /*    :                  */
152 /*    :                  */             // !!! RECORD SPAN FROM START OF INNERMOST CONTAINING BLOCK (THE FUNCTION IN THIS CASE) TO END OF MATCH EXPRESSION
153 /*    :                  */             // If `match`, `while`, `loop`, `for`, `if`, etc. expression has a `return`, `break`, or `continue`
154 /*    :                  */             // (if legal), then RECORD SPAN FROM START OF INNERMOST CONTAINING BLOCK TO END OF `return` EXPRESSION
155 /*    :                  */             // If the expression includes lazy booleans, nest calls to `__incr_cov()`.
156 /*    :   I              */             Red => {println!("roses"); __incr_cov(from!("Red => or end of MatchArmGuard expression inside pattern, if any"));}
157 /*    :   -              */             Green => {
158 /*    :   ┃              */                 let spidey = 100;
159 /*    :   ┃              */                 let goblin = 50;
160 /*    :   ┃              */                 // if spidey > goblin {__incr_cov(from!(""),{
161 /*    :   ┃              */                 //     println!("what ev");
162 /*    :   ┃              */                 // })}
163 /*    :   ┃              */                 // ACTUALLY, WRAPPING THE ENTIRE IF BLOCK IN `__incr_cov` IS NOT A GREAT GENERAL RULE.
164 /*    :   ┃              */                 // JUST INSERTING A `return`, `break`, or `continue` IN THAT BLOCK (without an intermediate condition)
165 /*    :   ┃              */                 // MAKES THE `__incr_cov()` CALL UNREACHABLE!
166 /*    :   ┃              */                 // MY ORIGINAL SOLUTION WORKS BETTER (WRAP LAST EXPRESSION OR AFTER LAST SEMICOLON STATEMENT IN BLOCK)
167 /*    :   ┃              */                 // UNLESS THE EXPRESSION IS NOT A BLOCK.
168 /*    :   ┃   -          */                 if { let __result = spidey > goblin; __incr_cov(from!("Green => or end of MatchArmGuard expression inside pattern, if any")); __result } {
169 /*    :   :   ┃          */                     println!("spidey beats goblin");
170 /*    :   :   ┃          */                     __incr_cov(from!("block start"));
171 /*    :   ┃   -          */                 } else if { let __result = spidey == goblin; __incr_cov(from!("`else if` on this line")); __result } {
172 /*    :   :   ┃          */                     // COVERAGE NOTE: Do we mark only the expression span (that may be trivial, as in this case),
173 /*    :   :   ┃          */                     // or associate it with the outer block, similar to how the `if` expression is associated with
174 /*    :   :   ┃          */                     // the outer block? (Although it is a continuation, in a sense, it is discontiguous in this case,
175 /*    :   :   ┃          */                     // so I think simpler to just make it its own coverage region.)
176 /*    :   :   ┃          */                     println!("it's a draw");
177 /*    :   :   ┃          */                     __incr_cov(from!("block start"));
178 /*    :   ┃   -   -   -  */                 } else if if { let __result = true; __incr_cov(from!("`else if` on this line")); __result } {
179 /*    :   :       :   ┃  */                             // return __incr_cov(from!("after `if true`"),Ok(()));
180 /*    :   :       :   ┃  */                             // ACTUALLY, BECAUSE OF `return`, WE DO NOT RECORD THE `if true` EVEN THOUGH WE COVERED IT.
181 /*    :   :       :   ┃  */                             // IN FACT, IF THIS NESTED CONDITIONAL IN A CONDITIONAL EXPRESSION WAS AN `if` (WITHOUT PRECEDING ELSE)
182 /*    :   :       :   ┃  */                             // WE WOULD NOT HAVE RECORDED THE COVERAGE OF STATEMENTS LEADING UP TO THE `if`, SO
183 /*    :   :       :   ┃  */                             // IT SHOULD BE:
184 /*  ┏-:---:-------:---<  */                             return { let __result = Ok(()); __incr_cov(from!("")); __result };
185 /*  V :   :       :   :  */                             // NOTE THE `from` STRING IS SAME FOR THE `else if`s `__incr_cov` AND THIS `return`.
186 /*    :   :       :   :  */                             // ONLY ONE OF THESE WILL EXECUTE, TO RECORD COVERAGE FROM THAT SPOT.
187 /*    :   :       ┃   -  */                         } else {
188 /*    :   :       :   I  */                             { let __result = false; __incr_cov(from!("`else`")); __result }
189 /*    :   :   -   -      */                         } {
190 /*    :   :   ┃          */                     println!("wierd science");
191 /*    :   :   ┃          */                     __incr_cov(from!("block start"));
192 /*    :   ┃   -          */                 } else {
193 /*    :   :   ┃          */                     println!("goblin wins");
194 /*  ┏-:---:---<          */                     return { let __result = Ok(()); __incr_cov(from!("`else`")); __result }; // THIS COUNTS LAST STATEMENT IN `else` BLOCK
195 /*  V :   :   :          */                     // COVERAGE NOTE: When counting the span for `return`,
196 /*    :   :   :          */                     // `break`, or `continue`, also report the outer spans
197 /*    :   :   :          */                     // got this far--including this `else` block. Record
198 /*    :   :   :          */                     // The start positions for those outer blocks, but:
199 /*    :   :   :          */                     // * For the block containing the `return`, `break`, or
200 /*    :   :   :          */                     //   `continue`, end report the end position is the
201 /*    :   :   :          */                     //   start of the `return` span (or 1 char before it).
202 /*    :   :   :          */                     // * Anything else?
203 /*    :   ┃   -          */                 }
204 /*    :   ┃   -          */                 // __incr_cov(from!("")); // DO NOT COUNT HERE IF NO STATEMENTS AFTER LAST `if` or `match`
205 /*    :   -              */             },
206 /*    :   I              */             Blue => { println!("violets"); __incr_cov(from!("Blue => or end of MatchArmGuard expression inside pattern, if any")); }
207 /*    ┃                  */         }
208 /*    ┃                  */
209 /*    ┃                  */         let condition1 = true;
210 /*    ┃                  */         let condition2 = false;
211 /*    ┃                  */         let condition3 = true;
212 /*    ┃                  */
213 /*    ┃                  */         println!("Called `various()` for TestStruct with field={}", self.field);
214 /*    ┃                  */
215 /*    ┃   -              */         if { let __result = condition1; __incr_cov(from!("after block end of prior `match` (or `if-else if-else`)")); __result } {
216 /*    :   ┃              */             println!("before for loop");
217 /*    :   ┃   -          */             for index in { let __result = 0..10; __incr_cov(from!("block start")); __result } {
218 /*    :   :   ┃          */                 println!("top of `for` loop");
219 /*    :   :   ┃   -      */                 if { let __result = index == 8; __incr_cov(from!("block start")); __result } {
220 /*    :   :   :   ┃      */                     println!("before break");
221 /*    :   :   :   ┃      */                     // note the following is not legal here:
222 /*    :   :   :   ┃      */                     //   "can only break with a value inside `loop` or breakable block"
223 /*    :   :   :   ┃      */                     // break __incr_cov(from!(""));
224 /*    :   :   :   ┃      */                     __incr_cov(from!("block start"));
225 /*    :   : ┏-----<      */                     break;
226 /*    :   : V :   :      */
227 /*    :   :   :   :      */                     // FIXME(richkadel): add examples with loop labels, breaking out of inner and outer loop to outer loop label, with expression.
228 /*    :   :   :   :      */                     // May want to record both the span and the start position after the broken out block depdnding on label
229 /*    :   :   ┃   -      */                 }
230 /*    :   :   ┃          */                 println!("after `break` test");
231 /*    :   :   ┃   -      */                 if { let __result = condition2; __incr_cov(from!("block end of `if index == 8`")); __result } {
232 /*  ┏-:---:---:---<      */                     return { let __result = Ok(()); __incr_cov(from!("block start")); __result };
233 /*  V :   :   ┃   -      */                 }
234 /*    :   :   ┃          */
235 /*    :   :   ┃          */                 // BECAUSE THE PREVIOUS COVERAGE REGION HAS A `return`, THEN
236 /*    :   :   ┃          */                 // IF PREVIOUS COVERAGE REGION IS NOT COUNTED THEN OUTER REGION REACHED HERE.
237 /*    :   :   ┃          */                 // ADD A COVERAGE REGION FOR THE SPAN FROM JUST AFTER PREVIOUS REGION TO END
238 /*    :   :   ┃          */                 // OF OUTER SPAN, THEN TRUNCATE TO NEXT REGION NOT REACHED.
239 /*    :   :   ┃   -      */                 if index % 3 == 2 { // NO __incr_cov() HERE BECAUSE NO STATEMENTS BETWEEN LAST CONDITIONAL BLOCK AND START OF THIS ONE
240 /*    :   : Λ :   ┃      */                     __incr_cov(from!("block end of `if condition2`"));
241 /*    :   : ┗-----<      */                     continue;
242 /*    :   :   ┃   -      */                 }
243 /*    :   :   ┃          */                 println!("after `continue` test");
244 /*    :   :   ┃          */                 // maybe add a runtime flag for a possible `return` here?
245 /*    :   :   ┃          */                 __incr_cov(from!(""));
246 /*    :   ┃   -          */             }
247 /*    :   ┃              */             println!("after for loop");
248 /*    :   ┃              */             let result = if { // START OF NEW CONDITIONAL EXPRESSION. NEXT "GUARANTEED" COUNTER SHOULD COUNT FROM END OF LAST CONDITIONAL EXPRESSION
249 /*    :   ┃              */                               // A "GUARANTEED" COUNTER CALL IS ONE THAT WILL BE CALLED REGARDLESS OF OTHER CONDITIONS. THIS INCLUDES:
250 /*    :   ┃              */                               //   * A CONDITIONAL EXPRESSION THAT IS NOT A BLOCK (OR ANOTHER CONDITIONAL STATEMENT, WHICH WOULD CONTAIN A BLOCK)
251 /*    :   ┃              */                               //   * OR IF THE NEXT CONDITIONAL EXPRESSION IS A BLOCK OR CONDITIONAL STATEMENT, THEN THE FIRST "GUARANTEED" COUNTER IN THAT BLOCK
252 /*    :   ┃              */                               //   * END OF BLOCK IF THE BLOCK DOES NOT HAVE INNER CONDITIONAL EXPRESSIONS
253 /*    :   ┃              */                               //   * BRANCHING STATEMENTS (`return`, `break`, `continue`) BY EITHER WRAPPING THE BRANCH STATEMENT NON-BLOCK EXPRESSION,
254 /*    :   ┃              */                               //     OR PREPENDING A COUNTER WITH EMPTY TUPLE IF NO EXPRESSION, OR IF EXPRESSION IS A BLOCK, THEN THE NEXT "GUARANTEED"
255 /*    :   ┃              */                               //     COUNTER CALL WITHIN THAT BLOCK.
256 /*    :   ┃              */                               //   BASICALLY, CARRY THE START OF COVERAGE SPAN FORWARD UNTIL THE GUARANTEED COUNTER IS FOUND
257 /*    :   ┃              */                 println!("after result = if ...");
258 /*    :   ┃       -      */                 if { let __result = condition2; __incr_cov(from!("block end of `for` loop")); __result } {
259 /*    :   :       ┃      */                     println!("before first return");
260 /*  ┏-:---:-------<      */                     return { let __result = Ok(()); __incr_cov(from!("block start")); __result };
261 /*  V :   :       -      */                 } else if { let __result = condition3; __incr_cov(from!("`else`")); __result } {
262 /*    :   :       ┃      */                     // THE ABOVE COUNTER IS _NOT_ REALLY NECESSARY IF EXPRESSION IS GUARANTEED TO EXECUTE.
263 /*    :   :       ┃      */                     // IF WE GET COUNTER IN `else if` BLOCK WE COVERED EXPRESSION.
264 /*    :   :       ┃      */                     // IF WE GET TO ANY REMAINING `else` or `else if` BLOCK WE KNOW WE EVALUATED THIS CONDITION
265 /*    :   :       ┃      */                     // AND ALL OTHERS UP TO THE EXECUTED BLOCK. BUT THE SPAN WOULD HAVE "HOLES" FOR UNEXECUTED BLOCKS.
266 /*    :   :       ┃      */                     println!("not second return");
267 /*  ┏-:---:-------<      */                     return { let __result = Ok(()); __incr_cov(from!("block start")); __result };
268 /*  V :   :       -      */                 } else {
269 /*    :   :       ┃      */                     println!("not returning");
270 /*    :   :       ┃      */                     { let __result = false; __incr_cov(from!("block start")); __result }
271 /*    :   :       -      */                 }
272 /*    :   ┃              */                 // NO COUNTER HERE BECAUSE NO STATEMENTS AFTER CONDITIONAL BLOCK
273 /*    :   ┃   -          */             } {
274 /*    :   :   ┃          */                 println!("branched condition returned true");
275 /*    :   :   ┃          */                 { let __result = Ok(()); __incr_cov(from!("")); __result }
276 /*    :   ┃   -          */             } else if self.call_closure(
277 /*    :   :       -      */                     |closure_param| {
278 /*    :   :       ┃   -  */                         let __result = if condition3 {
279 /*    :   :       :   ┃  */                             println!("in closure, captured condition said to print the param {}", closure_param);
280 /*    :   :       :   ┃  */                             { let __result = false; __incr_cov(from!("")); __result }
281 /*    :   :       ┃   -  */                         } else {
282 /*    :   :       :   ┃  */                             println!("in closure, captured condition was false");
283 /*    :   :       :   ┃  */                             { let __result = true; __incr_cov(from!("")); __result }
284 /*    :   :       ┃   -  */                         };
285 /*    :   :       -      */                         __incr_cov(from!("")); __result }
286 /*    :   :   -          */                 ) {
287 /*    :   :   ┃          */                 println!("closure returned true");
288 /*    :   :   ┃          */                 { let __result = Err(Error::new(ErrorKind::Other, "Result is error if closure returned true")); __incr_cov(from!("")); __result }
289 /*    :   ┃   -          */             } else {
290 /*    :   :   ┃          */                 println!("closure returned false");
291 /*    :   :   ┃          */                 { let __result = Err(Error::new(ErrorKind::Other, "Result is error if closure returned false")); __incr_cov(from!("")); __result }
292 /*    :   ┃   -          */             };
293 /*    :   ┃              */             println!("bottom of function might be skipped if early `return`");
294 /*    :   ┃              */             { let __result = result; __incr_cov(from!("if condition1")); __result }
295 /*    ┃   -              */         } else {
296 /*    :   ┃              */             println!("skipping everything in `various()`");
297 /*    :   ┃              */             { let __result = Ok(()); __incr_cov(from!("")); __result }
298 /*    ┃   -              */         }
299 /*    ┃   -              */         // __incr_cov(from!(""),0) // DO NOT COUNT IF NO STATEMENTS AFTER CONDITIONAL BLOCK. ALL COVERAGE IS ALREADY COUNTED
300 /*    -                  */     }
301 /*                       */ }
302 /*                       */
303 /*    -                  */ fn main() -> Result<(), std::io::Error> {
304 /*    ┃                  */     //let mut status: u8 = 2;
305 /*    ┃                  */     let mut status: u8 = 1;
306 /*    :       -          */     let result = if status < 2 &&
307 /*    :       ┃          */             { let __result = {
308 /*    :       ┃          */                 status -= 1;
309 /*    :       ┃          */                 status == 0
310 /*    :   -   -          */             }; __incr_cov(from!("")); __result } {
311 /*    :   ┃              */         let test_struct = TestStruct::new_with_value(100);
312 /*    :   ┃              */         let _ = test_struct.various();
313 /*  ┏-:---<              */         return { let __result = Err(Error::new(ErrorKind::Other, format!("Error status {}", status))); __incr_cov(from!("")); __report(); __result }
314 /*  V :   -              */     } else {
315 /*    :   ┃              */         let test_struct = TestStruct::new();
316 /*    :   ┃              */         { let __result = test_struct.various(); __incr_cov(from!("")); __result }
317 /*    :   -              */     };
318 /*    ┃                  */     println!("done");
319 /*    ┃                  */     { let __result = result; __incr_cov(from!("")); __report(); __result }
320 /*    -                  */ }