--- tags: decompiler --- # Initial target block selection Original file (fig 1): ![](https://i.imgur.com/jCyIfL8.png) Full error output (fig 2): ![](https://i.imgur.com/E9oHec9.png) CFG (fig 3): ![](https://i.imgur.com/3tZELu3.png) For initial target block selection, we first parse the error from uncompyle6 (fig 2) to pin point the initial instruction where the decompiler fails. From the error, we find the offset and the function name where the decompiler fails to parse. Using this information, we know the exact instruction to start from and so in cfg we mark the initial target block as shown in figure 3. ## Realistic example 1: ```python= import os def _resolve_relative_to(path, original_root, new_root): """ If the given ``path`` is a relative path, then assume it is relative to ``original_root``. This method will update the path to be resolve it relative to ``new_root`` and return. Examples ------- # Assume a file called template.txt at location /tmp/original/root/template.txt expressed as relative path # We are trying to update it to be relative to /tmp/new/root instead of the /tmp/original/root >>> result = _resolve_relative_to("template.txt", \ "/tmp/original/root", \ "/tmp/new/root") >>> result ../../original/root/template.txt Returns ------- Updated path if the given path is a relative path. None, if the path is not a relative path. """ if ( not isinstance(path, str) or path.startswith("s3://") or path.startswith("http://") or path.startswith("https://") or os.path.isabs(path) ): # Value is definitely NOT a relative path. It is either a S3 URi or Absolute path or not a string at all return None # Value is definitely a relative path. Change it relative to the destination directory return os.path.relpath( os.path.normpath(os.path.join(original_root, path)), new_root # Absolute original path w.r.t ``original_root`` ) # Resolve the original path with respect to ``new_root`` ``` full output: ```python= # uncompyle6 version 3.7.4 # Python bytecode 3.7 (3394) # Decompiled from: Python 3.7.11 (default, Jun 29 2021, 20:31:06) # [GCC 8.3.0] # Embedded file name: samples/target_py/main.py # Compiled at: 2021-10-02 16:01:17 # Size of source mod 2**32: 1513 bytes import os def _resolve_relative_to--- This code section failed: --- L. 24 0 LOAD_GLOBAL isinstance 2 LOAD_FAST 'path' 4 LOAD_GLOBAL str 6 CALL_FUNCTION_2 2 '2 positional arguments' 8 POP_JUMP_IF_FALSE 52 'to 52' L. 25 10 LOAD_FAST 'path' 12 LOAD_METHOD startswith 14 LOAD_STR 's3://' 16 CALL_METHOD_1 1 '1 positional argument' 18 POP_JUMP_IF_TRUE 52 'to 52' L. 26 20 LOAD_FAST 'path' 22 LOAD_METHOD startswith 24 LOAD_STR 'http://' 26 CALL_METHOD_1 1 '1 positional argument' 28 POP_JUMP_IF_TRUE 52 'to 52' L. 27 30 LOAD_FAST 'path' 32 LOAD_METHOD startswith 34 LOAD_STR 'https://' 36 CALL_METHOD_1 1 '1 positional argument' 38 POP_JUMP_IF_TRUE 52 'to 52' L. 28 40 LOAD_GLOBAL os 42 LOAD_ATTR path 44 LOAD_METHOD isabs 46 LOAD_FAST 'path' 48 CALL_METHOD_1 1 '1 positional argument' 50 POP_JUMP_IF_FALSE 56 'to 56' 52_0 COME_FROM 38 '38' 52_1 COME_FROM 28 '28' 52_2 COME_FROM 18 '18' 52_3 COME_FROM 8 '8' L. 31 52 LOAD_CONST None 54 RETURN_VALUE 56_0 COME_FROM 50 '50' L. 34 56 LOAD_GLOBAL os 58 LOAD_ATTR path 60 LOAD_METHOD relpath L. 35 62 LOAD_GLOBAL os 64 LOAD_ATTR path 66 LOAD_METHOD normpath 68 LOAD_GLOBAL os 70 LOAD_ATTR path 72 LOAD_METHOD join 74 LOAD_FAST 'original_root' 76 LOAD_FAST 'path' 78 CALL_METHOD_2 2 '2 positional arguments' 80 CALL_METHOD_1 1 '1 positional argument' 82 LOAD_FAST 'new_root' 84 CALL_METHOD_2 2 '2 positional arguments' 86 RETURN_VALUE -1 RETURN_LAST Parse error at or near `RETURN_VALUE' instruction at offset 86 ``` CFG of function: ![](https://i.imgur.com/PAck9tT.png) ## Realistic example 2: MWE: https://hackmd.io/@aliahad97/BJNrSJ0pd#Error-152 ```python= import pandas as pd NoneType = type(None) def convert(column, field_type='STRING', mode='NULLABLE', fields=[], infer_required=False): field_type = field_type.upper() mode = mode.upper() if field_type == 'INTEGER': converted_column = [ to_integer(value, mode, infer_required) for value in column ] elif field_type == 'STRING': converted_column = [ to_string(value, mode, infer_required) for value in column ] elif field_type == 'NUMERIC': converted_column = [ to_numeric(value, mode, infer_required) for value in column ] elif field_type == 'FLOAT': converted_column = [ to_float(value, mode, infer_required) for value in column ] elif field_type == 'BOOLEAN': converted_column = [ to_boolean(value, mode, infer_required) for value in column ] elif field_type == 'BYTES': converted_column = [ to_bytes(value, mode, infer_required) for value in column ] elif field_type == 'DATETIME': converted_column = [ to_datetime(value, mode, infer_required) for value in column ] elif field_type == 'DATE': converted_column = [ to_date(value, mode, infer_required) for value in column ] elif field_type == 'TIME': converted_column = [ to_time(value, mode, infer_required) for value in column ] elif field_type == 'TIMESTAMP': converted_column = [ to_timestamp(value, mode, infer_required) for value in column ] elif field_type in ['STRUCT', 'RECORD']: if not fields: raise ValueError('Fields must be provided for STRUCT/RECORD') if mode == 'REPEATED': if not isinstance(column[0], list): raise ValueError('For REPEATED mode in STRUCT/RECORD a list of dicts must be provided for each row') converted_column = [] for r in column: columns = pd.DataFrame(r).to_dict('list') output = {} for f in fields: output[f.name] = convert(columns.get(f.name, []), f.field_type, f.mode, f.fields) converted_column.append(pd.DataFrame(output).to_dict('records')) elif mode == 'NULLABLE': if not isinstance(column[0], dict): raise ValueError('For NULLABLE mode in STRUCT/RECORD only one dict is accepted per row') columns = pd.DataFrame(column).to_dict('list') output = {} for f in fields: output[f.name] = convert(columns.get(f.name, []), f.field_type, f.mode, f.fields) converted_column = pd.DataFrame(output).to_dict('records') elif field_type in ['ARRAY', 'GEOGRAPHY']: raise NotImplementedError('Types ARRAY and GEOGRAPHY are not yet implemented.') else: raise ValueError('{} not a valid field_type.'.format(field_type)) return converted_column ``` Full output: ``` # uncompyle6 version 3.7.4 # Python bytecode 3.7 (3394) # Decompiled from: Python 3.7.11 (default, Jun 29 2021, 20:31:06) # [GCC 8.3.0] # Embedded file name: samples/target_py/main.py # Compiled at: 2021-10-02 20:58:27 # Size of source mod 2**32: 3053 bytes import pandas as pd NoneType = type(None) def convert--- This code section failed: --- L. 5 0 LOAD_FAST 'field_type' 2 LOAD_METHOD upper 4 CALL_METHOD_0 0 '0 positional arguments' 6 STORE_FAST 'field_type' L. 6 8 LOAD_DEREF 'mode' 10 LOAD_METHOD upper 12 CALL_METHOD_0 0 '0 positional arguments' 14 STORE_DEREF 'mode' L. 8 16 LOAD_FAST 'field_type' 18 LOAD_STR 'INTEGER' 20 COMPARE_OP == 22 POP_JUMP_IF_FALSE 48 'to 48' L. 10 24 LOAD_CLOSURE 'infer_required' 26 LOAD_CLOSURE 'mode' 28 BUILD_TUPLE_2 2 30 LOAD_LISTCOMP '<code_object <listcomp>>' 32 LOAD_STR 'convert.<locals>.<listcomp>' 34 MAKE_FUNCTION_8 'closure' 36 LOAD_FAST 'column' 38 GET_ITER 40 CALL_FUNCTION_1 1 '1 positional argument' 42 STORE_FAST 'converted_column' 44_46 JUMP_FORWARD 674 'to 674' 48_0 COME_FROM 22 '22' L. 12 48 LOAD_FAST 'field_type' 50 LOAD_STR 'STRING' 52 COMPARE_OP == 54 POP_JUMP_IF_FALSE 80 'to 80' L. 14 56 LOAD_CLOSURE 'infer_required' 58 LOAD_CLOSURE 'mode' 60 BUILD_TUPLE_2 2 62 LOAD_LISTCOMP '<code_object <listcomp>>' 64 LOAD_STR 'convert.<locals>.<listcomp>' 66 MAKE_FUNCTION_8 'closure' 68 LOAD_FAST 'column' 70 GET_ITER 72 CALL_FUNCTION_1 1 '1 positional argument' 74 STORE_FAST 'converted_column' 76_78 JUMP_FORWARD 674 'to 674' 80_0 COME_FROM 54 '54' L. 16 80 LOAD_FAST 'field_type' 82 LOAD_STR 'NUMERIC' 84 COMPARE_OP == 86 POP_JUMP_IF_FALSE 112 'to 112' L. 18 88 LOAD_CLOSURE 'infer_required' 90 LOAD_CLOSURE 'mode' 92 BUILD_TUPLE_2 2 94 LOAD_LISTCOMP '<code_object <listcomp>>' 96 LOAD_STR 'convert.<locals>.<listcomp>' 98 MAKE_FUNCTION_8 'closure' 100 LOAD_FAST 'column' 102 GET_ITER 104 CALL_FUNCTION_1 1 '1 positional argument' 106 STORE_FAST 'converted_column' 108_110 JUMP_FORWARD 674 'to 674' 112_0 COME_FROM 86 '86' L. 20 112 LOAD_FAST 'field_type' 114 LOAD_STR 'FLOAT' 116 COMPARE_OP == 118 POP_JUMP_IF_FALSE 144 'to 144' L. 22 120 LOAD_CLOSURE 'infer_required' 122 LOAD_CLOSURE 'mode' 124 BUILD_TUPLE_2 2 126 LOAD_LISTCOMP '<code_object <listcomp>>' 128 LOAD_STR 'convert.<locals>.<listcomp>' 130 MAKE_FUNCTION_8 'closure' 132 LOAD_FAST 'column' 134 GET_ITER 136 CALL_FUNCTION_1 1 '1 positional argument' 138 STORE_FAST 'converted_column' 140_142 JUMP_FORWARD 674 'to 674' 144_0 COME_FROM 118 '118' L. 24 144 LOAD_FAST 'field_type' 146 LOAD_STR 'BOOLEAN' 148 COMPARE_OP == 150 POP_JUMP_IF_FALSE 176 'to 176' L. 26 152 LOAD_CLOSURE 'infer_required' 154 LOAD_CLOSURE 'mode' 156 BUILD_TUPLE_2 2 158 LOAD_LISTCOMP '<code_object <listcomp>>' 160 LOAD_STR 'convert.<locals>.<listcomp>' 162 MAKE_FUNCTION_8 'closure' 164 LOAD_FAST 'column' 166 GET_ITER 168 CALL_FUNCTION_1 1 '1 positional argument' 170 STORE_FAST 'converted_column' 172_174 JUMP_FORWARD 674 'to 674' 176_0 COME_FROM 150 '150' L. 28 176 LOAD_FAST 'field_type' 178 LOAD_STR 'BYTES' 180 COMPARE_OP == 182 POP_JUMP_IF_FALSE 208 'to 208' L. 30 184 LOAD_CLOSURE 'infer_required' 186 LOAD_CLOSURE 'mode' 188 BUILD_TUPLE_2 2 190 LOAD_LISTCOMP '<code_object <listcomp>>' 192 LOAD_STR 'convert.<locals>.<listcomp>' 194 MAKE_FUNCTION_8 'closure' 196 LOAD_FAST 'column' 198 GET_ITER 200 CALL_FUNCTION_1 1 '1 positional argument' 202 STORE_FAST 'converted_column' 204_206 JUMP_FORWARD 674 'to 674' 208_0 COME_FROM 182 '182' L. 32 208 LOAD_FAST 'field_type' 210 LOAD_STR 'DATETIME' 212 COMPARE_OP == 214 POP_JUMP_IF_FALSE 240 'to 240' L. 34 216 LOAD_CLOSURE 'infer_required' 218 LOAD_CLOSURE 'mode' 220 BUILD_TUPLE_2 2 222 LOAD_LISTCOMP '<code_object <listcomp>>' 224 LOAD_STR 'convert.<locals>.<listcomp>' 226 MAKE_FUNCTION_8 'closure' 228 LOAD_FAST 'column' 230 GET_ITER 232 CALL_FUNCTION_1 1 '1 positional argument' 234 STORE_FAST 'converted_column' 236_238 JUMP_FORWARD 674 'to 674' 240_0 COME_FROM 214 '214' L. 36 240 LOAD_FAST 'field_type' 242 LOAD_STR 'DATE' 244 COMPARE_OP == 246_248 POP_JUMP_IF_FALSE 274 'to 274' L. 38 250 LOAD_CLOSURE 'infer_required' 252 LOAD_CLOSURE 'mode' 254 BUILD_TUPLE_2 2 256 LOAD_LISTCOMP '<code_object <listcomp>>' 258 LOAD_STR 'convert.<locals>.<listcomp>' 260 MAKE_FUNCTION_8 'closure' 262 LOAD_FAST 'column' 264 GET_ITER 266 CALL_FUNCTION_1 1 '1 positional argument' 268 STORE_FAST 'converted_column' 270_272 JUMP_FORWARD 674 'to 674' 274_0 COME_FROM 246 '246' L. 40 274 LOAD_FAST 'field_type' 276 LOAD_STR 'TIME' 278 COMPARE_OP == 280_282 POP_JUMP_IF_FALSE 308 'to 308' L. 42 284 LOAD_CLOSURE 'infer_required' 286 LOAD_CLOSURE 'mode' 288 BUILD_TUPLE_2 2 290 LOAD_LISTCOMP '<code_object <listcomp>>' 292 LOAD_STR 'convert.<locals>.<listcomp>' 294 MAKE_FUNCTION_8 'closure' 296 LOAD_FAST 'column' 298 GET_ITER 300 CALL_FUNCTION_1 1 '1 positional argument' 302 STORE_FAST 'converted_column' 304_306 JUMP_FORWARD 674 'to 674' 308_0 COME_FROM 280 '280' L. 44 308 LOAD_FAST 'field_type' 310 LOAD_STR 'TIMESTAMP' 312 COMPARE_OP == 314_316 POP_JUMP_IF_FALSE 342 'to 342' L. 46 318 LOAD_CLOSURE 'infer_required' 320 LOAD_CLOSURE 'mode' 322 BUILD_TUPLE_2 2 324 LOAD_LISTCOMP '<code_object <listcomp>>' 326 LOAD_STR 'convert.<locals>.<listcomp>' 328 MAKE_FUNCTION_8 'closure' 330 LOAD_FAST 'column' 332 GET_ITER 334 CALL_FUNCTION_1 1 '1 positional argument' 336 STORE_FAST 'converted_column' 338_340 JUMP_FORWARD 674 'to 674' 342_0 COME_FROM 314 '314' L. 48 342 LOAD_FAST 'field_type' 344 LOAD_CONST ('STRUCT', 'RECORD') 346 COMPARE_OP in 348_350 POP_JUMP_IF_FALSE 640 'to 640' L. 49 352 LOAD_FAST 'fields' 354_356 POP_JUMP_IF_TRUE 366 'to 366' L. 50 358 LOAD_GLOBAL ValueError 360 LOAD_STR 'Fields must be provided for STRUCT/RECORD' 362 CALL_FUNCTION_1 1 '1 positional argument' 364 RAISE_VARARGS_1 1 'exception instance' 366_0 COME_FROM 354 '354' L. 51 366 LOAD_DEREF 'mode' 368 LOAD_STR 'REPEATED' 370 COMPARE_OP == 372_374 POP_JUMP_IF_FALSE 516 'to 516' L. 52 376 LOAD_GLOBAL isinstance 378 LOAD_FAST 'column' 380 LOAD_CONST 0 382 BINARY_SUBSCR 384 LOAD_GLOBAL list 386 CALL_FUNCTION_2 2 '2 positional arguments' 388_390 POP_JUMP_IF_TRUE 400 'to 400' L. 53 392 LOAD_GLOBAL ValueError 394 LOAD_STR 'For REPEATED mode in STRUCT/RECORD a list of dicts must be provided for each row' 396 CALL_FUNCTION_1 1 '1 positional argument' 398 RAISE_VARARGS_1 1 'exception instance' 400_0 COME_FROM 388 '388' L. 54 400 BUILD_LIST_0 0 402 STORE_FAST 'converted_column' L. 55 404 SETUP_LOOP 638 'to 638' 406 LOAD_FAST 'column' 408 GET_ITER 410 FOR_ITER 512 'to 512' 412 STORE_FAST 'r' L. 56 414 LOAD_GLOBAL pd 416 LOAD_METHOD DataFrame 418 LOAD_FAST 'r' 420 CALL_METHOD_1 1 '1 positional argument' 422 LOAD_METHOD to_dict 424 LOAD_STR 'list' 426 CALL_METHOD_1 1 '1 positional argument' 428 STORE_FAST 'columns' L. 57 430 BUILD_MAP_0 0 432 STORE_FAST 'output' L. 58 434 SETUP_LOOP 486 'to 486' 436 LOAD_FAST 'fields' 438 GET_ITER 440 FOR_ITER 484 'to 484' 442 STORE_FAST 'f' L. 59 444 LOAD_GLOBAL convert 446 LOAD_FAST 'columns' 448 LOAD_METHOD get 450 LOAD_FAST 'f' 452 LOAD_ATTR name 454 BUILD_LIST_0 0 456 CALL_METHOD_2 2 '2 positional arguments' 458 LOAD_FAST 'f' 460 LOAD_ATTR field_type 462 LOAD_FAST 'f' 464 LOAD_ATTR mode 466 LOAD_FAST 'f' 468 LOAD_ATTR fields 470 CALL_FUNCTION_4 4 '4 positional arguments' 472 LOAD_FAST 'output' 474 LOAD_FAST 'f' 476 LOAD_ATTR name 478 STORE_SUBSCR 480_482 JUMP_BACK 440 'to 440' 484 POP_BLOCK 486_0 COME_FROM_LOOP 434 '434' L. 60 486 LOAD_FAST 'converted_column' 488 LOAD_METHOD append 490 LOAD_GLOBAL pd 492 LOAD_METHOD DataFrame 494 LOAD_FAST 'output' 496 CALL_METHOD_1 1 '1 positional argument' 498 LOAD_METHOD to_dict 500 LOAD_STR 'records' 502 CALL_METHOD_1 1 '1 positional argument' 504 CALL_METHOD_1 1 '1 positional argument' 506 POP_TOP 508_510 JUMP_BACK 410 'to 410' 512 POP_BLOCK 514 JUMP_FORWARD 638 'to 638' 516_0 COME_FROM 372 '372' L. 61 516 LOAD_DEREF 'mode' 518 LOAD_STR 'NULLABLE' 520 COMPARE_OP == 522_524 POP_JUMP_IF_FALSE 674 'to 674' L. 62 526 LOAD_GLOBAL isinstance 528 LOAD_FAST 'column' 530 LOAD_CONST 0 532 BINARY_SUBSCR 534 LOAD_GLOBAL dict 536 CALL_FUNCTION_2 2 '2 positional arguments' 538_540 POP_JUMP_IF_TRUE 550 'to 550' L. 63 542 LOAD_GLOBAL ValueError 544 LOAD_STR 'For NULLABLE mode in STRUCT/RECORD only one dict is accepted per row' 546 CALL_FUNCTION_1 1 '1 positional argument' 548 RAISE_VARARGS_1 1 'exception instance' 550_0 COME_FROM 538 '538' L. 64 550 LOAD_GLOBAL pd 552 LOAD_METHOD DataFrame 554 LOAD_FAST 'column' 556 CALL_METHOD_1 1 '1 positional argument' 558 LOAD_METHOD to_dict 560 LOAD_STR 'list' 562 CALL_METHOD_1 1 '1 positional argument' 564 STORE_FAST 'columns' L. 65 566 BUILD_MAP_0 0 568 STORE_FAST 'output' L. 66 570 SETUP_LOOP 622 'to 622' 572 LOAD_FAST 'fields' 574 GET_ITER 576 FOR_ITER 620 'to 620' 578 STORE_FAST 'f' L. 67 580 LOAD_GLOBAL convert 582 LOAD_FAST 'columns' 584 LOAD_METHOD get 586 LOAD_FAST 'f' 588 LOAD_ATTR name 590 BUILD_LIST_0 0 592 CALL_METHOD_2 2 '2 positional arguments' 594 LOAD_FAST 'f' 596 LOAD_ATTR field_type 598 LOAD_FAST 'f' 600 LOAD_ATTR mode 602 LOAD_FAST 'f' 604 LOAD_ATTR fields 606 CALL_FUNCTION_4 4 '4 positional arguments' 608 LOAD_FAST 'output' 610 LOAD_FAST 'f' 612 LOAD_ATTR name 614 STORE_SUBSCR 616_618 JUMP_BACK 576 'to 576' 620 POP_BLOCK 622_0 COME_FROM_LOOP 570 '570' L. 68 622 LOAD_GLOBAL pd 624 LOAD_METHOD DataFrame 626 LOAD_FAST 'output' 628 CALL_METHOD_1 1 '1 positional argument' 630 LOAD_METHOD to_dict 632 LOAD_STR 'records' 634 CALL_METHOD_1 1 '1 positional argument' 636 STORE_FAST 'converted_column' 638_0 COME_FROM 514 '514' 638_1 COME_FROM_LOOP 404 '404' 638 JUMP_FORWARD 674 'to 674' 640_0 COME_FROM 348 '348' L. 70 640 LOAD_FAST 'field_type' 642 LOAD_CONST ('ARRAY', 'GEOGRAPHY') 644 COMPARE_OP in 646_648 POP_JUMP_IF_FALSE 660 'to 660' L. 71 650 LOAD_GLOBAL NotImplementedError 652 LOAD_STR 'Types ARRAY and GEOGRAPHY are not yet implemented.' 654 CALL_FUNCTION_1 1 '1 positional argument' 656 RAISE_VARARGS_1 1 'exception instance' 658 JUMP_FORWARD 674 'to 674' 660_0 COME_FROM 646 '646' L. 73 660 LOAD_GLOBAL ValueError 662 LOAD_STR '{} not a valid field_type.' 664 LOAD_METHOD format 666 LOAD_FAST 'field_type' 668 CALL_METHOD_1 1 '1 positional argument' 670 CALL_FUNCTION_1 1 '1 positional argument' 672 RAISE_VARARGS_1 1 'exception instance' 674_0 COME_FROM 658 '658' 674_1 COME_FROM 638 '638' 674_2 COME_FROM 522 '522' 674_3 COME_FROM 338 '338' 674_4 COME_FROM 304 '304' 674_5 COME_FROM 270 '270' 674_6 COME_FROM 236 '236' 674_7 COME_FROM 204 '204' 674_8 COME_FROM 172 '172' 674_9 COME_FROM 140 '140' 674_10 COME_FROM 108 '108' 674_11 COME_FROM 76 '76' 674_12 COME_FROM 44 '44' L. 74 674 LOAD_FAST 'converted_column' 676 RETURN_VALUE -1 RETURN_LAST Parse error at or near `COME_FROM_LOOP' instruction at offset 638_1 ``` # Updating target block Updated cfg (fig 4): ![](https://i.imgur.com/WbBYrhA.png) Output file (fig 5): ![](https://i.imgur.com/sQeClOf.png) To apply the fix, we first check for rules that apply to the target block itself where in the example above there are none. Then, we immediately move to the direct predecessors (parent) or successors (child) blocks and try to apply rules to match them. In the example we can see that the example matches the rule XXX, and so we apply the transformation as shown in figure 4. Diff of files (fig 6): # Regular Expression example: For fig 4, we use the following regular expression: `^([POP_JUMP_IF_FALSE:Arg_i, POP_JUMP_IF_TRUE:Arg_i].*)+[POP_JUMP_IF_FALSE:Arg_N, POP_JUMP_IF_TRUE:Arg_N]$` - Where each `POP_JUMP_IF_FALSE` corresponds to an `and` and each `POP_JUMP_IF_TRUE` corresponds to an `or`. - For each of these, the jump target is the same. - For each `Arg_i` of instructions, it is greater than the offset of `[POP_JUMP_IF_FALSE:Arg_N, POP_JUMP_IF_TRUE:Arg_N]`. - All instructions with `Arg_i` less than the offset of `[POP_JUMP_IF_FALSE:Arg_N, POP_JUMP_IF_TRUE:Arg_N]` will be ignored. - No offset of instruction will be greater than `Arg_i`. The above pattern is for a series of `b1 and/or b2 and/or ... and/or bN` where `bN`will always be before the jump target of all `POP_JUMP_IF_FALSE`/`POP_JUMP_IF_TRUE` . <!-- For the `exit_set` which mark the end of the pattern are as follows: ``` exit_set = [ 90, # name_op('STORE_NAME', 90) 95, # name_op('STORE_ATTR', 95) # Index in name list 97, # name_op('STORE_GLOBAL', 97) # "" 125, # def_op('STORE_FAST', 125) # Local variable number 83, # def_op('RETURN_VALUE', 83) 86, # def_op('YIELD_VALUE', 86) ] ``` --> # Transformation: For the transformation in the previous example, we follow the following steps. 1. Add `STORE_FAST` and `LOAD_FAST` to introduce a new local variable to store boolean result and then load it immediately for the next boolean expression. (This will be added before the last `POP_JUMP_IF_FALSE`/`POP_JUMP_IF_TRUE` marking the end of condition) 2. Convert all `POP_JUMP_IF_FALSE`/`POP_JUMP_IF_TRUE` before the instrumented instruction to `JUMP_IF_FALSE_OR_POP`/`JUMP_IF_TRUE_OR_POP` respectively to preserve boolean value for variable added. 3. Assign jump arg of all `JUMP_IF_FALSE_OR_POP`/`JUMP_IF_TRUE_OR_POP` to our newly instrumented instructions.